Upstream version 10.38.208.0 73/27873/1
authorEurogiciel-BOT <eurogiciel.tizen@gmail.com>
Mon, 22 Sep 2014 08:55:59 +0000 (08:55 +0000)
committerEurogiciel-BOT <eurogiciel.tizen@gmail.com>
Mon, 22 Sep 2014 08:55:59 +0000 (08:55 +0000)
Upstream commit-id 02c6da07e0fef51b93c12eb621e79309b0e39cb0

Change-Id: I6dcc823be744c844650431b0d54038f184f3b63f
Signed-off-by: Eurogiciel-BOT <eurogiciel.tizen@gmail.com>
932 files changed:
packaging/crosswalk.spec
src/.DEPS.git
src/DEPS
src/android_webview/android_webview.gyp
src/android_webview/browser/aw_contents_client_bridge_base.cc
src/android_webview/browser/aw_contents_client_bridge_base.h
src/android_webview/browser/aw_javascript_dialog_manager.cc
src/android_webview/browser/browser_view_renderer.cc
src/android_webview/browser/hardware_renderer.cc
src/android_webview/browser/net/aw_url_request_context_getter.cc
src/android_webview/browser/net/aw_url_request_context_getter.h
src/android_webview/browser/renderer_host/aw_render_view_host_ext.cc
src/android_webview/browser/renderer_host/aw_render_view_host_ext.h
src/android_webview/common/render_view_messages.h
src/android_webview/java/src/org/chromium/android_webview/AwAssets.java
src/android_webview/java/src/org/chromium/android_webview/AwContents.java
src/android_webview/javatests/src/org/chromium/android_webview/test/AwJavaBridgeTest.java [new file with mode: 0644]
src/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
src/android_webview/lib/main/webview_entry_point.cc
src/android_webview/native/aw_contents.cc
src/android_webview/native/aw_contents.h
src/android_webview/native/aw_contents_client_bridge.cc
src/android_webview/renderer/aw_content_renderer_client.cc
src/android_webview/renderer/aw_content_renderer_client.h
src/android_webview/renderer/aw_execution_termination_filter.cc [deleted file]
src/android_webview/renderer/aw_execution_termination_filter.h [deleted file]
src/ash/display/display_controller.cc
src/ash/shell.cc
src/ash/system/web_notification/ash_popup_alignment_delegate.cc
src/ash/system/web_notification/web_notification_tray.cc
src/ash/wm/ash_native_cursor_manager.cc
src/ash/wm/ash_native_cursor_manager_unittest.cc
src/ash/wm/lock_layout_manager_unittest.cc
src/ash/wm/lock_window_state.cc
src/base/BUILD.gn
src/base/android/base_jni_registrar.cc
src/base/android/java/src/org/chromium/base/ContentUriUtils.java
src/base/android/java/src/org/chromium/base/JNIUtils.java [new file with mode: 0644]
src/base/android/java/src/org/chromium/base/library_loader/Linker.java
src/base/android/jni_android.cc
src/base/android/jni_android.h
src/base/android/jni_generator/golden_sample_for_tests_jni.h
src/base/android/jni_generator/jni_generator.py
src/base/android/jni_generator/testCalledByNatives.golden
src/base/android/jni_generator/testConstantsFromJavaP.golden
src/base/android/jni_generator/testEagerCalledByNativesOption.golden
src/base/android/jni_generator/testFromJavaP.golden
src/base/android/jni_generator/testFromJavaPGenerics.golden
src/base/android/jni_generator/testInnerClassNatives.golden
src/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
src/base/android/jni_generator/testInnerClassNativesMultiple.golden
src/base/android/jni_generator/testJNIInitNativeNameOption.golden
src/base/android/jni_generator/testJarJarRemapping.golden
src/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
src/base/android/jni_generator/testNativeExportsOption.golden
src/base/android/jni_generator/testNatives.golden
src/base/android/jni_generator/testNativesLong.golden
src/base/android/jni_generator/testPureNativeMethodsOption.golden
src/base/android/jni_generator/testSingleJNIAdditionalImport.golden
src/base/android/jni_utils.cc [new file with mode: 0644]
src/base/android/jni_utils.h [new file with mode: 0644]
src/base/android/linker/linker_jni.cc
src/base/base.gyp
src/base/base.gypi
src/base/mac/sdk_forward_declarations.h
src/base/mac/sdk_forward_declarations.mm
src/base/message_loop/incoming_task_queue.cc
src/base/message_loop/incoming_task_queue.h
src/base/message_loop/message_loop.cc
src/base/message_loop/message_loop.h
src/base/message_loop/message_loop_unittest.cc
src/base/message_loop/message_pump.h
src/base/pending_task.cc
src/base/pending_task.h
src/base/time/time.h
src/base/time/time_win.cc
src/base/timer/hi_res_timer_manager_unittest.cc
src/build/util/LASTCHANGE
src/build/util/LASTCHANGE.blink
src/cc/base/tiling_data.cc
src/cc/base/tiling_data.h
src/cc/base/tiling_data_unittest.cc
src/cc/layers/layer_impl.cc
src/cc/layers/picture_layer.cc
src/cc/layers/picture_layer_impl.cc
src/cc/layers/picture_layer_impl.h
src/cc/layers/picture_layer_impl_unittest.cc
src/cc/resources/picture_layer_tiling.cc
src/cc/resources/picture_layer_tiling.h
src/cc/resources/picture_layer_tiling_unittest.cc
src/cc/resources/picture_pile.cc
src/cc/resources/picture_pile_base.cc
src/cc/resources/picture_pile_base.h
src/cc/resources/picture_pile_unittest.cc
src/cc/resources/pixel_buffer_raster_worker_pool.cc
src/cc/resources/prioritized_tile_set.cc
src/cc/resources/raster_worker_pool_unittest.cc
src/cc/resources/resource_provider.cc
src/cc/resources/tile.h
src/cc/resources/tile_manager.h
src/cc/resources/video_resource_updater.cc
src/cc/test/fake_picture_layer_impl.h
src/cc/test/fake_picture_layer_tiling_client.cc
src/cc/test/fake_picture_layer_tiling_client.h
src/cc/test/test_in_process_context_provider.cc
src/cc/trees/layer_tree_host_impl.cc
src/cc/trees/layer_tree_host_impl.h
src/cc/trees/layer_tree_host_impl_unittest.cc
src/cc/trees/layer_tree_impl.cc
src/cc/trees/layer_tree_impl.h
src/cc/trees/thread_proxy.cc
src/chrome/VERSION
src/chrome/android/java/res/anim/menu_enter.xml
src/chrome/android/java/res/values-sw600dp/dimens.xml
src/chrome/android/java/res/values/dimens.xml
src/chrome/android/java/src/org/chromium/chrome/browser/EmptyTabObserver.java
src/chrome/android/java/src/org/chromium/chrome/browser/FileProviderHelper.java [new file with mode: 0644]
src/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
src/chrome/android/java/src/org/chromium/chrome/browser/TabObserver.java
src/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
src/chrome/android/java/src/org/chromium/chrome/browser/profiles/Profile.java
src/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
src/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
src/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelBase.java
src/chrome/android/shell/java/AndroidManifest.xml
src/chrome/android/shell/java/src/org/chromium/chrome/shell/ChromeShellActivity.java
src/chrome/android/shell/res/xml/file_paths.xml [new file with mode: 0644]
src/chrome/app/app-Info.plist
src/chrome/app/chromium_strings.grd
src/chrome/app/generated_resources.grd
src/chrome/app/google_chrome_strings.grd
src/chrome/app/resources/locale_settings_chromiumos.grd
src/chrome/app/resources/locale_settings_google_chromeos.grd
src/chrome/app/resources/platform_locale_settings/locale_settings_cros_ja.xtb
src/chrome/app/resources/platform_locale_settings/locale_settings_cros_ko.xtb
src/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-CN.xtb
src/chrome/app/resources/platform_locale_settings/locale_settings_cros_zh-TW.xtb
src/chrome/browser/about_flags.cc
src/chrome/browser/android/dev_tools_server.cc
src/chrome/browser/android/most_visited_sites.cc
src/chrome/browser/android/most_visited_sites.h
src/chrome/browser/android/tab_android.cc
src/chrome/browser/android/tab_android.h
src/chrome/browser/app_controller_mac.mm
src/chrome/browser/autocomplete/keyword_extensions_delegate_impl.cc
src/chrome/browser/autofill/autofill_server_browsertest.cc
src/chrome/browser/chrome_browser_main.cc
src/chrome/browser/chrome_browser_main_linux.cc
src/chrome/browser/chrome_browser_main_linux.h
src/chrome/browser/chromeos/boot_times_loader.cc
src/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
src/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
src/chrome/browser/chromeos/login/chrome_restart_request.cc
src/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
src/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h
src/chrome/browser/chromeos/login/existing_user_controller.cc
src/chrome/browser/chromeos/login/screens/chrome_user_selection_screen.cc
src/chrome/browser/chromeos/login/screens/chrome_user_selection_screen.h
src/chrome/browser/chromeos/login/screens/user_selection_screen.cc
src/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
src/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
src/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
src/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
src/chrome/browser/chromeos/policy/server_backed_state_keys_broker.cc
src/chrome/browser/chromeos/policy/server_backed_state_keys_broker.h
src/chrome/browser/chromeos/policy/server_backed_state_keys_broker_unittest.cc
src/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
src/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
src/chrome/browser/chromeos/system/input_device_settings.cc
src/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
src/chrome/browser/chromeos/system_logs/debug_daemon_log_source.h
src/chrome/browser/component_updater/widevine_cdm_component_installer.cc
src/chrome/browser/devtools/device/adb/adb_client_socket.cc
src/chrome/browser/devtools/device/adb/adb_client_socket.h
src/chrome/browser/devtools/device/android_device_manager.cc
src/chrome/browser/devtools/device/android_device_manager.h
src/chrome/browser/devtools/device/android_web_socket.cc
src/chrome/browser/devtools/device/devtools_android_bridge.cc
src/chrome/browser/devtools/device/devtools_android_bridge.h
src/chrome/browser/devtools/device/port_forwarding_controller.cc
src/chrome/browser/devtools/device/port_forwarding_controller.h
src/chrome/browser/devtools/device/self_device_provider.cc
src/chrome/browser/devtools/device/usb/usb_device_provider.cc
src/chrome/browser/domain_reliability/service_factory.cc
src/chrome/browser/extensions/api/app_window/app_window_api.cc
src/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.cc
src/chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h
src/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
src/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h
src/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_bluetooth_util.cc
src/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_bluetooth_util.h
src/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_bluetooth_util_chromeos.cc
src/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate_chromeos.cc
src/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc
src/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc
src/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
src/chrome/browser/extensions/updater/extension_downloader.cc
src/chrome/browser/extensions/updater/extension_downloader.h
src/chrome/browser/extensions/updater/extension_downloader_delegate.cc
src/chrome/browser/extensions/updater/extension_downloader_delegate.h
src/chrome/browser/extensions/updater/extension_updater.cc
src/chrome/browser/extensions/updater/extension_updater.h
src/chrome/browser/extensions/updater/extension_updater_unittest.cc
src/chrome/browser/extensions/updater/manifest_fetch_data.cc
src/chrome/browser/extensions/updater/manifest_fetch_data.h
src/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
src/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
src/chrome/browser/net/chrome_network_delegate.cc
src/chrome/browser/net/chrome_network_delegate.h
src/chrome/browser/net/prediction_options.cc
src/chrome/browser/net/prediction_options.h
src/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_unittest_android.cc
src/chrome/browser/password_manager/chrome_password_manager_client.cc
src/chrome/browser/password_manager/chrome_password_manager_client.h
src/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
src/chrome/browser/password_manager/password_manager_browsertest.cc
src/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
src/chrome/browser/prefetch/prefetch.cc
src/chrome/browser/prefetch/prefetch_browsertest.cc
src/chrome/browser/prefs/incognito_mode_prefs.cc
src/chrome/browser/prerender/prerender_manager.cc
src/chrome/browser/printing/pdf_to_emf_converter.cc
src/chrome/browser/printing/pdf_to_emf_converter.h
src/chrome/browser/printing/print_preview_dialog_controller.cc
src/chrome/browser/printing/print_view_manager_base.cc
src/chrome/browser/printing/print_view_manager_base.h
src/chrome/browser/profiles/gaia_info_update_service.cc
src/chrome/browser/profiles/off_the_record_profile_impl.cc
src/chrome/browser/profiles/profile_android.cc
src/chrome/browser/profiles/profile_android.h
src/chrome/browser/profiles/profile_info_cache.cc
src/chrome/browser/profiles/profile_info_cache.h
src/chrome/browser/profiles/profile_info_cache_unittest.cc
src/chrome/browser/profiles/profile_manager.cc
src/chrome/browser/profiles/profile_manager_unittest.cc
src/chrome/browser/profiles/profile_metrics.h
src/chrome/browser/profiles/profiles_state.cc
src/chrome/browser/renderer_context_menu/render_view_context_menu.cc
src/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js
src/chrome/browser/resources/chromeos/echo/manifest.json
src/chrome/browser/resources/chromeos/genius_app/manifest.json
src/chrome/browser/resources/cryptotoken/manifest.json
src/chrome/browser/resources/cryptotoken/usbgnubbydevice.js
src/chrome/browser/resources/easy_unlock/manifest.json
src/chrome/browser/resources/gesture_config.css
src/chrome/browser/resources/help_app/manifest.json
src/chrome/browser/resources/local_ntp/local_ntp.css
src/chrome/browser/resources/local_ntp/local_ntp.html
src/chrome/browser/resources/local_ntp/local_ntp.js
src/chrome/browser/resources/local_ntp/local_ntp_design.js
src/chrome/browser/resources/local_ntp/most_visited_thumbnail.css
src/chrome/browser/resources/local_ntp/most_visited_thumbnail.js
src/chrome/browser/resources/local_ntp/most_visited_util.js
src/chrome/browser/resources/options/browser_options.css
src/chrome/browser/resources/options/browser_options.html
src/chrome/browser/resources/options/browser_options.js
src/chrome/browser/resources/options/chromeos/internet_detail.js
src/chrome/browser/resources/options/cookies_list.js
src/chrome/browser/resources/options/cookies_view.css
src/chrome/browser/resources/plugin_metadata/plugins_win.json
src/chrome/browser/resources/sync_setup_overlay.js
src/chrome/browser/resources/user_manager/user_manager.css
src/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
src/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
src/chrome/browser/safe_browsing/incident_reporting/module_integrity_verifier_win.cc
src/chrome/browser/search/local_ntp_source.cc
src/chrome/browser/search/suggestions/suggestions_source.cc
src/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
src/chrome/browser/signin/easy_unlock_screenlock_state_handler.h
src/chrome/browser/signin/easy_unlock_service.cc
src/chrome/browser/signin/screenlock_bridge.cc
src/chrome/browser/signin/screenlock_bridge.h
src/chrome/browser/sync/profile_sync_service.cc
src/chrome/browser/sync/test/integration/sync_auth_test.cc
src/chrome/browser/thumbnails/thumbnail_list_source.cc
src/chrome/browser/ui/android/website_settings_popup_android.cc
src/chrome/browser/ui/apps/chrome_app_delegate.cc
src/chrome/browser/ui/autofill/password_generation_popup_controller.h
src/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_bridge.mm
src/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.h
src/chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.mm
src/chrome/browser/ui/cocoa/browser_window_controller.h
src/chrome/browser/ui/cocoa/browser_window_controller_private.mm
src/chrome/browser/ui/cocoa/cocoa_profile_test.mm
src/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
src/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
src/chrome/browser/ui/cocoa/profiles/profile_chooser_controller_unittest.mm
src/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
src/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
src/chrome/browser/ui/pdf/adobe_reader_info_win.cc
src/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
src/chrome/browser/ui/views/autofill/password_generation_popup_view_views.cc
src/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
src/chrome/browser/ui/views/desktop_media_picker_views.cc
src/chrome/browser/ui/views/desktop_media_picker_views.h
src/chrome/browser/ui/views/desktop_media_picker_views_unittest.cc
src/chrome/browser/ui/views/location_bar/location_bar_view.cc
src/chrome/browser/ui/views/profiles/new_avatar_button.cc
src/chrome/browser/ui/views/profiles/new_avatar_button.h
src/chrome/browser/ui/views/profiles/profile_chooser_view.cc
src/chrome/browser/ui/views/toolbar/browser_actions_container.cc
src/chrome/browser/ui/webui/certificate_viewer_webui.cc
src/chrome/browser/ui/webui/chromeos/login/demo_mode_detector.cc
src/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.cc
src/chrome/browser/ui/webui/chromeos/login/l10n_util.cc
src/chrome/browser/ui/webui/chromeos/login/l10n_util.h
src/chrome/browser/ui/webui/chromeos/login/l10n_util_unittest.cc
src/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
src/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
src/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
src/chrome/browser/ui/webui/constrained_web_dialog_ui.h
src/chrome/browser/ui/webui/constrained_web_dialog_ui_browsertest.cc
src/chrome/browser/ui/webui/options/manage_profile_handler.cc
src/chrome/browser/ui/webui/signin/profile_signin_confirmation_dialog.cc
src/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
src/chrome/browser/ui/webui/signin/user_manager_screen_handler.h
src/chrome/chrome.gyp
src/chrome/common/chrome_content_client.cc
src/chrome/common/crash_keys.cc
src/chrome/common/extensions/api/_manifest_features.json
src/chrome/common/extensions/api/_permission_features.json
src/chrome/common/extensions/api/easy_unlock_private.idl
src/chrome/common/extensions/api/file_browser_private.idl
src/chrome/common/extensions/api/push_messaging.idl
src/chrome/common/extensions/docs/examples/api/desktopCapture/app.js
src/chrome/common/extensions/docs/examples/api/desktopCapture/background.js
src/chrome/common/extensions/docs/examples/api/desktopCapture/index.html
src/chrome/common/extensions/docs/templates/articles/cloudMessagingV1.html
src/chrome/common/extensions/docs/templates/articles/gcm_server.html
src/chrome/installer/mac/app_resource_rules.plist.in
src/chrome/installer/util/channel_info.cc
src/chrome/installer/util/channel_info_unittest.cc
src/chrome/installer/util/util_constants.cc
src/chrome/installer/util/util_constants.h
src/chrome/service/DEPS
src/chrome/service/service_utility_process_host.cc
src/chrome/test/data/extensions/api_test/file_manager_browsertest/file_manager/multi_profile.js
src/chrome/test/nacl/pnacl_header_test.cc
src/chrome/test/nacl/pnacl_header_test.h
src/chrome_elf/blacklist/blacklist.cc
src/chromeos/dbus/fake_session_manager_client.cc
src/chromeos/dbus/fake_session_manager_client.h
src/chromeos/dbus/session_manager_client.cc
src/chromeos/dbus/session_manager_client.h
src/components/autofill/core/browser/autofill_external_delegate.cc
src/components/autofill/core/browser/autofill_manager.cc
src/components/autofill/core/browser/autofill_manager.h
src/components/autofill/core/common/form_data.cc
src/components/autofill/core/common/form_data_unittest.cc
src/components/copresence/rpc/rpc_handler.cc
src/components/copresence/rpc/rpc_handler_unittest.cc
src/components/data_reduction_proxy/browser/data_reduction_proxy_params.cc
src/components/data_reduction_proxy/browser/data_reduction_proxy_params.h
src/components/data_reduction_proxy/browser/data_reduction_proxy_params_unittest.cc
src/components/data_reduction_proxy/browser/data_reduction_proxy_settings.cc
src/components/data_reduction_proxy/browser/data_reduction_proxy_settings.h
src/components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.cc
src/components/data_reduction_proxy/browser/data_reduction_proxy_settings_test_utils.h
src/components/data_reduction_proxy/browser/data_reduction_proxy_settings_unittest.cc
src/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.cc
src/components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h
src/components/domain_reliability.gypi
src/components/domain_reliability/bake_in_configs.py
src/components/domain_reliability/baked_in_configs/accounts_google_com.json
src/components/domain_reliability/baked_in_configs/ad_doubleclick_net.json
src/components/domain_reliability/baked_in_configs/apis_google_com.json
src/components/domain_reliability/baked_in_configs/c_admob_com.json
src/components/domain_reliability/baked_in_configs/clients2_google_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/csi_gstatic_com.json
src/components/domain_reliability/baked_in_configs/ddm_google_com.json
src/components/domain_reliability/baked_in_configs/docs_google_com.json
src/components/domain_reliability/baked_in_configs/drive_google_com.json
src/components/domain_reliability/baked_in_configs/e_admob_com.json
src/components/domain_reliability/baked_in_configs/fonts_googleapis_com.json
src/components/domain_reliability/baked_in_configs/googleads4_g_doubleclick_net.json
src/components/domain_reliability/baked_in_configs/googleads_g_doubleclick_net.json
src/components/domain_reliability/baked_in_configs/gstatic_com.json
src/components/domain_reliability/baked_in_configs/lh3_ggpht_com.json
src/components/domain_reliability/baked_in_configs/lh4_ggpht_com.json
src/components/domain_reliability/baked_in_configs/lh5_ggpht_com.json
src/components/domain_reliability/baked_in_configs/lh6_ggpht_com.json
src/components/domain_reliability/baked_in_configs/mail_google_com.json
src/components/domain_reliability/baked_in_configs/media_admob_com.json
src/components/domain_reliability/baked_in_configs/pagead2_googlesyndication_com.json
src/components/domain_reliability/baked_in_configs/partner_googleadservices_com.json
src/components/domain_reliability/baked_in_configs/pubads_g_doubleclick_net.json
src/components/domain_reliability/baked_in_configs/redirector_googlevideo_com.json
src/components/domain_reliability/baked_in_configs/s0_2mdn_net.json
src/components/domain_reliability/baked_in_configs/ssl_gstatic_com.json
src/components/domain_reliability/baked_in_configs/star_admob_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_doubleclick_net.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_g_doubleclick_net.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_ggpht_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_cn.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_co_uk.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_com_au.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_de.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_fr.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_it.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_jp.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_org.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_google_ru.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_googleadservices_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_googleapis_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_googlesyndication_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_googleusercontent_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_googlevideo_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_gstatic_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_gvt1_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_youtube_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/star_ytimg_com.json [new file with mode: 0644]
src/components/domain_reliability/baked_in_configs/t0_gstatic_com.json
src/components/domain_reliability/baked_in_configs/t1_gstatic_com.json
src/components/domain_reliability/baked_in_configs/t2_gstatic_com.json
src/components/domain_reliability/baked_in_configs/t3_gstatic_com.json
src/components/domain_reliability/baked_in_configs/themes_googleusercontent_com.json
src/components/domain_reliability/baked_in_configs/www_google_com.json
src/components/domain_reliability/baked_in_configs/www_googleadservices_com.json
src/components/domain_reliability/baked_in_configs/www_gstatic_com.json
src/components/domain_reliability/baked_in_configs/www_youtube_com.json
src/components/nacl/renderer/ppb_nacl_private_impl.cc
src/components/password_manager/core/browser/password_form_manager.cc
src/components/password_manager/core/browser/password_form_manager.h
src/components/password_manager/core/browser/password_form_manager_unittest.cc
src/components/policy/resources/policy_templates.json
src/components/renderer_context_menu/render_view_context_menu_base.cc
src/components/renderer_context_menu/render_view_context_menu_base.h
src/components/suggestions.gypi
src/components/suggestions/BUILD.gn
src/components/suggestions/suggestions_service.cc
src/components/suggestions/suggestions_service.h
src/components/suggestions/suggestions_service_unittest.cc
src/components/suggestions/suggestions_utils.cc [new file with mode: 0644]
src/components/suggestions/suggestions_utils.h [new file with mode: 0644]
src/components/user_manager/user_manager_base.cc
src/content/browser/android/content_view_core_impl.cc
src/content/browser/android/content_view_render_view.cc
src/content/browser/android/content_view_render_view.h
src/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
src/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
src/content/browser/android/java/gin_java_bridge_dispatcher_host.h
src/content/browser/android/system_ui_resource_manager_impl.cc
src/content/browser/devtools/render_view_devtools_agent_host.cc
src/content/browser/devtools/render_view_devtools_agent_host.h
src/content/browser/devtools/renderer_overrides_handler.cc
src/content/browser/devtools/renderer_overrides_handler.h
src/content/browser/indexed_db/indexed_db_backing_store.cc
src/content/browser/indexed_db/indexed_db_callbacks.cc
src/content/browser/indexed_db/indexed_db_leveldb_coding.cc
src/content/browser/media/android/browser_media_player_manager.cc
src/content/browser/media/android/browser_media_player_manager.h
src/content/browser/media/capture/desktop_capture_device.cc
src/content/browser/media/capture/desktop_capture_device_aura.cc
src/content/browser/renderer_host/compositing_iosurface_layer_mac.mm
src/content/browser/renderer_host/compositor_impl_android.cc
src/content/browser/renderer_host/input/touch_selection_controller.cc
src/content/browser/renderer_host/input/touch_selection_controller.h
src/content/browser/renderer_host/input/touch_selection_controller_unittest.cc
src/content/browser/renderer_host/media/audio_input_renderer_host.cc
src/content/browser/renderer_host/media/audio_input_sync_writer.cc
src/content/browser/renderer_host/media/audio_sync_reader.cc
src/content/browser/renderer_host/render_process_host_impl.cc
src/content/browser/renderer_host/render_widget_host_impl.cc
src/content/browser/renderer_host/render_widget_host_impl.h
src/content/browser/renderer_host/render_widget_host_unittest.cc
src/content/browser/renderer_host/render_widget_host_view_android.cc
src/content/browser/renderer_host/render_widget_host_view_android.h
src/content/browser/renderer_host/render_widget_host_view_base.cc
src/content/browser/renderer_host/render_widget_host_view_base.h
src/content/browser/renderer_host/render_widget_host_view_browsertest.cc
src/content/browser/renderer_host/render_widget_host_view_mac.h
src/content/browser/renderer_host/render_widget_host_view_mac.mm
src/content/browser/web_contents/aura/overscroll_navigation_overlay.cc
src/content/browser/web_contents/web_contents_android.cc
src/content/browser/web_contents/web_contents_android.h
src/content/browser/web_contents/web_contents_view_aura.cc
src/content/common/android/gin_java_bridge_errors.cc
src/content/common/android/gin_java_bridge_errors.h
src/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
src/content/common/gpu/client/gpu_video_decode_accelerator_host.h
src/content/common/gpu/gpu_messages.h
src/content/common/gpu/media/android_video_decode_accelerator.cc
src/content/common/gpu/media/dxva_video_decode_accelerator.cc
src/content/common/gpu/media/dxva_video_decode_accelerator.h
src/content/common/gpu/media/gpu_video_decode_accelerator.cc
src/content/common/gpu/media/rendering_helper.cc
src/content/common/gpu/media/rendering_helper.h
src/content/common/gpu/media/v4l2_video_decode_accelerator.cc
src/content/common/gpu/media/vaapi_video_decode_accelerator.cc
src/content/common/gpu/media/video_decode_accelerator_unittest.cc
src/content/common/gpu/media/vt_video_decode_accelerator.cc
src/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
src/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
src/content/public/android/java/src/org/chromium/content/browser/ResourceExtractor.java
src/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
src/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
src/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
src/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
src/content/public/common/content_switches.cc
src/content/public/common/content_switches.h
src/content/renderer/context_menu_params_builder.cc
src/content/renderer/media/android/webmediaplayer_android.cc
src/content/renderer/media/android/webmediaplayer_android.h
src/content/renderer/media/audio_input_message_filter.cc
src/content/renderer/media/media_stream_video_source.cc
src/content/renderer/media/media_stream_video_source.h
src/content/renderer/media/rtc_video_decoder.cc
src/content/renderer/media/rtc_video_decoder.h
src/content/renderer/media/rtc_video_decoder_unittest.cc
src/content/renderer/media/rtc_video_encoder.cc
src/content/renderer/media/rtc_video_encoder_factory.cc
src/content/renderer/media/video_track_adapter.cc
src/content/renderer/media/webmediaplayer_impl.cc
src/content/renderer/media/webmediaplayer_impl.h
src/content/renderer/media/webmediaplayer_ms.cc
src/content/renderer/media/webmediaplayer_ms.h
src/content/renderer/media/webrtc/media_stream_remote_video_source.cc
src/content/renderer/media/webrtc/video_destination_handler.cc
src/content/renderer/media/webrtc_audio_capturer.cc
src/content/renderer/media/webrtc_audio_renderer.cc
src/content/renderer/media/webrtc_audio_renderer.h
src/content/renderer/media/webrtc_audio_renderer_unittest.cc
src/content/renderer/pepper/content_decryptor_delegate.cc
src/content/renderer/pepper/pepper_video_decoder_host.cc
src/content/renderer/pepper/ppb_video_decoder_impl.cc
src/content/renderer/pepper/video_decoder_shim.cc
src/content/renderer/render_widget.cc
src/content/renderer/renderer_font_platform_win.cc
src/dbus/property.cc
src/dbus/property_unittest.cc
src/device/bluetooth/bluetooth_device_chromeos.cc
src/device/bluetooth/bluetooth_device_chromeos.h
src/device/bluetooth/bluetooth_socket_chromeos.cc
src/device/bluetooth/bluetooth_socket_chromeos.h
src/device/hid/hid_connection_mac.cc
src/device/hid/hid_connection_mac.h
src/device/serial/serial_io_handler.cc
src/extensions/browser/api/hid/hid_api.cc
src/extensions/browser/content_hash_reader.cc
src/extensions/browser/content_hash_reader.h
src/extensions/browser/content_verify_job.cc
src/extensions/browser/extension_function_histogram_value.h
src/google_apis/gaia/oauth2_access_token_fetcher_impl.cc
src/google_apis/gcm/engine/connection_factory_impl.cc
src/gpu/command_buffer/client/gl_in_process_context.cc
src/gpu/command_buffer/client/gl_in_process_context.h
src/gpu/command_buffer/service/async_pixel_transfer_manager_android.cc
src/gpu/command_buffer/service/in_process_command_buffer.cc
src/gpu/config/software_rendering_list_json.cc
src/ios/web/public/user_agent.mm
src/ipc/ipc_channel_win.cc
src/ipc/ipc_channel_win.h
src/jingle/glue/proxy_resolving_client_socket.cc
src/media/audio/audio_input_controller.cc
src/media/audio/audio_input_controller.h
src/media/audio/mac/audio_low_latency_input_mac.cc
src/media/audio/sample_rates.cc
src/media/audio/sample_rates.h
src/media/base/cdm_promise.cc
src/media/base/cdm_promise.h
src/media/cast/sender/congestion_control.cc
src/media/cdm/ppapi/cdm_adapter.cc
src/media/cdm/ppapi/cdm_adapter.h
src/media/cdm/ppapi/cdm_wrapper.h
src/media/filters/ffmpeg_demuxer.cc
src/media/filters/ffmpeg_demuxer_unittest.cc
src/media/filters/gpu_video_decoder.cc
src/media/filters/skcanvas_video_renderer.cc
src/media/filters/skcanvas_video_renderer.h
src/media/filters/skcanvas_video_renderer_unittest.cc
src/media/video/picture.cc
src/media/video/picture.h
src/native_client/src/shared/platform/build.scons
src/native_client/src/shared/platform/win/nacl_host_desc.c
src/native_client/src/tools/validator_tools/build.scons
src/native_client/src/trusted/service_runtime/mmap_unittest.cc
src/native_client/src/trusted/validator/x86/testing/enuminsts/build.scons
src/native_client_sdk/src/README
src/native_client_sdk/src/build_tools/build_sdk.py
src/native_client_sdk/src/build_tools/build_version.py
src/native_client_sdk/src/build_tools/tests/build_version_test.py [new file with mode: 0755]
src/native_client_sdk/src/test_all.py
src/native_client_sdk/src/tools/getos.py
src/native_client_sdk/src/tools/tests/getos_test.py
src/net/base/mime_util.cc
src/net/base/network_delegate.cc
src/net/base/network_delegate.h
src/net/cert/ev_root_ca_metadata.cc
src/net/disk_cache/entry_unittest.cc
src/net/disk_cache/simple/simple_backend_impl.cc
src/net/disk_cache/simple/simple_backend_impl.h
src/net/disk_cache/simple/simple_entry_impl.cc
src/net/disk_cache/simple/simple_entry_impl.h
src/net/http/http_stream_factory_impl_job.cc
src/net/http/transport_security_state_static.h
src/net/http/transport_security_state_static.json
src/net/proxy/proxy_info.cc
src/net/proxy/proxy_info.h
src/net/proxy/proxy_info_unittest.cc
src/net/proxy/proxy_list.cc
src/net/proxy/proxy_list.h
src/net/proxy/proxy_list_unittest.cc
src/net/proxy/proxy_retry_info.h
src/net/proxy/proxy_service.cc
src/net/proxy/proxy_service.h
src/net/proxy/proxy_service_unittest.cc
src/net/quic/quic_http_stream.cc
src/net/quic/quic_http_stream_test.cc
src/ozone/media/vaapi_video_decode_accelerator.cc
src/printing/emf_win.cc
src/printing/emf_win.h
src/remoting/remoting_android.gypi
src/remoting/webapp/client_session.js
src/sync/android/java/src/org/chromium/sync/internal_api/pub/base/ModelType.java
src/third_party/WebKit/LayoutTests/TestExpectations
src/third_party/WebKit/LayoutTests/accessibility/adopt-node-causes-crash-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/accessibility/adopt-node-causes-crash.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/accessibility/inline-text-word-boundary-causes-crash-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/accessibility/inline-text-word-boundary-causes-crash.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-ancestor-reason-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-ancestor-reason.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-intrinsic-reason-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-intrinsic-reason.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow-expected.txt
src/third_party/WebKit/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-layer-expected.txt
src/third_party/WebKit/LayoutTests/compositing/filters/sw-shadow-overlaps-hw-shadow-expected.txt
src/third_party/WebKit/LayoutTests/compositing/gestures/gesture-tapHighlight-adjustment-clipping-expected.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/gestures/gesture-tapHighlight-adjustment-clipping.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/gestures/resources/link-highlight-helper.js
src/third_party/WebKit/LayoutTests/compositing/gestures/resources/link-highlight-style.css
src/third_party/WebKit/LayoutTests/compositing/overflow/do-not-crash-use-after-free-update-widget-positions-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/overflow/do-not-crash-use-after-free-update-widget-positions.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/overflow/resources/do-not-crash-use-after-free-update-widget-positions-iframe.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/overflow/resources/do-not-crash-use-after-free-update-widget-positions.svg [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/overflow/scroller-with-border-radius-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/overflow/scroller-with-border-radius.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-viewport-scrolling-layer-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-viewport-scrolling-layer.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/squashing/invalidate-when-leaving-squashed-layer-expected.txt
src/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/squashing/squash-above-fixed-1-expected.txt
src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-with-reparented-scrolling-expected.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-with-reparented-scrolling.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/css3/filters/composited-layer-promotion-after-outset-overlap-change-using-composited-shadow-expected.txt
src/third_party/WebKit/LayoutTests/css3/filters/composited-layer-promotion-after-outset-overlap-change-using-sw-shadow-expected.txt
src/third_party/WebKit/LayoutTests/editing/selection/collapse-null-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/editing/selection/collapse-null.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/canvas/canvas-drawImage-animated.html
src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPoint-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPoint.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPointUpdateLayout-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPointUpdateLayout.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/events/hit-test-counts-expected.txt
src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scrollbar-mainframe-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scrollbar-mainframe.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scrollbar.html
src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/tap-target-matches-active-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/tap-target-matches-active.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-gc-iframe-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-gc-iframe.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/files/resources/file-reader-abort-gc-iframe.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/forms/form-associated-element-crash4-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/forms/form-associated-element-crash4.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/forms/input-appearance-autocomplete-expected.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/forms/input-appearance-autocomplete.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/forms/select/listbox-tap-input-change-event-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/forms/select/listbox-tap-input-change-event.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/fast/text/sub-pixel/text-scaling-webfont.html
src/third_party/WebKit/LayoutTests/fast/transforms/matrix-with-zoom.html
src/third_party/WebKit/LayoutTests/http/tests/dom/crash-on-querying-event-path-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/http/tests/dom/crash-on-querying-event-path.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/http/tests/security/referrer-policy-conflicting-policies-expected.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/http/tests/security/referrer-policy-conflicting-policies.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/http/tests/security/resources/green-if-no-referrer.php [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/http/tests/security/resources/referrer-policy-conflicting-policies.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/media/audio-controls-do-not-fade-out.html
src/third_party/WebKit/LayoutTests/media/media-controls.js
src/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/media/video-controls-focus-movement-on-hide.html
src/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/media/video-controls-hide-on-move-outside-controls.html
src/third_party/WebKit/LayoutTests/media/video-controls-show-on-focus.html
src/third_party/WebKit/LayoutTests/media/video-controls-visible-exiting-fullscreen.html
src/third_party/WebKit/LayoutTests/platform/linux/fast/dom/Window/webkitConvertPoint-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/platform/win-xp/fast/dom/Window/webkitConvertPoint-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/plugins/page-scale-does-not-affect-plugin-height-expected.txt [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/plugins/page-scale-does-not-affect-plugin-height.html [new file with mode: 0644]
src/third_party/WebKit/LayoutTests/transforms/2d/cssmatrix-2d-zoom.html
src/third_party/WebKit/LayoutTests/transforms/2d/set-transform-and-top.html
src/third_party/WebKit/LayoutTests/transforms/3d/general/cssmatrix-3d-zoom.html
src/third_party/WebKit/LayoutTests/transforms/3d/general/matrix-with-zoom-3d.html
src/third_party/WebKit/Source/core/dom/Node.cpp
src/third_party/WebKit/Source/core/dom/Node.h
src/third_party/WebKit/Source/core/dom/TreeScopeAdopter.cpp
src/third_party/WebKit/Source/core/editing/Caret.cpp
src/third_party/WebKit/Source/core/editing/Caret.h
src/third_party/WebKit/Source/core/editing/DOMSelection.cpp
src/third_party/WebKit/Source/core/editing/FrameSelection.cpp
src/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
src/third_party/WebKit/Source/core/editing/InputMethodController.cpp
src/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
src/third_party/WebKit/Source/core/editing/Selection.idl
src/third_party/WebKit/Source/core/events/Event.cpp
src/third_party/WebKit/Source/core/events/Event.h
src/third_party/WebKit/Source/core/fileapi/File.cpp
src/third_party/WebKit/Source/core/fileapi/File.h
src/third_party/WebKit/Source/core/fileapi/FileReader.cpp
src/third_party/WebKit/Source/core/frame/FrameView.cpp
src/third_party/WebKit/Source/core/frame/FrameView.h
src/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
src/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
src/third_party/WebKit/Source/core/frame/UseCounter.h
src/third_party/WebKit/Source/core/frame/Window.idl
src/third_party/WebKit/Source/core/html/FormAssociatedElement.cpp
src/third_party/WebKit/Source/core/html/FormAssociatedElement.h
src/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
src/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
src/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.cpp
src/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.h
src/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
src/third_party/WebKit/Source/core/html/shadow/MediaControls.h
src/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp
src/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h
src/third_party/WebKit/Source/core/loader/EmptyClients.cpp
src/third_party/WebKit/Source/core/loader/EmptyClients.h
src/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
src/third_party/WebKit/Source/core/page/Chrome.cpp
src/third_party/WebKit/Source/core/page/Chrome.h
src/third_party/WebKit/Source/core/page/ChromeClient.h
src/third_party/WebKit/Source/core/page/EventHandler.cpp
src/third_party/WebKit/Source/core/rendering/AbstractInlineTextBox.cpp
src/third_party/WebKit/Source/core/rendering/PaintInvalidationState.cpp
src/third_party/WebKit/Source/core/rendering/RenderBox.cpp
src/third_party/WebKit/Source/core/rendering/RenderLayer.cpp
src/third_party/WebKit/Source/core/rendering/RenderLayerScrollableArea.cpp
src/third_party/WebKit/Source/core/rendering/RenderObject.cpp
src/third_party/WebKit/Source/core/rendering/RenderSelectionInfo.h
src/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp
src/third_party/WebKit/Source/core/rendering/compositing/CompositingInputsUpdater.cpp
src/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.cpp
src/third_party/WebKit/Source/core/rendering/svg/RenderSVGResourceFilter.cpp
src/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
src/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
src/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js
src/third_party/WebKit/Source/devtools/front_end/helpScreen.css
src/third_party/WebKit/Source/devtools/front_end/main/Main.js
src/third_party/WebKit/Source/devtools/front_end/main/OverridesView.js
src/third_party/WebKit/Source/devtools/front_end/main/Toolbox.js
src/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
src/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
src/third_party/WebKit/Source/devtools/front_end/source_frame/CodeMirrorTextEditor.js
src/third_party/WebKit/Source/devtools/front_end/ui/DataGrid.js
src/third_party/WebKit/Source/devtools/front_end/ui/ShortcutRegistry.js
src/third_party/WebKit/Source/devtools/front_end/ui/ViewportDataGrid.js
src/third_party/WebKit/Source/modules/filesystem/DOMFileSystemBase.cpp
src/third_party/WebKit/Source/modules/filesystem/DOMFileSystemBase.h
src/third_party/WebKit/Source/modules/filesystem/DOMFileSystemBaseTest.cpp [new file with mode: 0644]
src/third_party/WebKit/Source/modules/filesystem/DOMFileSystemSync.cpp
src/third_party/WebKit/Source/modules/filesystem/FileSystemCallbacks.cpp
src/third_party/WebKit/Source/modules/modules.gypi
src/third_party/WebKit/Source/platform/DateTimeChooser.h
src/third_party/WebKit/Source/platform/DateTimeChooserClient.cpp
src/third_party/WebKit/Source/platform/DateTimeChooserClient.h
src/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.cpp
src/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.h
src/third_party/WebKit/Source/platform/fonts/skia/SimpleFontDataSkia.cpp
src/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp
src/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp
src/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp
src/third_party/WebKit/Source/platform/graphics/BitmapImage.h
src/third_party/WebKit/Source/platform/graphics/Canvas2DImageBufferSurface.h
src/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
src/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
src/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
src/third_party/WebKit/Source/platform/graphics/Canvas2DLayerManagerTest.cpp
src/third_party/WebKit/Source/platform/graphics/CompositingReasons.cpp
src/third_party/WebKit/Source/platform/graphics/CompositingReasons.h
src/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
src/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
src/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
src/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h
src/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
src/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h
src/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
src/third_party/WebKit/Source/platform/graphics/test/MockWebGraphicsContext3D.h
src/third_party/WebKit/Source/platform/heap/Handle.h
src/third_party/WebKit/Source/web/ChromeClientImpl.cpp
src/third_party/WebKit/Source/web/ChromeClientImpl.h
src/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
src/third_party/WebKit/Source/web/DateTimeChooserImpl.h
src/third_party/WebKit/Source/web/ExternalDateTimeChooser.cpp
src/third_party/WebKit/Source/web/ExternalDateTimeChooser.h
src/third_party/WebKit/Source/web/ExternalPopupMenu.cpp
src/third_party/WebKit/Source/web/ExternalPopupMenu.h
src/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp [new file with mode: 0644]
src/third_party/WebKit/Source/web/WebViewImpl.cpp
src/third_party/WebKit/Source/web/tests/WebViewTest.cpp
src/third_party/WebKit/Source/web/tests/data/smartclip_user_select_none.html [new file with mode: 0644]
src/third_party/WebKit/Source/web/web.gypi
src/third_party/ffmpeg/README.chromium
src/third_party/ffmpeg/ffmpeg.gyp
src/third_party/ffmpeg/libavcodec/aac_parser.c
src/third_party/ffmpeg/libavcodec/ac3_parser.c
src/third_party/libjpeg_turbo/README.chromium
src/third_party/libjpeg_turbo/google.patch
src/third_party/libjpeg_turbo/libjpeg.gyp
src/third_party/libjpeg_turbo/simd/jsimd_arm64.c [new file with mode: 0644]
src/third_party/libjpeg_turbo/simd/jsimd_arm64_neon.S [new file with mode: 0644]
src/third_party/libjpeg_turbo/simd/jsimd_arm_neon.S
src/third_party/libvpx/source/libvpx/vp9/common/vp9_alloccommon.c
src/third_party/libvpx/source/libvpx/vp9/common/vp9_onyxc_int.h
src/third_party/libvpx/source/libvpx/vp9/decoder/vp9_decodeframe.c
src/third_party/libvpx/source/libvpx/vp9/encoder/vp9_bitstream.c
src/third_party/skia/src/core/SkBBoxHierarchyRecord.cpp
src/third_party/skia/src/core/SkGlyph.h
src/third_party/skia/src/core/SkStroke.cpp
src/third_party/skia/src/pathops/SkOpContour.cpp
src/third_party/skia/src/pathops/SkOpSegment.cpp
src/third_party/skia/src/ports/SkScalerContext_win_dw.cpp
src/third_party/skia/src/ports/SkScalerContext_win_dw.h
src/third_party/skia/tests/ImageFilterTest.cpp
src/third_party/skia/tests/PathOpsOpTest.cpp
src/third_party/skia/tests/PathTest.cpp
src/tools/metrics/histograms/histograms.xml
src/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
src/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
src/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
src/ui/base/l10n/l10n_util.cc
src/ui/base/l10n/l10n_util.h
src/ui/base/l10n/l10n_util_unittest.cc
src/ui/compositor/layer.cc
src/ui/compositor/layer_unittest.cc
src/ui/file_manager/file_manager/audio_player/css/audio_player.css
src/ui/file_manager/file_manager/audio_player/elements/track_list.css
src/ui/file_manager/file_manager/foreground/css/file_manager.css
src/ui/file_manager/file_manager/foreground/js/file_manager.js
src/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
src/ui/file_manager/file_manager/main.html
src/ui/file_manager/gallery/css/gallery.css
src/ui/file_manager/gallery/js/gallery.js
src/ui/file_manager/video_player/css/video_player.css
src/ui/gfx/font_list.cc
src/ui/gfx/font_list.h
src/ui/gfx/font_list_unittest.cc
src/ui/gfx/font_render_params_linux.cc
src/ui/gfx/platform_font_pango.cc
src/ui/gfx/platform_font_pango.h
src/ui/gfx/render_text_pango.cc
src/ui/gl/android/scoped_java_surface.cc
src/ui/keyboard/keyboard_controller.cc
src/ui/keyboard/keyboard_layout_manager.cc
src/ui/login/account_picker/user_pod_row.css
src/ui/login/account_picker/user_pod_row.js
src/ui/resources/default_100_percent/common/close_3_mask.png [new file with mode: 0644]
src/ui/resources/default_100_percent/common/easy_unlock_unlocked.png
src/ui/resources/default_100_percent/common/ntp_default_favicon.png [new file with mode: 0644]
src/ui/resources/default_200_percent/common/close_3_mask.png [new file with mode: 0644]
src/ui/resources/default_200_percent/common/easy_unlock_unlocked.png
src/ui/resources/default_200_percent/common/ntp_default_favicon.png [new file with mode: 0644]
src/ui/resources/ui_resources.grd
src/ui/strings/translations/app_locale_settings_ja.xtb
src/ui/strings/translations/app_locale_settings_ko.xtb
src/ui/strings/translations/app_locale_settings_zh-CN.xtb
src/ui/strings/translations/app_locale_settings_zh-TW.xtb
src/ui/views/bubble/bubble_border.cc
src/ui/views/bubble/bubble_border.h
src/ui/views/bubble/bubble_border_unittest.cc
src/ui/views/bubble/tray_bubble_view.cc
src/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
src/v8/src/heap/spaces.cc
src/v8/src/hydrogen-instructions.cc
src/v8/src/hydrogen.cc
src/v8/src/property-details-inl.h
src/v8/src/property-details.h
src/v8/src/version.cc
src/v8/test/cctest/test-spaces.cc
src/v8/test/mjsunit/regress/regress-crbug-407946.js [new file with mode: 0644]
src/v8/test/mjsunit/regress/regress-force-constant-representation.js [new file with mode: 0644]
src/v8/test/webkit/webkit.status
src/v8/tools/run-tests.py
src/webkit/common/gpu/context_provider_in_process.cc
src/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
src/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
src/xwalk/DEPS.xwalk
src/xwalk/VERSION
src/xwalk/app/android/runtime_activity/src/org/xwalk/app/XWalkRuntimeActivityBase.java
src/xwalk/app/tools/android/customize.py
src/xwalk/app/tools/android/customize_launch_screen.py
src/xwalk/app/tools/android/make_apk.py
src/xwalk/app/tools/android/make_apk_test.py
src/xwalk/app/tools/android/util.py
src/xwalk/application/browser/application.cc
src/xwalk/application/browser/application_protocols.cc
src/xwalk/application/browser/application_service.cc
src/xwalk/application/browser/application_tizen.cc
src/xwalk/application/common/application_data.cc
src/xwalk/application/common/application_data.h
src/xwalk/application/common/application_manifest_constants.cc
src/xwalk/application/common/application_manifest_constants.h
src/xwalk/application/common/manifest_handlers/tizen_setting_handler.cc
src/xwalk/application/common/manifest_handlers/tizen_setting_handler.h
src/xwalk/application/common/manifest_handlers/tizen_splash_screen_handler.cc
src/xwalk/application/common/tizen/signature_validator.cc
src/xwalk/application/common/tizen/signature_xmlsec_adaptor.cc [new file with mode: 0644]
src/xwalk/application/common/tizen/signature_xmlsec_adaptor.h [new file with mode: 0644]
src/xwalk/application/common/xwalk_application_common.gypi
src/xwalk/application/test/application_test.cc [moved from src/xwalk/application/test/application_multi_app_test.cc with 83% similarity]
src/xwalk/application/test/data/unsafe_start_URL/manifest.json [new file with mode: 0644]
src/xwalk/application/tools/tizen/xwalk_backend_plugin.cc
src/xwalk/application/tools/tizen/xwalk_package_installer.cc
src/xwalk/build/android/generate_app_packaging_tool.py
src/xwalk/build/android/generate_xwalk_core_library.py
src/xwalk/build/android/generate_xwalk_core_library_aar.py
src/xwalk/packaging/crosswalk.spec
src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/ReflectionHelper.java
src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewDelegate.java
src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/XWalkViewInternal.java
src/xwalk/runtime/android/core_internal/src/org/xwalk/core/internal/extension/api/presentation/PresentationExtension.java
src/xwalk/runtime/android/core_internal_empty/AndroidManifest.xml [moved from src/xwalk/runtime/android/core_library_empty/AndroidManifest.xml with 100% similarity]
src/xwalk/runtime/android/core_internal_empty/src/README.md [moved from src/xwalk/runtime/android/core_library_empty/src/README.md with 100% similarity]
src/xwalk/runtime/browser/xwalk_browser_main_parts.cc
src/xwalk/runtime/browser/xwalk_browser_main_parts_android.cc
src/xwalk/xwalk_core_library_android.gypi
src/xwalk/xwalk_tests.gypi

index 7444d33..6b19c90 100644 (file)
@@ -16,7 +16,7 @@
 %endif
 
 Name:           crosswalk
-Version:        9.38.207.0
+Version:        10.38.208.0
 Release:        0
 Summary:        Chromium-based app runtime
 License:        (BSD-3-Clause and LGPL-2.1+)
@@ -74,6 +74,7 @@ BuildRequires:  pkgconfig(nspr)
 BuildRequires:  pkgconfig(nss)
 BuildRequires:  pkgconfig(sensor)
 BuildRequires:  pkgconfig(vconf)
+BuildRequires:  pkgconfig(xmlsec1)
 %if %{with x}
 BuildRequires:  pkgconfig(x11)
 BuildRequires:  pkgconfig(xcomposite)
@@ -102,6 +103,7 @@ BuildRequires:  pkgconfig(xkbcommon)
 %else
 BuildRequires:  pkgconfig(scim)
 %endif
+Requires:  ca-certificates-tizen
 
 %description
 Crosswalk is an app runtime based on Chromium. It is an open source project started by the Intel Open Source Technology Center (http://www.01.org).
index 5312dae..4e1f8f3 100644 (file)
@@ -7,7 +7,7 @@ vars = {
     'eyes-free':
          'http://eyes-free.googlecode.com/svn',
     'webkit_rev':
-         '@435519d7eb441a56c058e5e98fbd363f3f3aed30',
+         '@43aff830b25c0894823834d6ac417112fefb1fb2',
     'blink':
          'http://src.chromium.org/blink',
     'skia':
@@ -138,7 +138,7 @@ deps = {
     'src/chrome/browser/resources/pdf/html_office':
         Var('git_url') + '/chromium/html-office-public.git@eeff97614f65e0578529490d44d412032c3d7359',
     'src/chrome/test/data/extensions/api_test/permissions/nacl_enabled/bin':
-        Var('git_url') + '/native_client/src/native_client/tests/prebuilt.git@3e17365176c94624f46cace174f61834b7f3c35d',
+        Var('git_url') + '/native_client/src/native_client/tests/prebuilt.git@e65f794ce4a809d92d5cacae55ae119946bdb9c5',
     'src/chrome/test/data/perf/canvas_bench':
         Var('git_url') + '/chromium/canvas_bench.git@a7b40ea5ae0239517d78845a5fc9b12976bfc732',
     'src/chrome/test/data/perf/frame_rate/content':
@@ -146,7 +146,7 @@ deps = {
     'src/media/cdm/ppapi/api':
         Var('git_url') + '/chromium/cdm.git@41c8183a3966a17b440dbe606cb2840e1b7ce884',
     'src/native_client':
-        Var('git_url') + '/native_client/src/native_client.git@4a2be76975082aad3f769115f23661acca318949',
+        Var('git_url') + '/native_client/src/native_client.git@792e992d22507e6ff10e5088f7f2a1b61e3742a2',
     'src/sdch/open-vcdiff':
         Var('git_url') + '/external/open-vcdiff.git@438f2a5be6d809bc21611a94cd37bfc8c28ceb33',
     'src/testing/gmock':
@@ -174,7 +174,7 @@ deps = {
     'src/third_party/colorama/src':
         Var('git_url') + '/external/colorama.git@799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8',
     'src/third_party/ffmpeg':
-        Var('git_url') + '/chromium/third_party/ffmpeg.git@5961d8ac36f995dc3162aff7f8039ef7d772aaac',
+        Var('git_url') + '/chromium/third_party/ffmpeg.git@98ca32e50f6e38447bc81705d0689ebceb6ac649',
     'src/third_party/flac':
         Var('git_url') + '/chromium/deps/flac.git@0635a091379d9677f1ddde5f2eec85d0f096f219',
     'src/third_party/hunspell':
@@ -200,7 +200,7 @@ deps = {
     'src/third_party/libjingle/source/talk':
         Var('git_url') + '/external/webrtc/trunk/talk.git@3541181607ffe656d8db759a6095864d9f72248d',
     'src/third_party/libjpeg_turbo':
-        Var('git_url') + '/chromium/deps/libjpeg_turbo.git@841fff8cddd73c0d6b966902f83bea7ad366bd4b',
+        Var('git_url') + '/chromium/deps/libjpeg_turbo.git@2ed5319ce40b0ba2cd9b962713ea0ef775781e69',
     'src/third_party/libphonenumber/src/phonenumbers':
         Var('git_url') + '/external/libphonenumber/cpp/src/phonenumbers.git@8d8b5b3b2035197795d27573d4cf566b5d9ad689',
     'src/third_party/libphonenumber/src/resources':
@@ -210,7 +210,7 @@ deps = {
     'src/third_party/libsrtp':
         Var('git_url') + '/chromium/deps/libsrtp.git@662d81de5cbf3667f1baaafe051b8b4ab0b12fe2',
     'src/third_party/libvpx':
-        Var('git_url') + '/chromium/deps/libvpx.git@6e18fa2139dd88a8a5c529e3e6d0fe6d6f76ad1c',
+        Var('git_url') + '/chromium/deps/libvpx.git@8110782824f708dd3630cd55375019648567c31c',
     'src/third_party/libwebm/source':
         Var('git_url') + '/webm/libwebm.git@0d4cb404ea4195e5e21d04db2c955615535ce62e',
     'src/third_party/libyuv':
@@ -238,7 +238,7 @@ deps = {
     'src/third_party/sfntly/cpp/src':
         Var('git_url') + '/external/sfntly/cpp/src.git@1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
     'src/third_party/skia':
-        Var('git_url') + '/skia.git@1313b3f69370915a4fd911f97b4975d90bdf8869',
+        Var('git_url') + '/skia.git@773a327b12f653c3bb0630fee1b3ba9629f5717e',
     'src/third_party/smhasher/src':
         Var('git_url') + '/external/smhasher.git@e87738e57558e0ec472b2fc3a643b838e5b6e88f',
     'src/third_party/snappy/src':
@@ -258,7 +258,7 @@ deps = {
     'src/third_party/webpagereplay':
         Var('git_url') + '/external/web-page-replay.git@b62c02d3b64cf00a2f65a82cca0721aa42c3d6ad',
     'src/third_party/webrtc':
-        Var('git_url') + '/external/webrtc/trunk/webrtc.git@6c2b7b2432cb42cbef1b32d9ea21b3e9f33b0cda',
+        Var('git_url') + '/external/webrtc/trunk/webrtc.git@a6ed0dfa13f606d7f173f740510c2ed5855aa7fd',
     'src/third_party/yasm/source/patched-yasm':
         Var('git_url') + '/chromium/deps/yasm/patched-yasm.git@c960eb11ccda80b10ed50be39df4f0663b371d1d',
     'src/tools/deps2git':
@@ -272,7 +272,7 @@ deps = {
     'src/tools/swarming_client':
         Var('git_url') + '/external/swarming.client.git@bbf1fcca7932d92cca9d7dab46ea271a7f6d61fb',
     'src/v8':
-        Var('git_url') + '/external/v8.git@0bb343f5ed1becef0996a234d5d7d431e60ef72a',
+        Var('git_url') + '/external/v8.git@895fe777a81b25528620c70eadc4c7463ccfd749',
 }
 
 deps_os = {
index 9563061..c571868 100644 (file)
--- a/src/DEPS
+++ b/src/DEPS
@@ -267,7 +267,7 @@ deps = {
   'src/third_party/libwebm/source':\r
     (Var("git.chromium.org")) + '/webm/libwebm.git@0d4cb404ea4195e5e21d04db2c955615535ce62e',\r
   'src/third_party/WebKit':\r
-    (Var("blink")) + '/branches/chromium/2125@180871',\r
+    (Var("blink")) + '/branches/chromium/2125@182060',\r
   'src/third_party/openmax_dl':\r
     (Var("webrtc")) + '/deps/third_party/openmax@6777',\r
   'src/third_party/libc++abi/trunk':\r
@@ -281,7 +281,7 @@ deps = {
   'src/media/cdm/ppapi/api':\r
     '/trunk/deps/cdm@288172',\r
   'src/third_party/skia':\r
-    (Var("git.chromium.org")) + '/skia.git@1313b3f69370915a4fd911f97b4975d90bdf8869',\r
+    (Var("git.chromium.org")) + '/skia.git@773a327b12f653c3bb0630fee1b3ba9629f5717e',\r
   'src/tools/swarming_client':\r
     (Var("git.chromium.org")) + '/external/swarming.client.git@bbf1fcca7932d92cca9d7dab46ea271a7f6d61fb',\r
   'src/chrome/test/data/perf/frame_rate/content':\r
@@ -303,13 +303,13 @@ deps = {
   'src/third_party/smhasher/src':\r
     (Var("smhasher")) + '/trunk@152',\r
   'src/third_party/webrtc':\r
-    (Var("webrtc")) + '/branches/38/webrtc@6941',\r
+    (Var("webrtc")) + '/branches/38/webrtc@7177',\r
   'build/scripts/tools/deps2git':\r
     '/trunk/tools/deps2git@285662',\r
   'src/third_party/hunspell_dictionaries':\r
     '/trunk/deps/third_party/hunspell_dictionaries@255132',\r
   'src/native_client':\r
-    (Var("native_client")) + '/trunk/src/native_client@13626',\r
+    (Var("native_client")) + '/branches/2125/src/native_client@13665',\r
   'src/third_party/brotli/src':\r
     (Var("git.chromium.org")) + '/external/font-compression-reference.git@6cef49677dc4c650ef6e3f56041e0a41803afa8c',\r
   'src/tools/page_cycler/acid3':\r
@@ -317,7 +317,7 @@ deps = {
   'src/third_party/cacheinvalidation/src':\r
     (Var("google-cache-invalidation-api")) + '/trunk/src@335',\r
   'src/chrome/test/data/extensions/api_test/permissions/nacl_enabled/bin':\r
-    (Var("native_client")) + '/trunk/src/native_client/tests/prebuilt@13626',\r
+    (Var("native_client")) + '/branches/2125/src/native_client/tests/prebuilt@13665',\r
   'src/third_party/leveldatabase/src':\r
     (Var("leveldb")) + '/trunk@80',\r
   'src/third_party/webpagereplay':\r
@@ -369,7 +369,7 @@ deps = {
   'src/third_party/safe_browsing/testing':\r
     (Var("google-safe-browsing")) + '/trunk/testing@112',\r
   'src/third_party/ffmpeg':\r
-    (Var("git.chromium.org")) + '/chromium/third_party/ffmpeg.git@5961d8ac36f995dc3162aff7f8039ef7d772aaac',\r
+    (Var("git.chromium.org")) + '/chromium/third_party/ffmpeg.git@98ca32e50f6e38447bc81705d0689ebceb6ac649',\r
   'build':\r
     '/trunk/tools/build@290047',\r
   'build/scripts/command_wrapper/bin':\r
@@ -399,15 +399,15 @@ deps = {
   'src/tools/deps2git':\r
     '/trunk/tools/deps2git@276439',\r
   'src/third_party/libjpeg_turbo':\r
-    '/trunk/deps/third_party/libjpeg_turbo@272637',\r
+    '/trunk/deps/third_party/libjpeg_turbo@291725',\r
   'src/third_party/libsrtp':\r
     '/trunk/deps/third_party/libsrtp@283418',\r
   'src/v8':\r
-    (Var("v8")) + '/branches/3.28@23373',\r
+    (Var("v8")) + '/branches/3.28@23836',\r
   'src/third_party/pywebsocket/src':\r
     (Var("pywebsocket")) + '/trunk/src@790',\r
   'src/third_party/libvpx':\r
-    '/branches/2125/deps/third_party/libvpx@291144',\r
+    '/branches/2125/deps/third_party/libvpx@291831',\r
   'src/third_party/boringssl/src':\r
     'https://boringssl.googlesource.com/boringssl.git@c3d79605ab06cffa87877bcfe0792f767bde8b90',\r
   'src/third_party/swig/Lib':\r
index ea98629..60896e8 100644 (file)
         '../printing/printing.gyp:printing',
         '../skia/skia.gyp:skia',
         '../third_party/WebKit/public/blink.gyp:blink',
-        '../v8/tools/gyp/v8.gyp:v8',
         '../ui/gl/gl.gyp:gl',
         '../ui/shell_dialogs/shell_dialogs.gyp:shell_dialogs',
         '../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
         'public/browser/draw_gl.h',
         'renderer/aw_content_renderer_client.cc',
         'renderer/aw_content_renderer_client.h',
-        'renderer/aw_execution_termination_filter.cc',
-        'renderer/aw_execution_termination_filter.h',
         'renderer/aw_key_systems.cc',
         'renderer/aw_key_systems.h',
         'renderer/aw_permission_client.cc',
index 4e31f71..ffd7160 100644 (file)
@@ -47,6 +47,11 @@ void AwContentsClientBridgeBase::Associate(
                             new UserData(handler));
 }
 
+void AwContentsClientBridgeBase::Disassociate(
+  WebContents* web_contents) {
+  web_contents->RemoveUserData(kAwContentsClientBridgeBase);
+}
+
 // static
 AwContentsClientBridgeBase* AwContentsClientBridgeBase::FromWebContents(
     WebContents* web_contents) {
index a24aa4b..3bc1815 100644 (file)
@@ -34,6 +34,7 @@ class AwContentsClientBridgeBase {
   // Adds the handler to the UserData registry.
   static void Associate(content::WebContents* web_contents,
                         AwContentsClientBridgeBase* handler);
+  static void Disassociate(content::WebContents* web_contents);
   static AwContentsClientBridgeBase* FromWebContents(
       content::WebContents* web_contents);
   static AwContentsClientBridgeBase* FromID(int render_process_id,
index 630c7bf..476935a 100644 (file)
@@ -25,6 +25,11 @@ void AwJavaScriptDialogManager::RunJavaScriptDialog(
     bool* did_suppress_message) {
   AwContentsClientBridgeBase* bridge =
       AwContentsClientBridgeBase::FromWebContents(web_contents);
+  if (!bridge) {
+    callback.Run(false, base::string16());
+    return;
+  }
+
   bridge->RunJavaScriptDialog(message_type,
                               origin_url,
                               message_text,
@@ -39,6 +44,11 @@ void AwJavaScriptDialogManager::RunBeforeUnloadDialog(
     const DialogClosedCallback& callback) {
   AwContentsClientBridgeBase* bridge =
       AwContentsClientBridgeBase::FromWebContents(web_contents);
+  if (!bridge) {
+    callback.Run(false, base::string16());
+    return;
+  }
+
   bridge->RunBeforeUnloadDialog(web_contents->GetURL(),
                                 message_text,
                                 callback);
index 93ab0a8..98e2394 100644 (file)
@@ -247,6 +247,9 @@ bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) {
   if (!compositor_)
     return false;
 
+  if (last_on_draw_global_visible_rect_.IsEmpty())
+    return client_->RequestDrawGL(java_canvas, false);
+
   if (!hardware_enabled_) {
     hardware_enabled_ = compositor_->InitializeHwDraw();
     if (hardware_enabled_) {
@@ -717,6 +720,9 @@ void BrowserViewRenderer::PostFallbackTick() {
         FROM_HERE,
         fallback_tick_fired_.callback(),
         base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
+  } else {
+    // Pretend we just composited to unblock further invalidates.
+    DidComposite();
   }
 }
 
@@ -729,8 +735,12 @@ void BrowserViewRenderer::FallbackTickFired() {
   // This should only be called if OnDraw or DrawGL did not come in time, which
   // means block_invalidates_ must still be true.
   DCHECK(block_invalidates_);
-  if (compositor_needs_continuous_invalidate_ && compositor_)
+  if (compositor_needs_continuous_invalidate_ && compositor_) {
     ForceFakeCompositeSW();
+  } else {
+    // Pretend we just composited to unblock further invalidates.
+    DidComposite();
+  }
 }
 
 void BrowserViewRenderer::ForceFakeCompositeSW() {
index 6a3d54b..1598ac6 100644 (file)
@@ -53,16 +53,17 @@ scoped_refptr<cc::ContextProvider> CreateContext(
       attributes, &attribs_for_gles2);
   attribs_for_gles2.lose_context_when_out_of_memory = true;
 
-  scoped_ptr<gpu::GLInProcessContext> context(
-      gpu::GLInProcessContext::Create(service,
-                                      surface,
-                                      surface->IsOffscreen(),
-                                      gfx::kNullAcceleratedWidget,
-                                      surface->GetSize(),
-                                      share_context,
-                                      false /* share_resources */,
-                                      attribs_for_gles2,
-                                      gpu_preference));
+  scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create(
+      service,
+      surface,
+      surface->IsOffscreen(),
+      gfx::kNullAcceleratedWidget,
+      surface->GetSize(),
+      share_context,
+      false /* share_resources */,
+      attribs_for_gles2,
+      gpu_preference,
+      gpu::GLInProcessContextSharedMemoryLimits()));
   DCHECK(context.get());
 
   return webkit::gpu::ContextProviderInProcess::Create(
@@ -135,10 +136,9 @@ void HardwareRenderer::DidBeginMainFrame() {
 
 void HardwareRenderer::CommitFrame() {
   scoped_ptr<DrawGLInput> input = shared_renderer_state_->PassDrawGLInput();
-  if (!input.get()) {
-    DLOG(WARNING) << "No frame to commit";
+  // Happens with empty global visible rect.
+  if (!input.get())
     return;
-  }
 
   DCHECK(!input->frame.gl_frame_data);
   DCHECK(!input->frame.software_frame_data);
@@ -188,11 +188,6 @@ void HardwareRenderer::DrawGL(bool stencil_enabled,
     return;
   }
 
-  if (!delegated_layer_.get()) {
-    DLOG(ERROR) << "No frame committed";
-    return;
-  }
-
   // TODO(boliu): Handle context loss.
   if (last_egl_context_ != current_context)
     DLOG(WARNING) << "EGLContextChanged";
@@ -212,6 +207,9 @@ void HardwareRenderer::DrawGL(bool stencil_enabled,
         draw_constraints);
   }
 
+  if (!delegated_layer_.get())
+    return;
+
   viewport_.SetSize(draw_info->width, draw_info->height);
   layer_tree_host_->SetViewportSize(viewport_);
   clip_.SetRect(draw_info->clip_left,
index 22666fb..6e39cd7 100644 (file)
@@ -208,11 +208,6 @@ void AwURLRequestContextGetter::InitializeURLRequestContext() {
   ApplyCmdlineOverridesToURLRequestContextBuilder(&builder);
 
   url_request_context_.reset(builder.Build());
-  channel_id_service_.reset(
-      new net::ChannelIDService(
-          new net::DefaultChannelIDStore(NULL),
-          base::WorkerPool::GetTaskRunner(true)));
-  url_request_context_->set_channel_id_service(channel_id_service_.get());
   // TODO(mnaganov): Fix URLRequestContextBuilder to use proper threads.
   net::HttpNetworkSession::Params network_session_params;
 
index 712893a..1ec4123 100644 (file)
@@ -11,7 +11,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "content/public/browser/content_browser_client.h"
 #include "net/http/http_network_session.h"
-#include "net/ssl/channel_id_service.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_job_factory.h"
 
@@ -75,7 +74,6 @@ class AwURLRequestContextGetter : public net::URLRequestContextGetter {
       data_reduction_proxy_auth_request_handler_;
   scoped_ptr<net::URLRequestJobFactory> job_factory_;
   scoped_ptr<net::HttpTransactionFactory> main_http_factory_;
-  scoped_ptr<net::ChannelIDService> channel_id_service_;
 
   // ProtocolHandlers and interceptors are stored here between
   // SetHandlersAndInterceptors() and the first GetURLRequestContext() call.
index 676616a..0428baa 100644 (file)
@@ -99,10 +99,6 @@ void AwRenderViewHostExt::SetJsOnlineProperty(bool network_up) {
   Send(new AwViewMsg_SetJsOnlineProperty(network_up));
 }
 
-void AwRenderViewHostExt::SendCheckRenderThreadResponsiveness() {
-  Send(new AwViewMsg_CheckRenderThreadResponsiveness());
-}
-
 void AwRenderViewHostExt::RenderViewCreated(
     content::RenderViewHost* render_view_host) {
   Send(new AwViewMsg_SetBackgroundColor(web_contents()->GetRoutingID(),
index 773e504..635c7fc 100644 (file)
@@ -77,8 +77,6 @@ class AwRenderViewHostExt : public content::WebContentsObserver,
   void SetBackgroundColor(SkColor c);
   void SetJsOnlineProperty(bool network_up);
 
-  void SendCheckRenderThreadResponsiveness();
-
  private:
   // content::WebContentsObserver implementation.
   virtual void RenderViewCreated(content::RenderViewHost* view_host) OVERRIDE;
index 7592fb7..9354db5 100644 (file)
@@ -74,10 +74,6 @@ IPC_MESSAGE_ROUTED1(AwViewMsg_SetBackgroundColor,
 IPC_MESSAGE_CONTROL1(AwViewMsg_SetJsOnlineProperty,
                      bool /* network_up */)
 
-// Sent prior to making a navigation via loadUrl to make sure that
-// render thread isn't stuck in a loop induced by JavaScript code.
-IPC_MESSAGE_CONTROL0(AwViewMsg_CheckRenderThreadResponsiveness)
-
 //-----------------------------------------------------------------------------
 // RenderView messages
 // These are messages sent from the renderer to the browser process.
index 97e292f..55c94b6 100644 (file)
@@ -24,15 +24,24 @@ public class AwAssets {
 
     @CalledByNative
     public static long[] openAsset(Context context, String fileName) {
+        AssetFileDescriptor afd = null;
         try {
             AssetManager manager = context.getAssets();
-            AssetFileDescriptor afd = manager.openFd(fileName);
+            afd = manager.openFd(fileName);
             return new long[] { afd.getParcelFileDescriptor().detachFd(),
                                 afd.getStartOffset(),
                                 afd.getLength() };
         } catch (IOException e) {
-            Log.e(LOGTAG, "Error while loading asset " + fileName + ": " + e.getMessage());
+            Log.e(LOGTAG, "Error while loading asset " + fileName + ": " + e);
             return new long[] {-1, -1, -1};
+        } finally {
+            try {
+                if (afd != null) {
+                    afd.close();
+                }
+            } catch (IOException e2) {
+                Log.e(LOGTAG, "Unable to close AssetFileDescriptor", e2);
+            }
         }
     }
 }
index 436e65c..552d614 100644 (file)
@@ -182,6 +182,7 @@ public class AwContents {
     private final AwLayoutChangeListener mLayoutChangeListener;
     private final Context mContext;
     private ContentViewCore mContentViewCore;
+    private WindowAndroid mWindowAndroid;
     private final AwContentsClient mContentsClient;
     private final AwContentViewClient mContentViewClient;
     private WebContentsObserverAndroid mWebContentsObserver;
@@ -615,12 +616,11 @@ public class AwContents {
             Context context, InternalAccessDelegate internalDispatcher, long nativeWebContents,
             GestureStateListener gestureStateListener,
             ContentViewClient contentViewClient,
-            ContentViewCore.ZoomControlsDelegate zoomControlsDelegate) {
+            ContentViewCore.ZoomControlsDelegate zoomControlsDelegate,
+            WindowAndroid windowAndroid) {
         ContentViewCore contentViewCore = new ContentViewCore(context);
         contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents,
-                context instanceof Activity ?
-                        new ActivityWindowAndroid((Activity) context) :
-                        new WindowAndroid(context.getApplicationContext()));
+                windowAndroid);
         contentViewCore.addGestureStateListener(gestureStateListener);
         contentViewCore.setContentViewClient(contentViewClient);
         contentViewCore.setZoomControlsDelegate(zoomControlsDelegate);
@@ -756,9 +756,13 @@ public class AwContents {
         mCleanupReference = new CleanupReference(this, new DestroyRunnable(mNativeAwContents));
 
         long nativeWebContents = nativeGetWebContents(mNativeAwContents);
+
+        mWindowAndroid = mContext instanceof Activity ?
+                new ActivityWindowAndroid((Activity) mContext) :
+                new WindowAndroid(mContext.getApplicationContext());
         mContentViewCore = createAndInitializeContentViewCore(
                 mContainerView, mContext, mInternalAccessAdapter, nativeWebContents,
-                new AwGestureStateListener(), mContentViewClient, mZoomControls);
+                new AwGestureStateListener(), mContentViewClient, mZoomControls, mWindowAndroid);
         nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
                 mIoThreadClient, mInterceptNavigationDelegate);
         installWebContentsObserver();
@@ -1057,8 +1061,6 @@ public class AwContents {
      * @param params Parameters for this load.
      */
     public void loadUrl(LoadUrlParams params) {
-        if (mNativeAwContents == 0) return;
-
         if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
                 !params.isBaseUrlDataScheme()) {
             // This allows data URLs with a non-data base URL access to file:///android_asset/ and
@@ -1097,11 +1099,12 @@ public class AwContents {
             }
         }
 
-        nativeSetExtraHeadersForUrl(
-                mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString());
+        if (mNativeAwContents != 0) {
+            nativeSetExtraHeadersForUrl(
+                    mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString());
+        }
         params.setExtraHeaders(new HashMap<String, String>());
 
-        nativeSendCheckRenderThreadResponsiveness(mNativeAwContents);
         mContentViewCore.loadUrl(params);
 
         // The behavior of WebViewClassic uses the populateVisitedLinks callback in WebKit.
@@ -2040,13 +2043,20 @@ public class AwContents {
 
     @CalledByNative
     private void postInvalidateOnAnimation() {
-        if (SUPPORTS_ON_ANIMATION) {
+        if (SUPPORTS_ON_ANIMATION && !mWindowAndroid.isInsideVSync()) {
             mContainerView.postInvalidateOnAnimation();
         } else {
-            mContainerView.postInvalidate();
+            mContainerView.invalidate();
         }
     }
 
+    // Call postInvalidateOnAnimation for invalidations. This is only used to synchronize
+    // draw functor destruction.
+    @CalledByNative
+    private void invalidateOnFunctorDestroy() {
+        mContainerView.invalidate();
+    }
+
     @CalledByNative
     private int[] getLocationOnScreen() {
         int[] result = new int[2];
@@ -2489,7 +2499,6 @@ public class AwContents {
     private native void nativeClearView(long nativeAwContents);
     private native void nativeSetExtraHeadersForUrl(long nativeAwContents,
             String url, String extraHeaders);
-    private native void nativeSendCheckRenderThreadResponsiveness(long nativeAwContents);
 
     private native void nativeInvokeGeolocationCallback(
             long nativeAwContents, boolean value, String requestingFrame);
diff --git a/src/android_webview/javatests/src/org/chromium/android_webview/test/AwJavaBridgeTest.java b/src/android_webview/javatests/src/org/chromium/android_webview/test/AwJavaBridgeTest.java
new file mode 100644 (file)
index 0000000..6a15244
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.android_webview.test;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.android_webview.AwContents;
+import org.chromium.base.test.util.Feature;
+import org.chromium.content.browser.JavascriptInterface;
+
+/**
+ * Test suite for the WebView specific JavaBridge features.
+ */
+public class AwJavaBridgeTest extends AwTestBase {
+
+    private TestAwContentsClient mContentsClient = new TestAwContentsClient();
+    private AwTestContainerView mTestContainerView;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTestContainerView = createAwTestContainerViewOnMainSync(mContentsClient);
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView", "Android-JavaBridge"})
+    public void testDestroyFromJavaObject() throws Throwable {
+        final String HTML = "<html>Hello World</html>";
+        final TestAwContentsClient client2 = new TestAwContentsClient();
+        final AwTestContainerView view2 = createAwTestContainerViewOnMainSync(client2);
+        final AwContents awContents = mTestContainerView.getAwContents();
+
+        class Test {
+            @JavascriptInterface
+            public void destroy() {
+                try {
+                    runTestOnUiThread(new Runnable() {
+                            @Override
+                            public void run() {
+                                awContents.destroy();
+                            }
+                    });
+                    // Destroying one AwContents from within the JS callback should still
+                    // leave others functioning.
+                    loadDataSync(view2.getAwContents(), client2.getOnPageFinishedHelper(),
+                            HTML, "text/html", false);
+                } catch (Throwable t) {
+                    throw new RuntimeException(t);
+                }
+            }
+        }
+
+        enableJavaScriptOnUiThread(awContents);
+        runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    awContents.addPossiblyUnsafeJavascriptInterface(new Test(), "test", null);
+            }
+        });
+
+        loadDataSync(awContents, mContentsClient.getOnPageFinishedHelper(), HTML,
+                "text/html", false);
+
+        // Ensure the JS interface object is there, and invoke the test method.
+        assertEquals("\"function\"", executeJavaScriptAndWaitForResult(
+                awContents, mContentsClient, "typeof test.destroy"));
+        awContents.evaluateJavaScript("test.destroy()", null);
+
+        client2.getOnPageFinishedHelper().waitForCallback(
+                client2.getOnPageFinishedHelper().getCallCount());
+    }
+}
index 77fb370..4a6bab5 100644 (file)
@@ -4,12 +4,9 @@
 
 package org.chromium.android_webview.test;
 
-import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Pair;
 
-import junit.framework.Assert;
-
 import org.apache.http.Header;
 import org.apache.http.HttpRequest;
 import org.chromium.android_webview.AwContents;
@@ -334,71 +331,4 @@ public class LoadUrlTest extends AwTestBase {
             if (webServer != null) webServer.shutdown();
         }
     }
-
-    private static class TestController {
-        private final Object mLock = new Object();
-        private boolean mIsReady = false;
-        public void notifyPageIsReady() {
-            synchronized (mLock) {
-                mIsReady = true;
-                mLock.notify();
-            }
-        }
-        public void waitUntilIsReady() {
-            synchronized (mLock) {
-                while (!mIsReady) {
-                    try {
-                        mLock.wait(WAIT_TIMEOUT_MS);
-                    } catch (Exception e) {
-                        continue;
-                    }
-                    if (!mIsReady) {
-                        Assert.fail("Wait timed out");
-                    }
-                }
-                mIsReady = false;
-            }
-        }
-    }
-
-    // Verify that it is possible to interrupt JS scripts stuck in an infinite loop
-    // by calling loadUrl on a WebView.
-    @LargeTest
-    @Feature({"AndroidWebView"})
-    public void testLoadUrlInterruptsLoopedScripts() throws Throwable {
-        final String infiniteLoopPage =
-            "<html><head>" +
-            "  <script>" +
-            "    function infiniteLoop() {" +
-            "      test.notifyPageIsReady();" +
-            "      while(1);" +
-            "    }" +
-            "  </script>" +
-            "</head><body onload='setTimeout(infiniteLoop, 0)'>" +
-            "</body></html>";
-        final String simplePage = "<html><body onload='test.notifyPageIsReady()'></body></html>";
-        final String expectedTitle = "PASS";
-        final String pageWithTitle = "<html><body onload='document.title=\"" + expectedTitle +
-                "\"; test.notifyPageIsReady()'></body></html>";
-
-        final AwTestContainerView testContainerView =
-                createAwTestContainerViewOnMainSync(new TestAwContentsClient());
-        final AwContents awContents = testContainerView.getAwContents();
-        getAwSettingsOnUiThread(awContents).setJavaScriptEnabled(true);
-        final TestController testController = new TestController();
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                awContents.addPossiblyUnsafeJavascriptInterface(testController, "test", null);
-            }
-        });
-        loadDataAsync(awContents, infiniteLoopPage, "text/html", false);
-        testController.waitUntilIsReady();
-        loadDataAsync(awContents, simplePage, "text/html", false);
-        testController.waitUntilIsReady();
-        // Load another page that runs JS to make sure that the WebView is still functional.
-        loadDataAsync(awContents, pageWithTitle, "text/html", false);
-        testController.waitUntilIsReady();
-        assertEquals(expectedTitle, getTitleOnUiThread(awContents));
-    }
 }
index 1aa1d27..73bf8f7 100644 (file)
@@ -6,6 +6,7 @@
 #include "android_webview/native/android_webview_jni_registrar.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_registrar.h"
+#include "base/android/jni_utils.h"
 #include "base/android/library_loader/library_loader_hooks.h"
 #include "components/navigation_interception/component_jni_registrar.h"
 #include "components/web_contents_delegate_android/component_jni_registrar.h"
@@ -47,6 +48,9 @@ JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
   if (!android_webview::RegisterJni(env))
     return -1;
 
+  base::android::InitReplacementClassLoader(env,
+                                            base::android::GetClassLoader(env));
+
   content::SetContentMainDelegate(new android_webview::AwMainDelegate());
 
   // Initialize url lib here while we are still single-threaded, in case we use
index 4c8a4f2..19ed04f 100644 (file)
@@ -297,6 +297,7 @@ void AwContents::Destroy(JNIEnv* env, jobject obj) {
   // the java peer. This is important for the popup window case, where we are
   // swapping AwContents out that share the same java AwContentsClientBridge.
   // See b/15074651.
+  AwContentsClientBridgeBase::Disassociate(web_contents_.get());
   contents_client_bridge_.reset();
 
   // We do not delete AwContents immediately. Some applications try to delete
@@ -898,6 +899,11 @@ void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) {
 void AwContents::ReleaseHardwareDrawIfNeeded() {
   InsideHardwareReleaseReset inside_reset(&shared_renderer_state_);
 
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (!obj.is_null())
+    Java_AwContents_invalidateOnFunctorDestroy(env, obj.obj());
+
   bool hardware_initialized = browser_view_renderer_.hardware_enabled();
   if (hardware_initialized) {
     bool draw_functor_succeeded = RequestDrawGL(NULL, true);
@@ -1143,11 +1149,6 @@ void AwContents::SetExtraHeadersForUrl(JNIEnv* env, jobject obj,
                                     extra_headers);
 }
 
-void AwContents::SendCheckRenderThreadResponsiveness(JNIEnv* env, jobject obj) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  render_view_host_ext_->SendCheckRenderThreadResponsiveness();
-}
-
 void AwContents::SetJsOnlineProperty(JNIEnv* env,
                                      jobject obj,
                                      jboolean network_up) {
index da13d6f..a390375 100644 (file)
@@ -127,7 +127,6 @@ class AwContents : public FindHelper::Listener,
   void ClearView(JNIEnv* env, jobject obj);
   void SetExtraHeadersForUrl(JNIEnv* env, jobject obj,
                              jstring url, jstring extra_headers);
-  void SendCheckRenderThreadResponsiveness(JNIEnv* env, jobject obj);
 
   void DrawGL(AwDrawGLInfo* draw_info);
 
index 5431be7..f5bccdf 100644 (file)
@@ -262,8 +262,10 @@ void AwContentsClientBridge::RunJavaScriptDialog(
   JNIEnv* env = AttachCurrentThread();
 
   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
-  if (obj.is_null())
+  if (obj.is_null()) {
+    callback.Run(false, base::string16());
     return;
+  }
 
   int callback_id = pending_js_dialog_callbacks_.Add(
       new content::JavaScriptDialogManager::DialogClosedCallback(callback));
@@ -310,8 +312,10 @@ void AwContentsClientBridge::RunBeforeUnloadDialog(
   JNIEnv* env = AttachCurrentThread();
 
   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
-  if (obj.is_null())
+  if (obj.is_null()) {
+    callback.Run(false, base::string16());
     return;
+  }
 
   int callback_id = pending_js_dialog_callbacks_.Add(
       new content::JavaScriptDialogManager::DialogClosedCallback(callback));
index f4f0b1e..9ae387b 100644 (file)
@@ -7,7 +7,6 @@
 #include "android_webview/common/aw_resource.h"
 #include "android_webview/common/render_view_messages.h"
 #include "android_webview/common/url_constants.h"
-#include "android_webview/renderer/aw_execution_termination_filter.h"
 #include "android_webview/renderer/aw_key_systems.h"
 #include "android_webview/renderer/aw_permission_client.h"
 #include "android_webview/renderer/aw_render_frame_ext.h"
@@ -32,7 +31,6 @@
 #include "third_party/WebKit/public/platform/WebURLError.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
-#include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebNavigationType.h"
 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
 #include "url/gurl.h"
@@ -63,17 +61,6 @@ void AwContentRendererClient::RenderThreadStarted() {
 
   visited_link_slave_.reset(new visitedlink::VisitedLinkSlave);
   thread->AddObserver(visited_link_slave_.get());
-
-  execution_termination_filter_ = new AwExecutionTerminationFilter(
-      thread->GetIOMessageLoopProxy(),
-      thread->GetMessageLoop()->message_loop_proxy());
-  thread->AddFilter(execution_termination_filter_.get());
-  thread->AddObserver(this);
-}
-
-void AwContentRendererClient::WebKitInitialized() {
-  execution_termination_filter_->SetRenderThreadIsolate(
-      blink::mainThreadIsolate());
 }
 
 bool AwContentRendererClient::HandleNavigation(
index dc02cce..30f44b4 100644 (file)
@@ -16,10 +16,7 @@ class VisitedLinkSlave;
 
 namespace android_webview {
 
-class AwExecutionTerminationFilter;
-
-class AwContentRendererClient : public content::ContentRendererClient,
-                                public content::RenderProcessObserver {
+class AwContentRendererClient : public content::ContentRendererClient {
  public:
   AwContentRendererClient();
   virtual ~AwContentRendererClient();
@@ -53,13 +50,9 @@ class AwContentRendererClient : public content::ContentRendererClient,
                                 blink::WebNavigationPolicy default_policy,
                                 bool is_redirect) OVERRIDE;
 
-  // content::RenderProcessObserver implementation.
-  virtual void WebKitInitialized() OVERRIDE;
-
  private:
   scoped_ptr<AwRenderProcessObserver> aw_render_process_observer_;
   scoped_ptr<visitedlink::VisitedLinkSlave> visited_link_slave_;
-  scoped_refptr<AwExecutionTerminationFilter> execution_termination_filter_;
 };
 
 }  // namespace android_webview
diff --git a/src/android_webview/renderer/aw_execution_termination_filter.cc b/src/android_webview/renderer/aw_execution_termination_filter.cc
deleted file mode 100644 (file)
index 75f130d..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "android_webview/renderer/aw_execution_termination_filter.h"
-
-#include <v8.h>
-
-#include "android_webview/common/render_view_messages.h"
-#include "base/message_loop/message_loop_proxy.h"
-
-namespace {
-const int kTerminationTimeoutInSeconds = 3;
-}  // namespace
-
-namespace android_webview {
-
-AwExecutionTerminationFilter::AwExecutionTerminationFilter(
-    const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
-    const scoped_refptr<base::MessageLoopProxy>& main_message_loop)
-    : io_message_loop_(io_message_loop),
-      main_message_loop_(main_message_loop),
-      render_thread_isolate_(NULL) {
-}
-
-AwExecutionTerminationFilter::~AwExecutionTerminationFilter() {
-}
-
-void AwExecutionTerminationFilter::SetRenderThreadIsolate(
-    v8::Isolate* isolate) {
-  render_thread_isolate_ = isolate;
-}
-
-bool AwExecutionTerminationFilter::OnMessageReceived(
-    const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(AwExecutionTerminationFilter, message)
-    IPC_MESSAGE_HANDLER(AwViewMsg_CheckRenderThreadResponsiveness,
-                        OnCheckRenderThreadResponsiveness)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void AwExecutionTerminationFilter::OnCheckRenderThreadResponsiveness() {
-  termination_timer_.Start(
-      FROM_HERE,
-      base::TimeDelta::FromSeconds(kTerminationTimeoutInSeconds),
-      base::Bind(&AwExecutionTerminationFilter::TerminateExecution, this));
-  // Post a request to stop the timer via render thread's message loop
-  // to ensure that render thread is responsive.
-  main_message_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&AwExecutionTerminationFilter::StopTimerOnMainThread,
-                 this));
-}
-
-void AwExecutionTerminationFilter::StopTimerOnMainThread() {
-  io_message_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&AwExecutionTerminationFilter::StopTimer, this));
-}
-
-void AwExecutionTerminationFilter::StopTimer() {
-  termination_timer_.Stop();
-}
-
-void AwExecutionTerminationFilter::TerminateExecution() {
-  if (render_thread_isolate_) {
-    LOG(WARNING) << "Trying to terminate JavaScript execution because "
-        "renderer is unresponsive";
-    v8::V8::TerminateExecution(render_thread_isolate_);
-  }
-}
-
-}  // namespace android_webview
diff --git a/src/android_webview/renderer/aw_execution_termination_filter.h b/src/android_webview/renderer/aw_execution_termination_filter.h
deleted file mode 100644 (file)
index 14b88b1..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ANDROID_WEBVIEW_RENDERER_AW_EXECUTION_TERMINATION_FILTER_H_
-#define ANDROID_WEBVIEW_RENDERER_AW_EXECUTION_TERMINATION_FILTER_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/timer/timer.h"
-#include "ipc/message_filter.h"
-
-namespace base {
-class MessageLoopProxy;
-}
-
-namespace v8 {
-class Isolate;
-}
-
-namespace android_webview {
-
-// The purpose of AwExecutionTerminationFilter is to attempt to terminate
-// any JavaScript code that is stuck in a loop before doing a navigation
-// originating from a Andoird WebView URL loading functions.
-//
-// This is how it works. AwExecutionTerminationFilter is created on render
-// thread. It listens on IO thread for navigation requests coming from
-// AwContents.loadUrl calls. On each such a request, it posts a delayed
-// cancellable task on the IO thread's message loop and, at the same time, posts
-// a cancellation task on the render thread's message loop. If render thread
-// is not stuck, the cancellation task runs and cancels the delayed task.
-// Otherwise, the delayed task runs and terminates execution of JS code
-// from the IO thread.
-class AwExecutionTerminationFilter : public IPC::MessageFilter {
- public:
-  AwExecutionTerminationFilter(
-      const scoped_refptr<base::MessageLoopProxy>& io_message_loop,
-      const scoped_refptr<base::MessageLoopProxy>& main_message_loop);
-
-  void SetRenderThreadIsolate(v8::Isolate* isolate);
-
- private:
-  virtual ~AwExecutionTerminationFilter();
-
-  // IPC::MessageFilter methods.
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
-  void OnCheckRenderThreadResponsiveness();
-  void StopTimerOnMainThread();
-  void StopTimer();
-  void TerminateExecution();
-
-  const scoped_refptr<base::MessageLoopProxy> io_message_loop_;
-  const scoped_refptr<base::MessageLoopProxy> main_message_loop_;
-
-  v8::Isolate* render_thread_isolate_;
-  base::OneShotTimer<AwExecutionTerminationFilter> termination_timer_;
-
-  DISALLOW_COPY_AND_ASSIGN(AwExecutionTerminationFilter);
-};
-
-}  // namespace android_webview
-
-#endif  // ANDROID_WEBVIEW_RENDERER_AW_EXECUTION_TERMINATION_FILTER_H_
index 4fb77b8..173b2b7 100644 (file)
@@ -25,6 +25,7 @@
 #include "ash/shell_delegate.h"
 #include "ash/wm/coordinate_conversion.h"
 #include "base/command_line.h"
+#include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/aura/client/capture_client.h"
@@ -266,17 +267,27 @@ void DisplayController::Shutdown() {
   virtual_keyboard_window_controller_.reset();
 
   Shell::GetScreen()->RemoveObserver(this);
-  // Delete all root window controllers, which deletes root window
-  // from the last so that the primary root window gets deleted last.
-  for (WindowTreeHostMap::const_reverse_iterator it =
-           window_tree_hosts_.rbegin();
-       it != window_tree_hosts_.rend();
-       ++it) {
-    RootWindowController* controller =
-        GetRootWindowController(GetWindow(it->second));
-    DCHECK(controller);
-    delete controller;
+
+  int64 primary_id = Shell::GetScreen()->GetPrimaryDisplay().id();
+
+  // Delete non primary root window controllers first, then
+  // delete the primary root window controller.
+  aura::Window::Windows root_windows = DisplayController::GetAllRootWindows();
+  std::vector<RootWindowController*> to_delete;
+  RootWindowController* primary_rwc = NULL;
+  for (aura::Window::Windows::iterator iter = root_windows.begin();
+       iter != root_windows.end();
+       ++iter) {
+    RootWindowController* rwc = GetRootWindowController(*iter);
+    if (GetRootWindowSettings(*iter)->display_id == primary_id)
+      primary_rwc = rwc;
+    else
+      to_delete.push_back(rwc);
   }
+  CHECK(primary_rwc);
+
+  STLDeleteElements(&to_delete);
+  delete primary_rwc;
 }
 
 void DisplayController::CreatePrimaryHost(
@@ -325,7 +336,7 @@ aura::Window* DisplayController::GetPrimaryRootWindow() {
 }
 
 aura::Window* DisplayController::GetRootWindowForDisplayId(int64 id) {
-  DCHECK_EQ(1u, window_tree_hosts_.count(id));
+  CHECK_EQ(1u, window_tree_hosts_.count(id));
   AshWindowTreeHost* host = window_tree_hosts_[id];
   CHECK(host);
   return GetWindow(host);
index 8254610..fd06ea8 100644 (file)
@@ -308,7 +308,7 @@ void Shell::DismissAppList() {
 }
 
 void Shell::ToggleAppList(aura::Window* window) {
-  if (GetAppListTargetVisibility()) {
+  if (app_list_controller_ && app_list_controller_->IsVisible()) {
     DismissAppList();
     return;
   }
index 1f8cd3a..a81b0e1 100644 (file)
@@ -51,6 +51,7 @@ void AshPopupAlignmentDelegate::StartObserving(gfx::Screen* screen,
                                                const gfx::Display& display) {
   screen_ = screen;
   display_id_ = display.id();
+  work_area_ = display.work_area();
   root_window_ = ash::Shell::GetInstance()->display_controller()->
       GetRootWindowForDisplayId(display_id_);
   UpdateShelf();
index e42c0f9..900dd93 100644 (file)
@@ -91,8 +91,8 @@ class WebNotificationBubbleWrapper {
     }
     views::TrayBubbleView* bubble_view = views::TrayBubbleView::Create(
         tray->GetBubbleWindowContainer(), anchor, tray, &init_params);
-    bubble_view->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
     bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_view));
+    bubble_view->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
     bubble->InitializeContents(bubble_view);
   }
 
index 91f1161..ae7bcd4 100644 (file)
@@ -13,6 +13,7 @@
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/base/cursor/image_cursors.h"
+#include "ui/base/layout.h"
 
 namespace ash {
 namespace  {
@@ -75,9 +76,17 @@ void AshNativeCursorManager::SetDisplay(
   DCHECK(display.is_valid());
   // Use the platform's device scale factor instead of the display's, which
   // might have been adjusted for the UI scale.
-  const float scale_factor = Shell::GetInstance()->display_manager()->
+  const float original_scale = Shell::GetInstance()->display_manager()->
       GetDisplayInfo(display.id()).device_scale_factor();
-  if (image_cursors_->SetDisplay(display, scale_factor))
+#if defined(OS_CHROMEOS)
+  // And use the nearest resource scale factor.
+  const float cursor_scale = ui::GetScaleForScaleFactor(
+      ui::GetSupportedScaleFactor(original_scale));
+#else
+  // TODO(oshima): crbug.com/143619
+  const float cursor_scale = original_scale;
+#endif
+  if (image_cursors_->SetDisplay(display, cursor_scale))
     SetCursor(delegate->GetCursor(), delegate);
 #if defined(OS_CHROMEOS)
   Shell::GetInstance()->display_controller()->cursor_window_controller()->
index ba7de8a..4d746f8 100644 (file)
@@ -146,6 +146,17 @@ TEST_F(AshNativeCursorManagerTest, SetDeviceScaleFactorAndRotation) {
   EXPECT_EQ(gfx::Display::ROTATE_270, test_api.GetCurrentCursorRotation());
 }
 
+#if defined(OS_CHROMEOS)
+// TODO(oshima): crbug.com/143619
+TEST_F(AshNativeCursorManagerTest, FractionalScale) {
+  ::wm::CursorManager* cursor_manager = Shell::GetInstance()->cursor_manager();
+  CursorManagerTestApi test_api(cursor_manager);
+  // Cursor should use the resource scale factor.
+  UpdateDisplay("800x100*1.25");
+  EXPECT_EQ(1.0f, test_api.GetCurrentCursor().device_scale_factor());
+}
+#endif
+
 TEST_F(AshNativeCursorManagerTest, UIScaleShouldNotChangeCursor) {
   int64 display_id = Shell::GetScreen()->GetPrimaryDisplay().id();
   gfx::Display::SetInternalDisplayId(display_id);
index 70984c4..b680ba2 100644 (file)
@@ -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 "ash/display/display_manager.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
 #include "ash/shell.h"
@@ -187,7 +188,8 @@ TEST_F(LockLayoutManagerTest, MaximizedFullscreenWindowBoundsAreEqualToScreen) {
 }
 
 TEST_F(LockLayoutManagerTest, KeyboardBounds) {
-  gfx::Rect screen_bounds = Shell::GetScreen()->GetPrimaryDisplay().bounds();
+  gfx::Display primary_display = Shell::GetScreen()->GetPrimaryDisplay();
+  gfx::Rect screen_bounds = primary_display.bounds();
 
   views::Widget::InitParams widget_params(
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
@@ -203,8 +205,30 @@ TEST_F(LockLayoutManagerTest, KeyboardBounds) {
        keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_ENABLED);
   ShowKeyboard(true);
   EXPECT_EQ(screen_bounds.ToString(), window->GetBoundsInScreen().ToString());
+  gfx::Rect keyboard_bounds =
+      keyboard::KeyboardController::GetInstance()->current_keyboard_bounds();
+  EXPECT_NE(keyboard_bounds, gfx::Rect());
   ShowKeyboard(false);
 
+  // When keyboard is hidden make sure that rotating the screen gives 100% of
+  // screen size to window.
+  // Repro steps for http://crbug.com/401667:
+  // 1. Set up login screen defaults: VK override disabled
+  // 2. Show/hide keyboard, make sure that no stale keyboard bounds are cached.
+  keyboard::SetKeyboardOverscrollOverride(
+       keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED);
+  ShowKeyboard(true);
+  ShowKeyboard(false);
+  ash::DisplayManager* display_manager =
+      Shell::GetInstance()->display_manager();
+  display_manager->SetDisplayRotation(primary_display.id(),
+                                      gfx::Display::ROTATE_90);
+  primary_display = Shell::GetScreen()->GetPrimaryDisplay();
+  screen_bounds = primary_display.bounds();
+  EXPECT_EQ(screen_bounds.ToString(), window->GetBoundsInScreen().ToString());
+  display_manager->SetDisplayRotation(primary_display.id(),
+                                      gfx::Display::ROTATE_0);
+
   // When virtual keyboard overscroll is disabled keyboard bounds do
   // affect window bounds.
   keyboard::SetKeyboardOverscrollOverride(
@@ -212,6 +236,8 @@ TEST_F(LockLayoutManagerTest, KeyboardBounds) {
   ShowKeyboard(true);
   keyboard::KeyboardController* keyboard =
         keyboard::KeyboardController::GetInstance();
+  primary_display = Shell::GetScreen()->GetPrimaryDisplay();
+  screen_bounds = primary_display.bounds();
   gfx::Rect target_bounds(screen_bounds);
   target_bounds.set_height(target_bounds.height() -
       keyboard->proxy()->GetKeyboardWindow()->bounds().height());
index 5d38b59..fa1684f 100644 (file)
@@ -167,12 +167,17 @@ void LockWindowState::UpdateBounds(wm::WindowState* window_state) {
       keyboard::KeyboardController::GetInstance();
   gfx::Rect keyboard_bounds;
 
-  if (keyboard_controller && !keyboard::IsKeyboardOverscrollEnabled())
+  if (keyboard_controller &&
+      !keyboard::IsKeyboardOverscrollEnabled() &&
+      keyboard_controller->keyboard_visible()) {
     keyboard_bounds = keyboard_controller->current_keyboard_bounds();
+  }
 
   gfx::Rect bounds =
       ScreenUtil::GetDisplayBoundsInParent(window_state->window());
   bounds.set_height(bounds.height() - keyboard_bounds.height());
+
+  VLOG(1) << "Updating window bounds to: " << bounds.ToString();
   window_state->SetBoundsDirect(bounds);
 }
 
index 0f83b32..e8a27b9 100644 (file)
@@ -49,6 +49,8 @@ component("base") {
     "android/jni_registrar.h",
     "android/jni_string.cc",
     "android/jni_string.h",
+    "android/jni_utils.cc",
+    "android/jni_utils.h",
     "android/jni_weak_ref.cc",
     "android/jni_weak_ref.h",
     "android/library_loader/library_loader_hooks.cc",
@@ -1343,6 +1345,7 @@ if (is_android) {
       "android/java/src/org/chromium/base/EventLog.java",
       "android/java/src/org/chromium/base/FieldTrialList.java",
       "android/java/src/org/chromium/base/ImportantFileWriterAndroid.java",
+      "android/java/src/org/chromium/base/JNIUtils.java",
       "android/java/src/org/chromium/base/library_loader/LibraryLoader.java",
       "android/java/src/org/chromium/base/MemoryPressureListener.java",
       "android/java/src/org/chromium/base/JavaHandlerThread.java",
index a7a5fd2..b6d8a28 100644 (file)
@@ -15,6 +15,7 @@
 #include "base/android/java_handler_thread.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_registrar.h"
+#include "base/android/jni_utils.h"
 #include "base/android/memory_pressure_listener_android.h"
 #include "base/android/path_service_android.h"
 #include "base/android/path_utils.h"
@@ -40,6 +41,7 @@ static RegistrationMethod kBaseRegisteredMethods[] = {
   { "FieldTrialList", base::android::RegisterFieldTrialList },
   { "ImportantFileWriterAndroid",
     base::android::RegisterImportantFileWriterAndroid },
+  { "JNIUtils", base::android::RegisterJNIUtils },
   { "MemoryPressureListenerAndroid",
       base::android::MemoryPressureListenerAndroid::Register },
   { "JavaHandlerThread", base::android::JavaHandlerThread::RegisterBindings },
index b806b47..70c27ed 100644 (file)
@@ -11,15 +11,43 @@ import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
+import java.io.File;
+
 /**
  * This class provides methods to access content URI schemes.
  */
 public abstract class ContentUriUtils {
     private static final String TAG = "ContentUriUtils";
+    private static FileProviderUtil sFileProviderUtil;
+
+    /**
+     * Provides functionality to translate a file into a content URI for use
+     * with a content provider.
+     */
+    public interface FileProviderUtil {
+        /**
+         * Generate a content uri from the given file.
+         * @param context Application context.
+         * @param file The file to be translated.
+         */
+        public Uri getContentUriFromFile(Context context, File file);
+    }
 
     // Prevent instantiation.
     private ContentUriUtils() {}
 
+    public static void setFileProviderUtil(FileProviderUtil util) {
+        sFileProviderUtil = util;
+    }
+
+    public static Uri getContentUriFromFile(Context context, File file) {
+        ThreadUtils.assertOnUiThread();
+        if (sFileProviderUtil != null) {
+            return sFileProviderUtil.getContentUriFromFile(context, file);
+        }
+        return null;
+    }
+
     /**
      * Opens the content URI for reading, and returns the file descriptor to
      * the caller. The caller is responsible for closing the file desciptor.
diff --git a/src/base/android/java/src/org/chromium/base/JNIUtils.java b/src/base/android/java/src/org/chromium/base/JNIUtils.java
new file mode 100644 (file)
index 0000000..6f6cd54
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * This class provides JNI-related methods to the native library.
+ */
+public class JNIUtils {
+    /**
+     * This returns a ClassLoader that is capable of loading Chromium Java code. Such a ClassLoader
+     * is needed for the few cases where the JNI mechanism is unable to automatically determine the
+     * appropriate ClassLoader instance.
+     */
+    @CalledByNative
+    public static Object getClassLoader() {
+        return JNIUtils.class.getClassLoader();
+    }
+}
index 49a76b6..7771cbf 100644 (file)
@@ -1013,7 +1013,8 @@ public class Linker {
             mRelroStart = in.readLong();
             mRelroSize = in.readLong();
             ParcelFileDescriptor fd = in.readFileDescriptor();
-            mRelroFd = fd.detachFd();
+            // If CreateSharedRelro fails, the OS file descriptor will be -1 and |fd| will be null.
+            mRelroFd = (fd == null) ? -1 : fd.detachFd();
         }
 
         // from Parcelable
index 6f080fb..e09c2d5 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "base/android/build_info.h"
 #include "base/android/jni_string.h"
+#include "base/android/jni_utils.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 
@@ -21,6 +22,9 @@ JavaVM* g_jvm = NULL;
 // that may still be running at shutdown. There is no harm in doing this.
 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
     g_application_context = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
+    g_class_loader = LAZY_INSTANCE_INITIALIZER;
+jmethodID g_class_loader_load_class_method_id = 0;
 
 std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
   ScopedJavaLocalRef<jclass> throwable_clazz =
@@ -118,17 +122,68 @@ void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
   g_application_context.Get().Reset(context);
 }
 
+void InitReplacementClassLoader(JNIEnv* env,
+                                const JavaRef<jobject>& class_loader) {
+  DCHECK(g_class_loader.Get().is_null());
+  DCHECK(!class_loader.is_null());
+
+  ScopedJavaLocalRef<jclass> class_loader_clazz =
+      GetClass(env, "java/lang/ClassLoader");
+  CHECK(!ClearException(env));
+  g_class_loader_load_class_method_id =
+      env->GetMethodID(class_loader_clazz.obj(),
+                       "loadClass",
+                       "(Ljava/lang/String;)Ljava/lang/Class;");
+  CHECK(!ClearException(env));
+
+  DCHECK(env->IsInstanceOf(class_loader.obj(), class_loader_clazz.obj()));
+  g_class_loader.Get().Reset(class_loader);
+}
+
 const jobject GetApplicationContext() {
   DCHECK(!g_application_context.Get().is_null());
   return g_application_context.Get().obj();
 }
 
 ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
-  jclass clazz = env->FindClass(class_name);
+  jclass clazz;
+  if (!g_class_loader.Get().is_null()) {
+    clazz = static_cast<jclass>(
+        env->CallObjectMethod(g_class_loader.Get().obj(),
+                              g_class_loader_load_class_method_id,
+                              ConvertUTF8ToJavaString(env, class_name).obj()));
+  } else {
+    clazz = env->FindClass(class_name);
+  }
   CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name;
   return ScopedJavaLocalRef<jclass>(env, clazz);
 }
 
+jclass LazyGetClass(
+    JNIEnv* env,
+    const char* class_name,
+    base::subtle::AtomicWord* atomic_class_id) {
+  COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jclass),
+                 AtomicWord_SmallerThan_jMethodID);
+  subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_class_id);
+  if (value)
+    return reinterpret_cast<jclass>(value);
+  ScopedJavaGlobalRef<jclass> clazz;
+  clazz.Reset(GetClass(env, class_name));
+  subtle::AtomicWord null_aw = reinterpret_cast<subtle::AtomicWord>(NULL);
+  subtle::AtomicWord cas_result = base::subtle::Release_CompareAndSwap(
+      atomic_class_id,
+      null_aw,
+      reinterpret_cast<subtle::AtomicWord>(clazz.obj()));
+  if (cas_result == null_aw) {
+    // We intentionally leak the global ref since we now storing it as a raw
+    // pointer in |atomic_class_id|.
+    return clazz.Release();
+  } else {
+    return reinterpret_cast<jclass>(cas_result);
+  }
+}
+
 template<MethodID::Type type>
 jmethodID MethodID::Get(JNIEnv* env,
                         jclass clazz,
index faf53b7..b5e5526 100644 (file)
@@ -53,6 +53,15 @@ BASE_EXPORT bool IsVMInitialized();
 BASE_EXPORT void InitApplicationContext(JNIEnv* env,
                                         const JavaRef<jobject>& context);
 
+// Initializes the global ClassLoader used by the GetClass and LazyGetClass
+// methods. This is needed because JNI will use the base ClassLoader when there
+// is no Java code on the stack. The base ClassLoader doesn't know about any of
+// the application classes and will fail to lookup anything other than system
+// classes.
+BASE_EXPORT void InitReplacementClassLoader(
+    JNIEnv* env,
+    const JavaRef<jobject>& class_loader);
+
 // Gets a global ref to the application context set with
 // InitApplicationContext(). Ownership is retained by the function - the caller
 // must NOT release it.
@@ -66,6 +75,17 @@ const BASE_EXPORT jobject GetApplicationContext();
 BASE_EXPORT ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env,
                                                 const char* class_name);
 
+// The method will initialize |atomic_class_id| to contain a global ref to the
+// class. And will return that ref on subsequent calls.  It's the caller's
+// responsibility to release the ref when it is no longer needed.
+// The caller is responsible to zero-initialize |atomic_method_id|.
+// It's fine to simultaneously call this on multiple threads referencing the
+// same |atomic_method_id|.
+BASE_EXPORT jclass LazyGetClass(
+    JNIEnv* env,
+    const char* class_name,
+    base::subtle::AtomicWord* atomic_class_id);
+
 // This class is a wrapper for JNIEnv Get(Static)MethodID.
 class BASE_EXPORT MethodID {
  public:
index 7dbf71e..0fcdc69 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -26,10 +26,13 @@ const char kInnerStructBClassPath[] =
     "org/chromium/example/jni_generator/SampleForTests$InnerStructB";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_InnerStructA_clazz = NULL;
+#define InnerStructA_clazz(env) g_InnerStructA_clazz
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_SampleForTests_clazz = NULL;
+#define SampleForTests_clazz(env) g_SampleForTests_clazz
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_InnerStructB_clazz = NULL;
+#define InnerStructB_clazz(env) g_InnerStructB_clazz
 
 }  // namespace
 
@@ -99,11 +102,11 @@ static jint Java_SampleForTests_javaMethod(JNIEnv* env, jobject obj,
     JniIntWrapper bar) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_SampleForTests_clazz, 0);
+      SampleForTests_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "javaMethod",
 
 "("
@@ -123,12 +126,12 @@ static jint Java_SampleForTests_javaMethod(JNIEnv* env, jobject obj,
 static base::subtle::AtomicWord g_SampleForTests_staticJavaMethod = 0;
 static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_SampleForTests_clazz,
-      g_SampleForTests_clazz, false);
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), false);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "staticJavaMethod",
 
 "("
@@ -137,7 +140,7 @@ static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
       &g_SampleForTests_staticJavaMethod);
 
   jboolean ret =
-      env->CallStaticBooleanMethod(g_SampleForTests_clazz,
+      env->CallStaticBooleanMethod(SampleForTests_clazz(env),
           method_id);
   jni_generator::CheckException(env);
   return ret;
@@ -148,11 +151,11 @@ static void Java_SampleForTests_packagePrivateJavaMethod(JNIEnv* env, jobject
     obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_SampleForTests_clazz);
+      SampleForTests_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "packagePrivateJavaMethod",
 
 "("
@@ -171,11 +174,11 @@ static void Java_SampleForTests_methodThatThrowsException(JNIEnv* env, jobject
     obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_SampleForTests_clazz);
+      SampleForTests_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "methodThatThrowsException",
 
 "("
@@ -194,12 +197,12 @@ static base::android::ScopedJavaLocalRef<jobject>
     JniIntWrapper i,
     jstring s) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_InnerStructA_clazz,
-      g_InnerStructA_clazz, NULL);
+  CHECK_CLAZZ(env, InnerStructA_clazz(env),
+      InnerStructA_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_InnerStructA_clazz,
+      env, InnerStructA_clazz(env),
       "create",
 
 "("
@@ -211,7 +214,7 @@ static base::android::ScopedJavaLocalRef<jobject>
       &g_InnerStructA_create);
 
   jobject ret =
-      env->CallStaticObjectMethod(g_InnerStructA_clazz,
+      env->CallStaticObjectMethod(InnerStructA_clazz(env),
           method_id, l, as_jint(i), s);
   jni_generator::CheckException(env);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
@@ -222,11 +225,11 @@ static void Java_SampleForTests_addStructA(JNIEnv* env, jobject obj, jobject a)
     {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_SampleForTests_clazz);
+      SampleForTests_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "addStructA",
 
 "("
@@ -246,11 +249,11 @@ static void Java_SampleForTests_iterateAndDoSomething(JNIEnv* env, jobject obj)
     {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_SampleForTests_clazz);
+      SampleForTests_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "iterateAndDoSomething",
 
 "("
@@ -268,11 +271,11 @@ static base::subtle::AtomicWord g_InnerStructB_getKey = 0;
 static jlong Java_InnerStructB_getKey(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InnerStructB_clazz, 0);
+      InnerStructB_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InnerStructB_clazz,
+      env, InnerStructB_clazz(env),
       "getKey",
 
 "("
@@ -292,11 +295,11 @@ static base::android::ScopedJavaLocalRef<jstring>
     Java_InnerStructB_getValue(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InnerStructB_clazz, NULL);
+      InnerStructB_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InnerStructB_clazz,
+      env, InnerStructB_clazz(env),
       "getValue",
 
 "("
@@ -379,11 +382,11 @@ static bool RegisterNativesImpl(JNIEnv* env) {
 
   const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
 
-  if (env->RegisterNatives(g_SampleForTests_clazz,
+  if (env->RegisterNatives(SampleForTests_clazz(env),
                            kMethodsSampleForTests,
                            kMethodsSampleForTestsSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_SampleForTests_clazz, __FILE__);
+        env, SampleForTests_clazz(env), __FILE__);
     return false;
   }
 
index 88332fa..4342fed 100755 (executable)
@@ -731,7 +731,7 @@ class InlHeaderFileGenerator(object):
   def GetContent(self):
     """Returns the content of the JNI binding file."""
     template = Template("""\
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -947,11 +947,11 @@ ${CALLED_BY_NATIVES}
     template = Template("""\
   const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
 
-  if (env->RegisterNatives(g_${JAVA_CLASS}_clazz,
+  if (env->RegisterNatives(${JAVA_CLASS}_clazz(env),
                            kMethods${JAVA_CLASS},
                            kMethods${JAVA_CLASS}Size) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_${JAVA_CLASS}_clazz, __FILE__);
+        env, ${JAVA_CLASS}_clazz(env), __FILE__);
     return false;
   }
 """)
@@ -1122,11 +1122,10 @@ static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
 
   def GetCalledByNativeValues(self, called_by_native):
     """Fills in necessary values for the CalledByNative methods."""
+    java_class = called_by_native.java_class_name or self.class_name
     if called_by_native.static or called_by_native.is_constructor:
       first_param_in_declaration = ''
-      first_param_in_call = ('g_%s_clazz' %
-                             (called_by_native.java_class_name or
-                              self.class_name))
+      first_param_in_call = ('%s_clazz(env)' % java_class)
     else:
       first_param_in_declaration = ', jobject obj'
       first_param_in_call = 'obj'
@@ -1160,7 +1159,7 @@ static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
       else:
         return_clause = 'return ret;'
     return {
-        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+        'JAVA_CLASS': java_class,
         'RETURN_TYPE': return_type,
         'OPTIONAL_ERROR_RETURN': optional_error_return,
         'RETURN_DECLARATION': return_declaration,
@@ -1204,7 +1203,7 @@ static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
 ${FUNCTION_HEADER}
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL},
-      g_${JAVA_CLASS}_clazz${OPTIONAL_ERROR_RETURN});
+      ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN});
   jmethodID method_id =
     ${GET_METHOD_ID_IMPL}
   ${RETURN_DECLARATION}
@@ -1263,22 +1262,42 @@ const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
       }
       ret += [template.substitute(values)]
     ret += ''
-    for clazz in called_by_native_classes:
+
+    class_getter_methods = []
+    if self.options.native_exports:
+      template = Template("""\
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_${JAVA_CLASS}_clazz = 0;
+#define ${JAVA_CLASS}_clazz(env) \
+base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \
+&g_${JAVA_CLASS}_clazz)""")
+    else:
       template = Template("""\
 // Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_${JAVA_CLASS}_clazz = NULL;""")
+jclass g_${JAVA_CLASS}_clazz = NULL;
+#define ${JAVA_CLASS}_clazz(env) g_${JAVA_CLASS}_clazz""")
+
+    for clazz in called_by_native_classes:
       values = {
           'JAVA_CLASS': clazz,
       }
       ret += [template.substitute(values)]
+
     return '\n'.join(ret)
 
   def GetFindClasses(self):
     """Returns the imlementation of FindClass for all known classes."""
     if self.init_native:
-      template = Template("""\
+      if self.options.native_exports:
+        template = Template("""\
+    base::subtle::Release_Store(&g_${JAVA_CLASS}_clazz,
+      static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));""")
+      else:
+        template = Template("""\
   g_${JAVA_CLASS}_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));""")
     else:
+      if self.options.native_exports:
+        return '\n'
       template = Template("""\
   g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""")
@@ -1293,13 +1312,13 @@ jclass g_${JAVA_CLASS}_clazz = NULL;""")
     if self.options.eager_called_by_natives:
       template = Template("""\
 env->Get${STATIC_METHOD_PART}MethodID(
-      g_${JAVA_CLASS}_clazz,
+      ${JAVA_CLASS}_clazz(env),
       "${JNI_NAME}", ${JNI_SIGNATURE});""")
     else:
       template = Template("""\
   base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_${STATIC}>(
-      env, g_${JAVA_CLASS}_clazz,
+      env, ${JAVA_CLASS}_clazz(env),
       "${JNI_NAME}",
       ${JNI_SIGNATURE},
       &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
index abdc507..22aa45d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -22,8 +22,10 @@ const char kTestJniClassPath[] = "org/chromium/TestJni";
 const char kInfoBarClassPath[] = "org/chromium/TestJni$InfoBar";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_InfoBar_clazz = NULL;
+#define InfoBar_clazz(env) g_InfoBar_clazz
 
 }  // namespace
 
@@ -39,11 +41,11 @@ static base::android::ScopedJavaLocalRef<jobject>
     jobject icon) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "showConfirmInfoBar",
 
 "("
@@ -73,11 +75,11 @@ static base::android::ScopedJavaLocalRef<jobject>
     jstring args) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "showAutoLoginInfoBar",
 
 "("
@@ -100,11 +102,11 @@ static base::subtle::AtomicWord g_InfoBar_dismiss = 0;
 static void Java_InfoBar_dismiss(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InfoBar_clazz);
+      InfoBar_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InfoBar_clazz,
+      env, InfoBar_clazz(env),
       "dismiss",
 
 "("
@@ -124,12 +126,12 @@ static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view,
     jstring account,
     jstring args) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_TestJni_clazz,
-      g_TestJni_clazz, false);
+  CHECK_CLAZZ(env, TestJni_clazz(env),
+      TestJni_clazz(env), false);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "shouldShowAutoLogin",
 
 "("
@@ -142,7 +144,7 @@ static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view,
       &g_TestJni_shouldShowAutoLogin);
 
   jboolean ret =
-      env->CallStaticBooleanMethod(g_TestJni_clazz,
+      env->CallStaticBooleanMethod(TestJni_clazz(env),
           method_id, view, realm, account, args);
   jni_generator::CheckException(env);
   return ret;
@@ -152,12 +154,12 @@ static base::subtle::AtomicWord g_TestJni_openUrl = 0;
 static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv*
     env, jstring url) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_TestJni_clazz,
-      g_TestJni_clazz, NULL);
+  CHECK_CLAZZ(env, TestJni_clazz(env),
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "openUrl",
 
 "("
@@ -167,7 +169,7 @@ static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv*
       &g_TestJni_openUrl);
 
   jobject ret =
-      env->CallStaticObjectMethod(g_TestJni_clazz,
+      env->CallStaticObjectMethod(TestJni_clazz(env),
           method_id, url);
   jni_generator::CheckException(env);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
@@ -182,11 +184,11 @@ static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, jobject obj,
     JniIntWrapper iSecondaryID) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz);
+      TestJni_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "activateHardwareAcceleration",
 
 "("
@@ -211,11 +213,11 @@ static void Java_TestJni_uncheckedCall(JNIEnv* env, jobject obj, JniIntWrapper
     iParam) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz);
+      TestJni_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "uncheckedCall",
 
 "("
@@ -234,11 +236,11 @@ static base::android::ScopedJavaLocalRef<jbyteArray>
     Java_TestJni_returnByteArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "returnByteArray",
 
 "("
@@ -258,11 +260,11 @@ static base::android::ScopedJavaLocalRef<jbooleanArray>
     Java_TestJni_returnBooleanArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "returnBooleanArray",
 
 "("
@@ -282,11 +284,11 @@ static base::android::ScopedJavaLocalRef<jcharArray>
     Java_TestJni_returnCharArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "returnCharArray",
 
 "("
@@ -306,11 +308,11 @@ static base::android::ScopedJavaLocalRef<jshortArray>
     Java_TestJni_returnShortArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "returnShortArray",
 
 "("
@@ -330,11 +332,11 @@ static base::android::ScopedJavaLocalRef<jintArray>
     Java_TestJni_returnIntArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "returnIntArray",
 
 "("
@@ -354,11 +356,11 @@ static base::android::ScopedJavaLocalRef<jlongArray>
     Java_TestJni_returnLongArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "returnLongArray",
 
 "("
@@ -378,11 +380,11 @@ static base::android::ScopedJavaLocalRef<jdoubleArray>
     Java_TestJni_returnDoubleArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "returnDoubleArray",
 
 "("
@@ -402,11 +404,11 @@ static base::android::ScopedJavaLocalRef<jobjectArray>
     Java_TestJni_returnObjectArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "returnObjectArray",
 
 "("
@@ -426,11 +428,11 @@ static base::android::ScopedJavaLocalRef<jobjectArray>
     Java_TestJni_returnArrayOfByteArray(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "returnArrayOfByteArray",
 
 "("
@@ -450,11 +452,11 @@ static base::android::ScopedJavaLocalRef<jobject>
     Java_TestJni_getCompressFormat(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "getCompressFormat",
 
 "("
@@ -474,11 +476,11 @@ static base::android::ScopedJavaLocalRef<jobject>
     Java_TestJni_getCompressFormatList(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_TestJni_clazz, NULL);
+      TestJni_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_TestJni_clazz,
+      env, TestJni_clazz(env),
       "getCompressFormatList",
 
 "("
index 795bd54..f122529 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kMotionEventClassPath[] = "android/view/MotionEvent";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_MotionEvent_clazz = NULL;
+#define MotionEvent_clazz(env) g_MotionEvent_clazz
 
 }  // namespace
 
@@ -117,11 +118,11 @@ static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) __attribute__
 static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "finalize",
       "()V",
       &g_MotionEvent_finalize);
@@ -167,18 +168,18 @@ static base::android::ScopedJavaLocalRef<jobject>
     JniIntWrapper p12,
     JniIntWrapper p13) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, NULL);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "obtain",
 "(JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;",
       &g_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(g_MotionEvent_clazz,
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6),
               as_jint(p7), p8, p9, as_jint(p10), as_jint(p11), as_jint(p12),
               as_jint(p13));
@@ -219,18 +220,18 @@ static base::android::ScopedJavaLocalRef<jobject>
     JniIntWrapper p11,
     JniIntWrapper p12) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, NULL);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "obtain",
 "(JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;",
       &g_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(g_MotionEvent_clazz,
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6), p7,
               p8, as_jint(p9), as_jint(p10), as_jint(p11), as_jint(p12));
   jni_generator::CheckException(env);
@@ -266,18 +267,18 @@ static base::android::ScopedJavaLocalRef<jobject>
     JniIntWrapper p10,
     JniIntWrapper p11) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, NULL);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "obtain",
       "(JJIFFFFIFFII)Landroid/view/MotionEvent;",
       &g_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(g_MotionEvent_clazz,
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0, p1, as_jint(p2), p3, p4, p5, p6, as_jint(p7), p8, p9,
               as_jint(p10), as_jint(p11));
   jni_generator::CheckException(env);
@@ -315,18 +316,18 @@ static base::android::ScopedJavaLocalRef<jobject>
     JniIntWrapper p11,
     JniIntWrapper p12) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, NULL);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "obtain",
       "(JJIIFFFFIFFII)Landroid/view/MotionEvent;",
       &g_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(g_MotionEvent_clazz,
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, p6, p7,
               as_jint(p8), p9, p10, as_jint(p11), as_jint(p12));
   jni_generator::CheckException(env);
@@ -349,18 +350,18 @@ static base::android::ScopedJavaLocalRef<jobject>
     jfloat p4,
     JniIntWrapper p5) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, NULL);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "obtain",
       "(JJIFFI)Landroid/view/MotionEvent;",
       &g_MotionEvent_obtainAVME_J_J_I_F_F_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(g_MotionEvent_clazz,
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0, p1, as_jint(p2), p3, p4, as_jint(p5));
   jni_generator::CheckException(env);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
@@ -373,18 +374,18 @@ static base::android::ScopedJavaLocalRef<jobject>
 static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, jobject p0) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, NULL);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "obtain",
       "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
       &g_MotionEvent_obtainAVME_AVME);
 
   jobject ret =
-      env->CallStaticObjectMethod(g_MotionEvent_clazz,
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0);
   jni_generator::CheckException(env);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
@@ -397,18 +398,18 @@ static base::android::ScopedJavaLocalRef<jobject>
 static base::android::ScopedJavaLocalRef<jobject>
     Java_MotionEvent_obtainNoHistory(JNIEnv* env, jobject p0) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, NULL);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "obtainNoHistory",
       "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
       &g_MotionEvent_obtainNoHistory);
 
   jobject ret =
-      env->CallStaticObjectMethod(g_MotionEvent_clazz,
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, p0);
   jni_generator::CheckException(env);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
@@ -420,11 +421,11 @@ static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) __attribute__
 static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "recycle",
       "()V",
       &g_MotionEvent_recycle);
@@ -441,11 +442,11 @@ static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) __attribute__
 static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getDeviceId",
       "()I",
       &g_MotionEvent_getDeviceId);
@@ -463,11 +464,11 @@ static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) __attribute__
 static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getSource",
       "()I",
       &g_MotionEvent_getSource);
@@ -486,11 +487,11 @@ static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
     p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "setSource",
       "(I)V",
       &g_MotionEvent_setSource);
@@ -507,11 +508,11 @@ static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) __attribute__
 static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getAction",
       "()I",
       &g_MotionEvent_getAction);
@@ -529,11 +530,11 @@ static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj)
 static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getActionMasked",
       "()I",
       &g_MotionEvent_getActionMasked);
@@ -551,11 +552,11 @@ static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj)
 static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getActionIndex",
       "()I",
       &g_MotionEvent_getActionIndex);
@@ -573,11 +574,11 @@ static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) __attribute__
 static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getFlags",
       "()I",
       &g_MotionEvent_getFlags);
@@ -595,11 +596,11 @@ static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj)
 static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getDownTime",
       "()J",
       &g_MotionEvent_getDownTime);
@@ -617,11 +618,11 @@ static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj)
 static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getEventTime",
       "()J",
       &g_MotionEvent_getEventTime);
@@ -639,11 +640,11 @@ static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) __attribute__
 static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getX",
       "()F",
       &g_MotionEvent_getXF);
@@ -661,11 +662,11 @@ static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) __attribute__
 static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getY",
       "()F",
       &g_MotionEvent_getYF);
@@ -683,11 +684,11 @@ static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj)
 static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getPressure",
       "()F",
       &g_MotionEvent_getPressureF);
@@ -705,11 +706,11 @@ static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) __attribute__
 static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getSize",
       "()F",
       &g_MotionEvent_getSizeF);
@@ -727,11 +728,11 @@ static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj)
 static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getTouchMajor",
       "()F",
       &g_MotionEvent_getTouchMajorF);
@@ -749,11 +750,11 @@ static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj)
 static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getTouchMinor",
       "()F",
       &g_MotionEvent_getTouchMinorF);
@@ -771,11 +772,11 @@ static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj)
 static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getToolMajor",
       "()F",
       &g_MotionEvent_getToolMajorF);
@@ -793,11 +794,11 @@ static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj)
 static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getToolMinor",
       "()F",
       &g_MotionEvent_getToolMinorF);
@@ -815,11 +816,11 @@ static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj)
 static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getOrientation",
       "()F",
       &g_MotionEvent_getOrientationF);
@@ -838,11 +839,11 @@ static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getAxisValue",
       "(I)F",
       &g_MotionEvent_getAxisValueF_I);
@@ -860,11 +861,11 @@ static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj)
 static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getPointerCount",
       "()I",
       &g_MotionEvent_getPointerCount);
@@ -883,11 +884,11 @@ static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getPointerId",
       "(I)I",
       &g_MotionEvent_getPointerId);
@@ -906,11 +907,11 @@ static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
     p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getToolType",
       "(I)I",
       &g_MotionEvent_getToolType);
@@ -929,11 +930,11 @@ static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "findPointerIndex",
       "(I)I",
       &g_MotionEvent_findPointerIndex);
@@ -952,11 +953,11 @@ static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
     p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getX",
       "(I)F",
       &g_MotionEvent_getXF_I);
@@ -975,11 +976,11 @@ static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
     p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getY",
       "(I)F",
       &g_MotionEvent_getYF_I);
@@ -998,11 +999,11 @@ static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getPressure",
       "(I)F",
       &g_MotionEvent_getPressureF_I);
@@ -1021,11 +1022,11 @@ static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getSize",
       "(I)F",
       &g_MotionEvent_getSizeF_I);
@@ -1044,11 +1045,11 @@ static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getTouchMajor",
       "(I)F",
       &g_MotionEvent_getTouchMajorF_I);
@@ -1067,11 +1068,11 @@ static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getTouchMinor",
       "(I)F",
       &g_MotionEvent_getTouchMinorF_I);
@@ -1090,11 +1091,11 @@ static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getToolMajor",
       "(I)F",
       &g_MotionEvent_getToolMajorF_I);
@@ -1113,11 +1114,11 @@ static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getToolMinor",
       "(I)F",
       &g_MotionEvent_getToolMinorF_I);
@@ -1136,11 +1137,11 @@ static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getOrientation",
       "(I)F",
       &g_MotionEvent_getOrientationF_I);
@@ -1161,11 +1162,11 @@ static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getAxisValue",
       "(II)F",
       &g_MotionEvent_getAxisValueF_I_I);
@@ -1186,11 +1187,11 @@ static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
     jobject p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getPointerCoords",
       "(ILandroid/view/MotionEvent$PointerCoords;)V",
       &g_MotionEvent_getPointerCoords);
@@ -1210,11 +1211,11 @@ static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
     jobject p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getPointerProperties",
       "(ILandroid/view/MotionEvent$PointerProperties;)V",
       &g_MotionEvent_getPointerProperties);
@@ -1231,11 +1232,11 @@ static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj)
 static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getMetaState",
       "()I",
       &g_MotionEvent_getMetaState);
@@ -1253,11 +1254,11 @@ static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj)
 static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getButtonState",
       "()I",
       &g_MotionEvent_getButtonState);
@@ -1275,11 +1276,11 @@ static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) __attribute__
 static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getRawX",
       "()F",
       &g_MotionEvent_getRawX);
@@ -1297,11 +1298,11 @@ static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) __attribute__
 static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getRawY",
       "()F",
       &g_MotionEvent_getRawY);
@@ -1319,11 +1320,11 @@ static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj)
 static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getXPrecision",
       "()F",
       &g_MotionEvent_getXPrecision);
@@ -1341,11 +1342,11 @@ static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj)
 static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getYPrecision",
       "()F",
       &g_MotionEvent_getYPrecision);
@@ -1363,11 +1364,11 @@ static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj)
 static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistorySize",
       "()I",
       &g_MotionEvent_getHistorySize);
@@ -1386,11 +1387,11 @@ static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalEventTime",
       "(I)J",
       &g_MotionEvent_getHistoricalEventTime);
@@ -1409,11 +1410,11 @@ static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalX",
       "(I)F",
       &g_MotionEvent_getHistoricalXF_I);
@@ -1432,11 +1433,11 @@ static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalY",
       "(I)F",
       &g_MotionEvent_getHistoricalYF_I);
@@ -1455,11 +1456,11 @@ static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
     obj, JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalPressure",
       "(I)F",
       &g_MotionEvent_getHistoricalPressureF_I);
@@ -1478,11 +1479,11 @@ static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalSize",
       "(I)F",
       &g_MotionEvent_getHistoricalSizeF_I);
@@ -1501,11 +1502,11 @@ static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
     obj, JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalTouchMajor",
       "(I)F",
       &g_MotionEvent_getHistoricalTouchMajorF_I);
@@ -1524,11 +1525,11 @@ static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
     obj, JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalTouchMinor",
       "(I)F",
       &g_MotionEvent_getHistoricalTouchMinorF_I);
@@ -1547,11 +1548,11 @@ static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
     obj, JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalToolMajor",
       "(I)F",
       &g_MotionEvent_getHistoricalToolMajorF_I);
@@ -1570,11 +1571,11 @@ static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
     obj, JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalToolMinor",
       "(I)F",
       &g_MotionEvent_getHistoricalToolMinorF_I);
@@ -1593,11 +1594,11 @@ static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
     obj, JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalOrientation",
       "(I)F",
       &g_MotionEvent_getHistoricalOrientationF_I);
@@ -1618,11 +1619,11 @@ static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalAxisValue",
       "(II)F",
       &g_MotionEvent_getHistoricalAxisValueF_I_I);
@@ -1643,11 +1644,11 @@ static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalX",
       "(II)F",
       &g_MotionEvent_getHistoricalXF_I_I);
@@ -1668,11 +1669,11 @@ static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalY",
       "(II)F",
       &g_MotionEvent_getHistoricalYF_I_I);
@@ -1693,11 +1694,11 @@ static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalPressure",
       "(II)F",
       &g_MotionEvent_getHistoricalPressureF_I_I);
@@ -1718,11 +1719,11 @@ static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalSize",
       "(II)F",
       &g_MotionEvent_getHistoricalSizeF_I_I);
@@ -1743,11 +1744,11 @@ static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalTouchMajor",
       "(II)F",
       &g_MotionEvent_getHistoricalTouchMajorF_I_I);
@@ -1768,11 +1769,11 @@ static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalTouchMinor",
       "(II)F",
       &g_MotionEvent_getHistoricalTouchMinorF_I_I);
@@ -1793,11 +1794,11 @@ static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalToolMajor",
       "(II)F",
       &g_MotionEvent_getHistoricalToolMajorF_I_I);
@@ -1818,11 +1819,11 @@ static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalToolMinor",
       "(II)F",
       &g_MotionEvent_getHistoricalToolMinorF_I_I);
@@ -1843,11 +1844,11 @@ static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalOrientation",
       "(II)F",
       &g_MotionEvent_getHistoricalOrientationF_I_I);
@@ -1870,11 +1871,11 @@ static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
     JniIntWrapper p2) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalAxisValue",
       "(III)F",
       &g_MotionEvent_getHistoricalAxisValueF_I_I_I);
@@ -1897,11 +1898,11 @@ static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
     jobject p2) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getHistoricalPointerCoords",
       "(IILandroid/view/MotionEvent$PointerCoords;)V",
       &g_MotionEvent_getHistoricalPointerCoords);
@@ -1918,11 +1919,11 @@ static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj)
 static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, 0);
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "getEdgeFlags",
       "()I",
       &g_MotionEvent_getEdgeFlags);
@@ -1941,11 +1942,11 @@ static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
     JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "setEdgeFlags",
       "(I)V",
       &g_MotionEvent_setEdgeFlags);
@@ -1963,11 +1964,11 @@ static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
     p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "setAction",
       "(I)V",
       &g_MotionEvent_setAction);
@@ -1985,11 +1986,11 @@ static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
     jfloat p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "offsetLocation",
       "(FF)V",
       &g_MotionEvent_offsetLocation);
@@ -2007,11 +2008,11 @@ static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
     jfloat p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "setLocation",
       "(FF)V",
       &g_MotionEvent_setLocation);
@@ -2028,11 +2029,11 @@ static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0)
 static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "transform",
       "(Landroid/graphics/Matrix;)V",
       &g_MotionEvent_transform);
@@ -2060,11 +2061,11 @@ static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
     JniIntWrapper p5) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "addBatch",
       "(JFFFFI)V",
       &g_MotionEvent_addBatchV_J_F_F_F_F_I);
@@ -2086,11 +2087,11 @@ static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
     JniIntWrapper p2) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "addBatch",
       "(J[Landroid/view/MotionEvent$PointerCoords;I)V",
       &g_MotionEvent_addBatchV_J_LAVMEPC_I);
@@ -2109,11 +2110,11 @@ static base::android::ScopedJavaLocalRef<jstring>
     Java_MotionEvent_toString(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz, NULL);
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "toString",
       "()Ljava/lang/String;",
       &g_MotionEvent_toString);
@@ -2132,18 +2133,18 @@ static base::android::ScopedJavaLocalRef<jstring>
 static base::android::ScopedJavaLocalRef<jstring>
     Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, NULL);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "actionToString",
       "(I)Ljava/lang/String;",
       &g_MotionEvent_actionToString);
 
   jstring ret =
-      static_cast<jstring>(env->CallStaticObjectMethod(g_MotionEvent_clazz,
+      static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, as_jint(p0)));
   jni_generator::CheckException(env);
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
@@ -2156,18 +2157,18 @@ static base::android::ScopedJavaLocalRef<jstring>
 static base::android::ScopedJavaLocalRef<jstring>
     Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, NULL);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "axisToString",
       "(I)Ljava/lang/String;",
       &g_MotionEvent_axisToString);
 
   jstring ret =
-      static_cast<jstring>(env->CallStaticObjectMethod(g_MotionEvent_clazz,
+      static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
           method_id, as_jint(p0)));
   jni_generator::CheckException(env);
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
@@ -2178,18 +2179,18 @@ static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0)
     __attribute__ ((unused));
 static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_MotionEvent_clazz,
-      g_MotionEvent_clazz, 0);
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "axisFromString",
       "(Ljava/lang/String;)I",
       &g_MotionEvent_axisFromString);
 
   jint ret =
-      env->CallStaticIntMethod(g_MotionEvent_clazz,
+      env->CallStaticIntMethod(MotionEvent_clazz(env),
           method_id, p0);
   jni_generator::CheckException(env);
   return ret;
@@ -2202,11 +2203,11 @@ static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
     JniIntWrapper p1) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_MotionEvent_clazz);
+      MotionEvent_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_MotionEvent_clazz,
+      env, MotionEvent_clazz(env),
       "writeToParcel",
       "(Landroid/os/Parcel;I)V",
       &g_MotionEvent_writeToParcel);
index 4ff81ac..6c1323e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kTestClassPath[] = "org/chromium/example/jni_generator/Test";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_Test_clazz = NULL;
+#define Test_clazz(env) g_Test_clazz
 jmethodID g_Test_testMethodWithParam = NULL;
 jmethodID g_Test_testStaticMethodWithParam = NULL;
 jmethodID g_Test_testMethodWithNoParam = NULL;
@@ -46,20 +47,21 @@ static void testMethodWithParam(JNIEnv* env, jobject obj, JniIntWrapper iParam)
 }
 
 static jint testStaticMethodWithParam(JNIEnv* env, JniIntWrapper iParam) {
-  jint ret = env->CallStaticIntMethod(g_Test_clazz,
+  jint ret = env->CallStaticIntMethod(Test_clazz(env),
       g_Test_testStaticMethodWithParam, as_jint(iParam));
   return ret;
 }
 
 static jdouble testMethodWithNoParam(JNIEnv* env) {
-  jdouble ret = env->CallStaticDoubleMethod(g_Test_clazz,
+  jdouble ret = env->CallStaticDoubleMethod(Test_clazz(env),
       g_Test_testMethodWithNoParam);
   return ret;
 }
 
 static base::android::ScopedJavaLocalRef<jstring>
     testStaticMethodWithNoParam(JNIEnv* env) {
-  jstring ret = static_cast<jstring>(env->CallStaticObjectMethod(g_Test_clazz,
+  jstring ret =
+      static_cast<jstring>(env->CallStaticObjectMethod(Test_clazz(env),
       g_Test_testStaticMethodWithNoParam));
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
@@ -81,16 +83,16 @@ static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
 
   const int kMethodsTestSize = arraysize(kMethodsTest);
 
-  if (env->RegisterNatives(g_Test_clazz,
+  if (env->RegisterNatives(Test_clazz(env),
                            kMethodsTest,
                            kMethodsTestSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_Test_clazz, __FILE__);
+        env, Test_clazz(env), __FILE__);
     return false;
   }
 
   g_Test_testMethodWithParam = env->GetMethodID(
-      g_Test_clazz,
+      Test_clazz(env),
       "testMethodWithParam",
 "("
 "I"
@@ -101,7 +103,7 @@ static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
   }
 
   g_Test_testStaticMethodWithParam = env->GetStaticMethodID(
-      g_Test_clazz,
+      Test_clazz(env),
       "testStaticMethodWithParam",
 "("
 "I"
@@ -112,7 +114,7 @@ static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
   }
 
   g_Test_testMethodWithNoParam = env->GetStaticMethodID(
-      g_Test_clazz,
+      Test_clazz(env),
       "testMethodWithNoParam",
 "("
 ")"
@@ -122,7 +124,7 @@ static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
   }
 
   g_Test_testStaticMethodWithNoParam = env->GetStaticMethodID(
-      g_Test_clazz,
+      Test_clazz(env),
       "testStaticMethodWithNoParam",
 "("
 ")"
index 34e2118..5827410 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kInputStreamClassPath[] = "java/io/InputStream";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_InputStream_clazz = NULL;
+#define InputStream_clazz(env) g_InputStream_clazz
 
 }  // namespace
 
@@ -34,11 +35,11 @@ static jint Java_InputStream_available(JNIEnv* env, jobject obj) __attribute__
 static jint Java_InputStream_available(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InputStream_clazz, 0);
+      InputStream_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "available",
       "()I",
       &g_InputStream_available);
@@ -56,11 +57,11 @@ static void Java_InputStream_close(JNIEnv* env, jobject obj) __attribute__
 static void Java_InputStream_close(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InputStream_clazz);
+      InputStream_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "close",
       "()V",
       &g_InputStream_close);
@@ -77,11 +78,11 @@ static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0)
 static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InputStream_clazz);
+      InputStream_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "mark",
       "(I)V",
       &g_InputStream_mark);
@@ -98,11 +99,11 @@ static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj)
 static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InputStream_clazz, false);
+      InputStream_clazz(env), false);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "markSupported",
       "()Z",
       &g_InputStream_markSupported);
@@ -120,11 +121,11 @@ static jint Java_InputStream_readI(JNIEnv* env, jobject obj) __attribute__
 static jint Java_InputStream_readI(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InputStream_clazz, 0);
+      InputStream_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "read",
       "()I",
       &g_InputStream_readI);
@@ -142,11 +143,11 @@ static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0)
 static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InputStream_clazz, 0);
+      InputStream_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "read",
       "([B)I",
       &g_InputStream_readI_AB);
@@ -169,11 +170,11 @@ static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
     JniIntWrapper p2) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InputStream_clazz, 0);
+      InputStream_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "read",
       "([BII)I",
       &g_InputStream_readI_AB_I_I);
@@ -191,11 +192,11 @@ static void Java_InputStream_reset(JNIEnv* env, jobject obj) __attribute__
 static void Java_InputStream_reset(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InputStream_clazz);
+      InputStream_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "reset",
       "()V",
       &g_InputStream_reset);
@@ -212,11 +213,11 @@ static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0)
 static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_InputStream_clazz, 0);
+      InputStream_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "skip",
       "(J)J",
       &g_InputStream_skip);
@@ -234,18 +235,18 @@ static base::android::ScopedJavaLocalRef<jobject>
 static base::android::ScopedJavaLocalRef<jobject>
     Java_InputStream_Constructor(JNIEnv* env) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_InputStream_clazz,
-      g_InputStream_clazz, NULL);
+  CHECK_CLAZZ(env, InputStream_clazz(env),
+      InputStream_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_InputStream_clazz,
+      env, InputStream_clazz(env),
       "<init>",
       "()V",
       &g_InputStream_Constructor);
 
   jobject ret =
-      env->NewObject(g_InputStream_clazz,
+      env->NewObject(InputStream_clazz(env),
           method_id);
   jni_generator::CheckException(env);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
index 48582fd..5d78390 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kHashSetClassPath[] = "java/util/HashSet";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_HashSet_clazz = NULL;
+#define HashSet_clazz(env) g_HashSet_clazz
 
 }  // namespace
 
@@ -34,11 +35,11 @@ static void Java_HashSet_dummy(JNIEnv* env, jobject obj) __attribute__
 static void Java_HashSet_dummy(JNIEnv* env, jobject obj) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_HashSet_clazz);
+      HashSet_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_HashSet_clazz,
+      env, HashSet_clazz(env),
       "dummy",
       "()V",
       &g_HashSet_dummy);
index 56a2e9b..2dee84e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -22,6 +22,7 @@ const char kTestJniClassPath[] = "org/chromium/TestJni";
 const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
 
 }  // namespace
 
@@ -44,11 +45,11 @@ static bool RegisterNativesImpl(JNIEnv* env) {
 
   const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
 
-  if (env->RegisterNatives(g_MyInnerClass_clazz,
+  if (env->RegisterNatives(MyInnerClass_clazz(env),
                            kMethodsMyInnerClass,
                            kMethodsMyInnerClassSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_MyInnerClass_clazz, __FILE__);
+        env, MyInnerClass_clazz(env), __FILE__);
     return false;
   }
 
index 07b857f..6ffbaac 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -23,6 +23,7 @@ const char kMyOtherInnerClassClassPath[] =
 const char kTestJniClassPath[] = "org/chromium/TestJni";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
 
 }  // namespace
 
@@ -55,21 +56,21 @@ static bool RegisterNativesImpl(JNIEnv* env) {
   const int kMethodsMyOtherInnerClassSize =
       arraysize(kMethodsMyOtherInnerClass);
 
-  if (env->RegisterNatives(g_MyOtherInnerClass_clazz,
+  if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
                            kMethodsMyOtherInnerClass,
                            kMethodsMyOtherInnerClassSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_MyOtherInnerClass_clazz, __FILE__);
+        env, MyOtherInnerClass_clazz(env), __FILE__);
     return false;
   }
 
   const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
 
-  if (env->RegisterNatives(g_TestJni_clazz,
+  if (env->RegisterNatives(TestJni_clazz(env),
                            kMethodsTestJni,
                            kMethodsTestJniSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_TestJni_clazz, __FILE__);
+        env, TestJni_clazz(env), __FILE__);
     return false;
   }
 
index 6a7f04d..b74e65f 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -24,6 +24,7 @@ const char kTestJniClassPath[] = "org/chromium/TestJni";
 const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
 
 }  // namespace
 
@@ -56,21 +57,21 @@ static bool RegisterNativesImpl(JNIEnv* env) {
   const int kMethodsMyOtherInnerClassSize =
       arraysize(kMethodsMyOtherInnerClass);
 
-  if (env->RegisterNatives(g_MyOtherInnerClass_clazz,
+  if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
                            kMethodsMyOtherInnerClass,
                            kMethodsMyOtherInnerClassSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_MyOtherInnerClass_clazz, __FILE__);
+        env, MyOtherInnerClass_clazz(env), __FILE__);
     return false;
   }
 
   const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
 
-  if (env->RegisterNatives(g_MyInnerClass_clazz,
+  if (env->RegisterNatives(MyInnerClass_clazz(env),
                            kMethodsMyInnerClass,
                            kMethodsMyInnerClassSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_MyInnerClass_clazz, __FILE__);
+        env, MyInnerClass_clazz(env), __FILE__);
     return false;
   }
 
index 0d5d3c6..53b5f17 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kTestClassPath[] = "org/chromium/example/jni_generator/Test";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_Test_clazz = NULL;
+#define Test_clazz(env) g_Test_clazz
 
 }  // namespace
 
@@ -49,11 +50,11 @@ static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
 
   const int kMethodsTestSize = arraysize(kMethodsTest);
 
-  if (env->RegisterNatives(g_Test_clazz,
+  if (env->RegisterNatives(Test_clazz(env),
                            kMethodsTest,
                            kMethodsTestSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_Test_clazz, __FILE__);
+        env, Test_clazz(env), __FILE__);
     return false;
   }
 
index 9b2c0b3..75a35c5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kExampleClassPath[] = "com/test/jni_generator/Example";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_Example_clazz = NULL;
+#define Example_clazz(env) g_Example_clazz
 
 }  // namespace
 
@@ -69,11 +70,11 @@ static bool RegisterNativesImpl(JNIEnv* env) {
 
   const int kMethodsExampleSize = arraysize(kMethodsExample);
 
-  if (env->RegisterNatives(g_Example_clazz,
+  if (env->RegisterNatives(Example_clazz(env),
                            kMethodsExample,
                            kMethodsExampleSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_Example_clazz, __FILE__);
+        env, Example_clazz(env), __FILE__);
     return false;
   }
 
index 9cc1256..df5b1c8 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kFooClassPath[] = "org/chromium/foo/Foo";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_Foo_clazz = NULL;
+#define Foo_clazz(env) g_Foo_clazz
 
 }  // namespace
 
@@ -34,12 +35,12 @@ static base::subtle::AtomicWord g_Foo_calledByNative = 0;
 static void Java_Foo_calledByNative(JNIEnv* env, jobject callback1,
     jobject callback2) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_Foo_clazz,
-      g_Foo_clazz);
+  CHECK_CLAZZ(env, Foo_clazz(env),
+      Foo_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_Foo_clazz,
+      env, Foo_clazz(env),
       "calledByNative",
 
 "("
@@ -49,7 +50,7 @@ static void Java_Foo_calledByNative(JNIEnv* env, jobject callback1,
 "V",
       &g_Foo_calledByNative);
 
-     env->CallStaticVoidMethod(g_Foo_clazz,
+     env->CallStaticVoidMethod(Foo_clazz(env),
           method_id, callback1, callback2);
   jni_generator::CheckException(env);
 
@@ -72,11 +73,11 @@ static bool RegisterNativesImpl(JNIEnv* env) {
 
   const int kMethodsFooSize = arraysize(kMethodsFoo);
 
-  if (env->RegisterNatives(g_Foo_clazz,
+  if (env->RegisterNatives(Foo_clazz(env),
                            kMethodsFoo,
                            kMethodsFooSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_Foo_clazz, __FILE__);
+        env, Foo_clazz(env), __FILE__);
     return false;
   }
 
index 231be7c..5beaa82 100644 (file)
@@ -21,7 +21,8 @@ namespace {
 const char kSampleForTestsClassPath[] =
     "org/chromium/example/jni_generator/SampleForTests";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
-jclass g_SampleForTests_clazz = NULL;
+base::subtle::AtomicWord g_SampleForTests_clazz = 0;
+#define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz)
 
 }  // namespace
 
@@ -79,11 +80,11 @@ static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
     JniIntWrapper iParam) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_SampleForTests_clazz);
+      SampleForTests_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "testMethodWithParam",
 
 "("
@@ -105,11 +106,11 @@ static base::android::ScopedJavaLocalRef<jstring>
     JniIntWrapper iParam) {
   /* Must call RegisterNativesImpl()  */
   CHECK_CLAZZ(env, obj,
-      g_SampleForTests_clazz, NULL);
+      SampleForTests_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_INSTANCE>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "testMethodWithParamAndReturn",
 
 "("
@@ -129,12 +130,12 @@ static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
 static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
     JniIntWrapper iParam) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_SampleForTests_clazz,
-      g_SampleForTests_clazz, 0);
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "testStaticMethodWithParam",
 
 "("
@@ -144,7 +145,7 @@ static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
       &g_SampleForTests_testStaticMethodWithParam);
 
   jint ret =
-      env->CallStaticIntMethod(g_SampleForTests_clazz,
+      env->CallStaticIntMethod(SampleForTests_clazz(env),
           method_id, as_jint(iParam));
   jni_generator::CheckException(env);
   return ret;
@@ -153,12 +154,12 @@ static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
 static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
 static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_SampleForTests_clazz,
-      g_SampleForTests_clazz, 0);
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), 0);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "testMethodWithNoParam",
 
 "("
@@ -167,7 +168,7 @@ static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
       &g_SampleForTests_testMethodWithNoParam);
 
   jdouble ret =
-      env->CallStaticDoubleMethod(g_SampleForTests_clazz,
+      env->CallStaticDoubleMethod(SampleForTests_clazz(env),
           method_id);
   jni_generator::CheckException(env);
   return ret;
@@ -178,12 +179,12 @@ static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
 static base::android::ScopedJavaLocalRef<jstring>
     Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_SampleForTests_clazz,
-      g_SampleForTests_clazz, NULL);
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), NULL);
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_SampleForTests_clazz,
+      env, SampleForTests_clazz(env),
       "testStaticMethodWithNoParam",
 
 "("
@@ -192,7 +193,7 @@ static base::android::ScopedJavaLocalRef<jstring>
       &g_SampleForTests_testStaticMethodWithNoParam);
 
   jstring ret =
-      static_cast<jstring>(env->CallStaticObjectMethod(g_SampleForTests_clazz,
+static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
           method_id));
   jni_generator::CheckException(env);
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
@@ -202,7 +203,8 @@ static base::android::ScopedJavaLocalRef<jstring>
 // Step 3: RegisterNatives.
 
 static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
-  g_SampleForTests_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
+    base::subtle::Release_Store(&g_SampleForTests_clazz,
+      static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
 
   return true;
 }
index db69a5a..8708fa2 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kTestJniClassPath[] = "org/chromium/TestJni";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
 
 }  // namespace
 
@@ -202,11 +203,11 @@ static bool RegisterNativesImpl(JNIEnv* env) {
 
   const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
 
-  if (env->RegisterNatives(g_TestJni_clazz,
+  if (env->RegisterNatives(TestJni_clazz(env),
                            kMethodsTestJni,
                            kMethodsTestJniSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_TestJni_clazz, __FILE__);
+        env, TestJni_clazz(env), __FILE__);
     return false;
   }
 
index 25b5fad..11e7c49 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kTestJniClassPath[] = "org/chromium/TestJni";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
 
 }  // namespace
 
@@ -49,11 +50,11 @@ static bool RegisterNativesImpl(JNIEnv* env) {
 
   const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
 
-  if (env->RegisterNatives(g_TestJni_clazz,
+  if (env->RegisterNatives(TestJni_clazz(env),
                            kMethodsTestJni,
                            kMethodsTestJniSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_TestJni_clazz, __FILE__);
+        env, TestJni_clazz(env), __FILE__);
     return false;
   }
 
index 8d9ee9e..a45a386 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kTestClassPath[] = "org/chromium/example/jni_generator/Test";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_Test_clazz = NULL;
+#define Test_clazz(env) g_Test_clazz
 
 }  // namespace
 
@@ -50,11 +51,11 @@ static bool RegisterNativesImpl(JNIEnv* env) {
 
   const int kMethodsTestSize = arraysize(kMethodsTest);
 
-  if (env->RegisterNatives(g_Test_clazz,
+  if (env->RegisterNatives(Test_clazz(env),
                            kMethodsTest,
                            kMethodsTestSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_Test_clazz, __FILE__);
+        env, Test_clazz(env), __FILE__);
     return false;
   }
 
index e395657..787f7f5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -21,6 +21,7 @@ namespace {
 const char kFooClassPath[] = "org/chromium/foo/Foo";
 // Leaking this jclass as we cannot use LazyInstance from some threads.
 jclass g_Foo_clazz = NULL;
+#define Foo_clazz(env) g_Foo_clazz
 
 }  // namespace
 
@@ -32,12 +33,12 @@ static void DoSomething(JNIEnv* env, jclass jcaller,
 static base::subtle::AtomicWord g_Foo_calledByNative = 0;
 static void Java_Foo_calledByNative(JNIEnv* env, jobject callback) {
   /* Must call RegisterNativesImpl()  */
-  CHECK_CLAZZ(env, g_Foo_clazz,
-      g_Foo_clazz);
+  CHECK_CLAZZ(env, Foo_clazz(env),
+      Foo_clazz(env));
   jmethodID method_id =
       base::android::MethodID::LazyGet<
       base::android::MethodID::TYPE_STATIC>(
-      env, g_Foo_clazz,
+      env, Foo_clazz(env),
       "calledByNative",
 
 "("
@@ -46,7 +47,7 @@ static void Java_Foo_calledByNative(JNIEnv* env, jobject callback) {
 "V",
       &g_Foo_calledByNative);
 
-     env->CallStaticVoidMethod(g_Foo_clazz,
+     env->CallStaticVoidMethod(Foo_clazz(env),
           method_id, callback);
   jni_generator::CheckException(env);
 
@@ -68,11 +69,11 @@ static bool RegisterNativesImpl(JNIEnv* env) {
 
   const int kMethodsFooSize = arraysize(kMethodsFoo);
 
-  if (env->RegisterNatives(g_Foo_clazz,
+  if (env->RegisterNatives(Foo_clazz(env),
                            kMethodsFoo,
                            kMethodsFooSize) < 0) {
     jni_generator::HandleRegistrationError(
-        env, g_Foo_clazz, __FILE__);
+        env, Foo_clazz(env), __FILE__);
     return false;
   }
 
diff --git a/src/base/android/jni_utils.cc b/src/base/android/jni_utils.cc
new file mode 100644 (file)
index 0000000..b4d682b
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+
+#include "jni/JNIUtils_jni.h"
+
+namespace base {
+namespace android {
+
+ScopedJavaLocalRef<jobject> GetClassLoader(JNIEnv* env) {
+  return Java_JNIUtils_getClassLoader(env);
+}
+
+bool RegisterJNIUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
+
diff --git a/src/base/android/jni_utils.h b/src/base/android/jni_utils.h
new file mode 100644 (file)
index 0000000..b793aed
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_UTILS_H_
+#define BASE_ANDROID_JNI_UTILS_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+
+namespace base {
+
+namespace android {
+
+// Gets a ClassLoader instance capable of loading Chromium java classes.
+// This should be called either from JNI_OnLoad or from within a method called
+// via JNI from Java.
+BASE_EXPORT ScopedJavaLocalRef<jobject> GetClassLoader(JNIEnv* env);
+
+bool RegisterJNIUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_UTILS_H_
+
index b0b464b..d33e6fa 100644 (file)
@@ -451,7 +451,7 @@ static bool PostForLaterExecution(crazy_callback_t* callback_request,
   LOG_INFO("%s: Calling back to java with handler %p, opaque %p",
            __FUNCTION__, callback->handler, callback->opaque);
 
-  jlong arg = static_cast<jlong>(reinterpret_cast<intptr_t>(callback));
+  jlong arg = static_cast<jlong>(reinterpret_cast<uintptr_t>(callback));
   env->CallStaticVoidMethod(
       s_java_callback_bindings.clazz, s_java_callback_bindings.method_id, arg);
 
index 6a69195..9f55a7d 100644 (file)
             'android/java/src/org/chromium/base/EventLog.java',
             'android/java/src/org/chromium/base/FieldTrialList.java',
             'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java',
+            'android/java/src/org/chromium/base/JNIUtils.java',
             'android/java/src/org/chromium/base/library_loader/LibraryLoader.java',
             'android/java/src/org/chromium/base/MemoryPressureListener.java',
             'android/java/src/org/chromium/base/JavaHandlerThread.java',
index d18aa9e..7f25947 100644 (file)
@@ -55,6 +55,8 @@
           'android/jni_registrar.h',
           'android/jni_string.cc',
           'android/jni_string.h',
+          'android/jni_utils.cc',
+          'android/jni_utils.h',
           'android/jni_weak_ref.cc',
           'android/jni_weak_ref.h',
           'android/library_loader/library_loader_hooks.cc',
index 61b4a6a..fad141f 100644 (file)
@@ -254,4 +254,18 @@ typedef NSUInteger NSWindowOcclusionState;
 
 #endif  // MAC_OS_X_VERSION_10_9
 
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+
+@interface NSUserActivity : NSObject
+
+@property (readonly, copy) NSString* activityType;
+@property (copy) NSURL* webPageURL;
+
+@end
+
+BASE_EXPORT extern "C" NSString* const NSUserActivityTypeBrowsingWeb;
+
+#endif  // MAC_OS_X_VERSION_10_10
+
 #endif  // BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
index a402a41..22986da 100644 (file)
@@ -12,3 +12,12 @@ NSString* const NSWindowWillEnterFullScreenNotification =
     @"NSWindowWillEnterFullScreenNotification";
 
 #endif  // MAC_OS_X_VERSION_10_7
+
+// Replicate specific 10.10 SDK declarations for building with prior SDKs.
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+
+NSString* const NSUserActivityTypeBrowsingWeb =
+    @"NSUserActivityTypeBrowsingWeb";
+
+#endif  // MAC_OS_X_VERSION_10_10
index 9bd12ee..2ca32d6 100644 (file)
@@ -7,12 +7,14 @@
 #include "base/location.h"
 #include "base/message_loop/message_loop.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
 
 namespace base {
 namespace internal {
 
 IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
-    : message_loop_(message_loop),
+    : high_res_task_count_(0),
+      message_loop_(message_loop),
       next_sequence_num_(0) {
 }
 
@@ -24,15 +26,23 @@ bool IncomingTaskQueue::AddToIncomingQueue(
   AutoLock locked(incoming_queue_lock_);
   PendingTask pending_task(
       from_here, task, CalculateDelayedRuntime(delay), nestable);
+#if defined(OS_WIN)
+  // We consider the task needs a high resolution timer if the delay is
+  // more than 0 and less than 32ms. This caps the relative error to
+  // less than 50% : a 33ms wait can wake at 48ms since the default
+  // resolution on Windows is between 10 and 15ms.
+  if (delay > TimeDelta() &&
+      delay.InMilliseconds() < (2 * Time::kMinLowResolutionThresholdMs)) {
+    ++high_res_task_count_;
+    pending_task.is_high_res = true;
+  }
+#endif
   return PostPendingTask(&pending_task);
 }
 
-bool IncomingTaskQueue::IsHighResolutionTimerEnabledForTesting() {
-#if defined(OS_WIN)
-  return !high_resolution_timer_expiration_.is_null();
-#else
-  return true;
-#endif
+bool IncomingTaskQueue::HasHighResolutionTasks() {
+  AutoLock lock(incoming_queue_lock_);
+  return high_res_task_count_ > 0;
 }
 
 bool IncomingTaskQueue::IsIdleForTesting() {
@@ -40,29 +50,22 @@ bool IncomingTaskQueue::IsIdleForTesting() {
   return incoming_queue_.empty();
 }
 
-void IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
+int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
   // Make sure no tasks are lost.
   DCHECK(work_queue->empty());
 
   // Acquire all we can from the inter-thread queue with one lock acquisition.
   AutoLock lock(incoming_queue_lock_);
   if (!incoming_queue_.empty())
-    incoming_queue_.Swap(work_queue);  // Constant time
+    incoming_queue_.Swap(work_queue);
 
-  DCHECK(incoming_queue_.empty());
+  // Reset the count of high resolution tasks since our queue is now empty.
+  int high_res_tasks = high_res_task_count_;
+  high_res_task_count_ = 0;
+  return high_res_tasks;
 }
 
 void IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
-#if defined(OS_WIN)
-  // If we left the high-resolution timer activated, deactivate it now.
-  // Doing this is not-critical, it is mainly to make sure we track
-  // the high resolution timer activations properly in our unit tests.
-  if (!high_resolution_timer_expiration_.is_null()) {
-    Time::ActivateHighResolutionTimer(false);
-    high_resolution_timer_expiration_ = TimeTicks();
-  }
-#endif
-
   AutoLock lock(incoming_queue_lock_);
   message_loop_ = NULL;
 }
@@ -74,40 +77,10 @@ IncomingTaskQueue::~IncomingTaskQueue() {
 
 TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) {
   TimeTicks delayed_run_time;
-  if (delay > TimeDelta()) {
+  if (delay > TimeDelta())
     delayed_run_time = TimeTicks::Now() + delay;
-
-#if defined(OS_WIN)
-    if (high_resolution_timer_expiration_.is_null()) {
-      // Windows timers are granular to 15.6ms.  If we only set high-res
-      // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms,
-      // which as a percentage is pretty inaccurate.  So enable high
-      // res timers for any timer which is within 2x of the granularity.
-      // This is a tradeoff between accuracy and power management.
-      bool needs_high_res_timers = delay.InMilliseconds() <
-          (2 * Time::kMinLowResolutionThresholdMs);
-      if (needs_high_res_timers) {
-        if (Time::ActivateHighResolutionTimer(true)) {
-          high_resolution_timer_expiration_ = TimeTicks::Now() +
-              TimeDelta::FromMilliseconds(
-                  MessageLoop::kHighResolutionTimerModeLeaseTimeMs);
-        }
-      }
-    }
-#endif
-  } else {
+  else
     DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative";
-  }
-
-#if defined(OS_WIN)
-  if (!high_resolution_timer_expiration_.is_null()) {
-    if (TimeTicks::Now() > high_resolution_timer_expiration_) {
-      Time::ActivateHighResolutionTimer(false);
-      high_resolution_timer_expiration_ = TimeTicks();
-    }
-  }
-#endif
-
   return delayed_run_time;
 }
 
index 56c5638..30f2603 100644 (file)
@@ -38,16 +38,17 @@ class BASE_EXPORT IncomingTaskQueue
                           TimeDelta delay,
                           bool nestable);
 
-  // Returns true if the message loop has high resolution timers enabled.
-  // Provided for testing.
-  bool IsHighResolutionTimerEnabledForTesting();
+  // Returns true if the queue contains tasks that require higher than default
+  // timer resolution. Currently only needed for Windows.
+  bool HasHighResolutionTasks();
 
   // Returns true if the message loop is "idle". Provided for testing.
   bool IsIdleForTesting();
 
   // Loads tasks from the |incoming_queue_| into |*work_queue|. Must be called
-  // from the thread that is running the loop.
-  void ReloadWorkQueue(TaskQueue* work_queue);
+  // from the thread that is running the loop. Returns the number of tasks that
+  // require high resolution timers.
+  int ReloadWorkQueue(TaskQueue* work_queue);
 
   // Disconnects |this| from the parent message loop.
   void WillDestroyCurrentMessageLoop();
@@ -65,12 +66,11 @@ class BASE_EXPORT IncomingTaskQueue
   // does not retain |pending_task->task| beyond this function call.
   bool PostPendingTask(PendingTask* pending_task);
 
-#if defined(OS_WIN)
-  TimeTicks high_resolution_timer_expiration_;
-#endif
+  // Number of tasks that require high resolution timing. This value is kept
+  // so that ReloadWorkQueue() completes in constant time.
+  int high_res_task_count_;
 
-  // The lock that protects access to |incoming_queue_|, |message_loop_| and
-  // |next_sequence_num_|.
+  // The lock that protects access to the members of this class.
   base::Lock incoming_queue_lock_;
 
   // An incoming queue of tasks that are acquired under a mutex for processing
index ae165ea..c01e542 100644 (file)
@@ -127,6 +127,8 @@ MessageLoop::DestructionObserver::~DestructionObserver() {
 
 MessageLoop::MessageLoop(Type type)
     : type_(type),
+      pending_high_res_tasks_(0),
+      in_high_res_mode_(false),
       nestable_tasks_allowed_(true),
 #if defined(OS_WIN)
       os_modal_loop_(false),
@@ -141,6 +143,8 @@ MessageLoop::MessageLoop(Type type)
 MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
     : pump_(pump.Pass()),
       type_(TYPE_CUSTOM),
+      pending_high_res_tasks_(0),
+      in_high_res_mode_(false),
       nestable_tasks_allowed_(true),
 #if defined(OS_WIN)
       os_modal_loop_(false),
@@ -155,7 +159,10 @@ MessageLoop::~MessageLoop() {
   DCHECK_EQ(this, current());
 
   DCHECK(!run_loop_);
-
+#if defined(OS_WIN)
+  if (in_high_res_mode_)
+    Time::ActivateHighResolutionTimer(false);
+#endif
   // Clean up any unprocessed tasks, but take care: deleting a task could
   // result in the addition of more tasks (e.g., via DeleteSoon).  We set a
   // limit on the number of times we will allow a deleted task to generate more
@@ -369,8 +376,8 @@ bool MessageLoop::is_running() const {
   return run_loop_ != NULL;
 }
 
-bool MessageLoop::IsHighResolutionTimerEnabledForTesting() {
-  return incoming_task_queue_->IsHighResolutionTimerEnabledForTesting();
+bool MessageLoop::HasHighResolutionTasks() {
+  return incoming_task_queue_->HasHighResolutionTasks();
 }
 
 bool MessageLoop::IsIdleForTesting() {
@@ -425,6 +432,10 @@ bool MessageLoop::ProcessNextDelayedNonNestableTask() {
 void MessageLoop::RunTask(const PendingTask& pending_task) {
   DCHECK(nestable_tasks_allowed_);
 
+  if (pending_task.is_high_res) {
+    pending_high_res_tasks_--;
+    CHECK(pending_high_res_tasks_ >= 0);
+  }
   // Execute the task and assume the worst: It is probably not reentrant.
   nestable_tasks_allowed_ = false;
 
@@ -493,8 +504,10 @@ void MessageLoop::ReloadWorkQueue() {
   // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to
   // load. That reduces the number of locks-per-task significantly when our
   // queues get large.
-  if (work_queue_.empty())
-    incoming_task_queue_->ReloadWorkQueue(&work_queue_);
+  if (work_queue_.empty()) {
+    pending_high_res_tasks_ +=
+        incoming_task_queue_->ReloadWorkQueue(&work_queue_);
+  }
 }
 
 void MessageLoop::ScheduleWork(bool was_empty) {
@@ -597,6 +610,18 @@ bool MessageLoop::DoIdleWork() {
   if (run_loop_->quit_when_idle_received_)
     pump_->Quit();
 
+  // When we return we will do a kernel wait for more tasks.
+#if defined(OS_WIN)
+  // On Windows we activate the high resolution timer so that the wait
+  // _if_ triggered by the timer happens with good resolution. If we don't
+  // do this the default resolution is 15ms which might not be acceptable
+  // for some tasks.
+  bool high_res = pending_high_res_tasks_ > 0;
+  if (high_res != in_high_res_mode_) {
+    in_high_res_mode_ = high_res;
+    Time::ActivateHighResolutionTimer(in_high_res_mode_);
+  }
+#endif
   return false;
 }
 
index 39a1b68..8db1e77 100644 (file)
@@ -371,10 +371,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
   void AddTaskObserver(TaskObserver* task_observer);
   void RemoveTaskObserver(TaskObserver* task_observer);
 
-  // When we go into high resolution timer mode, we will stay in hi-res mode
-  // for at least 1s.
-  static const int kHighResolutionTimerModeLeaseTimeMs = 1000;
-
 #if defined(OS_WIN)
   void set_os_modal_loop(bool os_modal_loop) {
     os_modal_loop_ = os_modal_loop;
@@ -390,7 +386,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
 
   // Returns true if the message loop has high resolution timers enabled.
   // Provided for testing.
-  bool IsHighResolutionTimerEnabledForTesting();
+  bool HasHighResolutionTasks();
 
   // Returns true if the message loop is "idle". Provided for testing.
   bool IsIdleForTesting();
@@ -459,6 +455,14 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
   // this queue is only accessed (push/pop) by our current thread.
   TaskQueue work_queue_;
 
+  // How many high resolution tasks are in the pending task queue. This value
+  // increases by N every time we call ReloadWorkQueue() and decreases by 1
+  // every time we call RunTask() if the task needs a high resolution timer.
+  int pending_high_res_tasks_;
+  // Tracks if we have requested high resolution timers. Its only use is to
+  // turn off the high resolution timer upon loop destruction.
+  bool in_high_res_mode_;
+
   // Contains delayed tasks, sorted by their 'delayed_run_time' property.
   DelayedTaskQueue delayed_work_queue_;
 
index 1b09eb0..0a6e817 100644 (file)
@@ -726,34 +726,26 @@ TEST(MessageLoopTest, WaitForIO) {
 
 TEST(MessageLoopTest, HighResolutionTimer) {
   MessageLoop loop;
+  Time::EnableHighResolutionTimer(true);
 
   const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5);
   const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100);
 
-  EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting());
-
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
   // Post a fast task to enable the high resolution timers.
   loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
                        kFastTimer);
+  EXPECT_TRUE(loop.HasHighResolutionTasks());
   loop.Run();
-  EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting());
-
-  // Post a slow task and verify high resolution timers
-  // are still enabled.
-  loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
-                       kSlowTimer);
-  loop.Run();
-  EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting());
-
-  // Wait for a while so that high-resolution mode elapses.
-  PlatformThread::Sleep(TimeDelta::FromMilliseconds(
-      MessageLoop::kHighResolutionTimerModeLeaseTimeMs));
-
-  // Post a slow task to disable the high resolution timers.
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  EXPECT_FALSE(Time::IsHighResolutionTimerInUse());
+  // Check that a slow task does not trigger the high resolution logic.
   loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
                        kSlowTimer);
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
   loop.Run();
-  EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting());
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  Time::EnableHighResolutionTimer(false);
 }
 
 #endif  // defined(OS_WIN)
index 4dc501b..a2edb45 100644 (file)
@@ -39,7 +39,8 @@ class BASE_EXPORT MessagePump : public NonThreadSafe {
     virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;
 
     // Called from within Run just before the message pump goes to sleep.
-    // Returns true to indicate that idle work was done.
+    // Returns true to indicate that idle work was done. Returning false means
+    // the pump will now wait.
     virtual bool DoIdleWork() = 0;
   };
 
index b288f28..3d78914 100644 (file)
@@ -8,19 +8,14 @@
 
 namespace base {
 
-#if _MSC_VER >= 1700
-// This a temporary fix for compiling on VS2012. http://crbug.com/154744
-PendingTask::PendingTask() : sequence_num(-1), nestable(false) {
-}
-#endif
-
 PendingTask::PendingTask(const tracked_objects::Location& posted_from,
                          const base::Closure& task)
     : base::TrackingInfo(posted_from, TimeTicks()),
       task(task),
       posted_from(posted_from),
       sequence_num(0),
-      nestable(true) {
+      nestable(true),
+      is_high_res(false) {
 }
 
 PendingTask::PendingTask(const tracked_objects::Location& posted_from,
@@ -31,7 +26,8 @@ PendingTask::PendingTask(const tracked_objects::Location& posted_from,
       task(task),
       posted_from(posted_from),
       sequence_num(0),
-      nestable(nestable) {
+      nestable(nestable),
+      is_high_res(false) {
 }
 
 PendingTask::~PendingTask() {
index 65e17f8..a2edc69 100644 (file)
@@ -18,9 +18,6 @@ namespace base {
 // Contains data about a pending task. Stored in TaskQueue and DelayedTaskQueue
 // for use by classes that queue and execute tasks.
 struct BASE_EXPORT PendingTask : public TrackingInfo {
-#if _MSC_VER >= 1700
-  PendingTask();
-#endif
   PendingTask(const tracked_objects::Location& posted_from,
               const Closure& task);
   PendingTask(const tracked_objects::Location& posted_from,
@@ -43,6 +40,9 @@ struct BASE_EXPORT PendingTask : public TrackingInfo {
 
   // OK to dispatch from a nested loop.
   bool nestable;
+
+  // Needs high resolution timers.
+  bool is_high_res;
 };
 
 // Wrapper around std::queue specialized for PendingTask which adds a Swap
index 79346f1..084ff45 100644 (file)
@@ -340,13 +340,7 @@ class BASE_EXPORT Time {
   // treat it as static across all windows versions.
   static const int kMinLowResolutionThresholdMs = 16;
 
-  // Enable or disable Windows high resolution timer. If the high resolution
-  // timer is not enabled, calls to ActivateHighResolutionTimer will fail.
-  // When disabling the high resolution timer, this function will not cause
-  // the high resolution timer to be deactivated, but will prevent future
-  // activations.
-  // Must be called from the main thread.
-  // For more details see comments in time_win.cc.
+  // Enable or disable Windows high resolution timer.
   static void EnableHighResolutionTimer(bool enable);
 
   // Activates or deactivates the high resolution timer based on the |activate|
@@ -493,16 +487,6 @@ class BASE_EXPORT Time {
   // platform-dependent epoch.
   static const int64 kTimeTToMicrosecondsOffset;
 
-#if defined(OS_WIN)
-  // Indicates whether fast timers are usable right now.  For instance,
-  // when using battery power, we might elect to prevent high speed timers
-  // which would draw more power.
-  static bool high_resolution_timer_enabled_;
-  // Count of activations on the high resolution timer.  Only use in tests
-  // which are single threaded.
-  static int high_resolution_timer_activated_;
-#endif
-
   // Time in microseconds in UTC.
   int64 us_;
 };
index 5fa899d..2586cb3 100644 (file)
 //
 // To work around all this, we're going to generally use timeGetTime().  We
 // will only increase the system-wide timer if we're not running on battery
-// power.  Using timeBeginPeriod(1) is a requirement in order to make our
-// message loop waits have the same resolution that our time measurements
-// do.  Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when
-// there is nothing else to waken the Wait.
+// power.
 
 #include "base/time/time.h"
 
@@ -87,6 +84,19 @@ void InitializeClock() {
   initial_time = CurrentWallclockMicroseconds();
 }
 
+// The two values that ActivateHighResolutionTimer uses to set the systemwide
+// timer interrupt frequency on Windows. It controls how precise timers are
+// but also has a big impact on battery life.
+const int kMinTimerIntervalHighResMs = 1;
+const int kMinTimerIntervalLowResMs = 4;
+// Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active.
+bool g_high_res_timer_enabled = false;
+// How many times the high resolution timer has been called.
+uint32_t g_high_res_timer_count = 0;
+// The lock to control access to the above two variables.
+base::LazyInstance<base::Lock>::Leaky g_high_res_lock =
+    LAZY_INSTANCE_INITIALIZER;
+
 }  // namespace
 
 // Time -----------------------------------------------------------------------
@@ -98,9 +108,6 @@ void InitializeClock() {
 // static
 const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
 
-bool Time::high_resolution_timer_enabled_ = false;
-int Time::high_resolution_timer_activated_ = 0;
-
 // static
 Time Time::Now() {
   if (initial_time == 0)
@@ -165,44 +172,54 @@ FILETIME Time::ToFileTime() const {
 
 // static
 void Time::EnableHighResolutionTimer(bool enable) {
-  // Test for single-threaded access.
-  static PlatformThreadId my_thread = PlatformThread::CurrentId();
-  DCHECK(PlatformThread::CurrentId() == my_thread);
-
-  if (high_resolution_timer_enabled_ == enable)
+  base::AutoLock lock(g_high_res_lock.Get());
+  if (g_high_res_timer_enabled == enable)
     return;
-
-  high_resolution_timer_enabled_ = enable;
+  g_high_res_timer_enabled = enable;
+  if (!g_high_res_timer_count)
+    return;
+  // Since g_high_res_timer_count != 0, an ActivateHighResolutionTimer(true)
+  // was called which called timeBeginPeriod with g_high_res_timer_enabled
+  // with a value which is the opposite of |enable|. With that information we
+  // call timeEndPeriod with the same value used in timeBeginPeriod and
+  // therefore undo the period effect.
+  if (enable) {
+    timeEndPeriod(kMinTimerIntervalLowResMs);
+    timeBeginPeriod(kMinTimerIntervalHighResMs);
+  } else {
+    timeEndPeriod(kMinTimerIntervalHighResMs);
+    timeBeginPeriod(kMinTimerIntervalLowResMs);
+  }
 }
 
 // static
 bool Time::ActivateHighResolutionTimer(bool activating) {
-  if (!high_resolution_timer_enabled_ && activating)
-    return false;
-
-  // Using anything other than 1ms makes timers granular
-  // to that interval.
-  const int kMinTimerIntervalMs = 1;
-  MMRESULT result;
+  // We only do work on the transition from zero to one or one to zero so we
+  // can easily undo the effect (if necessary) when EnableHighResolutionTimer is
+  // called.
+  const uint32_t max = std::numeric_limits<uint32_t>::max();
+
+  base::AutoLock lock(g_high_res_lock.Get());
+  UINT period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs
+                                         : kMinTimerIntervalLowResMs;
   if (activating) {
-    result = timeBeginPeriod(kMinTimerIntervalMs);
-    high_resolution_timer_activated_++;
+    DCHECK(g_high_res_timer_count != max);
+    ++g_high_res_timer_count;
+    if (g_high_res_timer_count == 1)
+      timeBeginPeriod(period);
   } else {
-    result = timeEndPeriod(kMinTimerIntervalMs);
-    high_resolution_timer_activated_--;
+    DCHECK(g_high_res_timer_count != 0);
+    --g_high_res_timer_count;
+    if (g_high_res_timer_count == 0)
+      timeEndPeriod(period);
   }
-  return result == TIMERR_NOERROR;
+  return (period == kMinTimerIntervalHighResMs);
 }
 
 // static
 bool Time::IsHighResolutionTimerInUse() {
-  // Note:  we should track the high_resolution_timer_activated_ value
-  // under a lock if we want it to be accurate in a system with multiple
-  // message loops.  We don't do that - because we don't want to take the
-  // expense of a lock for this.  We *only* track this value so that unit
-  // tests can see if the high resolution timer is on or off.
-  return high_resolution_timer_enabled_ &&
-      high_resolution_timer_activated_ > 0;
+  base::AutoLock lock(g_high_res_lock.Get());
+  return g_high_res_timer_enabled && g_high_res_timer_count > 0;
 }
 
 // static
index ce10e37..5475a91 100644 (file)
 namespace base {
 
 #if defined(OS_WIN)
-// http://crbug.com/114048
-TEST(HiResTimerManagerTest, DISABLED_ToggleOnOff) {
-  base::MessageLoop loop;
+TEST(HiResTimerManagerTest, ToggleOnOff) {
+  // The power monitor creates Window to receive power notifications from
+  // Windows, which makes this test flaky if you run while the machine
+  // goes in or out of AC power.
+  base::MessageLoop loop(base::MessageLoop::TYPE_UI);
   scoped_ptr<base::PowerMonitorSource> power_monitor_source(
       new base::PowerMonitorDeviceSource());
   scoped_ptr<base::PowerMonitor> power_monitor(
       new base::PowerMonitor(power_monitor_source.Pass()));
-  HighResolutionTimerManager manager;
 
-  // At this point, we don't know if the high resolution timers are on or off,
-  // it depends on what system the tests are running on (for example, if this
-  // test is running on a laptop/battery, then the PowerMonitor would have
-  // already set the PowerState to battery power; but if we're running on a
-  // desktop, then the PowerState will be non-battery power).  Simulate a power
-  // level change to get to a deterministic state.
-  manager.OnPowerStateChange(/* on_battery */ false);
+  HighResolutionTimerManager manager;
+  // Simulate a on-AC power event to get to a known initial state.
+  manager.OnPowerStateChange(false);
 
   // Loop a few times to test power toggling.
-  for (int loop = 2; loop >= 0; --loop) {
+  for (int times = 0; times != 3; ++times) {
     // The manager has the high resolution clock enabled now.
     EXPECT_TRUE(manager.hi_res_clock_available());
     // But the Time class has it off, because it hasn't been activated.
@@ -43,12 +40,12 @@ TEST(HiResTimerManagerTest, DISABLED_ToggleOnOff) {
     EXPECT_TRUE(base::Time::IsHighResolutionTimerInUse());
 
     // Simulate a on-battery power event.
-    manager.OnPowerStateChange(/* on_battery */ true);
+    manager.OnPowerStateChange(true);
     EXPECT_FALSE(manager.hi_res_clock_available());
     EXPECT_FALSE(base::Time::IsHighResolutionTimerInUse());
 
-    // Simulate a off-battery power event.
-    manager.OnPowerStateChange(/* on_battery */ false);
+    // Back to on-AC power.
+    manager.OnPowerStateChange(false);
     EXPECT_TRUE(manager.hi_res_clock_available());
     EXPECT_TRUE(base::Time::IsHighResolutionTimerInUse());
 
index bb6266b..28d6e12 100644 (file)
@@ -1 +1 @@
-LASTCHANGE=290690
+LASTCHANGE=291211
index 9d4185d..879d421 100644 (file)
@@ -126,7 +126,7 @@ int TilingData::LastBorderTileYIndexFromSrcCoord(int src_position) const {
   return std::min(std::max(y, 0), num_tiles_y_ - 1);
 }
 
-gfx::Rect TilingData::ExpandRectIgnoringBordersToTileBoundsWithBorders(
+gfx::Rect TilingData::ExpandRectIgnoringBordersToTileBounds(
     const gfx::Rect& rect) const {
   if (rect.IsEmpty() || has_empty_bounds())
     return gfx::Rect();
@@ -137,8 +137,8 @@ gfx::Rect TilingData::ExpandRectIgnoringBordersToTileBoundsWithBorders(
   int index_right = TileXIndexFromSrcCoord(rect.right() - 1);
   int index_bottom = TileYIndexFromSrcCoord(rect.bottom() - 1);
 
-  gfx::Rect rect_top_left(TileBoundsWithBorder(index_x, index_y));
-  gfx::Rect rect_bottom_right(TileBoundsWithBorder(index_right, index_bottom));
+  gfx::Rect rect_top_left(TileBounds(index_x, index_y));
+  gfx::Rect rect_bottom_right(TileBounds(index_right, index_bottom));
 
   return gfx::UnionRects(rect_top_left, rect_bottom_right);
 }
@@ -379,24 +379,17 @@ TilingData::DifferenceIterator::DifferenceIterator(
     return;
   }
 
-  consider_left_ =
-      tiling_data_->FirstBorderTileXIndexFromSrcCoord(consider.x());
-  consider_top_ =
-      tiling_data_->FirstBorderTileYIndexFromSrcCoord(consider.y());
-  consider_right_ =
-      tiling_data_->LastBorderTileXIndexFromSrcCoord(consider.right() - 1);
+  consider_left_ = tiling_data_->TileXIndexFromSrcCoord(consider.x());
+  consider_top_ = tiling_data_->TileYIndexFromSrcCoord(consider.y());
+  consider_right_ = tiling_data_->TileXIndexFromSrcCoord(consider.right() - 1);
   consider_bottom_ =
-      tiling_data_->LastBorderTileYIndexFromSrcCoord(consider.bottom() - 1);
+      tiling_data_->TileYIndexFromSrcCoord(consider.bottom() - 1);
 
   if (!ignore.IsEmpty()) {
-    ignore_left_ =
-        tiling_data_->FirstBorderTileXIndexFromSrcCoord(ignore.x());
-    ignore_top_ =
-        tiling_data_->FirstBorderTileYIndexFromSrcCoord(ignore.y());
-    ignore_right_ =
-        tiling_data_->LastBorderTileXIndexFromSrcCoord(ignore.right() - 1);
-    ignore_bottom_ =
-        tiling_data_->LastBorderTileYIndexFromSrcCoord(ignore.bottom() - 1);
+    ignore_left_ = tiling_data_->TileXIndexFromSrcCoord(ignore.x());
+    ignore_top_ = tiling_data_->TileYIndexFromSrcCoord(ignore.y());
+    ignore_right_ = tiling_data_->TileXIndexFromSrcCoord(ignore.right() - 1);
+    ignore_bottom_ = tiling_data_->TileYIndexFromSrcCoord(ignore.bottom() - 1);
 
     // Clamp ignore indices to consider indices.
     ignore_left_ = std::max(ignore_left_, consider_left_);
@@ -488,21 +481,17 @@ TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator(
     return;
   }
 
-  consider_left_ =
-      tiling_data_->FirstBorderTileXIndexFromSrcCoord(consider.x());
-  consider_top_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(consider.y());
-  consider_right_ =
-      tiling_data_->LastBorderTileXIndexFromSrcCoord(consider.right() - 1);
+  consider_left_ = tiling_data_->TileXIndexFromSrcCoord(consider.x());
+  consider_top_ = tiling_data_->TileYIndexFromSrcCoord(consider.y());
+  consider_right_ = tiling_data_->TileXIndexFromSrcCoord(consider.right() - 1);
   consider_bottom_ =
-      tiling_data_->LastBorderTileYIndexFromSrcCoord(consider.bottom() - 1);
+      tiling_data_->TileYIndexFromSrcCoord(consider.bottom() - 1);
 
   if (!ignore.IsEmpty()) {
-    ignore_left_ = tiling_data_->FirstBorderTileXIndexFromSrcCoord(ignore.x());
-    ignore_top_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(ignore.y());
-    ignore_right_ =
-        tiling_data_->LastBorderTileXIndexFromSrcCoord(ignore.right() - 1);
-    ignore_bottom_ =
-        tiling_data_->LastBorderTileYIndexFromSrcCoord(ignore.bottom() - 1);
+    ignore_left_ = tiling_data_->TileXIndexFromSrcCoord(ignore.x());
+    ignore_top_ = tiling_data_->TileYIndexFromSrcCoord(ignore.y());
+    ignore_right_ = tiling_data_->TileXIndexFromSrcCoord(ignore.right() - 1);
+    ignore_bottom_ = tiling_data_->TileYIndexFromSrcCoord(ignore.bottom() - 1);
 
     // Clamp ignore indices to consider indices.
     ignore_left_ = std::max(ignore_left_, consider_left_);
@@ -524,7 +513,7 @@ TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator(
   else if (center.x() > tiling_data->tiling_size().width())
     around_left = tiling_data->num_tiles_x();
   else
-    around_left = tiling_data->FirstBorderTileXIndexFromSrcCoord(center.x());
+    around_left = tiling_data->TileXIndexFromSrcCoord(center.x());
 
   // Determine around top, such that it is between -1 and num_tiles_y.
   int around_top = 0;
@@ -533,7 +522,7 @@ TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator(
   else if (center.y() > tiling_data->tiling_size().height())
     around_top = tiling_data->num_tiles_y();
   else
-    around_top = tiling_data->FirstBorderTileYIndexFromSrcCoord(center.y());
+    around_top = tiling_data->TileYIndexFromSrcCoord(center.y());
 
   // Determine around right, such that it is between -1 and num_tiles_x.
   int right_src_coord = center.right() - 1;
@@ -543,8 +532,7 @@ TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator(
   } else if (right_src_coord > tiling_data->tiling_size().width()) {
     around_right = tiling_data->num_tiles_x();
   } else {
-    around_right =
-        tiling_data->LastBorderTileXIndexFromSrcCoord(right_src_coord);
+    around_right = tiling_data->TileXIndexFromSrcCoord(right_src_coord);
   }
 
   // Determine around bottom, such that it is between -1 and num_tiles_y.
@@ -555,8 +543,7 @@ TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator(
   } else if (bottom_src_coord > tiling_data->tiling_size().height()) {
     around_bottom = tiling_data->num_tiles_y();
   } else {
-    around_bottom =
-        tiling_data->LastBorderTileYIndexFromSrcCoord(bottom_src_coord);
+    around_bottom = tiling_data->TileYIndexFromSrcCoord(bottom_src_coord);
   }
 
   vertical_step_count_ = around_bottom - around_top + 1;
index 7cd9457..a2e0a13 100644 (file)
@@ -52,8 +52,7 @@ class CC_EXPORT TilingData {
   int LastBorderTileXIndexFromSrcCoord(int src_position) const;
   int LastBorderTileYIndexFromSrcCoord(int src_position) const;
 
-  gfx::Rect ExpandRectIgnoringBordersToTileBoundsWithBorders(
-      const gfx::Rect& rect) const;
+  gfx::Rect ExpandRectIgnoringBordersToTileBounds(const gfx::Rect& rect) const;
   gfx::Rect ExpandRectToTileBounds(const gfx::Rect& rect) const;
 
   gfx::Rect TileBounds(int i, int j) const;
@@ -103,14 +102,13 @@ class CC_EXPORT TilingData {
     int bottom_;
   };
 
-  // Iterate through all indices whose bounds + border intersect with
-  // |consider| but which also do not intersect with |ignore|.
+  // Iterate through all indices whose bounds (not including borders) intersect
+  // with |consider| but which also do not intersect with |ignore|.
   class CC_EXPORT DifferenceIterator : public BaseIterator {
    public:
-    DifferenceIterator(
-      const TilingData* tiling_data,
-      const gfx::Rect& consider_rect,
-      const gfx::Rect& ignore_rect);
+    DifferenceIterator(const TilingData* tiling_data,
+                       const gfx::Rect& consider_rect,
+                       const gfx::Rect& ignore_rect);
     DifferenceIterator& operator++();
 
    private:
index 60e5a21..9c2f944 100644 (file)
@@ -773,92 +773,82 @@ TEST(TilingDataTest, SetMaxTextureSizeBorders) {
   EXPECT_EQ(10, data.num_tiles_y());
 }
 
-TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBoundsWithBordersEmpty) {
+TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBoundsEmpty) {
   TilingData empty_total_size(gfx::Size(0, 0), gfx::Size(8, 8), true);
   EXPECT_RECT_EQ(
       gfx::Rect(),
-      empty_total_size.ExpandRectIgnoringBordersToTileBoundsWithBorders(
-          gfx::Rect()));
-  EXPECT_RECT_EQ(
-      gfx::Rect(),
-      empty_total_size.ExpandRectIgnoringBordersToTileBoundsWithBorders(
-          gfx::Rect(100, 100, 100, 100)));
-  EXPECT_RECT_EQ(
-      gfx::Rect(),
-      empty_total_size.ExpandRectIgnoringBordersToTileBoundsWithBorders(
-          gfx::Rect(100, 100)));
+      empty_total_size.ExpandRectIgnoringBordersToTileBounds(gfx::Rect()));
+  EXPECT_RECT_EQ(gfx::Rect(),
+                 empty_total_size.ExpandRectIgnoringBordersToTileBounds(
+                     gfx::Rect(100, 100, 100, 100)));
+  EXPECT_RECT_EQ(gfx::Rect(),
+                 empty_total_size.ExpandRectIgnoringBordersToTileBounds(
+                     gfx::Rect(100, 100)));
 
   TilingData empty_max_texture_size(gfx::Size(8, 8), gfx::Size(0, 0), true);
-  EXPECT_RECT_EQ(
-      gfx::Rect(),
-      empty_max_texture_size.ExpandRectIgnoringBordersToTileBoundsWithBorders(
-          gfx::Rect()));
-  EXPECT_RECT_EQ(
-      gfx::Rect(),
-      empty_max_texture_size.ExpandRectIgnoringBordersToTileBoundsWithBorders(
-          gfx::Rect(100, 100, 100, 100)));
-  EXPECT_RECT_EQ(
-      gfx::Rect(),
-      empty_max_texture_size.ExpandRectIgnoringBordersToTileBoundsWithBorders(
-          gfx::Rect(100, 100)));
+  EXPECT_RECT_EQ(gfx::Rect(),
+                 empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
+                     gfx::Rect()));
+  EXPECT_RECT_EQ(gfx::Rect(),
+                 empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
+                     gfx::Rect(100, 100, 100, 100)));
+  EXPECT_RECT_EQ(gfx::Rect(),
+                 empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
+                     gfx::Rect(100, 100)));
 }
 
-TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBoundsWithBorders) {
+TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBounds) {
   TilingData data(gfx::Size(4, 4), gfx::Size(16, 32), true);
 
   // Small rect at origin rounds up to tile 0, 0.
   gfx::Rect at_origin_src(1, 1);
-  gfx::Rect at_origin_result(data.TileBoundsWithBorder(0, 0));
+  gfx::Rect at_origin_result(data.TileBounds(0, 0));
   EXPECT_NE(at_origin_src, at_origin_result);
-  EXPECT_RECT_EQ(
-      at_origin_result,
-      data.ExpandRectIgnoringBordersToTileBoundsWithBorders(at_origin_src));
+  EXPECT_RECT_EQ(at_origin_result,
+                 data.ExpandRectIgnoringBordersToTileBounds(at_origin_src));
 
   // Arbitrary internal rect.
   gfx::Rect rect_src(6, 6, 1, 3);
   // Tile 2, 2 => gfx::Rect(4, 4, 4, 4)
   // Tile 2, 3 => gfx::Rect(4, 6, 4, 4)
-  gfx::Rect rect_result(gfx::UnionRects(data.TileBoundsWithBorder(2, 2),
-                                        data.TileBoundsWithBorder(2, 3)));
+  gfx::Rect rect_result(
+      gfx::UnionRects(data.TileBounds(2, 2), data.TileBounds(2, 3)));
   EXPECT_NE(rect_src, rect_result);
-  EXPECT_RECT_EQ(
-      rect_result,
-      data.ExpandRectIgnoringBordersToTileBoundsWithBorders(rect_src));
+  EXPECT_RECT_EQ(rect_result,
+                 data.ExpandRectIgnoringBordersToTileBounds(rect_src));
 
   // On tile bounds does not round up to next tile (ignores the border).
   gfx::Rect border_rect_src(
       gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
-  gfx::Rect border_rect_result(gfx::UnionRects(
-      data.TileBoundsWithBorder(1, 2), data.TileBoundsWithBorder(3, 4)));
-  EXPECT_RECT_EQ(
-      border_rect_result,
-      data.ExpandRectIgnoringBordersToTileBoundsWithBorders(border_rect_src));
+  gfx::Rect border_rect_result(
+      gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
+  EXPECT_RECT_EQ(border_rect_result,
+                 data.ExpandRectIgnoringBordersToTileBounds(border_rect_src));
 
   // Equal to tiling rect.
   EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()),
-                 data.ExpandRectIgnoringBordersToTileBoundsWithBorders(
+                 data.ExpandRectIgnoringBordersToTileBounds(
                      gfx::Rect(data.tiling_size())));
 
   // Containing, but larger than tiling rect.
-  EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()),
-                 data.ExpandRectIgnoringBordersToTileBoundsWithBorders(
-                     gfx::Rect(100, 100)));
+  EXPECT_RECT_EQ(
+      gfx::Rect(data.tiling_size()),
+      data.ExpandRectIgnoringBordersToTileBounds(gfx::Rect(100, 100)));
 
   // Non-intersecting with tiling rect.
   gfx::Rect non_intersect(200, 200, 100, 100);
   EXPECT_FALSE(non_intersect.Intersects(gfx::Rect(data.tiling_size())));
-  EXPECT_RECT_EQ(
-      gfx::Rect(),
-      data.ExpandRectIgnoringBordersToTileBoundsWithBorders(non_intersect));
+  EXPECT_RECT_EQ(gfx::Rect(),
+                 data.ExpandRectIgnoringBordersToTileBounds(non_intersect));
 
   TilingData data2(gfx::Size(8, 8), gfx::Size(32, 64), true);
 
   // Inside other tile border texels doesn't include other tiles.
   gfx::Rect inner_rect_src(data2.TileBounds(1, 1));
   inner_rect_src.Inset(data2.border_texels(), data.border_texels());
-  gfx::Rect inner_rect_result(data2.TileBoundsWithBorder(1, 1));
+  gfx::Rect inner_rect_result(data2.TileBounds(1, 1));
   gfx::Rect expanded =
-      data2.ExpandRectIgnoringBordersToTileBoundsWithBorders(inner_rect_src);
+      data2.ExpandRectIgnoringBordersToTileBounds(inner_rect_src);
   EXPECT_EQ(inner_rect_result.ToString(), expanded.ToString());
 }
 
@@ -1086,11 +1076,11 @@ void TestIterate(const TilingData& data,
   }
 
   // Make sure this also works with a difference iterator and an empty ignore.
-  // The difference iterator always includes borders, so ignore it otherwise.
-  if (include_borders) {
+  // The difference iterator never includes borders, so ignore it otherwise.
+  if (!include_borders) {
     std::vector<std::pair<int, int> > expected = original_expected;
-    for (TilingData::DifferenceIterator iter(&data, rect, gfx::Rect());
-         iter; ++iter) {
+    for (TilingData::DifferenceIterator iter(&data, rect, gfx::Rect()); iter;
+         ++iter) {
       bool found = false;
       for (size_t i = 0; i < expected.size(); ++i) {
         if (expected[i] == iter.index()) {
@@ -1250,16 +1240,14 @@ TEST(TilingDataTest, IteratorNoTiles) {
   TestIterateAll(data, gfx::Rect(100, 100), 0, 0, -1, -1);
 }
 
-void TestDiff(
-    const TilingData& data,
-    gfx::Rect consider,
-    gfx::Rect ignore,
-    size_t num_tiles) {
-
+void TestDiff(const TilingData& data,
+              gfx::Rect consider,
+              gfx::Rect ignore,
+              size_t num_tiles) {
   std::vector<std::pair<int, int> > expected;
   for (int y = 0; y < data.num_tiles_y(); ++y) {
     for (int x = 0; x < data.num_tiles_x(); ++x) {
-      gfx::Rect bounds = data.TileBoundsWithBorder(x, y);
+      gfx::Rect bounds = data.TileBounds(x, y);
       if (bounds.Intersects(consider) && !bounds.Intersects(ignore))
         expected.push_back(std::make_pair(x, y));
     }
@@ -1268,8 +1256,8 @@ void TestDiff(
   // Sanity check the test.
   EXPECT_EQ(num_tiles, expected.size());
 
-  for (TilingData::DifferenceIterator iter(&data, consider, ignore);
-       iter; ++iter) {
+  for (TilingData::DifferenceIterator iter(&data, consider, ignore); iter;
+       ++iter) {
     bool found = false;
     for (size_t i = 0; i < expected.size(); ++i) {
       if (expected[i] == iter.index()) {
@@ -1339,16 +1327,26 @@ TEST(TilingDataTest, DifferenceIteratorIgnoreGeometry) {
 TEST(TilingDataTest, DifferenceIteratorManyBorderTexels) {
   // X border index by src coord: [0-50), [10-60), [20-65)
   // Y border index by src coord: [0-60), [20-80), [40-100), [60-110)
+  // X tile bounds by src coord: [0-30), [30-40), [40-65)
+  // Y tile bounds by src coord: [0-40), [40-60), [60-80), [80-110)
   TilingData data(gfx::Size(50, 60), gfx::Size(65, 110), 20);
 
-  // Ignore one column, three rows
-  TestDiff(data, gfx::Rect(0, 30, 55, 80), gfx::Rect(5, 30, 5, 15), 9);
+  // Knock out two rows, but not the left column.
+  TestDiff(data, gfx::Rect(10, 30, 55, 80), gfx::Rect(30, 59, 20, 2), 8);
 
-  // Knock out three columns, leaving only one.
-  TestDiff(data, gfx::Rect(10, 30, 55, 80), gfx::Rect(30, 59, 20, 1), 3);
+  // Knock out one row.
+  TestDiff(data, gfx::Rect(10, 30, 55, 80), gfx::Rect(29, 59, 20, 1), 9);
 
   // Overlap all tiles with ignore rect.
-  TestDiff(data, gfx::Rect(65, 110), gfx::Rect(30, 59, 1, 2), 0);
+  TestDiff(data, gfx::Rect(65, 110), gfx::Rect(29, 39, 12, 42), 0);
+
+  gfx::Rect tile = data.TileBounds(1, 1);
+
+  // Ignore one tile.
+  TestDiff(data, gfx::Rect(20, 30, 45, 80), tile, 11);
+
+  // Include one tile.
+  TestDiff(data, tile, gfx::Rect(), 1);
 }
 
 TEST(TilingDataTest, DifferenceIteratorOneTile) {
index e6e60f5..87cb2f8 100644 (file)
@@ -771,7 +771,7 @@ bool LayerImpl::IsActive() const {
 
 // TODO(wjmaclean) Convert so that bounds returns SizeF.
 gfx::Size LayerImpl::bounds() const {
-  return ToFlooredSize(temporary_impl_bounds_);
+  return ToCeiledSize(temporary_impl_bounds_);
 }
 
 void LayerImpl::SetBounds(const gfx::Size& bounds) {
index 8b8558c..4207aa2 100644 (file)
@@ -21,7 +21,6 @@ PictureLayer::PictureLayer(ContentLayerClient* client)
     : client_(client),
       pile_(make_scoped_refptr(new PicturePile())),
       instrumentation_object_tracker_(id()),
-      is_mask_(false),
       update_source_frame_number_(-1),
       can_use_lcd_text_last_frame_(can_use_lcd_text()) {
 }
@@ -50,8 +49,6 @@ void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
     DCHECK_EQ(layer_impl->bounds().ToString(), pile_->tiling_size().ToString());
   }
 
-  layer_impl->SetIsMask(is_mask_);
-
   // Unlike other properties, invalidation must always be set on layer_impl.
   // See PictureLayerImpl::PushPropertiesTo for more details.
   layer_impl->invalidation_.Clear();
@@ -149,7 +146,7 @@ bool PictureLayer::Update(ResourceUpdateQueue* queue,
 }
 
 void PictureLayer::SetIsMask(bool is_mask) {
-  is_mask_ = is_mask;
+  pile_->set_is_mask(is_mask);
 }
 
 Picture::RecordingMode PictureLayer::RecordingMode() const {
index 49ad601..7636baf 100644 (file)
@@ -60,7 +60,6 @@ PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
     : LayerImpl(tree_impl, id),
       twin_layer_(NULL),
       pile_(PicturePileImpl::Create()),
-      is_mask_(false),
       ideal_page_scale_(0.f),
       ideal_device_scale_(0.f),
       ideal_source_scale_(0.f),
@@ -108,11 +107,10 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
   LayerImpl::PushPropertiesTo(base_layer);
 
   // When the pending tree pushes to the active tree, the pending twin
-  // disappears.
+  // becomes recycled.
   layer_impl->twin_layer_ = NULL;
   twin_layer_ = NULL;
 
-  layer_impl->SetIsMask(is_mask_);
   layer_impl->pile_ = pile_;
 
   // Tilings would be expensive to push, so we swap.
@@ -264,6 +262,12 @@ void PictureLayerImpl::AppendQuads(
   // unused can be considered for removal.
   std::vector<PictureLayerTiling*> seen_tilings;
 
+  // Ignore missing tiles outside of viewport for tile priority. This is
+  // normally the same as draw viewport but can be independently overridden by
+  // embedders like Android WebView with SetExternalDrawConstraints.
+  gfx::Rect scaled_viewport_for_tile_priority = gfx::ScaleToEnclosingRect(
+      GetViewportForTilePriorityInContentSpace(), max_contents_scale);
+
   size_t missing_tile_count = 0u;
   size_t on_demand_missing_tile_count = 0u;
   for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(),
@@ -281,6 +285,7 @@ void PictureLayerImpl::AppendQuads(
     append_quads_data->visible_content_area +=
         visible_geometry_rect.width() * visible_geometry_rect.height();
 
+    bool has_draw_quad = false;
     if (*iter && iter->IsReadyToDraw()) {
       const ManagedTileState::TileVersion& tile_version =
           iter->GetTileVersionForDrawing();
@@ -290,8 +295,10 @@ void PictureLayerImpl::AppendQuads(
           gfx::Rect opaque_rect = iter->opaque_rect();
           opaque_rect.Intersect(geometry_rect);
 
-          if (iter->contents_scale() != ideal_contents_scale_)
+          if (iter->contents_scale() != ideal_contents_scale_ &&
+              geometry_rect.Intersects(scaled_viewport_for_tile_priority)) {
             append_quads_data->num_incomplete_tiles++;
+          }
 
           TileDrawQuad* quad =
               render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
@@ -303,6 +310,7 @@ void PictureLayerImpl::AppendQuads(
                        texture_rect,
                        iter.texture_size(),
                        tile_version.contents_swizzled());
+          has_draw_quad = true;
           break;
         }
         case ManagedTileState::TileVersion::PICTURE_PILE_MODE: {
@@ -333,6 +341,7 @@ void PictureLayerImpl::AppendQuads(
                        iter->content_rect(),
                        iter->contents_scale(),
                        pile_);
+          has_draw_quad = true;
           break;
         }
         case ManagedTileState::TileVersion::SOLID_COLOR_MODE: {
@@ -343,10 +352,13 @@ void PictureLayerImpl::AppendQuads(
                        visible_geometry_rect,
                        tile_version.get_solid_color(),
                        false);
+          has_draw_quad = true;
           break;
         }
       }
-    } else {
+    }
+
+    if (!has_draw_quad) {
       if (draw_checkerboard_for_missing_tiles()) {
         CheckerboardDrawQuad* quad =
             render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
@@ -364,10 +376,12 @@ void PictureLayerImpl::AppendQuads(
                      false);
       }
 
-      append_quads_data->num_missing_tiles++;
+      if (geometry_rect.Intersects(scaled_viewport_for_tile_priority)) {
+        append_quads_data->num_missing_tiles++;
+        ++missing_tile_count;
+      }
       append_quads_data->approximated_visible_content_area +=
           visible_geometry_rect.width() * visible_geometry_rect.height();
-      ++missing_tile_count;
       continue;
     }
 
@@ -472,6 +486,28 @@ void PictureLayerImpl::UpdateTilePriorities(
   if (!tiling_needs_update)
     return;
 
+  gfx::Rect visible_rect_in_content_space(
+      GetViewportForTilePriorityInContentSpace());
+  visible_rect_in_content_space.Intersect(visible_content_rect());
+  gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
+      visible_rect_in_content_space, 1.f / contents_scale_x());
+  WhichTree tree =
+      layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
+  for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+    tilings_->tiling_at(i)->UpdateTilePriorities(tree,
+                                                 visible_layer_rect,
+                                                 ideal_contents_scale_,
+                                                 current_frame_time_in_seconds,
+                                                 occlusion_tracker,
+                                                 render_target(),
+                                                 draw_transform());
+  }
+
+  // Tile priorities were modified.
+  layer_tree_impl()->DidModifyTilePriorities();
+}
+
+gfx::Rect PictureLayerImpl::GetViewportForTilePriorityInContentSpace() const {
   // If visible_rect_for_tile_priority_ is empty or
   // viewport_rect_for_tile_priority_ is set to be different from the device
   // viewport, try to inverse project the viewport into layer space and use
@@ -492,22 +528,13 @@ void PictureLayerImpl::UpdateTilePriorities(
     }
   }
 
-  gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
-      visible_rect_in_content_space, 1.f / contents_scale_x());
-  WhichTree tree =
-      layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
-  for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
-    tilings_->tiling_at(i)->UpdateTilePriorities(tree,
-                                                 visible_layer_rect,
-                                                 ideal_contents_scale_,
-                                                 current_frame_time_in_seconds,
-                                                 occlusion_tracker,
-                                                 render_target(),
-                                                 draw_transform());
-  }
+  return visible_rect_in_content_space;
+}
 
-  // Tile priorities were modified.
-  layer_tree_impl()->DidModifyTilePriorities();
+PictureLayerImpl* PictureLayerImpl::GetRecycledTwinLayer() {
+  // TODO(vmpstr): Maintain recycled twin as a member. crbug.com/407418
+  return static_cast<PictureLayerImpl*>(
+      layer_tree_impl()->FindRecycleTreeLayerById(id()));
 }
 
 void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
@@ -552,9 +579,12 @@ scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling,
   // TODO(vmpstr): Revisit this. For now, enabling analysis means that we get as
   // much savings on memory as we can. However, for some cases like ganesh or
   // small layers, the amount of time we spend analyzing might not justify
-  // memory savings that we can get.
+  // memory savings that we can get. Note that we don't handle solid color
+  // masks, so we shouldn't bother analyzing those.
   // Bugs: crbug.com/397198, crbug.com/396908
-  int flags = Tile::USE_PICTURE_ANALYSIS;
+  int flags = 0;
+  if (!pile_->is_mask())
+    flags = Tile::USE_PICTURE_ANALYSIS;
 
   return layer_tree_impl()->tile_manager()->CreateTile(
       pile_.get(),
@@ -586,6 +616,14 @@ const PictureLayerTiling* PictureLayerImpl::GetTwinTiling(
   return NULL;
 }
 
+PictureLayerTiling* PictureLayerImpl::GetRecycledTwinTiling(
+    const PictureLayerTiling* tiling) {
+  PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
+  if (!recycled_twin || !recycled_twin->tilings_)
+    return NULL;
+  return recycled_twin->tilings_->TilingAtScale(tiling->contents_scale());
+}
+
 size_t PictureLayerImpl::GetMaxTilesForInterestArea() const {
   return layer_tree_impl()->settings().max_tiles_for_interest_area;
 }
@@ -608,16 +646,18 @@ int PictureLayerImpl::GetSkewportExtrapolationLimitInContentPixels() const {
 
 gfx::Size PictureLayerImpl::CalculateTileSize(
     const gfx::Size& content_bounds) const {
-  if (is_mask_) {
-    int max_size = layer_tree_impl()->MaxTextureSize();
-    return gfx::Size(
-        std::min(max_size, content_bounds.width()),
-        std::min(max_size, content_bounds.height()));
-  }
-
   int max_texture_size =
       layer_tree_impl()->resource_provider()->max_texture_size();
 
+  if (pile_->is_mask()) {
+    // Masks are not tiled, so if we can't cover the whole mask with one tile,
+    // don't make any tiles at all. Returning an empty size signals this.
+    if (content_bounds.width() > max_texture_size ||
+        content_bounds.height() > max_texture_size)
+      return gfx::Size();
+    return content_bounds;
+  }
+
   gfx::Size default_tile_size = layer_tree_impl()->settings().default_tile_size;
   if (layer_tree_impl()->use_gpu_rasterization()) {
     // TODO(ernstm) crbug.com/365877: We need a unified way to override the
@@ -719,14 +759,6 @@ void PictureLayerImpl::SyncTiling(
   }
 }
 
-void PictureLayerImpl::SetIsMask(bool is_mask) {
-  if (is_mask_ == is_mask)
-    return;
-  is_mask_ = is_mask;
-  if (tilings_)
-    tilings_->RemoveAllTiles();
-}
-
 ResourceProvider::ResourceId PictureLayerImpl::ContentsResourceId() const {
   gfx::Rect content_rect(content_bounds());
   float scale = MaximumTilingContentsScale();
@@ -738,8 +770,9 @@ ResourceProvider::ResourceId PictureLayerImpl::ContentsResourceId() const {
     return 0;
 
   // Masks only supported if they fit on exactly one tile.
-  if (iter.geometry_rect() != content_rect)
-    return 0;
+  DCHECK(iter.geometry_rect() == content_rect)
+      << "iter rect " << iter.geometry_rect().ToString() << " content rect "
+      << content_rect.ToString();
 
   const ManagedTileState::TileVersion& tile_version =
       iter->GetTileVersionForDrawing();
@@ -765,6 +798,12 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
 
   gfx::Rect rect(visible_content_rect());
 
+  // Only mark tiles inside the viewport for tile priority as required for
+  // activation. This viewport is normally the same as the draw viewport but
+  // can be independently overridden by embedders like Android WebView with
+  // SetExternalDrawConstraints.
+  rect.Intersect(GetViewportForTilePriorityInContentSpace());
+
   float min_acceptable_scale =
       std::min(raster_contents_scale_, ideal_contents_scale_);
 
@@ -1140,13 +1179,14 @@ void PictureLayerImpl::RecalculateRasterScales() {
     }
   }
 
-  // If this layer would only create one tile at this content scale,
+  // If this layer would create zero or one tiles at this content scale,
   // don't create a low res tiling.
   gfx::Size content_bounds =
       gfx::ToCeiledSize(gfx::ScaleSize(bounds(), raster_contents_scale_));
   gfx::Size tile_size = CalculateTileSize(content_bounds);
-  if (tile_size.width() >= content_bounds.width() &&
-      tile_size.height() >= content_bounds.height()) {
+  bool tile_covers_bounds = tile_size.width() >= content_bounds.width() &&
+                            tile_size.height() >= content_bounds.height();
+  if (tile_size.IsEmpty() || tile_covers_bounds) {
     low_res_raster_contents_scale_ = raster_contents_scale_;
     return;
   }
@@ -1214,8 +1254,7 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
   if (to_remove.empty())
     return;
 
-  PictureLayerImpl* recycled_twin = static_cast<PictureLayerImpl*>(
-      layer_tree_impl()->FindRecycleTreeLayerById(id()));
+  PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
   // Remove tilings on this tree and the twin tree.
   for (size_t i = 0; i < to_remove.size(); ++i) {
     const PictureLayerTiling* twin_tiling = GetTwinTiling(to_remove[i]);
index 7623c4d..6166720 100644 (file)
@@ -124,6 +124,8 @@ class CC_EXPORT PictureLayerImpl
   virtual const Region* GetInvalidation() OVERRIDE;
   virtual const PictureLayerTiling* GetTwinTiling(
       const PictureLayerTiling* tiling) const OVERRIDE;
+  virtual PictureLayerTiling* GetRecycledTwinTiling(
+      const PictureLayerTiling* tiling) OVERRIDE;
   virtual size_t GetMaxTilesForInterestArea() const OVERRIDE;
   virtual float GetSkewportTargetTimeInSeconds() const OVERRIDE;
   virtual int GetSkewportExtrapolationLimitInContentPixels() const OVERRIDE;
@@ -132,8 +134,7 @@ class CC_EXPORT PictureLayerImpl
   // PushPropertiesTo active tree => pending tree.
   void SyncTiling(const PictureLayerTiling* tiling);
 
-  // Mask-related functions
-  void SetIsMask(bool is_mask);
+  // Mask-related functions.
   virtual ResourceProvider::ResourceId ContentsResourceId() const OVERRIDE;
 
   virtual size_t GPUMemoryUsageInBytes() const OVERRIDE;
@@ -172,6 +173,8 @@ class CC_EXPORT PictureLayerImpl
       float contents_scale,
       const gfx::Rect& rect,
       const Region& missing_region) const;
+  gfx::Rect GetViewportForTilePriorityInContentSpace() const;
+  PictureLayerImpl* GetRecycledTwinLayer();
 
   void DoPostCommitInitializationIfNeeded() {
     if (needs_post_commit_initialization_)
@@ -196,8 +199,6 @@ class CC_EXPORT PictureLayerImpl
   scoped_refptr<PicturePileImpl> pile_;
   Region invalidation_;
 
-  bool is_mask_;
-
   float ideal_page_scale_;
   float ideal_device_scale_;
   float ideal_source_scale_;
index 5eae6a6..38e968e 100644 (file)
@@ -51,7 +51,10 @@ class PictureLayerImplTest : public testing::Test {
         host_impl_(ImplSidePaintingSettings(),
                    &proxy_,
                    &shared_bitmap_manager_),
-        id_(7) {}
+        id_(7),
+        pending_layer_(NULL),
+        old_pending_layer_(NULL),
+        active_layer_(NULL) {}
 
   explicit PictureLayerImplTest(const LayerTreeSettings& settings)
       : proxy_(base::MessageLoopProxy::current()),
@@ -84,6 +87,8 @@ class PictureLayerImplTest : public testing::Test {
   void ActivateTree() {
     host_impl_.ActivateSyncTree();
     CHECK(!host_impl_.pending_tree());
+    CHECK(host_impl_.recycle_tree());
+    old_pending_layer_ = pending_layer_;
     pending_layer_ = NULL;
     active_layer_ = static_cast<FakePictureLayerImpl*>(
         host_impl_.active_tree()->LayerById(id_));
@@ -102,8 +107,6 @@ class PictureLayerImplTest : public testing::Test {
     SetupPendingTree(active_pile);
     ActivateTree();
     SetupPendingTree(pending_pile);
-    host_impl_.pending_tree()->SetPageScaleFactorAndLimits(1.f, 0.25f, 100.f);
-    host_impl_.active_tree()->SetPageScaleFactorAndLimits(1.f, 0.25f, 100.f);
   }
 
   void CreateHighLowResAndSetAllTilesVisible() {
@@ -127,6 +130,7 @@ class PictureLayerImplTest : public testing::Test {
 
   void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
     host_impl_.CreatePendingTree();
+    host_impl_.pending_tree()->SetPageScaleFactorAndLimits(1.f, 0.25f, 100.f);
     LayerTreeImpl* pending_tree = host_impl_.pending_tree();
     // Clear recycled tree.
     pending_tree->DetachLayerTree();
@@ -264,6 +268,7 @@ class PictureLayerImplTest : public testing::Test {
   FakeLayerTreeHostImpl host_impl_;
   int id_;
   FakePictureLayerImpl* pending_layer_;
+  FakePictureLayerImpl* old_pending_layer_;
   FakePictureLayerImpl* active_layer_;
 
  private:
@@ -1079,6 +1084,12 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
     EXPECT_EQ(x, active_layer_->expression);  \
   } while (false)
 
+#define EXPECT_BOTH_NE(expression, x)         \
+  do {                                        \
+    EXPECT_NE(x, pending_layer_->expression); \
+    EXPECT_NE(x, active_layer_->expression);  \
+  } while (false)
+
 TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) {
   // Make sure this layer covers multiple tiles, since otherwise low
   // res won't get created because it is too small.
@@ -1190,8 +1201,8 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
   ResetTilingsAndRasterScales();
 
   // Mask layers dont create low res since they always fit on one tile.
-  pending_layer_->SetIsMask(true);
-  active_layer_->SetIsMask(true);
+  pending_layer_->pile()->set_is_mask(true);
+  active_layer_->pile()->set_is_mask(true);
   SetContentsScaleOnBothLayers(contents_scale,
                                device_scale,
                                page_scale,
@@ -1201,6 +1212,53 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
   EXPECT_BOTH_EQ(num_tilings(), 1u);
 }
 
+TEST_F(PictureLayerImplTest, HugeMasksDontGetTiles) {
+  gfx::Size tile_size(100, 100);
+
+  scoped_refptr<FakePicturePileImpl> valid_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
+  valid_pile->set_is_mask(true);
+  SetupPendingTree(valid_pile);
+
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+  EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
+  EXPECT_EQ(1u, pending_layer_->num_tilings());
+
+  pending_layer_->HighResTiling()->CreateAllTilesForTesting();
+  host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
+      pending_layer_->HighResTiling()->AllTilesForTesting());
+
+  ActivateTree();
+
+  // Mask layers have a tiling with a single tile in it.
+  EXPECT_EQ(1u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+  // The mask resource exists.
+  EXPECT_NE(0u, active_layer_->ContentsResourceId());
+
+  // Resize larger than the max texture size.
+  int max_texture_size = host_impl_.GetRendererCapabilities().max_texture_size;
+  scoped_refptr<FakePicturePileImpl> huge_pile =
+      FakePicturePileImpl::CreateFilledPile(
+          tile_size, gfx::Size(max_texture_size + 1, 10));
+  huge_pile->set_is_mask(true);
+  SetupPendingTree(huge_pile);
+
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+  EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
+  EXPECT_EQ(1u, pending_layer_->num_tilings());
+
+  pending_layer_->HighResTiling()->CreateAllTilesForTesting();
+  host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
+      pending_layer_->HighResTiling()->AllTilesForTesting());
+
+  ActivateTree();
+
+  // Mask layers have a tiling, but there should be no tiles in it.
+  EXPECT_EQ(0u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+  // The mask resource is empty.
+  EXPECT_EQ(0u, active_layer_->ContentsResourceId());
+}
+
 TEST_F(PictureLayerImplTest, ReleaseResources) {
   gfx::Size tile_size(400, 400);
   gfx::Size layer_bounds(1300, 1900);
@@ -1450,6 +1508,97 @@ TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
   EXPECT_GT(num_offscreen, 0);
 }
 
+TEST_F(PictureLayerImplTest, TileOutsideOfViewportForTilePriorityNotRequired) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(400, 400);
+  gfx::Rect external_viewport_for_tile_priority(400, 200);
+  gfx::Rect visible_content_rect(200, 400);
+
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupTrees(pending_pile, active_pile);
+
+  active_layer_->set_fixed_tile_size(tile_size);
+  pending_layer_->set_fixed_tile_size(tile_size);
+  ASSERT_TRUE(pending_layer_->CanHaveTilings());
+  PictureLayerTiling* tiling = pending_layer_->AddTiling(1.f);
+
+  // Set external viewport for tile priority.
+  gfx::Rect viewport = gfx::Rect(layer_bounds);
+  gfx::Transform transform;
+  gfx::Transform transform_for_tile_priority;
+  bool resourceless_software_draw = false;
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        external_viewport_for_tile_priority,
+                                        transform_for_tile_priority,
+                                        resourceless_software_draw);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  // Set visible content rect that is different from
+  // external_viewport_for_tile_priority.
+  pending_layer_->draw_properties().visible_content_rect = visible_content_rect;
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+  pending_layer_->UpdateTiles(NULL);
+
+  pending_layer_->MarkVisibleResourcesAsRequired();
+
+  // Intersect the two rects. Any tile outside should not be required for
+  // activation.
+  gfx::Rect viewport_for_tile_priority =
+      pending_layer_->GetViewportForTilePriorityInContentSpace();
+  viewport_for_tile_priority.Intersect(pending_layer_->visible_content_rect());
+
+  int num_inside = 0;
+  int num_outside = 0;
+  for (PictureLayerTiling::CoverageIterator iter(
+           tiling, pending_layer_->contents_scale_x(), gfx::Rect(layer_bounds));
+       iter;
+       ++iter) {
+    if (!*iter)
+      continue;
+    Tile* tile = *iter;
+    if (viewport_for_tile_priority.Intersects(iter.geometry_rect())) {
+      num_inside++;
+      // Mark everything in viewport for tile priority as ready to draw.
+      ManagedTileState::TileVersion& tile_version =
+          tile->GetTileVersionForTesting(
+              tile->DetermineRasterModeForTree(PENDING_TREE));
+      tile_version.SetSolidColorForTesting(SK_ColorRED);
+    } else {
+      num_outside++;
+      EXPECT_FALSE(tile->required_for_activation());
+    }
+  }
+
+  EXPECT_GT(num_inside, 0);
+  EXPECT_GT(num_outside, 0);
+
+  // Activate and draw active layer.
+  host_impl_.ActivateSyncTree();
+  host_impl_.active_tree()->UpdateDrawProperties();
+  active_layer_->draw_properties().visible_content_rect = visible_content_rect;
+
+  MockOcclusionTracker<LayerImpl> occlusion_tracker;
+  scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+  AppendQuadsData data;
+  active_layer_->WillDraw(DRAW_MODE_SOFTWARE, NULL);
+  active_layer_->AppendQuads(render_pass.get(), occlusion_tracker, &data);
+  active_layer_->DidDraw(NULL);
+
+  // All tiles in activation rect is ready to draw.
+  EXPECT_EQ(0u, data.num_missing_tiles);
+  EXPECT_EQ(0u, data.num_incomplete_tiles);
+}
+
 TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
@@ -3072,10 +3221,10 @@ TEST_F(PictureLayerImplTest, UpdateTilesForMasksWithNoVisibleContent) {
 
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, bounds);
+  pending_pile->set_is_mask(true);
   scoped_ptr<FakePictureLayerImpl> mask = FakePictureLayerImpl::CreateWithPile(
       host_impl_.pending_tree(), 3, pending_pile);
 
-  mask->SetIsMask(true);
   mask->SetBounds(bounds);
   mask->SetContentBounds(bounds);
   mask->SetDrawsContent(true);
@@ -3101,6 +3250,66 @@ TEST_F(PictureLayerImplTest, UpdateTilesForMasksWithNoVisibleContent) {
   EXPECT_NE(0u, pending_mask_content->num_tilings());
 }
 
+class PictureLayerImplTestWithDelegatingRenderer : public PictureLayerImplTest {
+ public:
+  PictureLayerImplTestWithDelegatingRenderer() : PictureLayerImplTest() {}
+
+  virtual void InitializeRenderer() OVERRIDE {
+    host_impl_.InitializeRenderer(
+        FakeOutputSurface::CreateDelegating3d().PassAs<OutputSurface>());
+  }
+};
+
+TEST_F(PictureLayerImplTestWithDelegatingRenderer,
+       DelegatingRendererWithTileOOM) {
+  // This test is added for crbug.com/402321, where quad should be produced when
+  // raster on demand is not allowed and tile is OOM.
+  gfx::Size tile_size = host_impl_.settings().default_tile_size;
+  gfx::Size layer_bounds(1000, 1000);
+
+  // Create tiles.
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTree(pending_pile);
+  pending_layer_->SetBounds(layer_bounds);
+  host_impl_.SetViewportSize(layer_bounds);
+  ActivateTree();
+  host_impl_.active_tree()->UpdateDrawProperties();
+  std::vector<Tile*> tiles =
+      active_layer_->HighResTiling()->AllTilesForTesting();
+  host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
+
+  // Force tiles after max_tiles to be OOM. TileManager uses
+  // GlobalStateThatImpactsTilesPriority from LayerTreeHostImpl, and we cannot
+  // directly set state to host_impl_, so we set policy that would change the
+  // state. We also need to update tree priority separately.
+  GlobalStateThatImpactsTilePriority state;
+  size_t max_tiles = 1;
+  size_t memory_limit = max_tiles * 4 * tile_size.width() * tile_size.height();
+  size_t resource_limit = max_tiles;
+  ManagedMemoryPolicy policy(memory_limit,
+                             gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
+                             resource_limit);
+  host_impl_.SetMemoryPolicy(policy);
+  host_impl_.SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
+  host_impl_.ManageTiles();
+
+  MockOcclusionTracker<LayerImpl> occlusion_tracker;
+  scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+  AppendQuadsData data;
+  active_layer_->WillDraw(DRAW_MODE_HARDWARE, NULL);
+  active_layer_->AppendQuads(render_pass.get(), occlusion_tracker, &data);
+  active_layer_->DidDraw(NULL);
+
+  // Even when OOM, quads should be produced, and should be different material
+  // from quads with resource.
+  EXPECT_LT(max_tiles, render_pass->quad_list.size());
+  EXPECT_EQ(DrawQuad::Material::TILED_CONTENT,
+            render_pass->quad_list.front()->material);
+  EXPECT_EQ(DrawQuad::Material::SOLID_COLOR,
+            render_pass->quad_list.back()->material);
+}
+
 class OcclusionTrackingSettings : public ImplSidePaintingSettings {
  public:
   OcclusionTrackingSettings() { use_occlusion_for_tile_prioritization = true; }
@@ -3709,5 +3918,31 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
   VerifyEvictionConsidersOcclusion(active_layer_,
                                    total_expected_occluded_tile_count);
 }
+
+TEST_F(PictureLayerImplTest, RecycledTwinLayer) {
+  gfx::Size tile_size(102, 102);
+  gfx::Size layer_bounds(1000, 1000);
+
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTree(pile);
+  EXPECT_FALSE(pending_layer_->GetRecycledTwinLayer());
+
+  ActivateTree();
+  EXPECT_TRUE(active_layer_->GetRecycledTwinLayer());
+  EXPECT_EQ(old_pending_layer_, active_layer_->GetRecycledTwinLayer());
+
+  SetupPendingTree(pile);
+  EXPECT_FALSE(pending_layer_->GetRecycledTwinLayer());
+  EXPECT_FALSE(active_layer_->GetRecycledTwinLayer());
+
+  ActivateTree();
+  EXPECT_TRUE(active_layer_->GetRecycledTwinLayer());
+  EXPECT_EQ(old_pending_layer_, active_layer_->GetRecycledTwinLayer());
+
+  host_impl_.ResetRecycleTreeForTesting();
+  EXPECT_FALSE(active_layer_->GetRecycledTwinLayer());
+}
+
 }  // namespace
 }  // namespace cc
index b335e50..5c75f78 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "base/debug/trace_event.h"
 #include "base/debug/trace_event_argument.h"
+#include "base/logging.h"
 #include "cc/base/math_util.h"
 #include "cc/resources/tile.h"
 #include "cc/resources/tile_priority.h"
@@ -88,6 +89,10 @@ PictureLayerTiling::PictureLayerTiling(float contents_scale,
   gfx::Size content_bounds =
       gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale));
   gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
+  if (tile_size.IsEmpty()) {
+    layer_bounds_ = gfx::Size();
+    content_bounds = gfx::Size();
+  }
 
   DCHECK(!gfx::ToFlooredSize(
       gfx::ScaleSize(layer_bounds, contents_scale)).IsEmpty()) <<
@@ -141,7 +146,7 @@ Tile* PictureLayerTiling::CreateTile(int i,
 
 void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
   const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
-  bool include_borders = true;
+  bool include_borders = false;
   for (TilingData::Iterator iter(
            &tiling_data_, live_tiles_rect_, include_borders);
        iter;
@@ -152,6 +157,8 @@ void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
       continue;
     CreateTile(key.first, key.second, twin_tiling);
   }
+
+  VerifyLiveTilesRect();
 }
 
 void PictureLayerTiling::UpdateTilesToCurrentPile(
@@ -159,19 +166,78 @@ void PictureLayerTiling::UpdateTilesToCurrentPile(
     const gfx::Size& new_layer_bounds) {
   DCHECK(!new_layer_bounds.IsEmpty());
 
-  gfx::Size old_layer_bounds = layer_bounds_;
-  layer_bounds_ = new_layer_bounds;
-
-  gfx::Size content_bounds =
-      gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_));
   gfx::Size tile_size = tiling_data_.max_texture_size();
 
-  if (layer_bounds_ != old_layer_bounds) {
-    // Drop tiles outside the new layer bounds if the layer shrank.
-    SetLiveTilesRect(
-        gfx::IntersectRects(live_tiles_rect_, gfx::Rect(content_bounds)));
-    tiling_data_.SetTilingSize(content_bounds);
+  if (new_layer_bounds != layer_bounds_) {
+    gfx::Size content_bounds =
+        gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
+
     tile_size = client_->CalculateTileSize(content_bounds);
+    if (tile_size.IsEmpty()) {
+      layer_bounds_ = gfx::Size();
+      content_bounds = gfx::Size();
+    } else {
+      layer_bounds_ = new_layer_bounds;
+    }
+
+    // The SetLiveTilesRect() method would drop tiles outside the new bounds,
+    // but may do so incorrectly if resizing the tiling causes the number of
+    // tiles in the tiling_data_ to change.
+    gfx::Rect content_rect(content_bounds);
+    int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x());
+    int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y());
+    int before_right =
+        tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+    int before_bottom =
+        tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+
+    // The live_tiles_rect_ is clamped to stay within the tiling size as we
+    // change it.
+    live_tiles_rect_.Intersect(content_rect);
+    tiling_data_.SetTilingSize(content_bounds);
+
+    int after_right = -1;
+    int after_bottom = -1;
+    if (!live_tiles_rect_.IsEmpty()) {
+      after_right =
+          tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+      after_bottom =
+          tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+    }
+
+    // Drop tiles outside the new layer bounds if the layer shrank.
+    for (int i = after_right + 1; i <= before_right; ++i) {
+      for (int j = before_top; j <= before_bottom; ++j) {
+        TileMap::iterator found = tiles_.find(TileMapKey(i, j));
+        if (found == tiles_.end())
+          continue;
+        ReleaseTile(found->second.get(), client_->GetTree());
+        tiles_.erase(found);
+      }
+    }
+    for (int i = before_left; i <= after_right; ++i) {
+      for (int j = after_bottom + 1; j <= before_bottom; ++j) {
+        TileMap::iterator found = tiles_.find(TileMapKey(i, j));
+        if (found == tiles_.end())
+          continue;
+        ReleaseTile(found->second.get(), client_->GetTree());
+        tiles_.erase(found);
+      }
+    }
+
+    // If the layer grew, the live_tiles_rect_ is not changed, but a new row
+    // and/or column of tiles may now exist inside the same live_tiles_rect_.
+    const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
+    if (after_right > before_right) {
+      DCHECK_EQ(after_right, before_right + 1);
+      for (int j = before_top; j <= after_bottom; ++j)
+        CreateTile(after_right, j, twin_tiling);
+    }
+    if (after_bottom > before_bottom) {
+      DCHECK_EQ(after_bottom, before_bottom + 1);
+      for (int i = before_left; i <= before_right; ++i)
+        CreateTile(i, after_bottom, twin_tiling);
+    }
   }
 
   if (tile_size != tiling_data_.max_texture_size()) {
@@ -186,6 +252,7 @@ void PictureLayerTiling::UpdateTilesToCurrentPile(
   PicturePileImpl* pile = client_->GetPile();
   for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
     it->second->set_picture_pile(pile);
+  VerifyLiveTilesRect();
 }
 
 void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) {
@@ -202,18 +269,24 @@ void PictureLayerTiling::DoInvalidate(const Region& layer_region,
                                       bool recreate_invalidated_tiles) {
   std::vector<TileMapKey> new_tile_keys;
   gfx::Rect expanded_live_tiles_rect =
-      tiling_data_.ExpandRectIgnoringBordersToTileBoundsWithBorders(
-          live_tiles_rect_);
+      tiling_data_.ExpandRectIgnoringBordersToTileBounds(live_tiles_rect_);
   for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) {
     gfx::Rect layer_rect = iter.rect();
     gfx::Rect content_rect =
         gfx::ScaleToEnclosingRect(layer_rect, contents_scale_);
+    // Consider tiles inside the live tiles rect even if only their border
+    // pixels intersect the invalidation. But don't consider tiles outside
+    // the live tiles rect with the same conditions, as they won't exist.
+    int border_pixels = tiling_data_.border_texels();
+    content_rect.Inset(-border_pixels, -border_pixels);
     // Avoid needless work by not bothering to invalidate where there aren't
     // tiles.
     content_rect.Intersect(expanded_live_tiles_rect);
     if (content_rect.IsEmpty())
       continue;
-    bool include_borders = true;
+    // Since the content_rect includes border pixels already, don't include
+    // borders when iterating to avoid double counting them.
+    bool include_borders = false;
     for (TilingData::Iterator iter(
              &tiling_data_, content_rect, include_borders);
          iter;
@@ -497,11 +570,10 @@ void PictureLayerTiling::UpdateTilePriorities(
   eviction_tiles_cache_valid_ = false;
 
   TilePriority now_priority(resolution_, TilePriority::NOW, 0);
-  float content_to_screen_scale =
-      1.0f / (contents_scale_ * ideal_contents_scale);
+  float content_to_screen_scale = ideal_contents_scale / contents_scale_;
 
   // Assign now priority to all visible tiles.
-  bool include_borders = true;
+  bool include_borders = false;
   has_visible_rect_tiles_ = false;
   for (TilingData::Iterator iter(
            &tiling_data_, visible_rect_in_content_space, include_borders);
@@ -603,6 +675,15 @@ void PictureLayerTiling::UpdateTilePriorities(
   current_eventually_rect_ = eventually_rect;
 }
 
+void PictureLayerTiling::RemoveTileAt(int i, int j) {
+  TileMapKey key(i, j);
+  TileMap::iterator found = tiles_.find(key);
+  if (found == tiles_.end())
+    return;
+  ReleaseTile(found->second.get(), client_->GetTree());
+  tiles_.erase(found);
+}
+
 void PictureLayerTiling::SetLiveTilesRect(
     const gfx::Rect& new_live_tiles_rect) {
   DCHECK(new_live_tiles_rect.IsEmpty() ||
@@ -613,6 +694,7 @@ void PictureLayerTiling::SetLiveTilesRect(
     return;
 
   // Iterate to delete all tiles outside of our new live_tiles rect.
+  PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
   for (TilingData::DifferenceIterator iter(&tiling_data_,
                                            live_tiles_rect_,
                                            new_live_tiles_rect);
@@ -625,6 +707,8 @@ void PictureLayerTiling::SetLiveTilesRect(
     if (found != tiles_.end()) {
       ReleaseTile(found->second.get(), client_->GetTree());
       tiles_.erase(found);
+      if (recycled_twin)
+        recycled_twin->RemoveTileAt(iter.index_x(), iter.index_y());
     }
   }
 
@@ -641,6 +725,30 @@ void PictureLayerTiling::SetLiveTilesRect(
   }
 
   live_tiles_rect_ = new_live_tiles_rect;
+  VerifyLiveTilesRect();
+}
+
+void PictureLayerTiling::VerifyLiveTilesRect() {
+#if DCHECK_IS_ON
+  for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+    if (!it->second.get())
+      continue;
+    DCHECK(it->first.first < tiling_data_.num_tiles_x())
+        << this << " " << it->first.first << "," << it->first.second
+        << " num_tiles_x " << tiling_data_.num_tiles_x() << " live_tiles_rect "
+        << live_tiles_rect_.ToString();
+    DCHECK(it->first.second < tiling_data_.num_tiles_y())
+        << this << " " << it->first.first << "," << it->first.second
+        << " num_tiles_y " << tiling_data_.num_tiles_y() << " live_tiles_rect "
+        << live_tiles_rect_.ToString();
+    DCHECK(tiling_data_.TileBounds(it->first.first, it->first.second)
+               .Intersects(live_tiles_rect_))
+        << this << " " << it->first.first << "," << it->first.second
+        << " tile bounds "
+        << tiling_data_.TileBounds(it->first.first, it->first.second).ToString()
+        << " live_tiles_rect " << live_tiles_rect_.ToString();
+  }
+#endif
 }
 
 void PictureLayerTiling::DidBecomeRecycled() {
@@ -936,7 +1044,7 @@ PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator(
 
   visible_iterator_ = TilingData::Iterator(&tiling_->tiling_data_,
                                            tiling_->current_visible_rect_,
-                                           true /* include_borders */);
+                                           false /* include_borders */);
   if (!visible_iterator_) {
     AdvancePhase();
     return;
index 415ad42..9ca0d41 100644 (file)
@@ -44,6 +44,8 @@ class CC_EXPORT PictureLayerTilingClient {
   virtual const Region* GetInvalidation() = 0;
   virtual const PictureLayerTiling* GetTwinTiling(
       const PictureLayerTiling* tiling) const = 0;
+  virtual PictureLayerTiling* GetRecycledTwinTiling(
+      const PictureLayerTiling* tiling) = 0;
   virtual size_t GetMaxTilesForInterestArea() const = 0;
   virtual float GetSkewportTargetTimeInSeconds() const = 0;
   virtual int GetSkewportExtrapolationLimitInContentPixels() const = 0;
@@ -294,7 +296,9 @@ class CC_EXPORT PictureLayerTiling {
                      const gfx::Size& layer_bounds,
                      PictureLayerTilingClient* client);
   void SetLiveTilesRect(const gfx::Rect& live_tiles_rect);
+  void VerifyLiveTilesRect();
   Tile* CreateTile(int i, int j, const PictureLayerTiling* twin_tiling);
+  void RemoveTileAt(int i, int j);
 
   // Computes a skewport. The calculation extrapolates the last visible
   // rect and the current visible rect to expand the skewport to where it
index 032ffec..f03c3bf 100644 (file)
@@ -65,6 +65,8 @@ class TestablePictureLayerTiling : public PictureLayerTiling {
         client));
   }
 
+  gfx::Rect live_tiles_rect() const { return live_tiles_rect_; }
+
   using PictureLayerTiling::ComputeSkewport;
 
  protected:
@@ -210,6 +212,196 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeDeletesTiles) {
   EXPECT_FALSE(tiling_->TileAt(0, 0));
 }
 
+TEST_F(PictureLayerTilingIteratorTest, CreateMissingTilesStaysInsideLiveRect) {
+  // The tiling has three rows and columns.
+  Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 250));
+  EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
+  EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y());
+
+  // The live tiles rect is at the very edge of the right-most and
+  // bottom-most tiles. Their border pixels would still be inside the live
+  // tiles rect, but the tiles should not exist just for that.
+  int right = tiling_->TilingDataForTesting().TileBounds(2, 2).x();
+  int bottom = tiling_->TilingDataForTesting().TileBounds(2, 2).y();
+
+  SetLiveRectAndVerifyTiles(gfx::Rect(right, bottom));
+  EXPECT_FALSE(tiling_->TileAt(2, 0));
+  EXPECT_FALSE(tiling_->TileAt(2, 1));
+  EXPECT_FALSE(tiling_->TileAt(2, 2));
+  EXPECT_FALSE(tiling_->TileAt(1, 2));
+  EXPECT_FALSE(tiling_->TileAt(0, 2));
+
+  // Verify CreateMissingTilesInLiveTilesRect respects this.
+  tiling_->CreateMissingTilesInLiveTilesRect();
+  EXPECT_FALSE(tiling_->TileAt(2, 0));
+  EXPECT_FALSE(tiling_->TileAt(2, 1));
+  EXPECT_FALSE(tiling_->TileAt(2, 2));
+  EXPECT_FALSE(tiling_->TileAt(1, 2));
+  EXPECT_FALSE(tiling_->TileAt(0, 2));
+}
+
+TEST_F(PictureLayerTilingIteratorTest, ResizeTilingOverTileBorders) {
+  // The tiling has four rows and three columns.
+  Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350));
+  EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
+  EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
+
+  // The live tiles rect covers the whole tiling.
+  SetLiveRectAndVerifyTiles(gfx::Rect(250, 350));
+
+  // Tiles in the bottom row and right column exist.
+  EXPECT_TRUE(tiling_->TileAt(2, 0));
+  EXPECT_TRUE(tiling_->TileAt(2, 1));
+  EXPECT_TRUE(tiling_->TileAt(2, 2));
+  EXPECT_TRUE(tiling_->TileAt(2, 3));
+  EXPECT_TRUE(tiling_->TileAt(1, 3));
+  EXPECT_TRUE(tiling_->TileAt(0, 3));
+
+  int right = tiling_->TilingDataForTesting().TileBounds(2, 2).x();
+  int bottom = tiling_->TilingDataForTesting().TileBounds(2, 3).y();
+
+  // Shrink the tiling so that the last tile row/column is entirely in the
+  // border pixels of the interior tiles. That row/column is removed.
+  Region invalidation;
+  tiling_->UpdateTilesToCurrentPile(invalidation,
+                                    gfx::Size(right + 1, bottom + 1));
+  EXPECT_EQ(2, tiling_->TilingDataForTesting().num_tiles_x());
+  EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y());
+
+  // The live tiles rect was clamped to the pile size.
+  EXPECT_EQ(gfx::Rect(right + 1, bottom + 1), tiling_->live_tiles_rect());
+
+  // Since the row/column is gone, the tiles should be gone too.
+  EXPECT_FALSE(tiling_->TileAt(2, 0));
+  EXPECT_FALSE(tiling_->TileAt(2, 1));
+  EXPECT_FALSE(tiling_->TileAt(2, 2));
+  EXPECT_FALSE(tiling_->TileAt(2, 3));
+  EXPECT_FALSE(tiling_->TileAt(1, 3));
+  EXPECT_FALSE(tiling_->TileAt(0, 3));
+
+  // Growing outside the current right/bottom tiles border pixels should create
+  // the tiles again, even though the live rect has not changed size.
+  tiling_->UpdateTilesToCurrentPile(invalidation,
+                                    gfx::Size(right + 2, bottom + 2));
+  EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
+  EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
+
+  // Not changed.
+  EXPECT_EQ(gfx::Rect(right + 1, bottom + 1), tiling_->live_tiles_rect());
+
+  // The last row/column tiles are inside the live tiles rect.
+  EXPECT_TRUE(gfx::Rect(right + 1, bottom + 1).Intersects(
+      tiling_->TilingDataForTesting().TileBounds(2, 0)));
+  EXPECT_TRUE(gfx::Rect(right + 1, bottom + 1).Intersects(
+      tiling_->TilingDataForTesting().TileBounds(0, 3)));
+
+  EXPECT_TRUE(tiling_->TileAt(2, 0));
+  EXPECT_TRUE(tiling_->TileAt(2, 1));
+  EXPECT_TRUE(tiling_->TileAt(2, 2));
+  EXPECT_TRUE(tiling_->TileAt(2, 3));
+  EXPECT_TRUE(tiling_->TileAt(1, 3));
+  EXPECT_TRUE(tiling_->TileAt(0, 3));
+}
+
+TEST_F(PictureLayerTilingIteratorTest, ResizeLiveTileRectOverTileBorders) {
+  // The tiling has three rows and columns.
+  Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350));
+  EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
+  EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
+
+  // The live tiles rect covers the whole tiling.
+  SetLiveRectAndVerifyTiles(gfx::Rect(250, 350));
+
+  // Tiles in the bottom row and right column exist.
+  EXPECT_TRUE(tiling_->TileAt(2, 0));
+  EXPECT_TRUE(tiling_->TileAt(2, 1));
+  EXPECT_TRUE(tiling_->TileAt(2, 2));
+  EXPECT_TRUE(tiling_->TileAt(2, 3));
+  EXPECT_TRUE(tiling_->TileAt(1, 3));
+  EXPECT_TRUE(tiling_->TileAt(0, 3));
+
+  // Shrink the live tiles rect to the very edge of the right-most and
+  // bottom-most tiles. Their border pixels would still be inside the live
+  // tiles rect, but the tiles should not exist just for that.
+  int right = tiling_->TilingDataForTesting().TileBounds(2, 3).x();
+  int bottom = tiling_->TilingDataForTesting().TileBounds(2, 3).y();
+
+  SetLiveRectAndVerifyTiles(gfx::Rect(right, bottom));
+  EXPECT_FALSE(tiling_->TileAt(2, 0));
+  EXPECT_FALSE(tiling_->TileAt(2, 1));
+  EXPECT_FALSE(tiling_->TileAt(2, 2));
+  EXPECT_FALSE(tiling_->TileAt(2, 3));
+  EXPECT_FALSE(tiling_->TileAt(1, 3));
+  EXPECT_FALSE(tiling_->TileAt(0, 3));
+
+  // Including the bottom row and right column again, should create the tiles.
+  SetLiveRectAndVerifyTiles(gfx::Rect(right + 1, bottom + 1));
+  EXPECT_TRUE(tiling_->TileAt(2, 0));
+  EXPECT_TRUE(tiling_->TileAt(2, 1));
+  EXPECT_TRUE(tiling_->TileAt(2, 2));
+  EXPECT_TRUE(tiling_->TileAt(2, 3));
+  EXPECT_TRUE(tiling_->TileAt(1, 2));
+  EXPECT_TRUE(tiling_->TileAt(0, 2));
+
+  // Shrink the live tiles rect to the very edge of the left-most and
+  // top-most tiles. Their border pixels would still be inside the live
+  // tiles rect, but the tiles should not exist just for that.
+  int left = tiling_->TilingDataForTesting().TileBounds(0, 0).right();
+  int top = tiling_->TilingDataForTesting().TileBounds(0, 0).bottom();
+
+  SetLiveRectAndVerifyTiles(gfx::Rect(left, top, 250 - left, 350 - top));
+  EXPECT_FALSE(tiling_->TileAt(0, 3));
+  EXPECT_FALSE(tiling_->TileAt(0, 2));
+  EXPECT_FALSE(tiling_->TileAt(0, 1));
+  EXPECT_FALSE(tiling_->TileAt(0, 0));
+  EXPECT_FALSE(tiling_->TileAt(1, 0));
+  EXPECT_FALSE(tiling_->TileAt(2, 0));
+
+  // Including the top row and left column again, should create the tiles.
+  SetLiveRectAndVerifyTiles(
+      gfx::Rect(left - 1, top - 1, 250 - left, 350 - top));
+  EXPECT_TRUE(tiling_->TileAt(0, 3));
+  EXPECT_TRUE(tiling_->TileAt(0, 2));
+  EXPECT_TRUE(tiling_->TileAt(0, 1));
+  EXPECT_TRUE(tiling_->TileAt(0, 0));
+  EXPECT_TRUE(tiling_->TileAt(1, 0));
+  EXPECT_TRUE(tiling_->TileAt(2, 0));
+}
+
+TEST_F(PictureLayerTilingIteratorTest, ResizeLiveTileRectOverSameTiles) {
+  // The tiling has four rows and three columns.
+  Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350));
+  EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
+  EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
+
+  // The live tiles rect covers the whole tiling.
+  SetLiveRectAndVerifyTiles(gfx::Rect(250, 350));
+
+  // All tiles exist.
+  for (int i = 0; i < 3; ++i) {
+    for (int j = 0; j < 4; ++j)
+      EXPECT_TRUE(tiling_->TileAt(i, j)) << i << "," << j;
+  }
+
+  // Shrink the live tiles rect, but still cover all the tiles.
+  SetLiveRectAndVerifyTiles(gfx::Rect(1, 1, 249, 349));
+
+  // All tiles still exist.
+  for (int i = 0; i < 3; ++i) {
+    for (int j = 0; j < 4; ++j)
+      EXPECT_TRUE(tiling_->TileAt(i, j)) << i << "," << j;
+  }
+
+  // Grow the live tiles rect, but still cover all the same tiles.
+  SetLiveRectAndVerifyTiles(gfx::Rect(0, 0, 250, 350));
+
+  // All tiles still exist.
+  for (int i = 0; i < 3; ++i) {
+    for (int j = 0; j < 4; ++j)
+      EXPECT_TRUE(tiling_->TileAt(i, j)) << i << "," << j;
+  }
+}
+
 TEST_F(PictureLayerTilingIteratorTest, ResizeOverBorderPixelsDeletesTiles) {
   // Verifies that a resize with invalidation for newly exposed pixels will
   // deletes tiles that intersect that invalidation.
@@ -513,11 +705,12 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
       Tile* tile = tiling->TileAt(i, j);
       TilePriority priority = tile->priority(ACTIVE_TREE);
 
-      if (viewport_in_content_space.Intersects(tile->content_rect())) {
+      gfx::Rect tile_rect = tiling->TilingDataForTesting().TileBounds(i, j);
+      if (viewport_in_content_space.Intersects(tile_rect)) {
         EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
         EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
         have_now = true;
-      } else if (soon_rect_in_content_space.Intersects(tile->content_rect())) {
+      } else if (soon_rect_in_content_space.Intersects(tile_rect)) {
         EXPECT_EQ(TilePriority::SOON, priority.priority_bin);
         have_soon = true;
       } else {
@@ -581,14 +774,15 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
       Tile* tile = tiling->TileAt(i, j);
       TilePriority priority = tile->priority(ACTIVE_TREE);
 
-      if (viewport_in_content_space.Intersects(tile->content_rect())) {
+      gfx::Rect tile_rect = tiling->TilingDataForTesting().TileBounds(i, j);
+      if (viewport_in_content_space.Intersects(tile_rect)) {
         EXPECT_EQ(TilePriority::NOW, priority.priority_bin) << "i: " << i
                                                             << " j: " << j;
         EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible) << "i: " << i
                                                            << " j: " << j;
         have_now = true;
-      } else if (skewport.Intersects(tile->content_rect()) ||
-                 soon_rect_in_content_space.Intersects(tile->content_rect())) {
+      } else if (skewport.Intersects(tile_rect) ||
+                 soon_rect_in_content_space.Intersects(tile_rect)) {
         EXPECT_EQ(TilePriority::SOON, priority.priority_bin) << "i: " << i
                                                              << " j: " << j;
         EXPECT_GT(priority.distance_to_visible, 0.f) << "i: " << i
@@ -615,20 +809,46 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
   EXPECT_FLOAT_EQ(28.f, priority.distance_to_visible);
 
   priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
-  EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+  EXPECT_FLOAT_EQ(4.f, priority.distance_to_visible);
 
   // Change the underlying layer scale.
   tiling->UpdateTilePriorities(
       ACTIVE_TREE, viewport, 2.0f, 3.0, NULL, NULL, gfx::Transform());
 
   priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
-  EXPECT_FLOAT_EQ(34.f, priority.distance_to_visible);
+  EXPECT_FLOAT_EQ(136.f, priority.distance_to_visible);
 
   priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
-  EXPECT_FLOAT_EQ(14.f, priority.distance_to_visible);
+  EXPECT_FLOAT_EQ(56.f, priority.distance_to_visible);
 
   priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
-  EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+  EXPECT_FLOAT_EQ(8.f, priority.distance_to_visible);
+
+  // Test additional scales.
+  tiling = TestablePictureLayerTiling::Create(0.2f, layer_bounds, &client);
+  tiling->UpdateTilePriorities(
+      ACTIVE_TREE, viewport, 1.0f, 4.0, NULL, NULL, gfx::Transform());
+
+  priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+  EXPECT_FLOAT_EQ(110.f, priority.distance_to_visible);
+
+  priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+  EXPECT_FLOAT_EQ(70.f, priority.distance_to_visible);
+
+  priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+  EXPECT_FLOAT_EQ(60.f, priority.distance_to_visible);
+
+  tiling->UpdateTilePriorities(
+      ACTIVE_TREE, viewport, 0.5f, 5.0, NULL, NULL, gfx::Transform());
+
+  priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+  EXPECT_FLOAT_EQ(55.f, priority.distance_to_visible);
+
+  priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+  EXPECT_FLOAT_EQ(35.f, priority.distance_to_visible);
+
+  priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+  EXPECT_FLOAT_EQ(30.f, priority.distance_to_visible);
 }
 
 TEST(PictureLayerTilingTest, ExpandRectEqual) {
@@ -1922,5 +2142,88 @@ TEST(PictureLayerTilingTest, ResetClearsPriorities) {
   tiles.clear();
 }
 
+TEST(PictureLayerTilingTest, RecycledTilesCleared) {
+  // This test performs the following:
+  // Setup:
+  // - Two tilings, one active one recycled with all tiles shared.
+  // Procedure:
+  // - Viewport moves somewhere far away and active tiling clears tiles.
+  // - Viewport moves back and a new active tiling tile is created.
+  // Result:
+  // - Recycle tiling does _not_ have the tile in the same location (thus it
+  //   will be shared next time a pending tiling is created).
+
+  FakePictureLayerTilingClient client;
+  scoped_ptr<TestablePictureLayerTiling> tiling;
+
+  client.SetTileSize(gfx::Size(100, 100));
+  client.set_tree(ACTIVE_TREE);
+  client.set_max_tiles_for_interest_area(10);
+  tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
+                                              gfx::Size(10000, 10000),
+                                              &client);
+  // Create all tiles on this tiling.
+  tiling->UpdateTilePriorities(ACTIVE_TREE,
+                               gfx::Rect(0, 0, 100, 100),
+                               1.0f,
+                               1.0f,
+                               NULL,               // occlusion tracker
+                               NULL,               // render target
+                               gfx::Transform());  // draw transform
+
+  FakePictureLayerTilingClient second_client;
+  second_client.SetTileSize(gfx::Size(100, 100));
+  second_client.set_tree(PENDING_TREE);
+  second_client.set_twin_tiling(tiling.get());
+  second_client.set_max_tiles_for_interest_area(10);
+
+  scoped_ptr<TestablePictureLayerTiling> second_tiling;
+  second_tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
+                                                     gfx::Size(10000, 10000),
+                                                     &second_client);
+
+  // Create all tiles on the second tiling. All tiles should be shared.
+  second_tiling->UpdateTilePriorities(ACTIVE_TREE,
+                                      gfx::Rect(0, 0, 100, 100),
+                                      1.0f,
+                                      1.0f,
+                                      NULL,               // occlusion tracker
+                                      NULL,               // render target
+                                      gfx::Transform());  // draw transform
+
+  // Verify that tiles exist and are shared.
+  ASSERT_TRUE(tiling->TileAt(0, 0));
+  ASSERT_EQ(tiling->TileAt(0, 0), second_tiling->TileAt(0, 0));
+
+  // Set the second tiling as recycled.
+  client.set_twin_tiling(NULL);
+  client.set_recycled_twin_tiling(second_tiling.get());
+  second_client.set_twin_tiling(NULL);
+
+  // Move the viewport far away from the (0, 0) tile.
+  tiling->UpdateTilePriorities(ACTIVE_TREE,
+                               gfx::Rect(9000, 9000, 100, 100),
+                               1.0f,
+                               2.0,
+                               NULL,               // occlusion tracker
+                               NULL,               // render target
+                               gfx::Transform());  // draw transform
+  // Ensure the tile was deleted.
+  EXPECT_FALSE(tiling->TileAt(0, 0));
+
+  // Move the viewport back to (0, 0) tile.
+  tiling->UpdateTilePriorities(ACTIVE_TREE,
+                               gfx::Rect(0, 0, 100, 100),
+                               1.0f,
+                               3.0,
+                               NULL,               // occlusion tracker
+                               NULL,               // render target
+                               gfx::Transform());  // draw transform
+
+  // Ensure that we now have a tile here, but the recycle tiling does not.
+  EXPECT_TRUE(tiling->TileAt(0, 0));
+  EXPECT_FALSE(second_tiling->TileAt(0, 0));
+}
+
 }  // namespace
 }  // namespace cc
index 3037521..46f589e 100644 (file)
@@ -226,34 +226,151 @@ bool PicturePile::UpdateAndExpandInvalidation(
     gfx::Rect old_tiling_rect_over_tiles =
         tiling_.ExpandRectToTileBounds(gfx::Rect(old_tiling_size));
     if (min_toss_x < tiling_.num_tiles_x()) {
-      int unrecorded_left = std::max(tiling_.TilePositionX(min_toss_x),
-                                     interest_rect_over_tiles.right());
+      // The bounds which we want to invalidate are the tiles along the old
+      // edge of the pile. We'll call this bounding box the OLD EDGE RECT.
+      //
+      // In the picture below, the old edge rect would be the bounding box
+      // of tiles {h,i,j}. |min_toss_x| would be equal to the horizontal index
+      // of the same tiles.
+      //
+      //  old pile edge-v  new pile edge-v
+      // ---------------+ - - - - - - - -+
+      // mmppssvvyybbeeh|h               .
+      // mmppssvvyybbeeh|h               .
+      // nnqqttwwzzccffi|i               .
+      // nnqqttwwzzccffi|i               .
+      // oorruuxxaaddggj|j               .
+      // oorruuxxaaddggj|j               .
+      // ---------------+ - - - - - - - -+ <- old pile edge
+      //                                 .
+      //  - - - - - - - - - - - - - - - -+ <- new pile edge
+      //
+      // If you were to slide a vertical beam from the left edge of the
+      // old edge rect toward the right, it would either hit the right edge
+      // of the old edge rect, or the interest rect (expanded to the bounds
+      // of the tiles it touches). The same is true for a beam parallel to
+      // any of the four edges, sliding accross the old edge rect. We use
+      // the union of these four rectangles generated by these beams to
+      // determine which part of the old edge rect is outside of the expanded
+      // interest rect.
+      //
+      // Case 1: Intersect rect is outside the old edge rect. It can be
+      // either on the left or the right. The |left_rect| and |right_rect|,
+      // cover this case, one will be empty and one will cover the full
+      // old edge rect. In the picture below, |left_rect| would cover the
+      // old edge rect, and |right_rect| would be empty.
+      // +----------------------+ |^^^^^^^^^^^^^^^|
+      // |===>   OLD EDGE RECT  | |               |
+      // |===>                  | | INTEREST RECT |
+      // |===>                  | |               |
+      // |===>                  | |               |
+      // +----------------------+ |vvvvvvvvvvvvvvv|
+      //
+      // Case 2: Interest rect is inside the old edge rect. It will always
+      // fill the entire old edge rect horizontally since the old edge rect
+      // is a single tile wide, and the interest rect has been expanded to the
+      // bounds of the tiles it touches. In this case the |left_rect| and
+      // |right_rect| will be empty, but the case is handled by the |top_rect|
+      // and |bottom_rect|. In the picture below, neither the |top_rect| nor
+      // |bottom_rect| would empty, they would each cover the area of the old
+      // edge rect outside the expanded interest rect.
+      // +-----------------+
+      // |:::::::::::::::::|
+      // |:::::::::::::::::|
+      // |vvvvvvvvvvvvvvvvv|
+      // |                 |
+      // +-----------------+
+      // | INTEREST RECT   |
+      // |                 |
+      // +-----------------+
+      // |                 |
+      // | OLD EDGE RECT   |
+      // +-----------------+
+      //
+      // Lastly, we need to consider tiles inside the expanded interest rect.
+      // For those tiles, we want to invalidate exactly the newly exposed
+      // pixels. In the picture below the tiles in the old edge rect have been
+      // resized and the area covered by periods must be invalidated. The
+      // |exposed_rect| will cover exactly that area.
+      //           v-old pile edge
+      // +---------+-------+
+      // |         ........|
+      // |         ........|
+      // |  OLD EDGE.RECT..|
+      // |         ........|
+      // |         ........|
+      // |         ........|
+      // |         ........|
+      // |         ........|
+      // |         ........|
+      // +---------+-------+
+
+      int left = tiling_.TilePositionX(min_toss_x);
+      int right = left + tiling_.TileSizeX(min_toss_x);
+      int top = old_tiling_rect_over_tiles.y();
+      int bottom = old_tiling_rect_over_tiles.bottom();
+
+      int left_until = std::min(interest_rect_over_tiles.x(), right);
+      int right_until = std::max(interest_rect_over_tiles.right(), left);
+      int top_until = std::min(interest_rect_over_tiles.y(), bottom);
+      int bottom_until = std::max(interest_rect_over_tiles.bottom(), top);
+
       int exposed_left = old_tiling_size.width();
-      int left = std::min(unrecorded_left, exposed_left);
-      int tile_right =
-          tiling_.TilePositionX(min_toss_x) + tiling_.TileSizeX(min_toss_x);
-      int exposed_right = tiling_size().width();
-      int right = std::min(tile_right, exposed_right);
-      gfx::Rect right_side(left,
-                           old_tiling_rect_over_tiles.y(),
-                           right - left,
-                           old_tiling_rect_over_tiles.height());
-      resize_invalidation.Union(right_side);
+      int exposed_left_until = tiling_size().width();
+      int exposed_top = top;
+      int exposed_bottom = tiling_size().height();
+      DCHECK_GE(exposed_left, left);
+
+      gfx::Rect left_rect(left, top, left_until - left, bottom - top);
+      gfx::Rect right_rect(right_until, top, right - right_until, bottom - top);
+      gfx::Rect top_rect(left, top, right - left, top_until - top);
+      gfx::Rect bottom_rect(
+          left, bottom_until, right - left, bottom - bottom_until);
+      gfx::Rect exposed_rect(exposed_left,
+                             exposed_top,
+                             exposed_left_until - exposed_left,
+                             exposed_bottom - exposed_top);
+      resize_invalidation.Union(left_rect);
+      resize_invalidation.Union(right_rect);
+      resize_invalidation.Union(top_rect);
+      resize_invalidation.Union(bottom_rect);
+      resize_invalidation.Union(exposed_rect);
     }
     if (min_toss_y < tiling_.num_tiles_y()) {
-      int unrecorded_top = std::max(tiling_.TilePositionY(min_toss_y),
-                                    interest_rect_over_tiles.bottom());
+      // The same thing occurs here as in the case above, but the invalidation
+      // rect is the bounding box around the bottom row of tiles in the old
+      // pile. This would be tiles {o,r,u,x,a,d,g,j} in the above picture.
+
+      int top = tiling_.TilePositionY(min_toss_y);
+      int bottom = top + tiling_.TileSizeY(min_toss_y);
+      int left = old_tiling_rect_over_tiles.x();
+      int right = old_tiling_rect_over_tiles.right();
+
+      int top_until = std::min(interest_rect_over_tiles.y(), bottom);
+      int bottom_until = std::max(interest_rect_over_tiles.bottom(), top);
+      int left_until = std::min(interest_rect_over_tiles.x(), right);
+      int right_until = std::max(interest_rect_over_tiles.right(), left);
+
       int exposed_top = old_tiling_size.height();
-      int top = std::min(unrecorded_top, exposed_top);
-      int tile_bottom =
-          tiling_.TilePositionY(min_toss_y) + tiling_.TileSizeY(min_toss_y);
-      int exposed_bottom = tiling_size().height();
-      int bottom = std::min(tile_bottom, exposed_bottom);
-      gfx::Rect bottom_side(old_tiling_rect_over_tiles.x(),
-                            top,
-                            old_tiling_rect_over_tiles.width(),
-                            bottom - top);
-      resize_invalidation.Union(bottom_side);
+      int exposed_top_until = tiling_size().height();
+      int exposed_left = left;
+      int exposed_right = tiling_size().width();
+      DCHECK_GE(exposed_top, top);
+
+      gfx::Rect left_rect(left, top, left_until - left, bottom - top);
+      gfx::Rect right_rect(right_until, top, right - right_until, bottom - top);
+      gfx::Rect top_rect(left, top, right - left, top_until - top);
+      gfx::Rect bottom_rect(
+          left, bottom_until, right - left, bottom - bottom_until);
+      gfx::Rect exposed_rect(exposed_left,
+                             exposed_top,
+                             exposed_right - exposed_left,
+                             exposed_top_until - exposed_top);
+      resize_invalidation.Union(left_rect);
+      resize_invalidation.Union(right_rect);
+      resize_invalidation.Union(top_rect);
+      resize_invalidation.Union(bottom_rect);
+      resize_invalidation.Union(exposed_rect);
     }
   }
 
index 146c886..c7a9680 100644 (file)
@@ -47,7 +47,8 @@ PicturePileBase::PicturePileBase()
       contents_fill_bounds_completely_(false),
       show_debug_picture_borders_(false),
       clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
-      has_any_recordings_(false) {
+      has_any_recordings_(false),
+      is_mask_(false) {
   tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
   tile_grid_info_.fTileInterval.setEmpty();
   tile_grid_info_.fMargin.setEmpty();
@@ -67,7 +68,9 @@ PicturePileBase::PicturePileBase(const PicturePileBase* other)
       contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
       show_debug_picture_borders_(other->show_debug_picture_borders_),
       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
-      has_any_recordings_(other->has_any_recordings_) {}
+      has_any_recordings_(other->has_any_recordings_),
+      is_mask_(other->is_mask_) {
+}
 
 PicturePileBase::PicturePileBase(const PicturePileBase* other,
                                  unsigned thread_index)
@@ -82,7 +85,8 @@ PicturePileBase::PicturePileBase(const PicturePileBase* other,
       contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
       show_debug_picture_borders_(other->show_debug_picture_borders_),
       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
-      has_any_recordings_(other->has_any_recordings_) {
+      has_any_recordings_(other->has_any_recordings_),
+      is_mask_(other->is_mask_) {
   for (PictureMap::const_iterator it = other->picture_map_.begin();
        it != other->picture_map_.end();
        ++it) {
index b188df7..102d798 100644 (file)
@@ -49,6 +49,9 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> {
   // If this pile contains any valid recordings. May have false positives.
   bool HasRecordings() const { return has_any_recordings_; }
 
+  void set_is_mask(bool is_mask) { is_mask_ = is_mask; }
+  bool is_mask() const { return is_mask_; }
+
   static void ComputeTileGridInfo(const gfx::Size& tile_grid_size,
                                   SkTileGridFactory::TileGridInfo* info);
 
@@ -117,6 +120,7 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> {
   // A hint about whether there are any recordings. This may be a false
   // positive.
   bool has_any_recordings_;
+  bool is_mask_;
 
  private:
   void SetBufferPixels(int buffer_pixels);
index 31e0a2a..ee78c9c 100644 (file)
@@ -36,9 +36,9 @@ class TestPicturePile : public PicturePile {
     virtual ~TestPicturePile() {}
 };
 
-class PicturePileTest : public testing::Test {
+class PicturePileTestBase {
  public:
-  PicturePileTest()
+  PicturePileTestBase()
       : pile_(new TestPicturePile()),
         background_color_(SK_ColorBLUE),
         min_scale_(0.125),
@@ -91,6 +91,8 @@ class PicturePileTest : public testing::Test {
   bool contents_opaque_;
 };
 
+class PicturePileTest : public PicturePileTestBase, public testing::Test {};
+
 TEST_F(PicturePileTest, SmallInvalidateInflated) {
   // Invalidate something inside a tile.
   Region invalidate_rect(gfx::Rect(50, 50, 1, 1));
@@ -384,14 +386,48 @@ TEST_F(PicturePileTest, InvalidationOutsideRecordingRect) {
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
 }
 
-TEST_F(PicturePileTest, ResizePileOutsideInterestRect) {
+enum Corner {
+  TOP_LEFT,
+  TOP_RIGHT,
+  BOTTOM_LEFT,
+  BOTTOM_RIGHT,
+};
+
+class PicturePileResizeCornerTest : public PicturePileTestBase,
+                                    public testing::TestWithParam<Corner> {
+ protected:
+  static gfx::Rect CornerSinglePixelRect(Corner corner, const gfx::Size& s) {
+    switch (corner) {
+      case TOP_LEFT:
+        return gfx::Rect(0, 0, 1, 1);
+      case TOP_RIGHT:
+        return gfx::Rect(s.width() - 1, 0, 1, 1);
+      case BOTTOM_LEFT:
+        return gfx::Rect(0, s.height() - 1, 1, 1);
+      case BOTTOM_RIGHT:
+        return gfx::Rect(s.width() - 1, s.height() - 1, 1, 1);
+    }
+    NOTREACHED();
+    return gfx::Rect();
+  }
+};
+
+TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
+  Corner corner = GetParam();
+
   // This size chosen to be larger than the interest rect size, which is
   // at least kPixelDistanceToRecord * 2 in each dimension.
   int tile_size = 100000;
-  gfx::Size base_tiling_size(5 * tile_size, 5 * tile_size);
-  gfx::Size grow_down_tiling_size(5 * tile_size, 7 * tile_size);
-  gfx::Size grow_right_tiling_size(7 * tile_size, 5 * tile_size);
-  gfx::Size grow_both_tiling_size(7 * tile_size, 7 * tile_size);
+  // The small number subtracted keeps the last tile in each axis larger than
+  // the interest rect also.
+  int offset = -100;
+  gfx::Size base_tiling_size(6 * tile_size + offset, 6 * tile_size + offset);
+  gfx::Size grow_down_tiling_size(6 * tile_size + offset,
+                                  8 * tile_size + offset);
+  gfx::Size grow_right_tiling_size(8 * tile_size + offset,
+                                   6 * tile_size + offset);
+  gfx::Size grow_both_tiling_size(8 * tile_size + offset,
+                                  8 * tile_size + offset);
 
   Region invalidation;
   Region expected_invalidation;
@@ -412,13 +448,15 @@ TEST_F(PicturePileTest, ResizePileOutsideInterestRect) {
   }
 
   UpdateAndExpandInvalidation(
-      &invalidation, grow_down_tiling_size, gfx::Rect(1, 1));
+      &invalidation,
+      grow_down_tiling_size,
+      CornerSinglePixelRect(corner, grow_down_tiling_size));
 
   // We should have lost the recordings in the bottom row.
   EXPECT_EQ(6, pile_->tiling().num_tiles_x());
   EXPECT_EQ(8, pile_->tiling().num_tiles_y());
-  for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) {
-    for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) {
+  for (int i = 0; i < 6; ++i) {
+    for (int j = 0; j < 6; ++j) {
       TestPicturePile::PictureMapKey key(i, j);
       TestPicturePile::PictureMap& map = pile_->picture_map();
       TestPicturePile::PictureMap::iterator it = map.find(key);
@@ -426,14 +464,22 @@ TEST_F(PicturePileTest, ResizePileOutsideInterestRect) {
     }
   }
 
-  // We invalidated the old bottom row.
-  expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
-                                          pile_->tiling().TileBounds(5, 5));
+  // We invalidated all new pixels in the recording.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  // But the new pixels don't cover the whole bottom row.
+  gfx::Rect bottom_row = gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
+                                         pile_->tiling().TileBounds(5, 5));
+  EXPECT_FALSE(expected_invalidation.Contains(bottom_row));
+  // We invalidated the entire old bottom row.
+  expected_invalidation.Union(bottom_row);
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
   UpdateWholePile();
-  UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1));
+  UpdateAndExpandInvalidation(&invalidation,
+                              base_tiling_size,
+                              CornerSinglePixelRect(corner, base_tiling_size));
 
   // We should have lost the recordings that are now outside the tiling only.
   EXPECT_EQ(6, pile_->tiling().num_tiles_x());
@@ -454,13 +500,15 @@ TEST_F(PicturePileTest, ResizePileOutsideInterestRect) {
 
   UpdateWholePile();
   UpdateAndExpandInvalidation(
-      &invalidation, grow_right_tiling_size, gfx::Rect(1, 1));
+      &invalidation,
+      grow_right_tiling_size,
+      CornerSinglePixelRect(corner, grow_right_tiling_size));
 
   // We should have lost the recordings in the right column.
   EXPECT_EQ(8, pile_->tiling().num_tiles_x());
   EXPECT_EQ(6, pile_->tiling().num_tiles_y());
-  for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) {
-    for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) {
+  for (int i = 0; i < 6; ++i) {
+    for (int j = 0; j < 6; ++j) {
       TestPicturePile::PictureMapKey key(i, j);
       TestPicturePile::PictureMap& map = pile_->picture_map();
       TestPicturePile::PictureMap::iterator it = map.find(key);
@@ -468,14 +516,22 @@ TEST_F(PicturePileTest, ResizePileOutsideInterestRect) {
     }
   }
 
-  // We invalidated the old right column.
-  expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
-                                          pile_->tiling().TileBounds(5, 5));
+  // We invalidated all new pixels in the recording.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  // But the new pixels don't cover the whole right_column.
+  gfx::Rect right_column = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+                                           pile_->tiling().TileBounds(5, 5));
+  EXPECT_FALSE(expected_invalidation.Contains(right_column));
+  // We invalidated the entire old right column.
+  expected_invalidation.Union(right_column);
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
   UpdateWholePile();
-  UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1));
+  UpdateAndExpandInvalidation(&invalidation,
+                              base_tiling_size,
+                              CornerSinglePixelRect(corner, base_tiling_size));
 
   // We should have lost the recordings that are now outside the tiling only.
   EXPECT_EQ(6, pile_->tiling().num_tiles_x());
@@ -496,13 +552,15 @@ TEST_F(PicturePileTest, ResizePileOutsideInterestRect) {
 
   UpdateWholePile();
   UpdateAndExpandInvalidation(
-      &invalidation, grow_both_tiling_size, gfx::Rect(1, 1));
+      &invalidation,
+      grow_both_tiling_size,
+      CornerSinglePixelRect(corner, grow_both_tiling_size));
 
   // We should have lost the recordings in the right column and bottom row.
   EXPECT_EQ(8, pile_->tiling().num_tiles_x());
   EXPECT_EQ(8, pile_->tiling().num_tiles_y());
-  for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) {
-    for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) {
+  for (int i = 0; i < 6; ++i) {
+    for (int j = 0; j < 6; ++j) {
       TestPicturePile::PictureMapKey key(i, j);
       TestPicturePile::PictureMap& map = pile_->picture_map();
       TestPicturePile::PictureMap::iterator it = map.find(key);
@@ -510,11 +568,18 @@ TEST_F(PicturePileTest, ResizePileOutsideInterestRect) {
     }
   }
 
-  // We invalidated the old right column and the old bottom row.
-  expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
-                                          pile_->tiling().TileBounds(5, 5));
-  expected_invalidation.Union(gfx::UnionRects(
-      pile_->tiling().TileBounds(0, 5), pile_->tiling().TileBounds(5, 5)));
+  // We invalidated all new pixels in the recording.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  // But the new pixels don't cover the whole right_column.
+  Region right_column_and_bottom_row =
+      UnionRegions(gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+                                   pile_->tiling().TileBounds(5, 5)),
+                   gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
+                                   pile_->tiling().TileBounds(5, 5)));
+  EXPECT_FALSE(expected_invalidation.Contains(right_column_and_bottom_row));
+  // We invalidated the entire old right column and the old bottom row.
+  expected_invalidation.Union(right_column_and_bottom_row);
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
@@ -539,14 +604,22 @@ TEST_F(PicturePileTest, ResizePileOutsideInterestRect) {
   invalidation.Clear();
 }
 
-TEST_F(PicturePileTest, SmallResizePileOutsideInterestRect) {
+TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) {
+  Corner corner = GetParam();
+
   // This size chosen to be larger than the interest rect size, which is
   // at least kPixelDistanceToRecord * 2 in each dimension.
   int tile_size = 100000;
-  gfx::Size base_tiling_size(5 * tile_size, 5 * tile_size);
-  gfx::Size grow_down_tiling_size(5 * tile_size, 5 * tile_size + 5);
-  gfx::Size grow_right_tiling_size(5 * tile_size + 5, 5 * tile_size);
-  gfx::Size grow_both_tiling_size(5 * tile_size + 5, 5 * tile_size + 5);
+  // The small number subtracted keeps the last tile in each axis larger than
+  // the interest rect also.
+  int offset = -100;
+  gfx::Size base_tiling_size(6 * tile_size + offset, 6 * tile_size + offset);
+  gfx::Size grow_down_tiling_size(6 * tile_size + offset,
+                                  6 * tile_size + offset + 5);
+  gfx::Size grow_right_tiling_size(6 * tile_size + offset + 5,
+                                   6 * tile_size + offset);
+  gfx::Size grow_both_tiling_size(6 * tile_size + offset + 5,
+                                  6 * tile_size + offset + 5);
 
   Region invalidation;
   Region expected_invalidation;
@@ -567,9 +640,12 @@ TEST_F(PicturePileTest, SmallResizePileOutsideInterestRect) {
   }
 
   UpdateAndExpandInvalidation(
-      &invalidation, grow_down_tiling_size, gfx::Rect(1, 1));
+      &invalidation,
+      grow_down_tiling_size,
+      CornerSinglePixelRect(corner, grow_down_tiling_size));
 
-  // We should have lost the recordings in the bottom row.
+  // We should have lost the recordings in the bottom row that do not intersect
+  // the interest rect.
   EXPECT_EQ(6, pile_->tiling().num_tiles_x());
   EXPECT_EQ(6, pile_->tiling().num_tiles_y());
   for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) {
@@ -577,18 +653,53 @@ TEST_F(PicturePileTest, SmallResizePileOutsideInterestRect) {
       TestPicturePile::PictureMapKey key(i, j);
       TestPicturePile::PictureMap& map = pile_->picture_map();
       TestPicturePile::PictureMap::iterator it = map.find(key);
-      EXPECT_EQ(j < 5, it != map.end() && it->second.GetPicture());
+      bool expect_tile;
+      switch (corner) {
+        case TOP_LEFT:
+        case TOP_RIGHT:
+          expect_tile = j < 5;
+          break;
+        case BOTTOM_LEFT:
+          // The interest rect in the bottom left tile means we'll record it.
+          expect_tile = j < 5 || (j == 5 && i == 0);
+          break;
+        case BOTTOM_RIGHT:
+          // The interest rect in the bottom right tile means we'll record it.
+          expect_tile = j < 5 || (j == 5 && i == 5);
+          break;
+      }
+      EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
     }
   }
 
-  // We invalidated the bottom row.
-  expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
-                                          pile_->tiling().TileBounds(5, 5));
+  // We invalidated the bottom row outside the new interest rect. The tile that
+  // insects the interest rect in invalidated only on its new pixels.
+  switch (corner) {
+    case TOP_LEFT:
+    case TOP_RIGHT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
+                                              pile_->tiling().TileBounds(5, 5));
+      break;
+    case BOTTOM_LEFT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(1, 5),
+                                              pile_->tiling().TileBounds(5, 5));
+      expected_invalidation.Union(SubtractRects(
+          pile_->tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size)));
+      break;
+    case BOTTOM_RIGHT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
+                                              pile_->tiling().TileBounds(4, 5));
+      expected_invalidation.Union(SubtractRects(
+          pile_->tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
+      break;
+  }
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
   UpdateWholePile();
-  UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1));
+  UpdateAndExpandInvalidation(&invalidation,
+                              base_tiling_size,
+                              CornerSinglePixelRect(corner, base_tiling_size));
 
   // We should have lost nothing.
   EXPECT_EQ(6, pile_->tiling().num_tiles_x());
@@ -609,7 +720,9 @@ TEST_F(PicturePileTest, SmallResizePileOutsideInterestRect) {
 
   UpdateWholePile();
   UpdateAndExpandInvalidation(
-      &invalidation, grow_right_tiling_size, gfx::Rect(1, 1));
+      &invalidation,
+      grow_right_tiling_size,
+      CornerSinglePixelRect(corner, grow_right_tiling_size));
 
   // We should have lost the recordings in the right column.
   EXPECT_EQ(6, pile_->tiling().num_tiles_x());
@@ -619,18 +732,53 @@ TEST_F(PicturePileTest, SmallResizePileOutsideInterestRect) {
       TestPicturePile::PictureMapKey key(i, j);
       TestPicturePile::PictureMap& map = pile_->picture_map();
       TestPicturePile::PictureMap::iterator it = map.find(key);
-      EXPECT_EQ(i < 5, it != map.end() && it->second.GetPicture());
+      bool expect_tile;
+      switch (corner) {
+        case TOP_LEFT:
+        case BOTTOM_LEFT:
+          expect_tile = i < 5;
+          break;
+        case TOP_RIGHT:
+          // The interest rect in the top right tile means we'll record it.
+          expect_tile = i < 5 || (j == 0 && i == 5);
+          break;
+        case BOTTOM_RIGHT:
+          // The interest rect in the bottom right tile means we'll record it.
+          expect_tile = i < 5 || (j == 5 && i == 5);
+          break;
+      }
+      EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
     }
   }
 
-  // We invalidated the right column.
-  expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
-                                          pile_->tiling().TileBounds(5, 5));
+  // We invalidated the right column outside the new interest rect. The tile
+  // that insects the interest rect in invalidated only on its new pixels.
+  switch (corner) {
+    case TOP_LEFT:
+    case BOTTOM_LEFT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+                                              pile_->tiling().TileBounds(5, 5));
+      break;
+    case TOP_RIGHT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 1),
+                                              pile_->tiling().TileBounds(5, 5));
+      expected_invalidation.Union(SubtractRects(
+          pile_->tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size)));
+      break;
+    case BOTTOM_RIGHT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+                                              pile_->tiling().TileBounds(5, 4));
+      expected_invalidation.Union(SubtractRects(
+          pile_->tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
+      break;
+  }
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
   UpdateWholePile();
-  UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1));
+  UpdateAndExpandInvalidation(&invalidation,
+                              base_tiling_size,
+                              CornerSinglePixelRect(corner, base_tiling_size));
 
   // We should have lost nothing.
   EXPECT_EQ(6, pile_->tiling().num_tiles_x());
@@ -651,9 +799,12 @@ TEST_F(PicturePileTest, SmallResizePileOutsideInterestRect) {
 
   UpdateWholePile();
   UpdateAndExpandInvalidation(
-      &invalidation, grow_both_tiling_size, gfx::Rect(1, 1));
+      &invalidation,
+      grow_both_tiling_size,
+      CornerSinglePixelRect(corner, grow_both_tiling_size));
 
-  // We should have lost the recordings in the right column and bottom row.
+  // We should have lost the recordings in the right column and bottom row. The
+  // tile that insects the interest rect in invalidated only on its new pixels.
   EXPECT_EQ(6, pile_->tiling().num_tiles_x());
   EXPECT_EQ(6, pile_->tiling().num_tiles_y());
   for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) {
@@ -661,20 +812,71 @@ TEST_F(PicturePileTest, SmallResizePileOutsideInterestRect) {
       TestPicturePile::PictureMapKey key(i, j);
       TestPicturePile::PictureMap& map = pile_->picture_map();
       TestPicturePile::PictureMap::iterator it = map.find(key);
-      EXPECT_EQ(i < 5 && j < 5, it != map.end() && it->second.GetPicture());
+      bool expect_tile;
+      switch (corner) {
+        case TOP_LEFT:
+          expect_tile = i < 5 && j < 5;
+          break;
+        case TOP_RIGHT:
+          // The interest rect in the top right tile means we'll record it.
+          expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5);
+          break;
+        case BOTTOM_LEFT:
+          // The interest rect in the bottom left tile means we'll record it.
+          expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0);
+          break;
+        case BOTTOM_RIGHT:
+          // The interest rect in the bottom right tile means we'll record it.
+          expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5);
+          break;
+      }
+      EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture())
+          << i << "," << j;
     }
   }
 
-  // We invalidated the right column and the bottom row.
-  expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
-                                          pile_->tiling().TileBounds(5, 5));
-  expected_invalidation.Union(gfx::UnionRects(
-      pile_->tiling().TileBounds(0, 5), pile_->tiling().TileBounds(5, 5)));
+  // We invalidated the right column and the bottom row outside the new interest
+  // rect. The tile that insects the interest rect in invalidated only on its
+  // new pixels.
+  switch (corner) {
+    case TOP_LEFT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+                                              pile_->tiling().TileBounds(5, 5));
+      expected_invalidation.Union(gfx::UnionRects(
+          pile_->tiling().TileBounds(0, 5), pile_->tiling().TileBounds(5, 5)));
+      break;
+    case TOP_RIGHT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 1),
+                                              pile_->tiling().TileBounds(5, 5));
+      expected_invalidation.Union(gfx::UnionRects(
+          pile_->tiling().TileBounds(0, 5), pile_->tiling().TileBounds(5, 5)));
+      expected_invalidation.Union(SubtractRects(
+          pile_->tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size)));
+      break;
+    case BOTTOM_LEFT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+                                              pile_->tiling().TileBounds(5, 5));
+      expected_invalidation.Union(gfx::UnionRects(
+          pile_->tiling().TileBounds(1, 5), pile_->tiling().TileBounds(5, 5)));
+      expected_invalidation.Union(SubtractRects(
+          pile_->tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size)));
+      break;
+    case BOTTOM_RIGHT:
+      expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+                                              pile_->tiling().TileBounds(5, 4));
+      expected_invalidation.Union(gfx::UnionRects(
+          pile_->tiling().TileBounds(0, 5), pile_->tiling().TileBounds(4, 5)));
+      expected_invalidation.Union(SubtractRegions(
+          pile_->tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
+      break;
+  }
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
   UpdateWholePile();
-  UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1));
+  UpdateAndExpandInvalidation(&invalidation,
+                              base_tiling_size,
+                              CornerSinglePixelRect(corner, base_tiling_size));
 
   // We should have lost nothing.
   EXPECT_EQ(6, pile_->tiling().num_tiles_x());
@@ -694,6 +896,11 @@ TEST_F(PicturePileTest, SmallResizePileOutsideInterestRect) {
   invalidation.Clear();
 }
 
+INSTANTIATE_TEST_CASE_P(
+    PicturePileResizeCornerTests,
+    PicturePileResizeCornerTest,
+    ::testing::Values(TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT));
+
 TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
   // This size chosen to be small enough that all the rects below fit inside the
   // the interest rect, so they are smaller than kPixelDistanceToRecord in each
@@ -738,9 +945,13 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
   }
 
   // We invalidated the newly exposed pixels on the bottom row of tiles.
-  expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
-                                          pile_->tiling().TileBounds(5, 5));
-  expected_invalidation.Subtract(gfx::Rect(base_tiling_size));
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  Region bottom_row_new_pixels =
+      SubtractRegions(gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
+                                      pile_->tiling().TileBounds(5, 5)),
+                      gfx::Rect(base_tiling_size));
+  EXPECT_TRUE(expected_invalidation.Contains(bottom_row_new_pixels));
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
@@ -780,9 +991,13 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
   }
 
   // We invalidated the newly exposed pixels on the right column of tiles.
-  expected_invalidation = gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
-                                          pile_->tiling().TileBounds(5, 5));
-  expected_invalidation.Subtract(gfx::Rect(base_tiling_size));
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  Region right_column_new_pixels =
+      SubtractRegions(gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+                                      pile_->tiling().TileBounds(5, 5)),
+                      gfx::Rect(base_tiling_size));
+  EXPECT_TRUE(expected_invalidation.Contains(right_column_new_pixels));
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
@@ -823,12 +1038,16 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
 
   // We invalidated the newly exposed pixels on the bottom row and right column
   // of tiles.
-  expected_invalidation =
-      UnionRegions(gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  Region bottom_row_and_right_column_new_pixels = SubtractRegions(
+      UnionRegions(gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
                                    pile_->tiling().TileBounds(5, 5)),
-                   gfx::UnionRects(pile_->tiling().TileBounds(0, 5),
-                                   pile_->tiling().TileBounds(5, 5)));
-  expected_invalidation.Subtract(gfx::Rect(base_tiling_size));
+                   gfx::UnionRects(pile_->tiling().TileBounds(5, 0),
+                                   pile_->tiling().TileBounds(5, 5))),
+      gfx::Rect(base_tiling_size));
+  EXPECT_TRUE(
+      expected_invalidation.Contains(bottom_row_and_right_column_new_pixels));
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
index d755473..67ae593 100644 (file)
@@ -515,10 +515,13 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
       continue;
     }
 
-    // All raster tasks need to be throttled by bytes of pending uploads.
+    // All raster tasks need to be throttled by bytes of pending uploads,
+    // but if it's the only task allow it to complete no matter what its size,
+    // to prevent starvation of the task queue.
     size_t new_bytes_pending_upload = bytes_pending_upload;
     new_bytes_pending_upload += task->resource()->bytes();
-    if (new_bytes_pending_upload > max_bytes_pending_upload_) {
+    if (new_bytes_pending_upload > max_bytes_pending_upload_ &&
+        bytes_pending_upload) {
       did_throttle_raster_tasks = true;
       if (item.required_for_activation)
         did_throttle_raster_tasks_required_for_activation = true;
index 82c7f16..d0104cb 100644 (file)
@@ -40,13 +40,20 @@ class BinComparator {
 
 namespace {
 
+bool TilePriorityTieBreaker(const Tile* tile_i, const Tile* tile_j) {
+  // When two tiles has same priority use Id as tie breaker.
+  return tile_i->id() < tile_j->id();
+}
+
 typedef std::vector<Tile*> TileVector;
 
 void SortBinTiles(ManagedTileBin bin, TileVector* tiles) {
   switch (bin) {
-    case NOW_AND_READY_TO_DRAW_BIN:
     case NEVER_BIN:
       break;
+    case NOW_AND_READY_TO_DRAW_BIN:
+      std::sort(tiles->begin(), tiles->end(), TilePriorityTieBreaker);
+      break;
     case NOW_BIN:
     case SOON_BIN:
     case EVENTUALLY_AND_ACTIVE_BIN:
index 3b43c09..2179161 100644 (file)
 namespace cc {
 namespace {
 
+const size_t kMaxTransferBufferUsageBytes = 10000U;
+// A resource of this dimension^2 * 4 must be greater than the above transfer
+// buffer constant.
+const size_t kLargeResourceDimension = 1000U;
+
 enum RasterWorkerPoolType {
   RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
   RASTER_WORKER_POOL_TYPE_IMAGE,
@@ -126,7 +131,7 @@ class RasterWorkerPoolTest
             RasterWorkerPool::GetTaskGraphRunner(),
             context_provider_.get(),
             resource_provider_.get(),
-            std::numeric_limits<size_t>::max());
+            kMaxTransferBufferUsageBytes);
         break;
       case RASTER_WORKER_POOL_TYPE_IMAGE:
         raster_worker_pool_ = ImageRasterWorkerPool::Create(
@@ -203,9 +208,7 @@ class RasterWorkerPoolTest
     raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
   }
 
-  void AppendTask(unsigned id) {
-    const gfx::Size size(1, 1);
-
+  void AppendTask(unsigned id, const gfx::Size& size) {
     scoped_ptr<ScopedResource> resource(
         ScopedResource::Create(resource_provider_.get()));
     resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888);
@@ -221,6 +224,8 @@ class RasterWorkerPoolTest
         &empty));
   }
 
+  void AppendTask(unsigned id) { AppendTask(id, gfx::Size(1, 1)); }
+
   void AppendBlockingTask(unsigned id, base::Lock* lock) {
     const gfx::Size size(1, 1);
 
@@ -324,6 +329,27 @@ TEST_P(RasterWorkerPoolTest, FalseThrottling) {
   RunMessageLoopUntilAllTasksHaveCompleted();
 }
 
+TEST_P(RasterWorkerPoolTest, LargeResources) {
+  gfx::Size size(kLargeResourceDimension, kLargeResourceDimension);
+
+  {
+    // Verify a resource of this size is larger than the transfer buffer.
+    scoped_ptr<ScopedResource> resource(
+        ScopedResource::Create(resource_provider_.get()));
+    resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888);
+    EXPECT_GE(resource->bytes(), kMaxTransferBufferUsageBytes);
+  }
+
+  AppendTask(0u, size);
+  AppendTask(1u, size);
+  AppendTask(2u, size);
+  ScheduleTasks();
+
+  // This will time out if a resource that is larger than the throttle limit
+  // never gets scheduled.
+  RunMessageLoopUntilAllTasksHaveCompleted();
+}
+
 INSTANTIATE_TEST_CASE_P(RasterWorkerPoolTests,
                         RasterWorkerPoolTest,
                         ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
index 30d5849..d88bdd2 100644 (file)
@@ -111,25 +111,16 @@ GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
   return kSkia8888_GrPixelConfig;
 }
 
-class IdentityAllocator : public SkBitmap::Allocator {
- public:
-  explicit IdentityAllocator(void* buffer) : buffer_(buffer) {}
-  virtual bool allocPixelRef(SkBitmap* dst, SkColorTable*) OVERRIDE {
-    dst->setPixels(buffer_);
-    return true;
-  }
-
- private:
-  void* buffer_;
-};
-
-void CopyBitmap(const SkBitmap& src, uint8_t* dst, SkColorType dst_colorType) {
-  SkBitmap dst_bitmap;
-  IdentityAllocator allocator(dst);
-  src.copyTo(&dst_bitmap, dst_colorType, &allocator);
+void CopyBitmap(const SkBitmap& src, uint8_t* dst, SkColorType dst_color_type) {
+  SkImageInfo dst_info = src.info();
+  dst_info.fColorType = dst_color_type;
   // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
-  // bitmap data. This check will be removed once crbug.com/293728 is fixed.
-  CHECK_EQ(0u, dst_bitmap.rowBytes() % 4);
+  // bitmap data. There will be no need to call SkAlign4 once crbug.com/293728
+  // is fixed.
+  const size_t dst_row_bytes = SkAlign4(dst_info.minRowBytes());
+  CHECK_EQ(0u, dst_row_bytes % 4);
+  bool success = src.readPixels(dst_info, dst, dst_row_bytes, 0, 0);
+  CHECK_EQ(true, success);
 }
 
 class ScopedSetActiveTexture {
index 6588ac5..5e1ce5a 100644 (file)
@@ -131,6 +131,7 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
 
   void set_picture_pile(scoped_refptr<PicturePileImpl> pile) {
     DCHECK(pile->CanRaster(contents_scale_, content_rect_))
+        << "Recording rect: "
         << gfx::ScaleToEnclosingRect(content_rect_, 1.f / contents_scale_)
                .ToString();
     picture_pile_ = pile;
index fa5c650..eec5629 100644 (file)
@@ -123,7 +123,8 @@ class CC_EXPORT TileManager : public RasterizerClient,
       ManagedTileState::TileVersion& tile_version =
           mts.tile_versions[HIGH_QUALITY_RASTER_MODE];
 
-      tile_version.resource_ = resource_pool_->AcquireResource(gfx::Size(1, 1));
+      tile_version.resource_ =
+          resource_pool_->AcquireResource(tiles[i]->size());
 
       bytes_releasable_ += BytesConsumedIfAllocated(tiles[i]);
       ++resources_releasable_;
index d113e8b..bf72b45 100644 (file)
@@ -249,11 +249,7 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
     {
       ResourceProvider::ScopedWriteLockSoftware lock(
           resource_provider_, plane_resources[0].resource_id);
-      video_renderer_->Paint(video_frame.get(),
-                             lock.sk_canvas(),
-                             video_frame->visible_rect(),
-                             0xff,
-                             media::VIDEO_ROTATION_0);
+      video_renderer_->Copy(video_frame.get(), lock.sk_canvas());
     }
 
     RecycleResourceData recycle_data = {
index 86d83ba..7b83226 100644 (file)
@@ -58,7 +58,9 @@ class FakePictureLayerImpl : public PictureLayerImpl {
   using PictureLayerImpl::MarkVisibleResourcesAsRequired;
   using PictureLayerImpl::DoPostCommitInitializationIfNeeded;
   using PictureLayerImpl::MinimumContentsScale;
+  using PictureLayerImpl::GetViewportForTilePriorityInContentSpace;
   using PictureLayerImpl::SanityCheckTilingState;
+  using PictureLayerImpl::GetRecycledTwinLayer;
 
   using PictureLayerImpl::UpdateIdealScales;
   using PictureLayerImpl::MaximumTilingContentsScale;
index 2bd756d..0503d22 100644 (file)
@@ -15,10 +15,12 @@ FakePictureLayerTilingClient::FakePictureLayerTilingClient()
     : tile_manager_(new FakeTileManager(&tile_manager_client_)),
       pile_(FakePicturePileImpl::CreateInfiniteFilledPile()),
       twin_tiling_(NULL),
+      recycled_twin_tiling_(NULL),
       allow_create_tile_(true),
       max_tiles_for_interest_area_(10000),
       skewport_target_time_in_seconds_(1.0f),
-      skewport_extrapolation_limit_in_content_pixels_(2000) {}
+      skewport_extrapolation_limit_in_content_pixels_(2000) {
+}
 
 FakePictureLayerTilingClient::FakePictureLayerTilingClient(
     ResourceProvider* resource_provider)
@@ -28,9 +30,11 @@ FakePictureLayerTilingClient::FakePictureLayerTilingClient(
           new FakeTileManager(&tile_manager_client_, resource_pool_.get())),
       pile_(FakePicturePileImpl::CreateInfiniteFilledPile()),
       twin_tiling_(NULL),
+      recycled_twin_tiling_(NULL),
       allow_create_tile_(true),
       max_tiles_for_interest_area_(10000),
-      skewport_target_time_in_seconds_(1.0f) {}
+      skewport_target_time_in_seconds_(1.0f) {
+}
 
 FakePictureLayerTilingClient::~FakePictureLayerTilingClient() {
 }
@@ -79,6 +83,11 @@ const PictureLayerTiling* FakePictureLayerTilingClient::GetTwinTiling(
   return twin_tiling_;
 }
 
+PictureLayerTiling* FakePictureLayerTilingClient::GetRecycledTwinTiling(
+    const PictureLayerTiling* tiling) {
+  return recycled_twin_tiling_;
+}
+
 WhichTree FakePictureLayerTilingClient::GetTree() const {
   return tree_;
 }
index f46cc84..edd2a61 100644 (file)
@@ -36,9 +36,14 @@ class FakePictureLayerTilingClient : public PictureLayerTilingClient {
   virtual const Region* GetInvalidation() OVERRIDE;
   virtual const PictureLayerTiling* GetTwinTiling(
       const PictureLayerTiling* tiling) const OVERRIDE;
+  virtual PictureLayerTiling* GetRecycledTwinTiling(
+      const PictureLayerTiling* tiling) OVERRIDE;
   virtual WhichTree GetTree() const OVERRIDE;
 
   void set_twin_tiling(PictureLayerTiling* tiling) { twin_tiling_ = tiling; }
+  void set_recycled_twin_tiling(PictureLayerTiling* tiling) {
+    recycled_twin_tiling_ = tiling;
+  }
   void set_text_rect(const gfx::Rect& rect) { text_rect_ = rect; }
   void set_allow_create_tile(bool allow) { allow_create_tile_ = allow; }
   void set_invalidation(const Region& region) { invalidation_ = region; }
@@ -64,6 +69,7 @@ class FakePictureLayerTilingClient : public PictureLayerTilingClient {
   scoped_refptr<PicturePileImpl> pile_;
   gfx::Size tile_size_;
   PictureLayerTiling* twin_tiling_;
+  PictureLayerTiling* recycled_twin_tiling_;
   gfx::Rect text_rect_;
   bool allow_create_tile_;
   Region invalidation_;
index a466d87..b4d580f 100644 (file)
@@ -36,16 +36,18 @@ scoped_ptr<gpu::GLInProcessContext> CreateTestInProcessContext() {
   attribs.bind_generates_resource = false;
   gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
 
-  scoped_ptr<gpu::GLInProcessContext> context = make_scoped_ptr(
-      gpu::GLInProcessContext::Create(NULL,
-                                      NULL,
-                                      is_offscreen,
-                                      gfx::kNullAcceleratedWidget,
-                                      gfx::Size(1, 1),
-                                      NULL,
-                                      share_resources,
-                                      attribs,
-                                      gpu_preference));
+  scoped_ptr<gpu::GLInProcessContext> context =
+      make_scoped_ptr(gpu::GLInProcessContext::Create(
+          NULL,
+          NULL,
+          is_offscreen,
+          gfx::kNullAcceleratedWidget,
+          gfx::Size(1, 1),
+          NULL,
+          share_resources,
+          attribs,
+          gpu_preference,
+          gpu::GLInProcessContextSharedMemoryLimits()));
 
   DCHECK(context);
   return context.Pass();
index 705598b..dd01600 100644 (file)
@@ -1168,6 +1168,12 @@ void LayerTreeHostImpl::ResetTreesForTesting() {
   recycle_tree_.reset();
 }
 
+void LayerTreeHostImpl::ResetRecycleTreeForTesting() {
+  if (recycle_tree_)
+    recycle_tree_->DetachLayerTree();
+  recycle_tree_.reset();
+}
+
 void LayerTreeHostImpl::EnforceManagedMemoryPolicy(
     const ManagedMemoryPolicy& policy) {
 
index 8787478..74e9896 100644 (file)
@@ -217,6 +217,7 @@ class CC_EXPORT LayerTreeHostImpl
 
   // Resets all of the trees to an empty state.
   void ResetTreesForTesting();
+  void ResetRecycleTreeForTesting();
 
   DrawMode GetDrawMode() const;
 
index 167b65a..f01d0f9 100644 (file)
@@ -3040,6 +3040,21 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) {
                  wheel_scroll_delta);
 }
 
+TEST_F(LayerTreeHostImplTest, ScrollViewportRounding) {
+  int width = 332;
+  int height = 20;
+  int scale = 3;
+  SetupScrollAndContentsLayers(gfx::Size(width, height));
+  host_impl_->SetViewportSize(gfx::Size(width * scale - 1, height * scale));
+  host_impl_->SetDeviceScaleFactor(scale);
+  host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
+
+  LayerImpl* inner_viewport_scroll_layer =
+      host_impl_->active_tree()->InnerViewportScrollLayer();
+  EXPECT_EQ(gfx::Vector2d(0, 0),
+            inner_viewport_scroll_layer->MaxScrollOffset());
+}
+
 class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate {
  public:
   TestScrollOffsetDelegate()
index 759b80e..ecb25fa 100644 (file)
@@ -475,7 +475,7 @@ bool LayerTreeImpl::UpdateDrawProperties() {
         device_scale_factor(),
         total_page_scale_factor(),
         page_scale_layer,
-        MaxTextureSize(),
+        resource_provider()->max_texture_size(),
         settings().can_use_lcd_text,
         can_render_to_separate_surface,
         settings().layer_transforms_should_scale_layer_contents,
@@ -736,10 +736,6 @@ LayerImpl* LayerTreeImpl::FindRecycleTreeLayerById(int id) {
   return tree->LayerById(id);
 }
 
-int LayerTreeImpl::MaxTextureSize() const {
-  return layer_tree_host_impl_->GetRendererCapabilities().max_texture_size;
-}
-
 bool LayerTreeImpl::PinchGestureActive() const {
   return layer_tree_host_impl_->pinch_gesture_active();
 }
index fa6d63a..6ed3f45 100644 (file)
@@ -88,7 +88,6 @@ class CC_EXPORT LayerTreeImpl {
   LayerImpl* FindActiveTreeLayerById(int id);
   LayerImpl* FindPendingTreeLayerById(int id);
   LayerImpl* FindRecycleTreeLayerById(int id);
-  int MaxTextureSize() const;
   bool PinchGestureActive() const;
   base::TimeTicks CurrentFrameTimeTicks() const;
   base::TimeDelta begin_impl_frame_interval() const;
index a4a630e..81a90cc 100644 (file)
@@ -1266,6 +1266,12 @@ void ThreadProxy::LayerTreeHostClosedOnImplThread(CompletionEvent* completion) {
   impl().scheduler.reset();
   impl().layer_tree_host_impl.reset();
   impl().weak_factory.InvalidateWeakPtrs();
+  // We need to explicitly cancel the notifier, since it isn't using weak ptrs.
+  // TODO(vmpstr): We should see if we can make it use weak ptrs and still keep
+  // the convention of having a weak ptr factory initialized last. Alternatively
+  // we should moved the notifier (and RenewTreePriority) to LTHI. See
+  // crbug.com/411972
+  impl().smoothness_priority_expiration_notifier.Cancel();
   impl().contents_texture_manager = NULL;
   completion->Signal();
 }
index c61ab1f..afc1a0d 100644 (file)
@@ -1,4 +1,4 @@
 MAJOR=38
 MINOR=0
 BUILD=2125
-PATCH=23
+PATCH=66
index 63194a9..e6c4936 100644 (file)
@@ -16,4 +16,8 @@
     <alpha android:interpolator="@android:anim/linear_interpolator"
         android:fromAlpha="0" android:toAlpha="1"
         android:duration="200" />
+    <translate android:interpolator="@interpolator/transform_curve_interpolator"
+        android:fromYDelta="@dimen/menu_negative_software_vertical_offset"
+        android:toYDelta="0"
+        android:duration="200" />
 </set>
\ No newline at end of file
index d8fed33..ba5395e 100644 (file)
@@ -7,5 +7,5 @@
 <resources>
     <!-- Menu Dimensions -->
     <!-- Necessary to align the menu icon with the actual button. -->
-    <dimen name="menu_software_vertical_offset">-6dp</dimen>
+    <dimen name="menu_negative_software_vertical_offset">6dp</dimen>
 </resources>
\ No newline at end of file
index 72172f2..fa87b13 100644 (file)
@@ -17,7 +17,7 @@
 
     <!-- Custom Menu dimensions -->
     <dimen name="menu_width">258dp</dimen>
-    <dimen name="menu_software_vertical_offset">0dp</dimen>
+    <dimen name="menu_negative_software_vertical_offset">0dp</dimen>
     <!-- The amount to fade the edges of the menu to indicate more content is available
          via scrolling. -->
     <dimen name="menu_vertical_fade_distance">15dp</dimen>
index 2ec6b9b..56c8a44 100644 (file)
@@ -39,6 +39,9 @@ public class EmptyTabObserver implements TabObserver {
     public void onContextMenuShown(Tab tab, ContextMenu menu) { }
 
     @Override
+    public void onWebContentsInstantSupportDisabled() { }
+
+    @Override
     public void onLoadStarted(Tab tabBase) { }
 
     @Override
diff --git a/src/chrome/android/java/src/org/chromium/chrome/browser/FileProviderHelper.java b/src/chrome/android/java/src/org/chromium/chrome/browser/FileProviderHelper.java
new file mode 100644 (file)
index 0000000..7576389
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.v4.content.FileProvider;
+
+import org.chromium.base.ContentUriUtils;
+
+import java.io.File;
+
+/**
+ * Utilities for translating a file into content URI.
+ */
+public class FileProviderHelper implements ContentUriUtils.FileProviderUtil {
+    // Keep this variable in sync with the value defined in file_paths.xml.
+    private static final String API_AUTHORITY_SUFFIX = ".FileProvider";
+
+    @Override
+    public Uri getContentUriFromFile(Context context, File file) {
+        return FileProvider.getUriForFile(context,
+                context.getPackageName() + API_AUTHORITY_SUFFIX, file);
+    }
+}
index c76ebc3..3c4a5b6 100644 (file)
@@ -830,6 +830,11 @@ public class Tab implements NavigationClient {
         }
 
         for (TabObserver observer : mObservers) observer.onContentChanged(this);
+
+        // For browser tabs, we want to set accessibility focus to the page
+        // when it loads. This is not the default behavior for embedded
+        // web views.
+        mContentViewCore.setShouldSetAccessibilityFocusOnPageLoad(true);
     }
 
     /**
@@ -998,6 +1003,15 @@ public class Tab implements NavigationClient {
     }
 
     /**
+     * A helper method to allow subclasses to handle the Instant support
+     * disabled event.
+     */
+    @CalledByNative
+    private void onWebContentsInstantSupportDisabled() {
+      for (TabObserver observer : mObservers) observer.onWebContentsInstantSupportDisabled();
+    }
+
+    /**
      * A helper method to allow subclasses to build their own menu populator.
      * @return An instance of a {@link ContextMenuPopulator}.
      */
index 42f0eb6..e801bc1 100644 (file)
@@ -78,6 +78,11 @@ public interface TabObserver {
      */
     void onContextMenuShown(Tab tab, ContextMenu menu);
 
+    /**
+     * Called when the WebContents Instant support is disabled.
+     */
+    void onWebContentsInstantSupportDisabled();
+
     // WebContentsDelegateAndroid methods ---------------------------------------------------------
 
     /**
index af48e84..3f3ac68 100644 (file)
@@ -9,6 +9,7 @@ import android.animation.AnimatorSet;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -46,7 +47,7 @@ public class AppMenu implements OnItemClickListener, OnKeyListener {
     private final int mItemRowHeight;
     private final int mItemDividerHeight;
     private final int mVerticalFadeDistance;
-    private final int mAdditionalVerticalOffset;
+    private final int mNegativeSoftwareVerticalOffset;
     private ListPopupWindow mPopup;
     private AppMenuAdapter mAdapter;
     private AppMenuHandler mHandler;
@@ -73,8 +74,8 @@ public class AppMenu implements OnItemClickListener, OnKeyListener {
         mItemDividerHeight = itemDividerHeight;
         assert mItemDividerHeight >= 0;
 
-        mAdditionalVerticalOffset =
-                res.getDimensionPixelSize(R.dimen.menu_software_vertical_offset);
+        mNegativeSoftwareVerticalOffset =
+                res.getDimensionPixelSize(R.dimen.menu_negative_software_vertical_offset);
         mVerticalFadeDistance = res.getDimensionPixelSize(R.dimen.menu_vertical_fade_distance);
     }
 
@@ -106,6 +107,11 @@ public class AppMenu implements OnItemClickListener, OnKeyListener {
             }
         });
 
+        // Some OEMs don't actually let us change the background... but they still return the
+        // padding of the new background, which breaks the menu height.  If we still have a
+        // drawable here even though our style says @null we should use this padding instead...
+        Drawable originalBgDrawable = mPopup.getBackground();
+
         // Need to explicitly set the background here.  Relying on it being set in the style caused
         // an incorrectly drawn background.
         if (isByHardwareButton) {
@@ -140,6 +146,14 @@ public class AppMenu implements OnItemClickListener, OnKeyListener {
             }
         }
 
+        Rect sizingPadding = new Rect(bgPadding);
+        if (isByHardwareButton && originalBgDrawable != null) {
+            Rect originalPadding = new Rect();
+            originalBgDrawable.getPadding(originalPadding);
+            sizingPadding.top = originalPadding.top;
+            sizingPadding.bottom = originalPadding.bottom;
+        }
+
         boolean showMenuButton = !mIsByHardwareButton;
         if (!SHOW_SW_MENU_BUTTON) showMenuButton = false;
         // A List adapter for visible items in the Menu. The first row is added as a header to the
@@ -148,8 +162,8 @@ public class AppMenu implements OnItemClickListener, OnKeyListener {
                 this, menuItems, LayoutInflater.from(context), showMenuButton);
         mPopup.setAdapter(mAdapter);
 
-        setMenuHeight(menuItems.size(), visibleDisplayFrame, screenHeight);
-        setPopupOffset(mPopup, mCurrentScreenRotation, visibleDisplayFrame);
+        setMenuHeight(menuItems.size(), visibleDisplayFrame, screenHeight, sizingPadding);
+        setPopupOffset(mPopup, mCurrentScreenRotation, visibleDisplayFrame, sizingPadding);
         mPopup.setOnItemClickListener(this);
         mPopup.show();
         mPopup.getListView().setItemsCanFocus(true);
@@ -175,9 +189,8 @@ public class AppMenu implements OnItemClickListener, OnKeyListener {
         }
     }
 
-    private void setPopupOffset(ListPopupWindow popup, int screenRotation, Rect appRect) {
-        Rect paddingRect = new Rect();
-        popup.getBackground().getPadding(paddingRect);
+    private void setPopupOffset(
+            ListPopupWindow popup, int screenRotation, Rect appRect, Rect padding) {
         int[] anchorLocation = new int[2];
         popup.getAnchorView().getLocationInWindow(anchorLocation);
         int anchorHeight = popup.getAnchorView().getHeight();
@@ -201,13 +214,13 @@ public class AppMenu implements OnItemClickListener, OnKeyListener {
                     break;
             }
             popup.setHorizontalOffset(horizontalOffset);
-            // The menu is displayed above the anchored view, so shift the menu up by the top
+            // The menu is displayed above the anchored view, so shift the menu up by the bottom
             // padding of the background.
-            popup.setVerticalOffset(-paddingRect.bottom);
+            popup.setVerticalOffset(-padding.bottom);
         } else {
             // The menu is displayed over and below the anchored view, so shift the menu up by the
             // height of the anchor view.
-            popup.setVerticalOffset(mAdditionalVerticalOffset - anchorHeight);
+            popup.setVerticalOffset(-mNegativeSoftwareVerticalOffset - anchorHeight);
         }
     }
 
@@ -274,7 +287,8 @@ public class AppMenu implements OnItemClickListener, OnKeyListener {
         return mPopup;
     }
 
-    private void setMenuHeight(int numMenuItems, Rect appDimensions, int screenHeight) {
+    private void setMenuHeight(
+            int numMenuItems, Rect appDimensions, int screenHeight, Rect padding) {
         assert mPopup.getAnchorView() != null;
         View anchorView = mPopup.getAnchorView();
         int[] anchorViewLocation = new int[2];
@@ -289,9 +303,8 @@ public class AppMenu implements OnItemClickListener, OnKeyListener {
         int availableScreenSpace = Math.max(anchorViewLocation[1],
                 appDimensions.height() - anchorViewLocation[1] - anchorViewImpactHeight);
 
-        Rect padding = new Rect();
-        mPopup.getBackground().getPadding(padding);
-        availableScreenSpace -= mIsByHardwareButton ? padding.top : padding.bottom;
+        availableScreenSpace -= padding.bottom;
+        if (mIsByHardwareButton) availableScreenSpace -= padding.top;
 
         int numCanFit = availableScreenSpace / (mItemRowHeight + mItemDividerHeight);
 
index aeff4b7..091d5af 100644 (file)
@@ -21,6 +21,22 @@ public class Profile {
         return (Profile) nativeGetLastUsedProfile();
     }
 
+    public Profile getOriginalProfile() {
+        return (Profile) nativeGetOriginalProfile(mNativeProfileAndroid);
+    }
+
+    public Profile getOffTheRecordProfile() {
+        return (Profile) nativeGetOffTheRecordProfile(mNativeProfileAndroid);
+    }
+
+    public boolean hasOffTheRecordProfile() {
+        return nativeHasOffTheRecordProfile(mNativeProfileAndroid);
+    }
+
+    public boolean isOffTheRecord() {
+        return nativeIsOffTheRecord(mNativeProfileAndroid);
+    }
+
     @CalledByNative
     private static Profile create(long nativeProfileAndroid) {
         return new Profile(nativeProfileAndroid);
@@ -37,4 +53,12 @@ public class Profile {
     }
 
     private static native Object nativeGetLastUsedProfile();
+    private native Object nativeGetOriginalProfile(
+            long nativeProfileAndroid);
+    private native Object nativeGetOffTheRecordProfile(
+            long nativeProfileAndroid);
+    private native boolean nativeHasOffTheRecordProfile(
+            long nativeProfileAndroid);
+    private native boolean nativeIsOffTheRecord(
+            long nativeProfileAndroid);
 }
index 30dd6c2..6f3bf0c 100644 (file)
@@ -57,11 +57,11 @@ public class ShareHelper {
      * @param screenshot Screenshot of the page to be shared.
      */
     public static void share(boolean shareDirectly, Activity activity, String title, String url,
-            Bitmap screenshot) {
+            Bitmap screenshot, int extraIntentFlags) {
         if (shareDirectly) {
-            shareWithLastUsed(activity, title, url, screenshot);
+            shareWithLastUsed(activity, title, url, screenshot, extraIntentFlags);
         } else {
-            showShareDialog(activity, title, url, screenshot);
+            showShareDialog(activity, title, url, screenshot, extraIntentFlags);
         }
     }
 
@@ -72,10 +72,11 @@ public class ShareHelper {
      * @param title Title of the page to be shared.
      * @param url URL of the page to be shared.
      * @param screenshot Screenshot of the page to be shared.
+     * @param extraIntentFlags Additional flags that should be added to the share intent.
      */
     private static void showShareDialog(final Activity activity, final String title,
-            final String url, final Bitmap screenshot) {
-        Intent intent = getShareIntent(title, url, screenshot);
+            final String url, final Bitmap screenshot, final int extraIntentFlags) {
+        Intent intent = getShareIntent(title, url, screenshot, extraIntentFlags);
         PackageManager manager = activity.getPackageManager();
         List<ResolveInfo> resolveInfoList = manager.queryIntentActivities(intent, 0);
         assert resolveInfoList.size() > 0;
@@ -98,7 +99,8 @@ public class ShareHelper {
                 ComponentName component =
                         new ComponentName(ai.applicationInfo.packageName, ai.name);
                 setLastShareComponentName(activity, component);
-                Intent intent = getDirectShareIntentForComponent(title, url, screenshot, component);
+                Intent intent = getDirectShareIntentForComponent(title, url, screenshot, component,
+                        extraIntentFlags);
                 activity.startActivity(intent);
                 dialog.dismiss();
             }
@@ -112,12 +114,14 @@ public class ShareHelper {
      * @param title Title of the page to be shared.
      * @param url URL of the page to be shared.
      * @param screenshot Screenshot of the page to be shared.
+     * @param extraIntentFlags Additional flags that should be added to the share intent.
      */
     private static void shareWithLastUsed(
-            Activity activity, String title, String url, Bitmap screenshot) {
+            Activity activity, String title, String url, Bitmap screenshot, int extraIntentFlags) {
         ComponentName component = getLastShareComponentName(activity);
         if (component == null) return;
-        Intent intent = getDirectShareIntentForComponent(title, url, screenshot, component);
+        Intent intent = getDirectShareIntentForComponent(
+                title, url, screenshot, component, extraIntentFlags);
         activity.startActivity(intent);
     }
 
@@ -150,8 +154,10 @@ public class ShareHelper {
         }
     }
 
-    private static Intent getShareIntent(String title, String url, Bitmap screenshot) {
+    private static Intent getShareIntent(String title, String url, Bitmap screenshot,
+            int extraIntentFlags) {
         Intent intent = new Intent(Intent.ACTION_SEND);
+        intent.addFlags(extraIntentFlags);
         intent.setType("text/plain");
         intent.putExtra(Intent.EXTRA_SUBJECT, title);
         intent.putExtra(Intent.EXTRA_TEXT, url);
@@ -160,8 +166,8 @@ public class ShareHelper {
     }
 
     private static Intent getDirectShareIntentForComponent(String title, String url,
-            Bitmap screenshot, ComponentName component) {
-        Intent intent = getShareIntent(title, url, screenshot);
+            Bitmap screenshot, ComponentName component, int extraIntentFlags) {
+        Intent intent = getShareIntent(title, url, screenshot, extraIntentFlags);
         intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
                 | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
         intent.setComponent(component);
index dbe2b4e..583eeb3 100644 (file)
@@ -141,6 +141,13 @@ public class SigninManager {
                 ChromeSigninController.get(mContext).getSignedInUser() == null;
     }
 
+    /**
+     * Returns true if signin is disabled by policy.
+     */
+    public boolean isSigninDisabledByPolicy() {
+        return !mSigninAllowedByPolicy;
+    }
+
     public void addSignInAllowedObserver(SignInAllowedObserver observer) {
         mSignInAllowedObservers.addObserver(observer);
     }
index 50dca1d..2586a8c 100644 (file)
@@ -10,6 +10,7 @@ import org.chromium.base.TraceEvent;
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.util.MathUtils;
+import org.chromium.content_public.browser.WebContents;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -433,6 +434,13 @@ public abstract class TabModelBase implements TabModel {
 
         // TODO(dtrainor): Update the list of undoable tabs instead of committing it.
         if (!canUndo) commitAllTabClosures();
+
+        // Cancel any media currently playing.
+        if (canUndo) {
+            WebContents webContents = tab.getWebContents();
+            if (webContents != null) webContents.releaseMediaPlayers();
+        }
+
         mTabs.remove(tab);
 
         boolean nextIsIncognito = nextTab == null ? false : nextTab.isIncognito();
index ad27000..84ca195 100644 (file)
                   android:authorities="org.chromium.chrome.shell"
                   android:exported="true" />
 
+        <!-- Provider for FileProvider. -->
+        <provider android:name="android.support.v4.content.FileProvider"
+            android:authorities="org.chromium.chrome.shell.FileProvider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_paths" />
+        </provider>
+
         <!-- Sync adapter for browser sync. -->
         <service android:exported="false"
                  android:name="org.chromium.chrome.shell.sync.ChromeShellSyncAdapterService">
index 05608d3..335ce04 100644 (file)
@@ -20,9 +20,11 @@ import com.google.common.annotations.VisibleForTesting;
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.BaseSwitches;
 import org.chromium.base.CommandLine;
+import org.chromium.base.ContentUriUtils;
 import org.chromium.base.MemoryPressureListener;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.chrome.browser.DevToolsServer;
+import org.chromium.chrome.browser.FileProviderHelper;
 import org.chromium.chrome.browser.appmenu.AppMenuHandler;
 import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
@@ -173,6 +175,7 @@ public class ChromeShellActivity extends Activity implements AppMenuPropertiesDe
         // In case this method is called after the first onStart(), we need to inform the
         // SyncController that we have started.
         mSyncController.onStart();
+        ContentUriUtils.setFileProviderUtil(new FileProviderHelper());
     }
 
     @Override
@@ -284,6 +287,7 @@ public class ChromeShellActivity extends Activity implements AppMenuPropertiesDe
         return super.onKeyDown(keyCode, event);
     }
 
+    @SuppressWarnings("deprecation")
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         ChromeShellTab activeTab = getActiveTab();
@@ -322,7 +326,8 @@ public class ChromeShellActivity extends Activity implements AppMenuPropertiesDe
             case R.id.share_menu_id:
             case R.id.direct_share_menu_id:
                 ShareHelper.share(item.getItemId() == R.id.direct_share_menu_id, this,
-                        activeTab.getTitle(), activeTab.getUrl(), null);
+                        activeTab.getTitle(), activeTab.getUrl(), null,
+                        Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                 return true;
             default:
                 return super.onOptionsItemSelected(item);
diff --git a/src/chrome/android/shell/res/xml/file_paths.xml b/src/chrome/android/shell/res/xml/file_paths.xml
new file mode 100644 (file)
index 0000000..f40426a
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the ContentProvider. -->
+
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <files-path name="images" path="images/"/>
+</paths>
index 3cd5f6a..b6fc276 100644 (file)
        <string>BrowserCrApplication</string>
        <key>NSSupportsAutomaticGraphicsSwitching</key>
        <true/>
+       <key>NSUserActivityTypes</key>
+       <array>
+               <string>NSUserActivityTypeBrowsingWeb</string>
+       </array>
        <key>UTExportedTypeDeclarations</key>
        <array>
                <dict>
index 06c5cf8..cfe9aef 100644 (file)
@@ -1205,7 +1205,7 @@ Signing in anyway will merge Chromium information like bookmarks, history, and o
 
       <!-- Contextual Search -->
       <message name="IDS_CONTEXTUAL_SEARCH_PROMO_DESCRIPTION" desc="Description of the Contextual Search feature.">
-        Enabling "Tap to Search" provides an easy way to search for terms on a web page by simply tapping on them.  The word tapped and surrounding page will be sent to Google.
+        “Touch to Search” provides an easy way to search for terms on a web page by simply touching on them.  The touched word and surrounding page will be sent to Google.
       </message>
       <message name="IDS_CONTEXTUAL_SEARCH_PROMO_OPTIN" desc="Text for the button the user clicks to opt in.">
         Yes, please
index ee46a22..ff61f5e 100644 (file)
@@ -14538,7 +14538,7 @@ Do you accept?
     </message>
     <!-- Strings for notification shown when the Chromebook is added to Easy Unlock -->
     <message name="IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_TITLE" desc="Title for notification shown when this Chromebook is added to Easy Unlock as an additional Easy Unlock device.">
-      Easy unock is now enabled
+      Easy unlock is now enabled
     </message>
     <message name="IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_MESSAGE" desc="Message for the notification shown when this Chromebook is added to Easy Unlock as an additional Easy Unlock device.">
       You can start using your Android phone to unlock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>, too - no additional setup necessary.
index f45570c..b6f2e50 100644 (file)
@@ -1130,7 +1130,7 @@ Signing in anyway will merge Chrome information like bookmarks, history, and oth
 
       <!-- Contextual Search -->
       <message name="IDS_CONTEXTUAL_SEARCH_PROMO_DESCRIPTION" desc="Description of the Contextual Search feature.">
-        Enabling "Tap to Search" provides an easy way to search for terms on a web page by simply tapping on them.  The word tapped and surrounding page will be sent to Google.
+        “Touch to Search” provides an easy way to search for terms on a web page by simply touching on them.  The touched word and surrounding page will be sent to Google.
       </message>
       <message name="IDS_CONTEXTUAL_SEARCH_PROMO_OPTIN" desc="Text for the button the user clicks to opt in.">
         Yes, please
index 8273021..6141a4f 100644 (file)
       <!-- The default value for |WebPreference::standard_font_family_map| for
            Japanese script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_JAPANESE" use_name_for_id="true">
-        IPAPGothic
+        Noto Sans CJK Japanese
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
       <!-- The default value for |WebPreference::sans_serif_font_family_map| for
            Japanese script.  -->
       <message name="IDS_SANS_SERIF_FONT_FAMILY_JAPANESE" use_name_for_id="true">
-        IPAPGothic
+        Noto Sans CJK Japanese
       </message>
 
      <!-- The default value for |WebPreference::standard_font_family_map| for
            Korean script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_KOREAN" use_name_for_id="true">
-        NanumGothic
+        Noto Sans CJK Korean
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
       <!-- The default value for |WebPreference::sans_serif_font_family_map| for
            Korean script.  -->
       <message name="IDS_SANS_SERIF_FONT_FAMILY_KOREAN" use_name_for_id="true">
-        NanumGothic
+        Noto Sans CJK Korean
       </message>
 
       <!-- The default value for |WebPreference::standard_font_family_map| for
            Simplified Chinese script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true">
-        Droid Sans Fallback
+        Noto Sans CJK Simplified Chinese
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Simplified Chinese script. -->
       <message name="IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true">
-        Droid Sans Fallback
+        Noto Sans CJK Simplfieid Chinese
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
            Simplified Chinese script. -->
       <message name="IDS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true">
-        Droid Sans Fallback
+        Noto Sans CJK Simplfieid Chinese
       </message>
 
       <!-- The default value for |WebPreference::sans_serif_font_family_map| for
            Simplified Chinese script.  -->
       <message name="IDS_SANS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true">
-        Droid Sans Fallback
+        Noto Sans CJK Simplfieid Chinese
       </message>
 
       <!-- The default value for |WebPreference::standard_font_family_map| for
            Traditional Chinese script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true">
-        Droid Sans Fallback
+        Noto Sans CJK Traditional Chinese
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Traditional Chinese script. -->
       <message name="IDS_FIXED_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true">
-        Droid Sans Fallback
+        Noto Sans CJK Traditional Chinese
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
            Traditional Chinese script. -->
       <message name="IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true">
-        Droid Sans Fallback
+        Noto Sans CJK Traditional Chinese
       </message>
 
       <!-- The default value for |WebPreference::sans_serif_font_family_map| for
            Traditional Chinese script.  -->
       <message name="IDS_SANS_SERIF_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true">
-        Droid Sans Fallback
+        Noto Sans CJK Traditional Chinese
       </message>
 
       <!-- The default value for |WebPreference::default_font_size| -->
index 2901289..a553732 100644 (file)
       <!-- The default value for |WebPreference::standard_font_family_map| for
            Japanese script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_JAPANESE" use_name_for_id="true">
-        MotoyaG04Gothic
+        Noto Sans CJK Japanese
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
       <!-- The default value for |WebPreference::sans_serif_font_family_map| for
            Japanese script.  -->
       <message name="IDS_SANS_SERIF_FONT_FAMILY_JAPANESE" use_name_for_id="true">
-        MotoyaG04Gothic
+        Noto Sans CJK Japanese
       </message>
 
      <!-- The default value for |WebPreference::standard_font_family_map| for
            Korean script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_KOREAN" use_name_for_id="true">
-        NanumGothic
+        Noto Sans CJK Korean
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
       <!-- The default value for |WebPreference::sans_serif_font_family_map| for
            Korean script.  -->
       <message name="IDS_SANS_SERIF_FONT_FAMILY_KOREAN" use_name_for_id="true">
-        NanumGothic
+        Noto Sans CJK Korean
       </message>
 
       <!-- The default value for |WebPreference::standard_font_family_map| for
            Simplified Chinese script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true">
-        MYingHeiGB18030
+        Noto Sans CJK Simplified Chinese
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Simplified Chinese script. -->
       <message name="IDS_FIXED_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true">
-        MYingHeiGB18030
+        Noto Sans CJK Simplified Chinese
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
       <!-- The default value for |WebPreference::sans_serif_font_family_map| for
            Simplified Chinese script.  -->
       <message name="IDS_SANS_SERIF_FONT_FAMILY_SIMPLIFIED_HAN" use_name_for_id="true">
-        MYingHeiGB18030
+        Noto Sans CJK Simplified Chinese
       </message>
 
       <!-- The default value for |WebPreference::standard_font_family_map| for
            Traditional Chinese script. -->
       <message name="IDS_STANDARD_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true">
-        MYingHeiB5HK
+        Noto Sans CJK Traditional  Chinese
       </message>
 
       <!-- The default value for |WebPreference::fixed_font_family_map| for
            Traditional Chinese script. -->
       <message name="IDS_FIXED_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true">
-        MYingHeiB5HK
+        Noto Sans CJK Traditional  Chinese
       </message>
 
       <!-- The default value for |WebPreference::serif_font_family_map| for
       <!-- The default value for |WebPreference::sans_serif_font_family_map| for
            Traditional Chinese script.  -->
       <message name="IDS_SANS_SERIF_FONT_FAMILY_TRADITIONAL_HAN" use_name_for_id="true">
-        MYingHeiB5HK
+        Noto Sans CJK Traditional  Chinese
       </message>
 
       <!-- The default value for |WebPreference::default_font_size| -->
index 7d36881..819d457 100644 (file)
@@ -1,17 +1,15 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="ja">
+<translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK Japanese</translation>
+<translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK Japanese</translation>
 <if expr="_google_chrome">
-  <translation id="IDS_STANDARD_FONT_FAMILY">MotoyaG04Gothic</translation>
   <translation id="IDS_FIXED_FONT_FAMILY">MotoyaG04GothicMono</translation>
   <translation id="IDS_SERIF_FONT_FAMILY">MotoyaG04Mincho</translation>
-  <translation id="IDS_SANS_SERIF_FONT_FAMILY">MotoyaG04Gothic</translation>
 </if>
 <if expr="not _google_chrome">
-  <translation id="IDS_STANDARD_FONT_FAMILY">IPAPGothic</translation>
   <translation id="IDS_FIXED_FONT_FAMILY">IPAGothic</translation>
   <translation id="IDS_SERIF_FONT_FAMILY">IPAPMincho</translation>
-  <translation id="IDS_SANS_SERIF_FONT_FAMILY">IPAPGothic</translation>
 </if>
 <translation id="IDS_MINIMUM_FONT_SIZE">10</translation>
 <translation id="IDS_MINIMUM_LOGICAL_FONT_SIZE">10</translation>
index cb0db2a..a696d89 100644 (file)
@@ -2,10 +2,10 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="ko">
 <!-- TODO(jungshik): remove this line once we fix bug 14691 -->
-<translation id="IDS_STANDARD_FONT_FAMILY">NanumGothic</translation>
+<translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK Korean</translation>
 <translation id="IDS_FIXED_FONT_FAMILY">Monospace</translation>
 <translation id="IDS_SERIF_FONT_FAMILY">NanumMyeongjo</translation>
-<translation id="IDS_SANS_SERIF_FONT_FAMILY">NanumGothic</translation>
+<translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK Korean</translation>
 <translation id="IDS_MINIMUM_FONT_SIZE">10</translation>
 <translation id="IDS_MINIMUM_LOGICAL_FONT_SIZE">10</translation>
 </translationbundle>
index cfd9f1e..1a98e1d 100644 (file)
@@ -1,16 +1,14 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-CN">
+<translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK Simplified Chinese</translation>
+<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans CJK Simplified Chinese</translation>
+<translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK Simplified Chinese</translation>
 <if expr="_google_chrome">
-  <translation id="IDS_STANDARD_FONT_FAMILY">MYingHeiGB18030</translation>
-  <translation id="IDS_FIXED_FONT_FAMILY">MYingHeiGB18030</translation>
   <translation id="IDS_SERIF_FONT_FAMILY">MSung GB18030</translation>
-  <translation id="IDS_SANS_SERIF_FONT_FAMILY">MYingHeiGB18030</translation>
 </if>
 <if expr="not _google_chrome">
-  <translation id="IDS_STANDARD_FONT_FAMILY">Droid Sans Fallback</translation>
-  <translation id="IDS_FIXED_FONT_FAMILY">Droid Sans Fallback</translation>
-  <translation id="IDS_SANS_SERIF_FONT_FAMILY">Droid Sans Fallback</translation>
+  <translation id="IDS_SERIF_FONT_FAMILY">Noto Sans CJK Simplified Chinese</translation>
 </if>
 <translation id="IDS_MINIMUM_FONT_SIZE">12</translation>
 <translation id="IDS_MINIMUM_LOGICAL_FONT_SIZE">12</translation>
index 74e2a1d..00e9094 100644 (file)
@@ -1,16 +1,14 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-TW">
+<translation id="IDS_STANDARD_FONT_FAMILY">Noto Sans CJK Traditional Chinese</translation>
+<translation id="IDS_FIXED_FONT_FAMILY">Noto Sans CJK Traditional Chinese</translation>
+<translation id="IDS_SANS_SERIF_FONT_FAMILY">Noto Sans CJK Traditional Chinese</translation>
 <if expr="_google_chrome">
-  <translation id="IDS_STANDARD_FONT_FAMILY">MYingHeiB5HK</translation>
-  <translation id="IDS_FIXED_FONT_FAMILY">MYingHeiB5HK</translation>
   <translation id="IDS_SERIF_FONT_FAMILY">MSung B5HK</translation>
-  <translation id="IDS_SANS_SERIF_FONT_FAMILY">MYingHeiB5HK</translation>
 </if>
 <if expr="not _google_chrome">
-  <translation id="IDS_STANDARD_FONT_FAMILY">Droid Sans Fallback</translation>
-  <translation id="IDS_FIXED_FONT_FAMILY">Droid Sans Fallback</translation>
-  <translation id="IDS_SANS_SERIF_FONT_FAMILY">Droid Sans Fallback</translation>
+<translation id="IDS_SERIF_FONT_FAMILY">Noto Sans CJK Traditional Chinese</translation>
 </if>
 <translation id="IDS_MINIMUM_FONT_SIZE">12</translation>
 <translation id="IDS_MINIMUM_LOGICAL_FONT_SIZE">12</translation>
index 2a87d86..881c154 100644 (file)
@@ -1119,7 +1119,7 @@ const Experiment kExperiments[] = {
     "enable-password-generation",
     IDS_FLAGS_ENABLE_PASSWORD_GENERATION_NAME,
     IDS_FLAGS_ENABLE_PASSWORD_GENERATION_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS,
+    kOsWin | kOsLinux | kOsCrOS | kOsMac,
     ENABLE_DISABLE_VALUE_TYPE(autofill::switches::kEnablePasswordGeneration,
                               autofill::switches::kDisablePasswordGeneration)
   },
index 158ef74..7afcdb2 100644 (file)
@@ -162,6 +162,9 @@ class TabTarget : public TargetBase {
     if (!web_contents) {
       // The tab has been pushed out of memory, pull it back.
       TabAndroid* tab = model->GetTabAt(index);
+      if (!tab)
+        return NULL;
+
       tab->LoadIfNeeded();
       web_contents = model->GetWebContentsAt(index);
       if (!web_contents)
@@ -205,7 +208,7 @@ class TabTarget : public TargetBase {
       TabModel* model = *iter;
       for (int i = 0; i < model->GetTabCount(); ++i) {
         TabAndroid* tab = model->GetTabAt(i);
-        if (tab->GetAndroidId() == tab_id_) {
+        if (tab && tab->GetAndroidId() == tab_id_) {
           *model_result = model;
           *index_result = i;
           return true;
@@ -337,6 +340,9 @@ class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
       TabModel* model = *iter;
       for (int i = 0; i < model->GetTabCount(); ++i) {
         TabAndroid* tab = model->GetTabAt(i);
+        if (!tab)
+          continue;
+
         WebContents* web_contents = model->GetWebContentsAt(i);
         if (web_contents) {
           tab_web_contents.insert(web_contents);
index e13597c..7b71164 100644 (file)
 #include "chrome/browser/profiles/profile_android.h"
 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
 #include "chrome/browser/search/suggestions/suggestions_source.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/thumbnails/thumbnail_list_source.h"
 #include "components/suggestions/suggestions_service.h"
+#include "components/suggestions/suggestions_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/url_data_source.h"
@@ -46,6 +49,7 @@ using suggestions::ChromeSuggestion;
 using suggestions::SuggestionsProfile;
 using suggestions::SuggestionsService;
 using suggestions::SuggestionsServiceFactory;
+using suggestions::SyncState;
 
 namespace {
 
@@ -171,6 +175,18 @@ void LogHistogramEvent(const std::string& histogram, int position,
     counter->Add(position);
 }
 
+// Return the current SyncState for use with the SuggestionsService.
+SyncState GetSyncState(Profile* profile) {
+  ProfileSyncService* sync =
+      ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
+  if (!sync)
+    return SyncState::SYNC_OR_HISTORY_SYNC_DISABLED;
+  return suggestions::GetSyncState(
+      sync->IsSyncEnabledAndLoggedIn(),
+      sync->sync_initialized(),
+      sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES));
+}
+
 }  // namespace
 
 MostVisitedSites::MostVisitedSites(Profile* profile)
@@ -182,9 +198,21 @@ MostVisitedSites::MostVisitedSites(Profile* profile)
   content::URLDataSource::Add(profile_,
                               new suggestions::SuggestionsSource(profile_));
   content::URLDataSource::Add(profile_, new ThumbnailListSource(profile_));
+
+  // Register this class as an observer to the sync service. It is important to
+  // be notified of changes in the sync state such as initialization, sync
+  // being enabled or disabled, etc.
+  ProfileSyncService* profile_sync_service =
+      ProfileSyncServiceFactory::GetForProfile(profile_);
+  if (profile_sync_service)
+    profile_sync_service->AddObserver(this);
 }
 
 MostVisitedSites::~MostVisitedSites() {
+  ProfileSyncService* profile_sync_service =
+      ProfileSyncServiceFactory::GetForProfile(profile_);
+  if (profile_sync_service && profile_sync_service->HasObserver(this))
+    profile_sync_service->RemoveObserver(this);
 }
 
 void MostVisitedSites::Destroy(JNIEnv* env, jobject obj) {
@@ -230,11 +258,13 @@ void MostVisitedSites::GetURLThumbnail(JNIEnv* env,
   std::string url_string = ConvertJavaStringToUTF8(env, url);
   scoped_refptr<TopSites> top_sites(profile_->GetTopSites());
 
-  // If the Suggestions service is enabled, create a callback to fetch a
-  // server thumbnail from it, in case the local thumbnail is not found.
+  // If the Suggestions service is enabled and in use, create a callback to
+  // fetch a server thumbnail from it, in case the local thumbnail is not found.
   SuggestionsService* suggestions_service =
       SuggestionsServiceFactory::GetForProfile(profile_);
-  base::Closure lookup_failed_callback = suggestions_service ?
+  bool use_suggestions_service = suggestions_service &&
+      mv_source_ == SUGGESTIONS_SERVICE;
+  base::Closure lookup_failed_callback = use_suggestions_service ?
       base::Bind(&MostVisitedSites::GetSuggestionsThumbnailOnUIThread,
                  weak_ptr_factory_.GetWeakPtr(),
                  suggestions_service, url_string,
@@ -317,6 +347,13 @@ void MostVisitedSites::Observe(int type,
   }
 }
 
+void MostVisitedSites::OnStateChanged() {
+  // There have been changes to the sync state. This class cares about a few
+  // (just initialized, enabled/disabled or history sync state changed). Re-run
+  // the query code which will use the proper state.
+  QueryMostVisitedURLs();
+}
+
 // static
 bool MostVisitedSites::Register(JNIEnv* env) {
   return RegisterNativesImpl(env);
@@ -328,6 +365,7 @@ void MostVisitedSites::QueryMostVisitedURLs() {
   if (suggestions_service) {
     // Suggestions service is enabled, initiate a query.
     suggestions_service->FetchSuggestionsData(
+        GetSyncState(profile_),
         base::Bind(
           &MostVisitedSites::OnSuggestionsProfileAvailable,
           weak_ptr_factory_.GetWeakPtr(),
index 39ecceb..4a24ad7 100644 (file)
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/history/history_types.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/profile_sync_service_observer.h"
 #include "components/suggestions/proto/suggestions.pb.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -21,7 +22,8 @@ class SuggestionsService;
 }
 
 // Provides the list of most visited sites and their thumbnails to Java.
-class MostVisitedSites : public content::NotificationObserver {
+class MostVisitedSites : public ProfileSyncServiceObserver,
+                         public content::NotificationObserver {
  public:
   typedef base::Callback<
       void(base::android::ScopedJavaGlobalRef<jobject>* bitmap,
@@ -47,6 +49,9 @@ class MostVisitedSites : public content::NotificationObserver {
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // ProfileSyncServiceObserver implementation.
+  virtual void OnStateChanged() OVERRIDE;
+
   // Registers JNI methods.
   static bool Register(JNIEnv* env);
 
index 0e40ea0..6d536f3 100644 (file)
@@ -306,6 +306,17 @@ void TabAndroid::SwapTabContents(content::WebContents* old_contents,
       did_finish_load);
 }
 
+void TabAndroid::OnWebContentsInstantSupportDisabled(
+    const content::WebContents* contents) {
+  DCHECK(contents);
+  if (web_contents() != contents)
+    return;
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_Tab_onWebContentsInstantSupportDisabled(env,
+                                               weak_java_tab_.get(env).obj());
+}
+
 void TabAndroid::Observe(int type,
                          const content::NotificationSource& source,
                          const content::NotificationDetails& details) {
@@ -371,6 +382,7 @@ void TabAndroid::InitWebContents(JNIEnv* env,
   WindowAndroidHelper::FromWebContents(web_contents())->
       SetWindowAndroid(content_view_core->GetWindowAndroid());
   CoreTabHelper::FromWebContents(web_contents())->set_delegate(this);
+  SearchTabHelper::FromWebContents(web_contents())->set_delegate(this);
   web_contents_delegate_.reset(
       new chrome::android::ChromeWebContentsDelegateAndroid(
           env, jweb_contents_delegate));
index d09aa93..c25d16e 100644 (file)
@@ -13,6 +13,7 @@
 #include "base/strings/string16.h"
 #include "chrome/browser/sessions/session_id.h"
 #include "chrome/browser/sync/glue/synced_tab_delegate_android.h"
+#include "chrome/browser/ui/search/search_tab_helper_delegate.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
 #include "chrome/browser/ui/toolbar/toolbar_model.h"
 #include "content/public/browser/notification_observer.h"
@@ -42,6 +43,7 @@ class PrerenderManager;
 }
 
 class TabAndroid : public CoreTabHelperDelegate,
+                   public SearchTabHelperDelegate,
                    public content::NotificationObserver {
  public:
   enum TabLoadStatus {
@@ -111,6 +113,10 @@ class TabAndroid : public CoreTabHelperDelegate,
                                bool did_start_load,
                                bool did_finish_load) OVERRIDE;
 
+  // Overridden from SearchTabHelperDelegate:
+  virtual void OnWebContentsInstantSupportDisabled(
+      const content::WebContents* web_contents) OVERRIDE;
+
   // NotificationObserver -----------------------------------------------------
   virtual void Observe(int type,
                        const content::NotificationSource& source,
index 57fb281..6c5f2bb 100644 (file)
@@ -1546,6 +1546,36 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
       WorkAreaChanged());
 }
 
+- (BOOL)application:(NSApplication*)application
+    willContinueUserActivityWithType:(NSString*)userActivityType {
+  return [userActivityType isEqualToString:NSUserActivityTypeBrowsingWeb];
+}
+
+- (BOOL)application:(NSApplication*)application
+    continueUserActivity:(NSUserActivity*)userActivity
+      restorationHandler:(void (^)(NSArray*))restorationHandler {
+  if (![userActivity.activityType
+          isEqualToString:NSUserActivityTypeBrowsingWeb]) {
+    return NO;
+  }
+
+  NSURL* url = userActivity.webPageURL;
+  if (!url)
+    return NO;
+
+  GURL gurl(base::SysNSStringToUTF8([url absoluteString]));
+  std::vector<GURL> gurlVector;
+  gurlVector.push_back(gurl);
+
+  [self openUrls:gurlVector];
+  return YES;
+}
+
+- (void)application:(NSApplication*)application
+    didFailToContinueUserActivityWithType:(NSString*)userActivityType
+                                    error:(NSError*)error {
+}
+
 @end  // @implementation AppController
 
 //---------------------------------------------------------------------------
index bc647ea..68b254d 100644 (file)
@@ -57,7 +57,7 @@ bool KeywordExtensionsDelegateImpl::IsEnabledExtension(
       extension_service->GetExtensionById(extension_id, false);
   return extension &&
       (!profile_->IsOffTheRecord() ||
-       !extensions::util::IsIncognitoEnabled(extension_id, profile_));
+       extensions::util::IsIncognitoEnabled(extension_id, profile_));
 }
 
 bool KeywordExtensionsDelegateImpl::Start(
index 4a8aa1e..24022d3 100644 (file)
@@ -157,7 +157,7 @@ IN_PROC_BROWSER_TEST_F(AutofillServerTest,
       "<autofillupload clientversion=\"6.1.1715.1442/en (GGLL)\""
       " formsignature=\"15916856893790176210\""
       " autofillused=\"false\""
-      " datapresent=\"1f7e0003780000080014\">"
+      " datapresent=\"1f7e0003780000080004\">"
       "<field signature=\"2594484045\" autofilltype=\"2\"/>"
       "<field signature=\"2750915947\" autofilltype=\"2\"/>"
       "<field signature=\"3494787134\" autofilltype=\"2\"/>"
index 5f49c00..06c0a28 100644 (file)
@@ -343,6 +343,13 @@ Profile* CreatePrimaryProfile(const content::MainFunctionParams& parameters,
 #else
   base::FilePath profile_path =
       GetStartupProfilePath(user_data_dir, parsed_command_line);
+
+  // Without NewAvatarMenu, replace guest with any existing profile.
+  if (!switches::IsNewAvatarMenu() &&
+      profile_path == ProfileManager::GetGuestProfilePath()) {
+    profile_path = g_browser_process->profile_manager()->GetProfileInfoCache().
+        GetPathOfProfileAtIndex(0);
+  }
   profile = g_browser_process->profile_manager()->GetProfile(
       profile_path);
 
@@ -1375,8 +1382,11 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
     const char kEnabledHttpOnlyGroupName[] = "EnabledHttpOnly";
     const char kDisabledAllGroupName[] = "DisabledAll";
 
-    base::StringPiece sdch_trial_group =
+    // Store in a string on return to keep underlying storage for
+    // StringPiece stable.
+    std::string sdch_trial_group_string =
         base::FieldTrialList::FindFullName(kSdchFieldTrialName);
+    base::StringPiece sdch_trial_group(sdch_trial_group_string);
     if (sdch_trial_group.starts_with(kEnabledAllGroupName)) {
       net::SdchManager::EnableSecureSchemeSupport(true);
       net::SdchManager::EnableSdchSupport(true);
index b7967f8..942daad 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chrome_browser_main_linux.h"
 
+#include <fontconfig/fontconfig.h>
+
 #include "chrome/browser/browser_process.h"
 #include "components/breakpad/app/breakpad_linux.h"
 #include "components/metrics/metrics_service.h"
@@ -22,6 +24,15 @@ ChromeBrowserMainPartsLinux::ChromeBrowserMainPartsLinux(
 ChromeBrowserMainPartsLinux::~ChromeBrowserMainPartsLinux() {
 }
 
+void ChromeBrowserMainPartsLinux::ToolkitInitialized() {
+  // Explicitly initialize Fontconfig early on to prevent races later due to
+  // implicit initialization in response to threads' first calls to Fontconfig:
+  // http://crbug.com/404311
+  FcInit();
+
+  ChromeBrowserMainPartsPosix::ToolkitInitialized();
+}
+
 void ChromeBrowserMainPartsLinux::PreProfileInit() {
 #if !defined(OS_CHROMEOS)
   // Needs to be called after we have chrome::DIR_USER_DATA and
index 37f35ce..9d9a92a 100644 (file)
@@ -17,6 +17,7 @@ class ChromeBrowserMainPartsLinux : public ChromeBrowserMainPartsPosix {
   virtual ~ChromeBrowserMainPartsLinux();
 
   // ChromeBrowserMainParts overrides.
+  virtual void ToolkitInitialized() OVERRIDE;
   virtual void PreProfileInit() OVERRIDE;
   virtual void PostProfileInit() OVERRIDE;
 
index eb4633e..1e5c22e 100644 (file)
@@ -146,7 +146,7 @@ BootTimesLoader::Stats BootTimesLoader::Stats::GetCurrentStats() {
 }
 
 std::string BootTimesLoader::Stats::SerializeToString() const {
-  if (uptime_.empty() || disk_.empty())
+  if (uptime_.empty() && disk_.empty())
     return std::string();
   base::DictionaryValue dictionary;
   dictionary.SetString(kUptime, uptime_);
index 094e5ff..5540993 100644 (file)
@@ -62,7 +62,7 @@ apps::AppWindow* GetCurrentAppWindow(ChromeSyncExtensionFunction* function) {
 }
 
 std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >
-GetLoggedInProfileInfoList(content::WebContents* contents) {
+GetLoggedInProfileInfoList() {
   DCHECK(user_manager::UserManager::IsInitialized());
   const std::vector<Profile*>& profiles =
       g_browser_process->profile_manager()->GetLoadedProfiles();
@@ -89,18 +89,6 @@ GetLoggedInProfileInfoList(content::WebContents* contents) {
     // TODO(hirono): Remove the property from the profile_info.
     profile_info->is_current_profile = true;
 
-    // Make an icon URL of the profile.
-    if (contents) {
-      const gfx::Image& image =
-          ash::GetAvatarImageForContext(contents->GetBrowserContext());
-      const gfx::ImageSkia& skia = image.AsImageSkia();
-      profile_info->profile_image.reset(
-          new api::file_browser_private::ImageSet);
-      profile_info->profile_image->scale1x_url =
-          webui::GetBitmapDataUrl(skia.GetRepresentation(1.0f).sk_bitmap());
-      profile_info->profile_image->scale2x_url =
-          webui::GetBitmapDataUrl(skia.GetRepresentation(2.0f).sk_bitmap());
-    }
     result_profiles.push_back(profile_info);
   }
 
@@ -380,7 +368,7 @@ void FileBrowserPrivateRequestWebStoreAccessTokenFunction::OnAccessTokenFetched(
 
 bool FileBrowserPrivateGetProfilesFunction::RunSync() {
   const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >&
-      profiles = GetLoggedInProfileInfoList(GetAssociatedWebContents());
+      profiles = GetLoggedInProfileInfoList();
 
   // Obtains the display profile ID.
   apps::AppWindow* const app_window = GetCurrentAppWindow(this);
@@ -404,7 +392,7 @@ bool FileBrowserPrivateVisitDesktopFunction::RunSync() {
   using api::file_browser_private::VisitDesktop::Params;
   const scoped_ptr<Params> params(Params::Create(*args_));
   const std::vector<linked_ptr<api::file_browser_private::ProfileInfo> >&
-      profiles = GetLoggedInProfileInfoList(GetAssociatedWebContents());
+      profiles = GetLoggedInProfileInfoList();
 
   chrome::MultiUserWindowManager* const window_manager =
       chrome::MultiUserWindowManager::GetInstance();
index 31c1c38..1c4cb33 100644 (file)
@@ -1221,24 +1221,6 @@ IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, MAYBE_BasicDrive) {
 
 // Slow tests are disabled on debug build. http://crbug.com/327719
 #if !defined(NDEBUG)
-#define MAYBE_PRE_Badge DISABLED_PRE_Badge
-#define MAYBE_Badge DISABLED_Badge
-#else
-#define MAYBE_PRE_Badge PRE_Badge
-#define MAYBE_Badge Badge
-#endif
-IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, MAYBE_PRE_Badge) {
-  AddAllUsers();
-}
-
-IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, MAYBE_Badge) {
-  // Test the profile badge to be correctly shown and hidden.
-  set_test_case_name("multiProfileBadge");
-  StartTest();
-}
-
-// Slow tests are disabled on debug build. http://crbug.com/327719
-#if !defined(NDEBUG)
 #define MAYBE_PRE_VisitDesktopMenu DISABLED_PRE_VisitDesktopMenu
 #define MAYBE_VisitDesktopMenu DISABLED_VisitDesktopMenu
 #else
index 7e6aeae..02757ab 100644 (file)
@@ -153,6 +153,7 @@ std::string DeriveCommandLine(const GURL& start_url,
     ::switches::kDisableWebRtcHWDecoding,
     ::switches::kDisableWebRtcHWEncoding,
     ::switches::kEnableWebRtcHWVp8Encoding,
+    ::switches::kEnableWebRtcHWH264Encoding,
 #endif
     ::switches::kDisableVaapiAcceleratedVideoEncode,
 #if defined(USE_OZONE)
index 7650d1a..d24d75c 100644 (file)
@@ -164,7 +164,7 @@ void AutoEnrollmentController::OnOwnershipStatusCheckDone(
 }
 
 void AutoEnrollmentController::StartClient(
-    const std::vector<std::string>& state_keys) {
+    const std::vector<std::string>& state_keys, bool first_boot) {
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   policy::DeviceManagementService* service =
@@ -185,7 +185,8 @@ void AutoEnrollmentController::StartClient(
   std::string device_id;
   if (GetMode() == MODE_FORCED_RE_ENROLLMENT) {
     retrieve_device_state = true;
-    device_id = state_keys.empty() ? std::string() : state_keys.front();
+    if (!state_keys.empty() && !first_boot)
+      device_id = state_keys.front();
   } else {
     device_id = policy::DeviceCloudPolicyManagerChromeOS::GetMachineID();
   }
index 67f31d5..cb7b2ee 100644 (file)
@@ -75,7 +75,7 @@ class AutoEnrollmentController {
       DeviceSettingsService::OwnershipStatus status);
 
   // Starts the auto-enrollment client.
-  void StartClient(const std::vector<std::string>& state_keys);
+  void StartClient(const std::vector<std::string>& state_keys, bool first_boot);
 
   // Sets |state_| and notifies |progress_callbacks_|.
   void UpdateState(policy::AutoEnrollmentState state);
index 0030ed7..719dd95 100644 (file)
@@ -860,18 +860,18 @@ void ExistingUserController::OnAuthSuccess(const UserContext& user_context) {
   login_performer_->set_delegate(NULL);
   ignore_result(login_performer_.release());
 
+  // Will call OnProfilePrepared() in the end.
+  LoginUtils::Get()->PrepareProfile(user_context,
+                                    has_auth_cookies,
+                                    false,          // Start session for user.
+                                    this);
+
   // Update user's displayed email.
   if (!display_email_.empty()) {
     user_manager::UserManager::Get()->SaveUserDisplayEmail(
         user_context.GetUserID(), display_email_);
     display_email_.clear();
   }
-
-  // Will call OnProfilePrepared() in the end.
-  LoginUtils::Get()->PrepareProfile(user_context,
-                                    has_auth_cookies,
-                                    false,          // Start session for user.
-                                    this);
 }
 
 void ExistingUserController::OnProfilePrepared(Profile* profile) {
index 4eecbd9..a6eff90 100644 (file)
@@ -126,28 +126,16 @@ void ChromeUserSelectionScreen::CheckForPublicSessionLocalePolicyChange(
     }
   }
 
-  if (new_recommended_locales.empty()) {
-    // There are no recommended locales.
-    PublicSessionRecommendedLocaleMap::iterator it =
-        public_session_recommended_locales_.find(user_id);
-    if (it != public_session_recommended_locales_.end()) {
-      // If there previously were recommended locales, remove them from
-      // |public_session_recommended_locales_| and notify the UI.
-      public_session_recommended_locales_.erase(it);
-      SetPublicSessionLocales(user_id, &new_recommended_locales);
-    }
-    return;
-  }
-
-  // There are recommended locales.
   std::vector<std::string>& recommended_locales =
       public_session_recommended_locales_[user_id];
-  if (new_recommended_locales != recommended_locales) {
-    // If the list of recommended locales has changed, update
-    // |public_session_recommended_locales_| and notify the UI.
+
+  if (new_recommended_locales != recommended_locales)
+    SetPublicSessionLocales(user_id, new_recommended_locales);
+
+  if (new_recommended_locales.empty())
+    public_session_recommended_locales_.erase(user_id);
+  else
     recommended_locales = new_recommended_locales;
-    SetPublicSessionLocales(user_id, &new_recommended_locales);
-  }
 }
 
 void ChromeUserSelectionScreen::SetPublicSessionDisplayName(
@@ -164,29 +152,31 @@ void ChromeUserSelectionScreen::SetPublicSessionDisplayName(
 
 void ChromeUserSelectionScreen::SetPublicSessionLocales(
     const std::string& user_id,
-    const std::vector<std::string>* recommended_locales) {
+    const std::vector<std::string>& recommended_locales) {
   if (!handler_initialized_)
     return;
 
   // Construct the list of available locales. This list consists of the
   // recommended locales, followed by all others.
-  scoped_ptr<base::ListValue> locales =
-      GetUILanguageList(recommended_locales, std::string());
+  scoped_ptr<base::ListValue> available_locales =
+      GetUILanguageList(&recommended_locales, std::string());
 
-  // Set the initially selected locale. If the list of recommended locales is
-  // not empty, select its first entry. Otherwise, select the current UI locale.
-  const std::string& default_locale = recommended_locales->empty() ?
-      g_browser_process->GetApplicationLocale() : recommended_locales->front();
+  // Set the initially selected locale to the first recommended locale that is
+  // actually available or the current UI locale if none of them are available.
+  const std::string default_locale = FindMostRelevantLocale(
+      recommended_locales,
+      *available_locales.get(),
+      g_browser_process->GetApplicationLocale());
 
   // Set a flag to indicate whether the list of recommended locales contains at
   // least two entries. This is used to decide whether the public session pod
   // expands to its basic form (for zero or one recommended locales) or the
   // advanced form (two or more recommended locales).
-  const bool two_or_more_recommended_locales = recommended_locales->size() >= 2;
+  const bool two_or_more_recommended_locales = recommended_locales.size() >= 2;
 
   // Notify the UI.
   handler_->SetPublicSessionLocales(user_id,
-                                    locales.Pass(),
+                                    available_locales.Pass(),
                                     default_locale,
                                     two_or_more_recommended_locales);
 }
index 46e71ff..db17645 100644 (file)
@@ -52,7 +52,7 @@ class ChromeUserSelectionScreen
   // of the |recommended_locales| followed by all other available locales.
   void SetPublicSessionLocales(
       const std::string& user_id,
-      const std::vector<std::string>* recommended_locales);
+      const std::vector<std::string>& recommended_locales);
 
   bool handler_initialized_;
 
index 41c3024..be0c782 100644 (file)
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/chromeos/login/screens/user_selection_screen.h"
 
-#include <vector>
-
 #include "ash/shell.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -66,23 +64,27 @@ void AddPublicSessionDetailsToUserDictionaryEntry(
   }
 
   std::vector<std::string> kEmptyRecommendedLocales;
-  const std::vector<std::string>* recommended_locales =
+  const std::vector<std::string>& recommended_locales =
       public_session_recommended_locales ?
-          public_session_recommended_locales : &kEmptyRecommendedLocales;
-
-  // Set |kKeyInitialLocales| to the list of available locales. This list
-  // consists of the recommended locales, followed by all others.
-  user_dict->Set(
-      kKeyInitialLocales,
-      GetUILanguageList(recommended_locales, std::string()).release());
-
-  // Set |kKeyInitialLocale| to the initially selected locale. If the list of
-  // recommended locales is not empty, select its first entry. Otherwise,
-  // select the current UI locale.
-  user_dict->SetString(kKeyInitialLocale,
-                       recommended_locales->empty() ?
-                           g_browser_process->GetApplicationLocale() :
-                           recommended_locales->front());
+          *public_session_recommended_locales : kEmptyRecommendedLocales;
+
+  // Construct the list of available locales. This list consists of the
+  // recommended locales, followed by all others.
+  scoped_ptr<base::ListValue> available_locales =
+      GetUILanguageList(&recommended_locales, std::string());
+
+  // Select the the first recommended locale that is actually available or the
+  // current UI locale if none of them are available.
+  const std::string selected_locale = FindMostRelevantLocale(
+      recommended_locales,
+      *available_locales.get(),
+      g_browser_process->GetApplicationLocale());
+
+  // Set |kKeyInitialLocales| to the list of available locales.
+  user_dict->Set(kKeyInitialLocales, available_locales.release());
+
+  // Set |kKeyInitialLocale| to the initially selected locale.
+  user_dict->SetString(kKeyInitialLocale, selected_locale);
 
   // Set |kKeyInitialMultipleRecommendedLocales| to indicate whether the list
   // of recommended locales contains at least two entries. This is used to
@@ -90,7 +92,7 @@ void AddPublicSessionDetailsToUserDictionaryEntry(
   // or one recommended locales) or the advanced form (two or more recommended
   // locales).
   user_dict->SetBoolean(kKeyInitialMultipleRecommendedLocales,
-                        recommended_locales->size() >= 2);
+                        recommended_locales.size() >= 2);
 
   // Set |kKeyInitialKeyboardLayout| to the current keyboard layout. This
   // value will be used temporarily only because the UI immediately requests a
@@ -362,6 +364,9 @@ void UserSelectionScreen::HandleGetUsers() {
 void UserSelectionScreen::SetAuthType(
     const std::string& username,
     ScreenlockBridge::LockHandler::AuthType auth_type) {
+  DCHECK(GetAuthType(username) !=
+             ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD ||
+         auth_type == ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD);
   user_auth_type_map_[username] = auth_type;
 }
 
index 32aab49..254ef61 100644 (file)
@@ -218,13 +218,7 @@ user_manager::UserList ChromeUserManagerImpl::GetUsersAdmittedForMultiProfile()
       // Users with a policy that prevents them being added to a session will be
       // shown in login UI but will be grayed out.
       // Same applies to owner account (see http://crbug.com/385034).
-      if (check == MultiProfileUserController::ALLOWED ||
-          check == MultiProfileUserController::NOT_ALLOWED_POLICY_FORBIDS ||
-          check == MultiProfileUserController::NOT_ALLOWED_OWNER_AS_SECONDARY ||
-          check ==
-              MultiProfileUserController::NOT_ALLOWED_POLICY_CERT_TAINTED) {
-        result.push_back(*it);
-      }
+      result.push_back(*it);
     }
   }
 
index 077d915..ec2803b 100644 (file)
 #include "net/url_request/url_request_status.h"
 #include "policy/policy_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/icu/source/common/unicode/locid.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/widget/widget.h"
 #include "url/gurl.h"
-//#include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace em = enterprise_management;
 
@@ -190,6 +190,9 @@ const char* kRecommendedLocales2[] = {
   "fr",
   "nl",
 };
+const char* kInvalidRecommendedLocale[] = {
+  "xx",
+};
 const char kPublicSessionLocale[] = "de";
 const char kPublicSessionInputMethodIDTemplate[] = "_comp_ime_%sxkb:de:neo:ger";
 
@@ -377,23 +380,6 @@ bool IsSessionStarted() {
   return user_manager::UserManager::Get()->IsSessionStarted();
 }
 
-// GetKeyboardLayoutsForLocale() posts a task to a background task runner. This
-// method flushes that task runner and the current thread's message loop to
-// ensure that GetKeyboardLayoutsForLocale() is finished.
-void WaitForGetKeyboardLayoutsForLocaleToFinish() {
-  base::SequencedWorkerPool* worker_pool =
-      content::BrowserThread::GetBlockingPool();
-   scoped_refptr<base::SequencedTaskRunner> background_task_runner =
-       worker_pool->GetSequencedTaskRunner(
-           worker_pool->GetNamedSequenceToken(kSequenceToken));
-  base::RunLoop run_loop;
-  background_task_runner->PostTaskAndReply(FROM_HERE,
-                                           base::Bind(&base::DoNothing),
-                                           run_loop.QuitClosure());
-  run_loop.Run();
-  base::RunLoop().RunUntilIdle();
-}
-
 }  // namespace
 
 class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest,
@@ -460,6 +446,9 @@ class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest,
   virtual void SetUpOnMainThread() OVERRIDE {
     DevicePolicyCrosBrowserTest::SetUpOnMainThread();
 
+    initial_locale_ = g_browser_process->GetApplicationLocale();
+    initial_language_ = l10n_util::GetLanguage(initial_locale_);
+
     content::WindowedNotificationObserver(
         chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
         content::NotificationService::AllSources()).Wait();
@@ -655,6 +644,47 @@ class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest,
     WaitForDisplayName(user_id_1_, kDisplayName1);
   }
 
+  void ExpandPublicSessionPod(bool expect_advanced) {
+    bool advanced = false;
+    // Click on the pod to expand it.
+    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+        contents_,
+        base::StringPrintf(
+            "var pod ="
+            "    document.getElementById('pod-row').getPodWithUsername_('%s');"
+            "pod.click();"
+            "domAutomationController.send(pod.classList.contains('advanced'));",
+            user_id_1_.c_str()),
+        &advanced));
+    // Verify that the pod expanded to its basic/advanced form, as expected.
+    EXPECT_EQ(expect_advanced, advanced);
+
+    // Verify that the construction of the pod's language list did not affect
+    // the current ICU locale.
+    EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage());
+  }
+
+  // GetKeyboardLayoutsForLocale() posts a task to a background task runner.
+  // This method flushes that task runner and the current thread's message loop
+  // to ensure that GetKeyboardLayoutsForLocale() is finished.
+  void WaitForGetKeyboardLayoutsForLocaleToFinish() {
+    base::SequencedWorkerPool* worker_pool =
+        content::BrowserThread::GetBlockingPool();
+     scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+         worker_pool->GetSequencedTaskRunner(
+             worker_pool->GetNamedSequenceToken(kSequenceToken));
+    base::RunLoop run_loop;
+    background_task_runner->PostTaskAndReply(FROM_HERE,
+                                             base::Bind(&base::DoNothing),
+                                             run_loop.QuitClosure());
+    run_loop.Run();
+    base::RunLoop().RunUntilIdle();
+
+    // Verify that the construction of the keyboard layout list did not affect
+    // the current ICU locale.
+    EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage());
+  }
+
   void StartLogin(const std::string& locale,
                   const std::string& input_method) {
     // Start login into the device-local account.
@@ -699,6 +729,9 @@ class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest,
   const std::string user_id_2_;
   const std::string public_session_input_method_id_;
 
+  std::string initial_locale_;
+  std::string initial_language_;
+
   scoped_ptr<base::RunLoop> run_loop_;
 
   UserPolicyBuilder device_local_account_policy_;
@@ -1395,26 +1428,12 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, LastWindowClosedLogoutReminder) {
 };
 
 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleNoSwitch) {
-  const std::string initial_locale = g_browser_process->GetApplicationLocale();
-
   UploadAndInstallDeviceLocalAccountPolicy();
   AddPublicSessionToDevicePolicy(kAccountId1);
 
   WaitForPolicy();
 
-  // Click on the pod to expand it. Verify that the pod expands to its basic
-  // form as there are no recommended locales.
-  bool advanced = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      contents_,
-      base::StringPrintf(
-          "var pod ="
-          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
-          "pod.click();"
-          "domAutomationController.send(pod.classList.contains('advanced'));",
-          user_id_1_.c_str()),
-      &advanced));
-  EXPECT_FALSE(advanced);
+  ExpandPublicSessionPod(false);
 
   // Click the enter button to start the session.
   ASSERT_TRUE(content::ExecuteScript(
@@ -1428,7 +1447,8 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleNoSwitch) {
 
   // Verify that the locale has not changed and the first keyboard layout
   // applicable to the locale was chosen.
-  EXPECT_EQ(initial_locale, g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage());
   VerifyKeyboardLayoutMatchesLocale();
 }
 
@@ -1438,22 +1458,11 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleSwitch) {
 
   WaitForPolicy();
 
-  // Click on the pod to expand it. Verify that the pod expands to its basic
-  // form as there are no recommended locales.
-  bool advanced = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      contents_,
-      base::StringPrintf(
-          "var pod ="
-          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
-          "pod.click();"
-          "domAutomationController.send(pod.classList.contains('advanced'));",
-          user_id_1_.c_str()),
-      &advanced));
-  EXPECT_FALSE(advanced);
+  ExpandPublicSessionPod(false);
 
   // Click the link that switches the pod to its advanced form. Verify that the
   // pod switches from basic to advanced.
+  bool advanced = false;
   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
       contents_,
       base::StringPrintf(
@@ -1498,6 +1507,8 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, NoRecommendedLocaleSwitch) {
 
   // Verify that the locale and keyboard layout have been applied.
   EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale),
+            icu::Locale::getDefault().getLanguage());
   EXPECT_EQ(public_session_input_method_id_,
             chromeos::input_method::InputMethodManager::Get()->
                 GetCurrentInputMethod().id());
@@ -1512,19 +1523,7 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, OneRecommendedLocale) {
 
   WaitForPolicy();
 
-  // Click on the pod to expand it. Verify that the pod expands to its basic
-  // form as there is only one recommended locale.
-  bool advanced = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      contents_,
-      base::StringPrintf(
-          "var pod ="
-          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
-          "pod.click();"
-          "domAutomationController.send(pod.classList.contains('advanced'));",
-          user_id_1_.c_str()),
-      &advanced));
-  EXPECT_FALSE(advanced);
+  ExpandPublicSessionPod(false);
 
   // Click the enter button to start the session.
   ASSERT_TRUE(content::ExecuteScript(
@@ -1540,6 +1539,8 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, OneRecommendedLocale) {
   // layout applicable to the locale was chosen.
   EXPECT_EQ(kSingleRecommendedLocale[0],
             g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(l10n_util::GetLanguage(kSingleRecommendedLocale[0]),
+            icu::Locale::getDefault().getLanguage());
   VerifyKeyboardLayoutMatchesLocale();
 }
 
@@ -1552,19 +1553,7 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, MultipleRecommendedLocales) {
 
   WaitForPolicy();
 
-  // Click on the pod to expand it. Verify that the pod expands to its advanced
-  // form directly as there are two or more recommended locales.
-  bool advanced = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      contents_,
-      base::StringPrintf(
-          "var pod ="
-          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
-          "pod.click();"
-          "domAutomationController.send(pod.classList.contains('advanced'));",
-          user_id_1_.c_str()),
-      &advanced));
-  EXPECT_TRUE(advanced);
+  ExpandPublicSessionPod(true);
 
   // Verify that the pod shows a list of locales beginning with the recommended
   // ones, followed by others.
@@ -1727,6 +1716,7 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, MultipleRecommendedLocales) {
   const base::DictionaryValue* state = NULL;
   ASSERT_TRUE(value_ptr);
   ASSERT_TRUE(value_ptr->GetAsDictionary(&state));
+  bool advanced = false;
   EXPECT_TRUE(state->GetBoolean("advanced", &advanced));
   EXPECT_TRUE(advanced);
   EXPECT_TRUE(state->GetString("locale", &selected_locale));
@@ -1747,15 +1737,58 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, MultipleRecommendedLocales) {
 
   // Verify that the locale and keyboard layout have been applied.
   EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale),
+            icu::Locale::getDefault().getLanguage());
   EXPECT_EQ(public_session_input_method_id_,
             chromeos::input_method::InputMethodManager::Get()->
                 GetCurrentInputMethod().id());
 }
 
+IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, InvalidRecommendedLocale) {
+  // Specify an invalid recommended locale.
+  SetRecommendedLocales(kInvalidRecommendedLocale,
+                        arraysize(kInvalidRecommendedLocale));
+  UploadAndInstallDeviceLocalAccountPolicy();
+  AddPublicSessionToDevicePolicy(kAccountId1);
+
+  WaitForPolicy();
+
+  // Click on the pod to expand it. Verify that the pod expands to its basic
+  // form as there is only one recommended locale.
+  bool advanced = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      contents_,
+      base::StringPrintf(
+          "var pod ="
+          "    document.getElementById('pod-row').getPodWithUsername_('%s');"
+          "pod.click();"
+          "domAutomationController.send(pod.classList.contains('advanced'));",
+          user_id_1_.c_str()),
+      &advanced));
+  EXPECT_FALSE(advanced);
+  EXPECT_EQ(l10n_util::GetLanguage(initial_locale_),
+            icu::Locale::getDefault().getLanguage());
+
+  // Click the enter button to start the session.
+  ASSERT_TRUE(content::ExecuteScript(
+      contents_,
+      base::StringPrintf(
+          "document.getElementById('pod-row').getPodWithUsername_('%s')"
+          "    .querySelector('.enter-button').click();",
+          user_id_1_.c_str())));
+
+  WaitForSessionStart();
+
+  // Verify that since the recommended locale was invalid, the locale has not
+  // changed and the first keyboard layout applicable to the locale was chosen.
+  EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(l10n_util::GetLanguage(initial_locale_),
+            icu::Locale::getDefault().getLanguage());
+  VerifyKeyboardLayoutMatchesLocale();
+}
+
 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest,
                        AutoLoginWithoutRecommendedLocales) {
-  const std::string initial_locale = g_browser_process->GetApplicationLocale();
-
   UploadAndInstallDeviceLocalAccountPolicy();
   AddPublicSessionToDevicePolicy(kAccountId1);
   EnableAutoLogin();
@@ -1766,7 +1799,8 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest,
 
   // Verify that the locale has not changed and the first keyboard layout
   // applicable to the locale was chosen.
-  EXPECT_EQ(initial_locale, g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(initial_language_, icu::Locale::getDefault().getLanguage());
   VerifyKeyboardLayoutMatchesLocale();
 }
 
@@ -1785,6 +1819,8 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest,
   // Verify that the first recommended locale has been applied and the first
   // keyboard layout applicable to the locale was chosen.
   EXPECT_EQ(kRecommendedLocales1[0], g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(l10n_util::GetLanguage(kRecommendedLocales1[0]),
+            icu::Locale::getDefault().getLanguage());
   VerifyKeyboardLayoutMatchesLocale();
 }
 
@@ -1872,6 +1908,8 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, TermsOfServiceWithLocaleSwitch) {
 
   // Verify that the locale and keyboard layout have been applied.
   EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale),
+            icu::Locale::getDefault().getLanguage());
   EXPECT_EQ(public_session_input_method_id_,
             chromeos::input_method::InputMethodManager::Get()->
                 GetCurrentInputMethod().id());
@@ -1884,6 +1922,8 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, TermsOfServiceWithLocaleSwitch) {
 
   // Verify that the locale and keyboard layout are still in force.
   EXPECT_EQ(kPublicSessionLocale, g_browser_process->GetApplicationLocale());
+  EXPECT_EQ(l10n_util::GetLanguage(kPublicSessionLocale),
+            icu::Locale::getDefault().getLanguage());
   EXPECT_EQ(public_session_input_method_id_,
             chromeos::input_method::InputMethodManager::Get()->
                 GetCurrentInputMethod().id());
index 5e447e9..a75e7b8 100644 (file)
@@ -207,7 +207,7 @@ void EnrollmentHandlerChromeOS::OnStoreError(CloudPolicyStore* store) {
 }
 
 void EnrollmentHandlerChromeOS::CheckStateKeys(
-    const std::vector<std::string>& state_keys) {
+    const std::vector<std::string>& state_keys, bool /* first_boot */) {
   CHECK_EQ(STEP_STATE_KEYS, enrollment_step_);
 
   // Make sure state keys are available if forced re-enrollment is on.
index 90d6516..275aa2b 100644 (file)
@@ -121,7 +121,8 @@ class EnrollmentHandlerChromeOS : public CloudPolicyClient::Observer,
   };
 
   // Handles the response to a request for server-backed state keys.
-  void CheckStateKeys(const std::vector<std::string>& state_keys);
+  void CheckStateKeys(const std::vector<std::string>& state_keys,
+                      bool first_boot);
 
   // Starts registration if the store is initialized.
   void AttemptRegistration();
index df174e2..99d945d 100644 (file)
@@ -28,6 +28,7 @@ ServerBackedStateKeysBroker::ServerBackedStateKeysBroker(
     scoped_refptr<base::TaskRunner> delayed_task_runner)
     : session_manager_client_(session_manager_client),
       delayed_task_runner_(delayed_task_runner),
+      first_boot_(false),
       requested_(false),
       initial_retrieval_completed_(false),
       weak_factory_(this) {
@@ -53,7 +54,7 @@ void ServerBackedStateKeysBroker::RequestStateKeys(
   }
 
   if (!callback.is_null())
-    callback.Run(state_keys_);
+    callback.Run(state_keys_, first_boot_);
   return;
 }
 
@@ -67,7 +68,7 @@ void ServerBackedStateKeysBroker::FetchStateKeys() {
 }
 
 void ServerBackedStateKeysBroker::StoreStateKeys(
-    const std::vector<std::string>& state_keys) {
+    const std::vector<std::string>& state_keys, bool first_boot) {
   bool send_notification = !initial_retrieval_completed_;
 
   requested_ = false;
@@ -80,6 +81,7 @@ void ServerBackedStateKeysBroker::StoreStateKeys(
   } else {
     send_notification |= state_keys_ != state_keys;
     state_keys_ = state_keys;
+    first_boot_ = first_boot;
   }
 
   if (send_notification)
@@ -92,7 +94,7 @@ void ServerBackedStateKeysBroker::StoreStateKeys(
        callback != callbacks.end();
        ++callback) {
     if (!callback->is_null())
-      callback->Run(state_keys_);
+      callback->Run(state_keys_, first_boot_);
   }
 
   delayed_task_runner_->PostDelayedTask(
index 3711cad..9f9add4 100644 (file)
@@ -30,7 +30,7 @@ namespace policy {
 class ServerBackedStateKeysBroker {
  public:
   typedef scoped_ptr<base::CallbackList<void()>::Subscription> Subscription;
-  typedef base::Callback<void(const std::vector<std::string>&)>
+  typedef base::Callback<void(const std::vector<std::string>&, bool)>
       StateKeysCallback;
 
   ServerBackedStateKeysBroker(
@@ -71,7 +71,8 @@ class ServerBackedStateKeysBroker {
   void FetchStateKeys();
 
   // Stores newly-received state keys and notifies consumers.
-  void StoreStateKeys(const std::vector<std::string>& state_keys);
+  void StoreStateKeys(const std::vector<std::string>& state_keys,
+                      bool first_boot);
 
   chromeos::SessionManagerClient* session_manager_client_;
 
@@ -80,6 +81,9 @@ class ServerBackedStateKeysBroker {
   // The current set of state keys.
   std::vector<std::string> state_keys_;
 
+  // Set to true on first run after factory reset.
+  bool first_boot_;
+
   // Whether a request for state keys is pending.
   bool requested_;
 
index 2dad66b..32ddf18 100644 (file)
@@ -20,6 +20,7 @@ class ServerBackedStateKeysBrokerTest : public testing::Test {
   ServerBackedStateKeysBrokerTest()
       : task_runner_(new base::TestSimpleTaskRunner()),
         broker_(&fake_session_manager_client_, task_runner_),
+        first_boot_(false),
         updated_(false),
         callback_invoked_(false) {
     state_keys_.push_back("1");
@@ -40,9 +41,11 @@ class ServerBackedStateKeysBrokerTest : public testing::Test {
     EXPECT_EQ(state_keys_.front(), broker_.current_state_key());
   }
 
-  void HandleStateKeysCallback(const std::vector<std::string>& state_keys) {
+  void HandleStateKeysCallback(const std::vector<std::string>& state_keys,
+                               bool first_boot) {
     callback_invoked_ = true;
     callback_state_keys_ = state_keys;
+    first_boot_ = first_boot;
   }
 
  protected:
@@ -51,6 +54,7 @@ class ServerBackedStateKeysBrokerTest : public testing::Test {
   chromeos::FakeSessionManagerClient fake_session_manager_client_;
   ServerBackedStateKeysBroker broker_;
   std::vector<std::string> state_keys_;
+  bool first_boot_;
   bool updated_;
   std::vector<std::string> callback_state_keys_;
   bool callback_invoked_;
@@ -133,6 +137,7 @@ TEST_F(ServerBackedStateKeysBrokerTest, Request) {
   base::RunLoop().RunUntilIdle();
   ExpectGood();
   EXPECT_TRUE(callback_invoked_);
+  EXPECT_FALSE(first_boot_);
   EXPECT_EQ(state_keys_, callback_state_keys_);
 }
 
index 1dc5111..d4b4dd0 100644 (file)
@@ -289,6 +289,16 @@ void UserCloudPolicyManagerChromeOS::GetChromePolicy(PolicyMap* policy_map) {
                     new base::StringValue("primary-only"),
                     NULL);
   }
+
+  // Set EasyUnlockAllowed policy to false by default for managed accounts.
+  if (store()->has_policy() &&
+      !policy_map->Get(key::kEasyUnlockAllowed)) {
+    policy_map->Set(key::kEasyUnlockAllowed,
+                    POLICY_LEVEL_MANDATORY,
+                    POLICY_SCOPE_USER,
+                    new base::FundamentalValue(false),
+                    NULL);
+  }
 }
 
 void UserCloudPolicyManagerChromeOS::FetchPolicyOAuthTokenUsingSigninProfile() {
index d25d7dc..980c255 100644 (file)
@@ -115,6 +115,10 @@ class UserCloudPolicyManagerChromeOSTest : public testing::Test {
                     POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
                     new base::StringValue("primary-only"),
                     NULL);
+    policy_map_.Set(key::kEasyUnlockAllowed,
+                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+                    new base::FundamentalValue(false),
+                    NULL);
     expected_bundle_.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
         .CopyFrom(policy_map_);
 
index 744c926..56f9fe6 100644 (file)
@@ -353,7 +353,10 @@ bool TouchpadSettings::Update(const TouchpadSettings& settings,
     if (argv)
       AddTPControlArguments("tapdrag", tap_dragging_.value(), argv);
   }
-  if (natural_scroll_.Update(settings.natural_scroll_)) {
+  natural_scroll_.Update(settings.natural_scroll_);
+  // Always send natural scrolling to the shell command, as a workaround.
+  // See crbug.com/406480
+  if (natural_scroll_.is_set()) {
     updated = true;
     if (argv)
       AddTPControlArguments("australian_scrolling", natural_scroll_.value(),
index fa3c395..213986f 100644 (file)
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
+#include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -134,20 +135,24 @@ void DebugDaemonLogSource::OnGetUserLogFiles(
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   if (succeeded) {
     SystemLogsResponse* response = new SystemLogsResponse;
-    std::vector<Profile*> last_used = ProfileManager::GetLastOpenedProfiles();
-
-    if (last_used.empty() && user_manager::UserManager::IsInitialized() &&
-        user_manager::UserManager::Get()->IsLoggedInAsKioskApp()) {
-      // Use the kiosk app profile explicitly because kiosk session does not
-      // open any browsers thus ProfileManager::GetLastOpenedProfiles returns
-      // an empty |last_used|.
-      last_used.push_back(ProfileManager::GetActiveUserProfile());
+
+    const user_manager::UserList& users =
+        user_manager::UserManager::Get()->GetLoggedInUsers();
+    std::vector<base::FilePath> profile_dirs;
+    for (user_manager::UserList::const_iterator it = users.begin();
+         it != users.end();
+         ++it) {
+      if ((*it)->username_hash().empty())
+        continue;
+      profile_dirs.push_back(
+          chromeos::ProfileHelper::GetProfilePathByUserIdHash(
+              (*it)->username_hash()));
     }
 
     content::BrowserThread::PostBlockingPoolTaskAndReply(
         FROM_HERE,
         base::Bind(&DebugDaemonLogSource::ReadUserLogFiles,
-                   user_log_files, last_used, response),
+                   user_log_files, profile_dirs, response),
         base::Bind(&DebugDaemonLogSource::MergeResponse,
                    weak_ptr_factory_.GetWeakPtr(),
                    base::Owned(response)));
@@ -160,9 +165,9 @@ void DebugDaemonLogSource::OnGetUserLogFiles(
 // static
 void DebugDaemonLogSource::ReadUserLogFiles(
     const KeyValueMap& user_log_files,
-    const std::vector<Profile*>& last_used_profiles,
+    const std::vector<base::FilePath>& profile_dirs,
     SystemLogsResponse* response) {
-  for (size_t i = 0; i < last_used_profiles.size(); ++i) {
+  for (size_t i = 0; i < profile_dirs.size(); ++i) {
     std::string profile_prefix = "Profile[" + base::UintToString(i) + "] ";
     for (KeyValueMap::const_iterator it = user_log_files.begin();
          it != user_log_files.end();
@@ -170,9 +175,8 @@ void DebugDaemonLogSource::ReadUserLogFiles(
       std::string key = it->first;
       std::string value;
       std::string filename = it->second;
-      base::FilePath profile_dir = last_used_profiles[i]->GetPath();
       bool read_success = base::ReadFileToString(
-          profile_dir.Append(filename), &value);
+          profile_dirs[i].Append(filename), &value);
 
       if (read_success && !value.empty())
         (*response)[profile_prefix + key] = value;
index f1c5728..8beb30d 100644 (file)
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/feedback/system_logs/system_logs_fetcher_base.h"
 
@@ -45,7 +46,7 @@ class DebugDaemonLogSource : public SystemLogsSource {
   // the response parameter.
   static void ReadUserLogFiles(
       const KeyValueMap& user_log_files,
-      const std::vector<Profile*>& last_used_profiles,
+      const std::vector<base::FilePath>& profile_dirs,
       SystemLogsResponse* response);
 
   // Merge the responses from ReadUserLogFiles into the main response dict and
index 3d04ec9..663f48e 100644 (file)
@@ -126,7 +126,9 @@ bool MakeWidevineCdmPluginInfo(
   plugin_info->is_out_of_process = true;
   plugin_info->path = path;
   plugin_info->name = kWidevineCdmDisplayName;
-  plugin_info->description = kWidevineCdmDescription;
+  plugin_info->description = kWidevineCdmDescription +
+                             std::string(" (version: ") + version.GetString() +
+                             ")";
   plugin_info->version = version.GetString();
   content::WebPluginMimeType widevine_cdm_mime_type(
       kWidevineCdmPluginMimeType,
index 41b3c9b..0845f92 100644 (file)
@@ -20,6 +20,9 @@ const char kOkayResponse[] = "OKAY";
 const char kHostTransportCommand[] = "host:transport:%s";
 const char kLocalhost[] = "127.0.0.1";
 
+typedef base::Callback<void(int, const std::string&)> CommandCallback;
+typedef base::Callback<void(int, net::StreamSocket*)> SocketCallback;
+
 std::string EncodeMessage(const std::string& message) {
   static const char kHexChars[] = "0123456789ABCDEF";
 
@@ -70,14 +73,14 @@ class AdbTransportSocket : public AdbClientSocket {
   void OnSocketAvailable(int result, const std::string& response) {
     if (!CheckNetResultOrDie(result))
       return;
-    callback_.Run(net::OK, socket_.Pass());
+    callback_.Run(net::OK, socket_.release());
     delete this;
   }
 
   bool CheckNetResultOrDie(int result) {
     if (result >= 0)
       return true;
-    callback_.Run(result, make_scoped_ptr<net::StreamSocket>(NULL));
+    callback_.Run(result, NULL);
     delete this;
     return false;
   }
index f331b02..f0d26ad 100644 (file)
@@ -13,7 +13,7 @@ class AdbClientSocket {
  public:
   typedef base::Callback<void(int, const std::string&)> CommandCallback;
   typedef base::Callback<void(int result,
-                              scoped_ptr<net::StreamSocket>)> SocketCallback;
+                              net::StreamSocket*)> SocketCallback;
 
   static void AdbQuery(int port,
                        const std::string& query,
index c35cdeb..9020d60 100644 (file)
@@ -50,9 +50,9 @@ static void PostSocketCallback(
     scoped_refptr<base::MessageLoopProxy> response_message_loop,
     const AndroidDeviceManager::SocketCallback& callback,
     int result,
-    scoped_ptr<net::StreamSocket> socket) {
-  response_message_loop->PostTask(
-      FROM_HERE, base::Bind(callback, result, base::Passed(&socket)));
+    net::StreamSocket* socket) {
+  response_message_loop->PostTask(FROM_HERE,
+                                  base::Bind(callback, result, socket));
 }
 
 class HttpRequest {
@@ -61,41 +61,39 @@ class HttpRequest {
   typedef AndroidDeviceManager::SocketCallback SocketCallback;
 
   static void CommandRequest(const std::string& request,
-                             const CommandCallback& callback,
-                             int result,
-                             scoped_ptr<net::StreamSocket> socket) {
+                           const CommandCallback& callback,
+                           int result,
+                           net::StreamSocket* socket) {
     if (result != net::OK) {
       callback.Run(result, std::string());
       return;
     }
-    new HttpRequest(socket.Pass(), request, callback);
+    new HttpRequest(socket, request, callback);
   }
 
   static void SocketRequest(const std::string& request,
-                            const SocketCallback& callback,
-                            int result,
-                            scoped_ptr<net::StreamSocket> socket) {
+                          const SocketCallback& callback,
+                          int result,
+                          net::StreamSocket* socket) {
     if (result != net::OK) {
-      callback.Run(result, make_scoped_ptr<net::StreamSocket>(NULL));
+      callback.Run(result, NULL);
       return;
     }
-    new HttpRequest(socket.Pass(), request, callback);
+    new HttpRequest(socket, request, callback);
   }
 
  private:
-  HttpRequest(scoped_ptr<net::StreamSocket> socket,
+  HttpRequest(net::StreamSocket* socket,
               const std::string& request,
               const CommandCallback& callback)
-      : socket_(socket.Pass()),
-        command_callback_(callback),
-        body_pos_(0) {
+      : socket_(socket), command_callback_(callback), body_pos_(0) {
     SendRequest(request);
   }
 
-  HttpRequest(scoped_ptr<net::StreamSocket> socket,
-              const std::string& request,
-              const SocketCallback& callback)
-    : socket_(socket.Pass()),
+  HttpRequest(net::StreamSocket* socket,
+                      const std::string& request,
+                      const SocketCallback& callback)
+    : socket_(socket),
       socket_callback_(callback),
       body_pos_(0) {
     SendRequest(request);
@@ -171,7 +169,7 @@ class HttpRequest {
       if (!command_callback_.is_null())
         command_callback_.Run(net::OK, response_.substr(body_pos_));
       else
-        socket_callback_.Run(net::OK, socket_.Pass());
+        socket_callback_.Run(net::OK, socket_.release());
       delete this;
       return;
     }
@@ -193,7 +191,7 @@ class HttpRequest {
     if (!command_callback_.is_null())
       command_callback_.Run(result, std::string());
     else
-      socket_callback_.Run(result, make_scoped_ptr<net::StreamSocket>(NULL));
+      socket_callback_.Run(result, NULL);
     delete this;
     return false;
   }
index fbc00cd..219e5ce 100644 (file)
@@ -24,8 +24,7 @@ class AndroidDeviceManager
       public base::NonThreadSafe {
  public:
   typedef base::Callback<void(int, const std::string&)> CommandCallback;
-  typedef base::Callback<void(int result, scoped_ptr<net::StreamSocket>)>
-      SocketCallback;
+  typedef base::Callback<void(int result, net::StreamSocket*)> SocketCallback;
   typedef base::Callback<void(const std::vector<std::string>&)> SerialsCallback;
 
   struct BrowserInfo {
@@ -54,21 +53,32 @@ class AndroidDeviceManager
 
   typedef base::Callback<void(const DeviceInfo&)> DeviceInfoCallback;
 
-  class AndroidWebSocket {
+  class AndroidWebSocket : public base::RefCountedThreadSafe<AndroidWebSocket> {
    public:
     class Delegate {
      public:
       virtual void OnSocketOpened() = 0;
       virtual void OnFrameRead(const std::string& message) = 0;
-      virtual void OnSocketClosed() = 0;
+      virtual void OnSocketClosed(bool closed_by_device) = 0;
 
      protected:
       virtual ~Delegate() {}
     };
 
-    virtual ~AndroidWebSocket() {}
+    AndroidWebSocket() {}
 
+    virtual void Connect() = 0;
+    virtual void Disconnect() = 0;
     virtual void SendFrame(const std::string& message) = 0;
+    virtual void ClearDelegate() = 0;
+
+   protected:
+    virtual ~AndroidWebSocket() {}
+
+   private:
+    friend class base::RefCountedThreadSafe<AndroidWebSocket>;
+
+    DISALLOW_COPY_AND_ASSIGN(AndroidWebSocket);
   };
 
   class DeviceProvider;
@@ -93,7 +103,7 @@ class AndroidDeviceManager
                      const std::string& url,
                      const SocketCallback& callback);
 
-    AndroidWebSocket* CreateWebSocket(
+    scoped_refptr<AndroidWebSocket> CreateWebSocket(
         const std::string& socket_name,
         const std::string& url,
         AndroidWebSocket::Delegate* delegate);
index a0054da..81d2627 100644 (file)
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
 #include "chrome/browser/devtools/device/android_device_manager.h"
@@ -19,127 +18,85 @@ namespace {
 
 const int kBufferSize = 16 * 1024;
 
-class WebSocketImpl {
+class WebSocketImpl : public AndroidDeviceManager::AndroidWebSocket {
  public:
-  typedef AndroidDeviceManager::AndroidWebSocket::Delegate Delegate;
-
-  WebSocketImpl(Delegate* delegate,
-                scoped_ptr<net::StreamSocket> socket);
-  void StartListening();
-  void SendFrame(const std::string& message);
-
- private:
-  void OnBytesRead(scoped_refptr<net::IOBuffer> response_buffer, int result);
-  void SendPendingRequests(int result);
-  void Disconnect();
-
-  Delegate* delegate_;
-  scoped_ptr<net::StreamSocket> socket_;
-  std::string response_buffer_;
-  std::string request_buffer_;
-  base::ThreadChecker thread_checker_;
-  DISALLOW_COPY_AND_ASSIGN(WebSocketImpl);
-};
-
-class DelegateWrapper
-    : public AndroidDeviceManager::AndroidWebSocket::Delegate {
- public:
-  DelegateWrapper(base::WeakPtr<Delegate> weak_delegate,
-                  scoped_refptr<base::MessageLoopProxy> message_loop)
-      : weak_delegate_(weak_delegate),
-        message_loop_(message_loop) {
-  }
-
-  virtual ~DelegateWrapper() {}
-
-  // AndroidWebSocket::Delegate implementation
-  virtual void OnSocketOpened() OVERRIDE {
-    message_loop_->PostTask(FROM_HERE,
-        base::Bind(&Delegate::OnSocketOpened, weak_delegate_));
-  }
-
-  virtual void OnFrameRead(const std::string& message) OVERRIDE {
-    message_loop_->PostTask(FROM_HERE,
-        base::Bind(&Delegate::OnFrameRead, weak_delegate_, message));
-  }
-
-  virtual void OnSocketClosed() OVERRIDE {
-    message_loop_->PostTask(FROM_HERE,
-        base::Bind(&Delegate::OnSocketClosed, weak_delegate_));
-  }
+  typedef AndroidDeviceManager::Device Device;
+  WebSocketImpl(scoped_refptr<base::MessageLoopProxy> device_message_loop,
+                scoped_refptr<Device> device,
+                const std::string& socket_name,
+                const std::string& url,
+                Delegate* delegate);
+
+  virtual void Connect() OVERRIDE;
+  virtual void Disconnect() OVERRIDE;
+  virtual void SendFrame(const std::string& message) OVERRIDE;
+  virtual void ClearDelegate() OVERRIDE;
 
  private:
-  base::WeakPtr<Delegate> weak_delegate_;
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
-};
+  friend class base::RefCountedThreadSafe<AndroidWebSocket>;
 
-class AndroidWebSocketImpl
-    : public AndroidDeviceManager::AndroidWebSocket,
-      public AndroidDeviceManager::AndroidWebSocket::Delegate {
- public:
-  typedef AndroidDeviceManager::Device Device;
-  AndroidWebSocketImpl(
-      scoped_refptr<base::MessageLoopProxy> device_message_loop,
-      scoped_refptr<Device> device,
-      const std::string& socket_name,
-      const std::string& url,
-      AndroidWebSocket::Delegate* delegate);
+  virtual ~WebSocketImpl();
 
-  virtual ~AndroidWebSocketImpl();
-
-  // AndroidWebSocket implementation
-  virtual void SendFrame(const std::string& message) OVERRIDE;
+  void Connected(int result, net::StreamSocket* socket);
+  void StartListeningOnHandlerThread();
+  void OnBytesRead(scoped_refptr<net::IOBuffer> response_buffer, int result);
+  void SendFrameOnHandlerThread(const std::string& message);
+  void SendPendingRequests(int result);
+  void DisconnectOnHandlerThread(bool closed_by_device);
 
-  // AndroidWebSocket::Delegate implementation
-  virtual void OnSocketOpened() OVERRIDE;
-  virtual void OnFrameRead(const std::string& message) OVERRIDE;
-  virtual void OnSocketClosed() OVERRIDE;
-
- private:
-  void Connected(int result, scoped_ptr<net::StreamSocket> socket);
+  void OnSocketOpened();
+  void OnFrameRead(const std::string& message);
+  void OnSocketClosed(bool closed_by_device);
 
   scoped_refptr<base::MessageLoopProxy> device_message_loop_;
   scoped_refptr<Device> device_;
   std::string socket_name_;
   std::string url_;
-  WebSocketImpl* connection_;
-  DelegateWrapper* delegate_wrapper_;
-  AndroidWebSocket::Delegate* delegate_;
-  base::WeakPtrFactory<AndroidWebSocketImpl> weak_factory_;
-  DISALLOW_COPY_AND_ASSIGN(AndroidWebSocketImpl);
+  scoped_ptr<net::StreamSocket> socket_;
+  Delegate* delegate_;
+  std::string response_buffer_;
+  std::string request_buffer_;
 };
 
-AndroidWebSocketImpl::AndroidWebSocketImpl(
+WebSocketImpl::WebSocketImpl(
     scoped_refptr<base::MessageLoopProxy> device_message_loop,
     scoped_refptr<Device> device,
     const std::string& socket_name,
     const std::string& url,
-    AndroidWebSocket::Delegate* delegate)
+    Delegate* delegate)
     : device_message_loop_(device_message_loop),
       device_(device),
       socket_name_(socket_name),
       url_(url),
-      delegate_(delegate),
-      weak_factory_(this) {
+      delegate_(delegate) {
+}
+
+void WebSocketImpl::Connect() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(delegate_);
   device_->HttpUpgrade(
-      socket_name_, url_,
-      base::Bind(&AndroidWebSocketImpl::Connected, weak_factory_.GetWeakPtr()));
+      socket_name_, url_, base::Bind(&WebSocketImpl::Connected, this));
 }
 
-void AndroidWebSocketImpl::SendFrame(const std::string& message) {
+void WebSocketImpl::Disconnect() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   device_message_loop_->PostTask(
       FROM_HERE,
-      base::Bind(&WebSocketImpl::SendFrame,
-                 base::Unretained(connection_), message));
+      base::Bind(&WebSocketImpl::DisconnectOnHandlerThread, this, false));
 }
 
 void WebSocketImpl::SendFrame(const std::string& message) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (!socket_)
-    return;
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  device_message_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&WebSocketImpl::SendFrameOnHandlerThread, this, message));
+}
+
+void WebSocketImpl::ClearDelegate() {
+  delegate_ = NULL;
+}
+
+void WebSocketImpl::SendFrameOnHandlerThread(const std::string& message) {
+  DCHECK_EQ(device_message_loop_, base::MessageLoopProxy::current());
   int mask = base::RandInt(0, 0x7FFFFFFF);
   std::string encoded_frame = WebSocket::EncodeFrameHybi17(message, mask);
   request_buffer_ += encoded_frame;
@@ -147,55 +104,43 @@ void WebSocketImpl::SendFrame(const std::string& message) {
     SendPendingRequests(0);
 }
 
-AndroidWebSocketImpl::~AndroidWebSocketImpl() {
+WebSocketImpl::~WebSocketImpl() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  device_message_loop_->DeleteSoon(FROM_HERE, connection_);
-  device_message_loop_->DeleteSoon(FROM_HERE, delegate_wrapper_);
-}
-
-WebSocketImpl::WebSocketImpl(Delegate* delegate,
-                             scoped_ptr<net::StreamSocket> socket)
-                             : delegate_(delegate),
-                               socket_(socket.Pass()) {
-  thread_checker_.DetachFromThread();
 }
 
-void AndroidWebSocketImpl::Connected(int result,
-                                     scoped_ptr<net::StreamSocket> socket) {
+void WebSocketImpl::Connected(int result, net::StreamSocket* socket) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (result != net::OK || socket == NULL) {
-    OnSocketClosed();
+    OnSocketClosed(true);
     return;
   }
-  delegate_wrapper_ = new DelegateWrapper(weak_factory_.GetWeakPtr(),
-                                          base::MessageLoopProxy::current());
-  connection_ = new WebSocketImpl(delegate_wrapper_, socket.Pass());
+  socket_.reset(socket);
   device_message_loop_->PostTask(
       FROM_HERE,
-      base::Bind(&WebSocketImpl::StartListening,
-                 base::Unretained(connection_)));
+      base::Bind(&WebSocketImpl::StartListeningOnHandlerThread, this));
   OnSocketOpened();
 }
 
-void WebSocketImpl::StartListening() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(socket_);
+void WebSocketImpl::StartListeningOnHandlerThread() {
+  DCHECK_EQ(device_message_loop_, base::MessageLoopProxy::current());
   scoped_refptr<net::IOBuffer> response_buffer =
       new net::IOBuffer(kBufferSize);
   int result = socket_->Read(
       response_buffer.get(),
       kBufferSize,
-      base::Bind(&WebSocketImpl::OnBytesRead,
-                 base::Unretained(this), response_buffer));
+      base::Bind(&WebSocketImpl::OnBytesRead, this, response_buffer));
   if (result != net::ERR_IO_PENDING)
     OnBytesRead(response_buffer, result);
 }
 
-void WebSocketImpl::OnBytesRead(scoped_refptr<net::IOBuffer> response_buffer,
-                                int result) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+void WebSocketImpl::OnBytesRead(
+    scoped_refptr<net::IOBuffer> response_buffer, int result) {
+  DCHECK_EQ(device_message_loop_, base::MessageLoopProxy::current());
+  if (!socket_)
+    return;
+
   if (result <= 0) {
-    Disconnect();
+    DisconnectOnHandlerThread(true);
     return;
   }
 
@@ -209,30 +154,32 @@ void WebSocketImpl::OnBytesRead(scoped_refptr<net::IOBuffer> response_buffer,
 
   while (parse_result == WebSocket::FRAME_OK) {
     response_buffer_ = response_buffer_.substr(bytes_consumed);
-    delegate_->OnFrameRead(output);
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+        base::Bind(&WebSocketImpl::OnFrameRead, this, output));
     parse_result = WebSocket::DecodeFrameHybi17(
         response_buffer_, false, &bytes_consumed, &output);
   }
 
   if (parse_result == WebSocket::FRAME_ERROR ||
       parse_result == WebSocket::FRAME_CLOSE) {
-    Disconnect();
+    DisconnectOnHandlerThread(true);
     return;
   }
 
   result = socket_->Read(
       response_buffer.get(),
       kBufferSize,
-      base::Bind(&WebSocketImpl::OnBytesRead,
-                 base::Unretained(this), response_buffer));
+      base::Bind(&WebSocketImpl::OnBytesRead, this, response_buffer));
   if (result != net::ERR_IO_PENDING)
     OnBytesRead(response_buffer, result);
 }
 
 void WebSocketImpl::SendPendingRequests(int result) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_EQ(device_message_loop_, base::MessageLoopProxy::current());
+  if (!socket_)
+    return;
   if (result < 0) {
-    Disconnect();
+    DisconnectOnHandlerThread(true);
     return;
   }
   request_buffer_ = request_buffer_.substr(result);
@@ -243,39 +190,43 @@ void WebSocketImpl::SendPendingRequests(int result) {
       new net::StringIOBuffer(request_buffer_);
   result = socket_->Write(buffer.get(), buffer->size(),
                           base::Bind(&WebSocketImpl::SendPendingRequests,
-                                     base::Unretained(this)));
+                                     this));
   if (result != net::ERR_IO_PENDING)
     SendPendingRequests(result);
 }
 
-void WebSocketImpl::Disconnect() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  socket_.reset();
-  delegate_->OnSocketClosed();
+void WebSocketImpl::DisconnectOnHandlerThread(bool closed_by_device) {
+  DCHECK_EQ(device_message_loop_, base::MessageLoopProxy::current());
+  if (!socket_)
+    return;
+  // Wipe out socket_ first since Disconnect can re-enter this method.
+  scoped_ptr<net::StreamSocket> socket(socket_.release());
+  socket->Disconnect();
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+      base::Bind(&WebSocketImpl::OnSocketClosed, this, closed_by_device));
 }
 
-void AndroidWebSocketImpl::OnSocketOpened() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  delegate_->OnSocketOpened();
+void WebSocketImpl::OnSocketOpened() {
+  if (delegate_)
+    delegate_->OnSocketOpened();
 }
 
-void AndroidWebSocketImpl::OnFrameRead(const std::string& message) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  delegate_->OnFrameRead(message);
+void WebSocketImpl::OnFrameRead(const std::string& message) {
+  if (delegate_)
+    delegate_->OnFrameRead(message);
 }
 
-void AndroidWebSocketImpl::OnSocketClosed() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  delegate_->OnSocketClosed();
+void WebSocketImpl::OnSocketClosed(bool closed_by_device) {
+  if (delegate_)
+    delegate_->OnSocketClosed(closed_by_device);
 }
 
 }  // namespace
 
-AndroidDeviceManager::AndroidWebSocket*
+scoped_refptr<AndroidDeviceManager::AndroidWebSocket>
 AndroidDeviceManager::Device::CreateWebSocket(
     const std::string& socket,
     const std::string& url,
     AndroidDeviceManager::AndroidWebSocket::Delegate* delegate) {
-  return new AndroidWebSocketImpl(
-      device_message_loop_, this, socket, url, delegate);
+  return new WebSocketImpl(device_message_loop_, this, socket, url, delegate);
 }
index e58a857..c25c469 100644 (file)
@@ -186,12 +186,11 @@ class ProtocolCommand
  private:
   virtual void OnSocketOpened() OVERRIDE;
   virtual void OnFrameRead(const std::string& message) OVERRIDE;
-  virtual void OnSocketClosed() OVERRIDE;
-  virtual ~ProtocolCommand();
+  virtual void OnSocketClosed(bool closed_by_device) OVERRIDE;
 
   const std::string command_;
   const base::Closure callback_;
-  scoped_ptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
+  scoped_refptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
 
   DISALLOW_COPY_AND_ASSIGN(ProtocolCommand);
 };
@@ -202,8 +201,9 @@ ProtocolCommand::ProtocolCommand(
     const std::string& command,
     const base::Closure callback)
     : command_(command),
-      callback_(callback),
-      web_socket_(browser->CreateWebSocket(debug_url, this)) {
+      callback_(callback){
+  web_socket_ = browser->CreateWebSocket(debug_url, this);
+  web_socket_->Connect();
 }
 
 void ProtocolCommand::OnSocketOpened() {
@@ -211,16 +211,14 @@ void ProtocolCommand::OnSocketOpened() {
 }
 
 void ProtocolCommand::OnFrameRead(const std::string& message) {
-  delete this;
-}
-
-void ProtocolCommand::OnSocketClosed() {
-  delete this;
+  web_socket_->Disconnect();
 }
 
-ProtocolCommand::~ProtocolCommand() {
-  if (!callback_.is_null())
+void ProtocolCommand::OnSocketClosed(bool closed_by_device) {
+  if (!callback_.is_null()) {
     callback_.Run();
+  }
+  delete this;
 }
 
 }  // namespace
@@ -293,15 +291,14 @@ class AgentHostDelegate
       const std::string& message) OVERRIDE;
   virtual void OnSocketOpened() OVERRIDE;
   virtual void OnFrameRead(const std::string& message) OVERRIDE;
-  virtual void OnSocketClosed() OVERRIDE;
+  virtual void OnSocketClosed(bool closed_by_device) OVERRIDE;
 
   const std::string id_;
-  scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser_;
-  const std::string debug_url_;
   bool socket_opened_;
+  bool detached_;
   bool is_web_view_;
   std::vector<std::string> pending_messages_;
-  scoped_ptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
+  scoped_refptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
   content::DevToolsAgentHost* agent_host_;
   content::DevToolsExternalAgentProxy* proxy_;
   DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate);
@@ -330,10 +327,10 @@ AgentHostDelegate::AgentHostDelegate(
     scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
     const std::string& debug_url)
     : id_(id),
-      browser_(browser),
-      debug_url_(debug_url),
       socket_opened_(false),
+      detached_(false),
       is_web_view_(browser->IsWebView()),
+      web_socket_(browser->CreateWebSocket(debug_url, this)),
       agent_host_(NULL),
       proxy_(NULL) {
   g_host_delegates.Get()[id] = this;
@@ -341,17 +338,20 @@ AgentHostDelegate::AgentHostDelegate(
 
 AgentHostDelegate::~AgentHostDelegate() {
   g_host_delegates.Get().erase(id_);
+  web_socket_->ClearDelegate();
 }
 
 void AgentHostDelegate::Attach(content::DevToolsExternalAgentProxy* proxy) {
   proxy_ = proxy;
   content::RecordAction(base::UserMetricsAction(is_web_view_ ?
       "DevTools_InspectAndroidWebView" : "DevTools_InspectAndroidPage"));
-  web_socket_.reset(browser_->CreateWebSocket(debug_url_, this));
+  web_socket_->Connect();
 }
 
 void AgentHostDelegate::Detach() {
-  web_socket_.reset();
+  detached_ = true;
+  if (socket_opened_)
+    web_socket_->Disconnect();
 }
 
 void AgentHostDelegate::SendMessageToBackend(const std::string& message) {
@@ -362,6 +362,11 @@ void AgentHostDelegate::SendMessageToBackend(const std::string& message) {
 }
 
 void AgentHostDelegate::OnSocketOpened() {
+  if (detached_) {
+    web_socket_->Disconnect();
+    return;
+  }
+
   socket_opened_ = true;
   for (std::vector<std::string>::iterator it = pending_messages_.begin();
        it != pending_messages_.end(); ++it) {
@@ -375,8 +380,8 @@ void AgentHostDelegate::OnFrameRead(const std::string& message) {
       proxy_->DispatchOnClientHost(message);
 }
 
-void AgentHostDelegate::OnSocketClosed() {
-  if (proxy_)
+void AgentHostDelegate::OnSocketClosed(bool closed_by_device) {
+  if (proxy_ && closed_by_device)
     proxy_->ConnectionClosed();
 }
 
@@ -609,7 +614,7 @@ DevToolsAndroidBridge::RemoteBrowser::GetAgentHost() {
       "adb:" + device_->serial() + ":" + socket_, this, kBrowserTargetSocket);
 }
 
-DevToolsAndroidBridge::AndroidWebSocket*
+scoped_refptr<DevToolsAndroidBridge::AndroidWebSocket>
 DevToolsAndroidBridge::RemoteBrowser::CreateWebSocket(
     const std::string& url,
     DevToolsAndroidBridge::AndroidWebSocket::Delegate* delegate) {
index b9cbb76..ddc34bb 100644 (file)
@@ -121,7 +121,7 @@ class DevToolsAndroidBridge
 
     scoped_refptr<content::DevToolsAgentHost> GetAgentHost();
 
-    AndroidWebSocket* CreateWebSocket(
+    scoped_refptr<AndroidWebSocket> CreateWebSocket(
         const std::string& url,
         DevToolsAndroidBridge::AndroidWebSocket::Delegate* delegate);
 
index 35c3652..df610d1 100644 (file)
@@ -59,11 +59,11 @@ class SocketTunnel : public base::NonThreadSafe {
                           int port,
                           const CounterCallback& callback,
                           int result,
-                          scoped_ptr<net::StreamSocket> socket) {
+                          net::StreamSocket* socket) {
     if (result < 0)
       return;
     SocketTunnel* tunnel = new SocketTunnel(callback);
-    tunnel->Start(socket.Pass(), host, port);
+    tunnel->Start(socket, host, port);
   }
 
  private:
@@ -75,9 +75,8 @@ class SocketTunnel : public base::NonThreadSafe {
     callback_.Run(1);
   }
 
-  void Start(scoped_ptr<net::StreamSocket> socket,
-             const std::string& host, int port) {
-    remote_socket_.swap(socket);
+  void Start(net::StreamSocket* socket, const std::string& host, int port) {
+    remote_socket_.reset(socket);
 
     host_resolver_ = net::HostResolver::CreateDefaultResolver(NULL);
     net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port));
@@ -255,13 +254,15 @@ FindBestBrowserForTethering(
 }  // namespace
 
 class PortForwardingController::Connection
-    : public DevToolsAndroidBridge::AndroidWebSocket::Delegate {
+    : public DevToolsAndroidBridge::AndroidWebSocket::Delegate,
+      public base::RefCountedThreadSafe<
+          Connection,
+          content::BrowserThread::DeleteOnUIThread> {
  public:
   Connection(Registry* registry,
              scoped_refptr<DevToolsAndroidBridge::RemoteDevice> device,
              scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
              const ForwardingMap& forwarding_map);
-  virtual ~Connection();
 
   const PortStatusMap& GetPortStatusMap();
 
@@ -274,6 +275,7 @@ class PortForwardingController::Connection
       content::BrowserThread::UI>;
   friend class base::DeleteHelper<Connection>;
 
+  virtual ~Connection();
 
   typedef std::map<int, std::string> ForwardingMap;
 
@@ -290,25 +292,23 @@ class PortForwardingController::Connection
   void ProcessBindResponse(int port, PortStatus status);
   void ProcessUnbindResponse(int port, PortStatus status);
 
-  static void UpdateSocketCountOnHandlerThread(
-      base::WeakPtr<Connection> weak_connection, int port, int increment);
+  void UpdateSocketCountOnHandlerThread(int port, int increment);
   void UpdateSocketCount(int port, int increment);
 
   // DevToolsAndroidBridge::AndroidWebSocket::Delegate implementation:
   virtual void OnSocketOpened() OVERRIDE;
   virtual void OnFrameRead(const std::string& message) OVERRIDE;
-  virtual void OnSocketClosed() OVERRIDE;
+  virtual void OnSocketClosed(bool closed_by_device) OVERRIDE;
 
   PortForwardingController::Registry* registry_;
   scoped_refptr<DevToolsAndroidBridge::RemoteDevice> device_;
   scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser_;
-  scoped_ptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
+  scoped_refptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
   int command_id_;
   bool connected_;
   ForwardingMap forwarding_map_;
   CommandCallbackMap pending_responses_;
   PortStatusMap port_status_;
-  base::WeakPtrFactory<Connection> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(Connection);
 };
@@ -323,18 +323,27 @@ PortForwardingController::Connection::Connection(
       browser_(browser),
       command_id_(0),
       connected_(false),
-      forwarding_map_(forwarding_map),
-      weak_factory_(this) {
+      forwarding_map_(forwarding_map) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   (*registry_)[device_->serial()] = this;
-  web_socket_.reset(
-      browser->CreateWebSocket(kDevToolsRemoteBrowserTarget, this));
+  web_socket_ = browser->CreateWebSocket(kDevToolsRemoteBrowserTarget, this);
+  web_socket_->Connect();
+  AddRef();  // Balanced in OnSocketClosed();
+}
+
+void PortForwardingController::Connection::Shutdown() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  registry_ = NULL;
+  // This will have no effect if the socket is not connected yet.
+  web_socket_->Disconnect();
 }
 
 PortForwardingController::Connection::~Connection() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(registry_->find(device_->serial()) != registry_->end());
-  registry_->erase(device_->serial());
+  if (registry_) {
+    DCHECK(registry_->find(device_->serial()) != registry_->end());
+    registry_->erase(device_->serial());
+  }
 }
 
 void PortForwardingController::Connection::UpdateForwardingMap(
@@ -431,12 +440,10 @@ void PortForwardingController::Connection::ProcessUnbindResponse(
     port_status_.erase(it);
 }
 
-// static
 void PortForwardingController::Connection::UpdateSocketCountOnHandlerThread(
-    base::WeakPtr<Connection> weak_connection, int port, int increment) {
+    int port, int increment) {
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-     base::Bind(&Connection::UpdateSocketCount,
-                weak_connection, port, increment));
+     base::Bind(&Connection::UpdateSocketCount, this, port, increment));
 }
 
 void PortForwardingController::Connection::UpdateSocketCount(
@@ -460,12 +467,19 @@ PortForwardingController::Connection::GetPortStatusMap() {
 
 void PortForwardingController::Connection::OnSocketOpened() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (!registry_) {
+    // Socket was created after Shutdown was called. Disconnect immediately.
+    web_socket_->Disconnect();
+    return;
+  }
   connected_ = true;
   SerializeChanges(kTetheringBind, ForwardingMap(), forwarding_map_);
 }
 
-void PortForwardingController::Connection::OnSocketClosed() {
-  delete this;
+void PortForwardingController::Connection::OnSocketClosed(
+    bool closed_by_device) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  Release();  // Balanced in the constructor.
 }
 
 void PortForwardingController::Connection::OnFrameRead(
@@ -505,8 +519,7 @@ void PortForwardingController::Connection::OnFrameRead(
   std::string destination_host = tokens[0];
 
   SocketTunnel::CounterCallback callback =
-      base::Bind(&Connection::UpdateSocketCountOnHandlerThread,
-                 weak_factory_.GetWeakPtr(), port);
+      base::Bind(&Connection::UpdateSocketCountOnHandlerThread, this, port);
 
   device_->OpenSocket(
       connection_id.c_str(),
@@ -593,7 +606,7 @@ void PortForwardingController::OnPrefsChange() {
     UpdateConnections();
   } else {
     StopListening();
-    STLDeleteValues(&registry_);
+    ShutdownConnections();
     NotifyListeners(DevicesStatus());
   }
 }
@@ -624,6 +637,12 @@ void PortForwardingController::UpdateConnections() {
     it->second->UpdateForwardingMap(forwarding_map_);
 }
 
+void PortForwardingController::ShutdownConnections() {
+  for (Registry::iterator it = registry_.begin(); it != registry_.end(); ++it)
+    it->second->Shutdown();
+  registry_.clear();
+}
+
 void PortForwardingController::NotifyListeners(
     const DevicesStatus& status) const {
   Listeners copy(listeners_);  // Iterate over copy.
index a904ef5..ae491d7 100644 (file)
@@ -77,6 +77,7 @@ class PortForwardingController
   void StopListening();
 
   void UpdateConnections();
+  void ShutdownConnections();
 
   void NotifyListeners(const DevicesStatus& status) const;
 
index f6930b5..ee0f043 100644 (file)
@@ -17,9 +17,9 @@ const char kSerial[] = "local";
 
 static void RunSocketCallback(
     const AndroidDeviceManager::SocketCallback& callback,
-    scoped_ptr<net::StreamSocket> socket,
+    net::StreamSocket* socket,
     int result) {
-  callback.Run(result, socket.Pass());
+  callback.Run(result, socket);
 }
 
 }  // namespace
@@ -61,8 +61,7 @@ void SelfAsDeviceProvider::OpenSocket(const std::string& serial,
   base::StringToInt(socket_name, &port);
   net::AddressList address_list =
       net::AddressList::CreateFromIPAddress(ip_number, port);
-  scoped_ptr<net::StreamSocket> socket(new net::TCPClientSocket(
-      address_list, NULL, net::NetLog::Source()));
-  socket->Connect(
-      base::Bind(&RunSocketCallback, callback, base::Passed(&socket)));
+  net::TCPClientSocket* socket = new net::TCPClientSocket(
+      address_list, NULL, net::NetLog::Source());
+  socket->Connect(base::Bind(&RunSocketCallback, callback, socket));
 }
index 4931499..93c9429 100644 (file)
@@ -19,12 +19,9 @@ const char kLocalAbstractCommand[] = "localabstract:%s";
 const int kBufferSize = 16 * 1024;
 
 void OnOpenSocket(const UsbDeviceProvider::SocketCallback& callback,
-                  net::StreamSocket* socket_raw,
+                  net::StreamSocket* socket,
                   int result) {
-  scoped_ptr<net::StreamSocket> socket(socket_raw);
-  if (result != net::OK)
-    socket.reset();
-  callback.Run(result, socket.Pass());
+  callback.Run(result, result == net::OK ? socket : NULL);
 }
 
 void OnRead(net::StreamSocket* socket,
@@ -71,8 +68,7 @@ void RunCommand(scoped_refptr<AndroidUsbDevice> device,
     callback.Run(net::ERR_CONNECTION_FAILED, std::string());
     return;
   }
-  int result = socket->Connect(
-      base::Bind(&OpenedForCommand, callback, socket));
+  int result = socket->Connect(base::Bind(&OpenedForCommand, callback, socket));
   if (result != net::ERR_IO_PENDING)
     callback.Run(result, std::string());
 }
@@ -111,21 +107,19 @@ void UsbDeviceProvider::OpenSocket(const std::string& serial,
                                    const SocketCallback& callback) {
   UsbDeviceMap::iterator it = device_map_.find(serial);
   if (it == device_map_.end()) {
-    callback.Run(net::ERR_CONNECTION_FAILED,
-                 make_scoped_ptr<net::StreamSocket>(NULL));
+    callback.Run(net::ERR_CONNECTION_FAILED, NULL);
     return;
   }
   std::string socket_name =
       base::StringPrintf(kLocalAbstractCommand, name.c_str());
   net::StreamSocket* socket = it->second->CreateSocket(socket_name);
   if (!socket) {
-    callback.Run(net::ERR_CONNECTION_FAILED,
-                 make_scoped_ptr<net::StreamSocket>(NULL));
+    callback.Run(net::ERR_CONNECTION_FAILED, NULL);
     return;
   }
   int result = socket->Connect(base::Bind(&OnOpenSocket, callback, socket));
   if (result != net::ERR_IO_PENDING)
-    callback.Run(result, make_scoped_ptr<net::StreamSocket>(NULL));
+    callback.Run(result, NULL);
 }
 
 void UsbDeviceProvider::ReleaseDevice(const std::string& serial) {
index 0809074..5b4f267 100644 (file)
@@ -6,7 +6,10 @@
 
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
 #include "components/domain_reliability/service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "content/public/browser/browser_context.h"
@@ -56,6 +59,11 @@ KeyedService* DomainReliabilityServiceFactory::BuildServiceInstanceFor(
   if (!IsDomainReliabilityMonitoringEnabled())
     return NULL;
 
+  if (!g_browser_process->local_state()->GetBoolean(
+          prefs::kMetricsReportingEnabled)) {
+    return NULL;
+  }
+
   return DomainReliabilityService::Create(
       kDomainReliabilityUploadReporterString);
 }
index 0f578ac..797596b 100644 (file)
@@ -242,6 +242,9 @@ bool AppWindowCreateFunction::RunAsync() {
 
     if (options->alpha_enabled.get()) {
       const char* whitelist[] = {
+#if defined(OS_CHROMEOS)
+        "B58B99751225318C7EB8CF4688B5434661083E07",  // http://crbug.com/410550
+#endif
         "0F42756099D914A026DADFA182871C015735DD95",  // http://crbug.com/323773
         "2D22CDB6583FD0A13758AEBE8B15E45208B4E9A7",
         "E7E2461CE072DF036CF9592740196159E2D7C089",  // http://crbug.com/356200
index eefdbbf..cbd8f83 100644 (file)
@@ -436,11 +436,13 @@ void BluetoothSocketListenUsingL2capFunction::CreateResults() {
   results_ = bluetooth_socket::ListenUsingL2cap::Results::Create();
 }
 
-BluetoothSocketConnectFunction::BluetoothSocketConnectFunction() {}
+BluetoothSocketAbstractConnectFunction::
+    BluetoothSocketAbstractConnectFunction() {}
 
-BluetoothSocketConnectFunction::~BluetoothSocketConnectFunction() {}
+BluetoothSocketAbstractConnectFunction::
+    ~BluetoothSocketAbstractConnectFunction() {}
 
-bool BluetoothSocketConnectFunction::Prepare() {
+bool BluetoothSocketAbstractConnectFunction::Prepare() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   params_ = bluetooth_socket::Connect::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params_.get());
@@ -449,13 +451,13 @@ bool BluetoothSocketConnectFunction::Prepare() {
   return socket_event_dispatcher_ != NULL;
 }
 
-void BluetoothSocketConnectFunction::AsyncWorkStart() {
+void BluetoothSocketAbstractConnectFunction::AsyncWorkStart() {
   DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
   device::BluetoothAdapterFactory::GetAdapter(
-      base::Bind(&BluetoothSocketConnectFunction::OnGetAdapter, this));
+      base::Bind(&BluetoothSocketAbstractConnectFunction::OnGetAdapter, this));
 }
 
-void BluetoothSocketConnectFunction::OnGetAdapter(
+void BluetoothSocketAbstractConnectFunction::OnGetAdapter(
     scoped_refptr<device::BluetoothAdapter> adapter) {
   DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
   BluetoothApiSocket* socket = GetSocket(params_->socket_id);
@@ -486,13 +488,10 @@ void BluetoothSocketConnectFunction::OnGetAdapter(
     return;
   }
 
-  device->ConnectToService(
-      uuid,
-      base::Bind(&BluetoothSocketConnectFunction::OnConnect, this),
-      base::Bind(&BluetoothSocketConnectFunction::OnConnectError, this));
+  ConnectToService(device, uuid);
 }
 
-void BluetoothSocketConnectFunction::OnConnect(
+void BluetoothSocketAbstractConnectFunction::OnConnect(
     scoped_refptr<device::BluetoothSocket> socket) {
   DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
 
@@ -516,13 +515,26 @@ void BluetoothSocketConnectFunction::OnConnect(
   AsyncWorkCompleted();
 }
 
-void BluetoothSocketConnectFunction::OnConnectError(
+void BluetoothSocketAbstractConnectFunction::OnConnectError(
     const std::string& message) {
   DCHECK(BrowserThread::CurrentlyOn(work_thread_id()));
   error_ = message;
   AsyncWorkCompleted();
 }
 
+BluetoothSocketConnectFunction::BluetoothSocketConnectFunction() {}
+
+BluetoothSocketConnectFunction::~BluetoothSocketConnectFunction() {}
+
+void BluetoothSocketConnectFunction::ConnectToService(
+    device::BluetoothDevice* device,
+    const device::BluetoothUUID& uuid) {
+  device->ConnectToService(
+      uuid,
+      base::Bind(&BluetoothSocketConnectFunction::OnConnect, this),
+      base::Bind(&BluetoothSocketConnectFunction::OnConnectError, this));
+}
+
 BluetoothSocketDisconnectFunction::BluetoothSocketDisconnectFunction() {}
 
 BluetoothSocketDisconnectFunction::~BluetoothSocketDisconnectFunction() {}
index 9ed7406..34da64b 100644 (file)
@@ -208,29 +208,49 @@ class BluetoothSocketListenUsingL2capFunction
   scoped_ptr<bluetooth_socket::ListenUsingL2cap::Params> params_;
 };
 
-class BluetoothSocketConnectFunction : public BluetoothSocketAsyncApiFunction {
+class BluetoothSocketAbstractConnectFunction :
+    public BluetoothSocketAsyncApiFunction {
  public:
-  DECLARE_EXTENSION_FUNCTION("bluetoothSocket.connect",
-                             BLUETOOTHSOCKET_CONNECT);
-
-  BluetoothSocketConnectFunction();
+  BluetoothSocketAbstractConnectFunction();
 
  protected:
-  virtual ~BluetoothSocketConnectFunction();
+  virtual ~BluetoothSocketAbstractConnectFunction();
 
   // BluetoothSocketAsyncApiFunction:
   virtual bool Prepare() OVERRIDE;
   virtual void AsyncWorkStart() OVERRIDE;
 
- private:
-  virtual void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter);
+  // Subclasses should implement this method to connect to the service
+  // registered with |uuid| on the |device|.
+  virtual void ConnectToService(device::BluetoothDevice* device,
+                                const device::BluetoothUUID& uuid) = 0;
+
   virtual void OnConnect(scoped_refptr<device::BluetoothSocket> socket);
   virtual void OnConnectError(const std::string& message);
 
+ private:
+  virtual void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter);
+
   scoped_ptr<bluetooth_socket::Connect::Params> params_;
   BluetoothSocketEventDispatcher* socket_event_dispatcher_;
 };
 
+class BluetoothSocketConnectFunction :
+    public BluetoothSocketAbstractConnectFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("bluetoothSocket.connect",
+                             BLUETOOTHSOCKET_CONNECT);
+
+  BluetoothSocketConnectFunction();
+
+ protected:
+  virtual ~BluetoothSocketConnectFunction();
+
+  // BluetoothSocketAbstractConnectFunction:
+  virtual void ConnectToService(device::BluetoothDevice* device,
+                                const device::BluetoothUUID& uuid) OVERRIDE;
+};
+
 class BluetoothSocketDisconnectFunction
     : public BluetoothSocketAsyncApiFunction {
  public:
index 2c242b1..2864688 100644 (file)
@@ -60,6 +60,8 @@ EasyUnlockScreenlockStateHandler::State ToScreenlockStateHandlerState(
       return EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE;
     case easy_unlock_private::STATE_PHONE_NOT_NEARBY:
       return EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY;
+    case easy_unlock_private::STATE_PHONE_UNSUPPORTED:
+      return EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED;
     case easy_unlock_private::STATE_AUTHENTICATED:
       return EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED;
     default:
@@ -401,6 +403,26 @@ void EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction::OnSeekCompleted(
   }
 }
 
+EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
+    EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {}
+
+EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
+    ~EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction() {}
+
+void EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
+    ConnectToService(device::BluetoothDevice* device,
+                     const device::BluetoothUUID& uuid) {
+  easy_unlock::ConnectToBluetoothServiceInsecurely(
+      device,
+      uuid,
+      base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
+                     OnConnect,
+                 this),
+      base::Bind(&EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction::
+                     OnConnectError,
+                 this));
+}
+
 EasyUnlockPrivateUpdateScreenlockStateFunction::
     EasyUnlockPrivateUpdateScreenlockStateFunction() {}
 
index 215b469..e325ff6 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "chrome/browser/extensions/api/bluetooth_socket/bluetooth_socket_api.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_function.h"
 
@@ -164,6 +165,25 @@ class EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction
       EasyUnlockPrivateSeekBluetoothDeviceByAddressFunction);
 };
 
+class EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction
+    : public BluetoothSocketAbstractConnectFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION(
+      "easyUnlockPrivate.connectToBluetoothServiceInsecurely",
+      EASYUNLOCKPRIVATE_CONNECTTOBLUETOOTHSERVICEINSECURELY)
+  EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction();
+
+ private:
+  virtual ~EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction();
+
+  // BluetoothSocketAbstractConnectFunction:
+  virtual void ConnectToService(device::BluetoothDevice* device,
+                                const device::BluetoothUUID& uuid) OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(
+      EasyUnlockPrivateConnectToBluetoothServiceInsecurelyFunction);
+};
+
 class EasyUnlockPrivateUpdateScreenlockStateFunction
     : public SyncExtensionFunction {
  public:
index 2881152..a8ee859 100644 (file)
@@ -6,6 +6,8 @@
 
 #include "base/callback.h"
 
+using device::BluetoothDevice;
+
 namespace extensions {
 namespace api {
 namespace easy_unlock {
@@ -24,6 +26,14 @@ void SeekBluetoothDeviceByAddress(const std::string& device_address,
   result.error_message = kApiUnavailable;
   callback.Run(result);
 }
+
+void ConnectToBluetoothServiceInsecurely(
+    device::BluetoothDevice* device,
+    const device::BluetoothUUID& uuid,
+    const BluetoothDevice::ConnectToServiceCallback& callback,
+    const BluetoothDevice::ConnectToServiceErrorCallback& error_callback) {
+  error_callback.Run(kApiUnavailable);
+}
 #endif  // !defined(OS_CHROMEOS)
 
 }  // namespace easy_unlock
index 7679ad4..10a0c28 100644 (file)
@@ -8,6 +8,11 @@
 #include <string>
 
 #include "base/callback_forward.h"
+#include "device/bluetooth/bluetooth_device.h"
+
+namespace device {
+class BluetoothUUID;
+}
 
 namespace extensions {
 namespace api {
@@ -28,6 +33,13 @@ typedef base::Callback<void(const SeekDeviceResult& result)> SeekDeviceCallback;
 void SeekBluetoothDeviceByAddress(const std::string& device_address,
                                   const SeekDeviceCallback& callback);
 
+void ConnectToBluetoothServiceInsecurely(
+    device::BluetoothDevice* device,
+    const device::BluetoothUUID& uuid,
+    const device::BluetoothDevice::ConnectToServiceCallback& callback,
+    const device::BluetoothDevice::ConnectToServiceErrorCallback&
+        error_callback);
+
 }  // namespace easy_unlock
 }  // namespace api
 }  // namespace extensions
index e83e9b7..80a8d2b 100644 (file)
@@ -22,6 +22,7 @@
 #include "base/time/time.h"
 #include "content/public/browser/browser_thread.h"
 #include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_device_chromeos.h"
 #include "net/socket/socket_descriptor.h"
 
 namespace extensions {
@@ -119,6 +120,15 @@ void SeekBluetoothDeviceByAddress(const std::string& device_address,
       callback);
 }
 
+void ConnectToBluetoothServiceInsecurely(
+    device::BluetoothDevice* device,
+    const device::BluetoothUUID& uuid,
+    const BluetoothDevice::ConnectToServiceCallback& callback,
+    const BluetoothDevice::ConnectToServiceErrorCallback& error_callback) {
+  static_cast<chromeos::BluetoothDeviceChromeOS*>(device)
+      ->ConnectToServiceInsecurely(uuid, callback, error_callback);
+}
+
 }  // namespace easy_unlock
 }  // namespace api
 }  // namespace extensions
index 5a18d9e..f5b0d11 100644 (file)
@@ -93,7 +93,7 @@ class EasyUnlockPrivateCryptoDelegateChromeOS
   }
 
  private:
-  scoped_ptr<chromeos::EasyUnlockClient> dbus_client_;
+  chromeos::EasyUnlockClient* dbus_client_;
 
   DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateCryptoDelegateChromeOS);
 };
index c579e44..5c0a185 100644 (file)
@@ -48,7 +48,9 @@ const char kUserAccessTokenFailure[] =
 const char kAPINotAvailableForUser[] =
     "The API is not available for this user.";
 const int kObfuscatedGaiaIdTimeoutInDays = 30;
-}
+const char kDeprecationMessage[] =
+    "The chrome.pushMessaging API is deprecated. Use chrome.gcm API instead.";
+}  // namespace
 
 namespace glue = api::push_messaging;
 
@@ -94,6 +96,9 @@ PushMessagingGetChannelIdFunction::PushMessagingGetChannelIdFunction()
 PushMessagingGetChannelIdFunction::~PushMessagingGetChannelIdFunction() {}
 
 bool PushMessagingGetChannelIdFunction::RunAsync() {
+  // Issue a deprecation message.
+  WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING, kDeprecationMessage);
+
   // Fetch the function arguments.
   scoped_ptr<glue::GetChannelId::Params> params(
       glue::GetChannelId::Params::Create(*args_));
index eb7b6e2..f5e44b2 100644 (file)
@@ -57,6 +57,8 @@ screenlock::AuthType FromLockHandlerAuthType(
       // locking.
       NOTREACHED();
       return screenlock::AUTH_TYPE_NONE;
+    case ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD:
+      return screenlock::AUTH_TYPE_OFFLINEPASSWORD;
   }
   NOTREACHED();
   return screenlock::AUTH_TYPE_OFFLINEPASSWORD;
index 9e6b95c..a25e02d 100644 (file)
@@ -29,6 +29,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_message_filter.h"
 #include "extensions/browser/extension_registry.h"
@@ -564,8 +565,12 @@ void ChromeContentBrowserClientExtensionsPart::
   if (!process)
     return;
   DCHECK(profile);
-  if (ProcessMap::Get(profile)->Contains(process->GetID()))
+  if (ProcessMap::Get(profile)->Contains(process->GetID())) {
     command_line->AppendSwitch(switches::kExtensionProcess);
+#if defined(ENABLE_WEBRTC)
+    command_line->AppendSwitch(::switches::kEnableWebRtcHWH264Encoding);
+#endif
+  }
 }
 
 }  // namespace extensions
index 5846380..95e6ab0 100644 (file)
@@ -210,10 +210,17 @@ bool ExtensionDownloader::AddExtension(const Extension& extension,
   if (!ManifestURL::UpdatesFromGallery(&extension))
     update_url_data = delegate_->GetUpdateUrlData(extension.id());
 
-  return AddExtensionData(extension.id(), *extension.version(),
+  std::string install_source;
+  bool force_update = delegate_->ShouldForceUpdate(extension.id(),
+                                                   &install_source);
+  return AddExtensionData(extension.id(),
+                          *extension.version(),
                           extension.GetType(),
                           ManifestURL::GetUpdateURL(&extension),
-                          update_url_data, request_id);
+                          update_url_data,
+                          request_id,
+                          force_update,
+                          install_source);
 }
 
 bool ExtensionDownloader::AddPendingExtension(const std::string& id,
@@ -230,7 +237,9 @@ bool ExtensionDownloader::AddPendingExtension(const std::string& id,
                           Manifest::TYPE_UNKNOWN,
                           update_url,
                           std::string(),
-                          request_id);
+                          request_id,
+                          false,
+                          std::string());
 }
 
 void ExtensionDownloader::StartAllPending(ExtensionCache* cache) {
@@ -273,7 +282,8 @@ void ExtensionDownloader::StartBlacklistUpdate(
                                 version,
                                 &ping_data,
                                 std::string(),
-                                kDefaultInstallSource);
+                                kDefaultInstallSource,
+                                false);
   StartUpdateCheck(blacklist_fetch.Pass());
 }
 
@@ -282,12 +292,15 @@ void ExtensionDownloader::SetWebstoreIdentityProvider(
   identity_provider_.swap(identity_provider);
 }
 
-bool ExtensionDownloader::AddExtensionData(const std::string& id,
-                                           const Version& version,
-                                           Manifest::Type extension_type,
-                                           const GURL& extension_update_url,
-                                           const std::string& update_url_data,
-                                           int request_id) {
+bool ExtensionDownloader::AddExtensionData(
+    const std::string& id,
+    const Version& version,
+    Manifest::Type extension_type,
+    const GURL& extension_update_url,
+    const std::string& update_url_data,
+    int request_id,
+    bool force_update,
+    const std::string& install_source_override) {
   GURL update_url(extension_update_url);
   // Skip extensions with non-empty invalid update URLs.
   if (!update_url.is_empty() && !update_url.is_valid()) {
@@ -353,6 +366,9 @@ bool ExtensionDownloader::AddExtensionData(const std::string& id,
 
     std::string install_source = i == 0 ?
         kDefaultInstallSource : kNotFromWebstoreInstallSource;
+    if (!install_source_override.empty()) {
+      install_source = install_source_override;
+    }
 
     ManifestFetchData::PingData ping_data;
     ManifestFetchData::PingData* optional_ping_data = NULL;
@@ -369,7 +385,8 @@ bool ExtensionDownloader::AddExtensionData(const std::string& id,
       ManifestFetchData* existing_fetch = existing_iter->second.back().get();
       if (existing_fetch->AddExtension(id, version.GetString(),
                                        optional_ping_data, update_url_data,
-                                       install_source)) {
+                                       install_source,
+                                       force_update)) {
         added = true;
       }
     }
@@ -383,7 +400,8 @@ bool ExtensionDownloader::AddExtensionData(const std::string& id,
       added = fetch->AddExtension(id, version.GetString(),
                                   optional_ping_data,
                                   update_url_data,
-                                  install_source);
+                                  install_source,
+                                  force_update);
       DCHECK(added);
     }
   }
@@ -639,12 +657,14 @@ void ExtensionDownloader::DetermineUpdates(
 
       VLOG(2) << id << " is at '" << version << "'";
 
-      Version existing_version(version);
-      Version update_version(update->version);
-
-      if (!update_version.IsValid() ||
-          update_version.CompareTo(existing_version) <= 0) {
-        continue;
+      // We should skip the version check if update was forced.
+      if (!fetch_data.DidForceUpdate(id)) {
+        Version existing_version(version);
+        Version update_version(update->version);
+        if (!update_version.IsValid() ||
+            update_version.CompareTo(existing_version) <= 0) {
+          continue;
+        }
       }
     }
 
index a040986..813a400 100644 (file)
@@ -166,7 +166,9 @@ class ExtensionDownloader
                         Manifest::Type extension_type,
                         const GURL& extension_update_url,
                         const std::string& update_url_data,
-                        int request_id);
+                        int request_id,
+                        bool force_update,
+                        const std::string& install_source_override);
 
   // Adds all recorded stats taken so far to histogram counts.
   void ReportStats() const;
index 2cddee3..ab3f734 100644 (file)
@@ -32,4 +32,10 @@ std::string ExtensionDownloaderDelegate::GetUpdateUrlData(
   return std::string();
 }
 
+bool ExtensionDownloaderDelegate::ShouldForceUpdate(
+    const std::string& id,
+    std::string* source) {
+  return false;
+}
+
 }  // namespace extensions
index a9914c7..03b5ac6 100644 (file)
@@ -111,6 +111,13 @@ class ExtensionDownloaderDelegate {
   // that extension is not installed.
   virtual bool GetExtensionExistingVersion(const std::string& id,
                                            std::string* version) = 0;
+
+  // Determines if a given extension should be forced to update and (if so)
+  // what the source of this forcing is (i.e. what string will be passed
+  // in |installsource| as part of the update query parameters). The default
+  // implementation always returns |false|.
+  virtual bool ShouldForceUpdate(const std::string& id,
+                                 std::string* source);
 };
 
 }  // namespace extensions
index 1c64bc9..3cd89a2 100644 (file)
@@ -8,6 +8,8 @@
 #include <set>
 
 #include "base/bind.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
@@ -22,6 +24,7 @@
 #include "chrome/browser/extensions/pending_extension_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
+#include "components/omaha_query_params/omaha_query_params.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
@@ -40,6 +43,9 @@ using base::RandInt;
 using base::Time;
 using base::TimeDelta;
 using content::BrowserThread;
+using extensions::Extension;
+using extensions::ExtensionSet;
+using omaha_query_params::OmahaQueryParams;
 
 typedef extensions::ExtensionDownloaderDelegate::Error Error;
 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult;
@@ -60,6 +66,10 @@ const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7;  // 7 days
 // checks.
 const int kMinUpdateThrottleTime = 5;
 
+// The installsource query parameter to use when forcing updates due to NaCl
+// arch mismatch.
+const char kWrongMultiCrxInstallSource[] = "wrong_multi_crx";
+
 // When we've computed a days value, we want to make sure we don't send a
 // negative value (due to the system clock being set backwards, etc.), since -1
 // is a special sentinel value that means "never pinged", and other negative
@@ -88,6 +98,73 @@ int CalculateActivePingDays(const Time& last_active_ping_day,
   return SanitizeDays((Time::Now() - last_active_ping_day).InDays());
 }
 
+void RespondWithForcedUpdates(
+    const base::Callback<void(const std::set<std::string>&)>& callback,
+    scoped_ptr<std::set<std::string> > forced_updates) {
+  callback.Run(*forced_updates.get());
+}
+
+void DetermineForcedUpdatesOnBlockingPool(
+    scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions,
+    const base::Callback<void(const std::set<std::string>&)>& callback) {
+  scoped_ptr<std::set<std::string> > forced_updates(
+      new std::set<std::string>());
+  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
+  for (std::vector<scoped_refptr<const Extension> >::const_iterator iter =
+          extensions->begin();
+       iter != extensions->end();
+       ++iter) {
+    scoped_refptr<const Extension> extension = *iter;
+    base::FilePath platform_specific_path = extension->path().Append(
+        extensions::kPlatformSpecificFolder);
+    if (base::PathExists(platform_specific_path)) {
+      bool force = true;
+      base::FileEnumerator all_archs(platform_specific_path,
+                                     false,
+                                     base::FileEnumerator::DIRECTORIES);
+      base::FilePath arch;
+      while (!(arch = all_archs.Next()).empty()) {
+        std::string arch_name = arch.BaseName().AsUTF8Unsafe();
+        std::replace(arch_name.begin(), arch_name.end(), '_', '-');
+        if (arch_name == OmahaQueryParams::GetNaclArch())
+          force = false;
+      }
+
+      if (force)
+        forced_updates->insert(extension->id());
+   }
+  }
+  BrowserThread::PostTask(
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(&RespondWithForcedUpdates,
+                 callback,
+                 base::Passed(&forced_updates)));
+}
+
+void CollectExtensionsFromSet(
+    const ExtensionSet& extensions,
+    std::vector<scoped_refptr<const Extension> >* paths) {
+  std::copy(extensions.begin(), extensions.end(), std::back_inserter(*paths));
+}
+
+void DetermineForcedUpdates(
+    content::BrowserContext* browser_context,
+    const base::Callback<void(const std::set<std::string>&)>& callback) {
+  scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions(
+      new std::vector<scoped_refptr<const Extension> >());
+  const extensions::ExtensionRegistry* registry =
+      extensions::ExtensionRegistry::Get(browser_context);
+  scoped_ptr<ExtensionSet> installed_extensions =
+      registry->GenerateInstalledExtensionsSet();
+  CollectExtensionsFromSet(*installed_extensions.get(), extensions.get());
+  BrowserThread::PostBlockingPoolTask(
+      FROM_HERE,
+      base::Bind(&DetermineForcedUpdatesOnBlockingPool,
+                 base::Passed(&extensions),
+                 callback));
+}
+
 }  // namespace
 
 namespace extensions {
@@ -335,6 +412,16 @@ void ExtensionUpdater::AddToDownloader(
 }
 
 void ExtensionUpdater::CheckNow(const CheckParams& params) {
+  DetermineForcedUpdates(
+      profile_,
+      base::Bind(&ExtensionUpdater::OnForcedUpdatesDetermined,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 params));
+}
+
+void ExtensionUpdater::OnForcedUpdatesDetermined(
+    const CheckParams& params,
+    const std::set<std::string>& forced_updates) {
   int request_id = next_request_id_++;
 
   VLOG(2) << "Starting update check " << request_id;
@@ -349,6 +436,8 @@ void ExtensionUpdater::CheckNow(const CheckParams& params) {
 
   EnsureDownloaderCreated();
 
+  forced_updates_ = forced_updates;
+
   // Add fetch records for extensions that should be fetched by an update URL.
   // These extensions are not yet installed. They come from group policy
   // and external install sources.
@@ -536,6 +625,18 @@ bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id,
   return true;
 }
 
+bool ExtensionUpdater::ShouldForceUpdate(
+    const std::string& extension_id,
+    std::string* source) {
+  bool force = forced_updates_.find(extension_id) != forced_updates_.end();
+  // Currently the only reason to force is a NaCl arch mismatch with the
+  // installed extension contents.
+  if (force) {
+    *source = kWrongMultiCrxInstallSource;
+  }
+  return force;
+}
+
 void ExtensionUpdater::UpdatePingData(const std::string& id,
                                       const PingResult& ping_result) {
   DCHECK(alive_);
index 29faf71..88401da 100644 (file)
@@ -157,6 +157,11 @@ class ExtensionUpdater : public ExtensionDownloaderDelegate,
 
   struct ThrottleInfo;
 
+  // Callback used to continue CheckNow after determining which extensions
+  // should be force-updated.
+  void OnForcedUpdatesDetermined(const CheckParams& params,
+                                 const std::set<std::string>& forced_updates);
+
   // Ensure that we have a valid ExtensionDownloader instance referenced by
   // |downloader|.
   void EnsureDownloaderCreated();
@@ -188,7 +193,6 @@ class ExtensionUpdater : public ExtensionDownloaderDelegate,
       Error error,
       const PingResult& ping,
       const std::set<int>& request_ids) OVERRIDE;
-
   virtual void OnExtensionDownloadFinished(
       const std::string& id,
       const base::FilePath& path,
@@ -197,25 +201,15 @@ class ExtensionUpdater : public ExtensionDownloaderDelegate,
       const std::string& version,
       const PingResult& ping,
       const std::set<int>& request_id) OVERRIDE;
-
-  // Implementation of ExtensionRegistryObserver.
-  virtual void OnExtensionWillBeInstalled(
-      content::BrowserContext* browser_context,
-      const Extension* extension,
-      bool is_update,
-      bool from_ephemeral,
-      const std::string& old_name) OVERRIDE;
-
   virtual bool GetPingDataForExtension(
       const std::string& id,
       ManifestFetchData::PingData* ping_data) OVERRIDE;
-
   virtual std::string GetUpdateUrlData(const std::string& id) OVERRIDE;
-
   virtual bool IsExtensionPending(const std::string& id) OVERRIDE;
-
   virtual bool GetExtensionExistingVersion(const std::string& id,
                                            std::string* version) OVERRIDE;
+  virtual bool ShouldForceUpdate(const std::string& extension_id,
+                                 std::string* source) OVERRIDE;
 
   void UpdatePingData(const std::string& id, const PingResult& ping_result);
 
@@ -227,6 +221,14 @@ class ExtensionUpdater : public ExtensionDownloaderDelegate,
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // Implementation of ExtensionRegistryObserver.
+  virtual void OnExtensionWillBeInstalled(
+      content::BrowserContext* browser_context,
+      const Extension* extension,
+      bool is_update,
+      bool from_ephemeral,
+      const std::string& old_name) OVERRIDE;
+
   // Send a notification that update checks are starting.
   void NotifyStarted();
 
@@ -284,6 +286,10 @@ class ExtensionUpdater : public ExtensionDownloaderDelegate,
   // checks to prevent too many requests from being made.
   std::map<std::string, ThrottleInfo> throttle_info_;
 
+  // Keeps track of extensions (by ID) whose update should be forced during the
+  // next update check.
+  std::set<std::string> forced_updates_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionUpdater);
 };
 
index b6ebb83..b410c91 100644 (file)
@@ -612,6 +612,7 @@ class ExtensionUpdaterTest : public testing::Test {
     EXPECT_TRUE(updater->timer_.IsRunning());
     updater->timer_.Stop();
     updater->TimerFired();
+    content::RunAllBlockingPoolTasksUntilIdle();
   }
 
   // Adds a Result with the given data to results.
@@ -702,7 +703,7 @@ class ExtensionUpdaterTest : public testing::Test {
     // option to appear in the x= parameter.
     ManifestFetchData fetch_data(GURL("http://localhost/foo"), 0);
     fetch_data.AddExtension(
-        id, version, &kNeverPingedData, std::string(), std::string());
+        id, version, &kNeverPingedData, std::string(), std::string(), false);
 
     std::map<std::string, std::string> params;
     VerifyQueryAndExtractParameters(fetch_data.full_url().query(), &params);
@@ -719,7 +720,7 @@ class ExtensionUpdaterTest : public testing::Test {
     // option to appear in the x= parameter.
     ManifestFetchData fetch_data(GURL("http://localhost/foo"), 0);
     fetch_data.AddExtension(
-        id, version, &kNeverPingedData, "bar", std::string());
+        id, version, &kNeverPingedData, "bar", std::string(), false);
     std::map<std::string, std::string> params;
     VerifyQueryAndExtractParameters(fetch_data.full_url().query(), &params);
     EXPECT_EQ(id, params["id"]);
@@ -735,7 +736,7 @@ class ExtensionUpdaterTest : public testing::Test {
     // option to appear in the x= parameter.
     ManifestFetchData fetch_data(GURL("http://localhost/foo"), 0);
     fetch_data.AddExtension(
-        id, version, &kNeverPingedData, "a=1&b=2&c", std::string());
+        id, version, &kNeverPingedData, "a=1&b=2&c", std::string(), false);
     std::map<std::string, std::string> params;
     VerifyQueryAndExtractParameters(fetch_data.full_url().query(), &params);
     EXPECT_EQ(id, params["id"]);
@@ -779,7 +780,7 @@ class ExtensionUpdaterTest : public testing::Test {
     // Make sure that an installsource= appears in the x= parameter.
     ManifestFetchData fetch_data(GURL("http://localhost/foo"), 0);
     fetch_data.AddExtension(id, version, &kNeverPingedData,
-                            kEmptyUpdateUrlData, install_source);
+                            kEmptyUpdateUrlData, install_source, false);
     std::map<std::string, std::string> params;
     VerifyQueryAndExtractParameters(fetch_data.full_url().query(), &params);
     EXPECT_EQ(id, params["id"]);
@@ -805,10 +806,12 @@ class ExtensionUpdaterTest : public testing::Test {
     const std::string id1 = id_util::GenerateId("1");
     const std::string id2 = id_util::GenerateId("2");
     fetch_data.AddExtension(
-        id1, "1.0.0.0", &kNeverPingedData, kEmptyUpdateUrlData, std::string());
+        id1, "1.0.0.0", &kNeverPingedData, kEmptyUpdateUrlData, std::string(),
+        false);
     AddParseResult(id1, "1.1", "http://localhost/e1_1.1.crx", &updates);
     fetch_data.AddExtension(
-        id2, "2.0.0.0", &kNeverPingedData, kEmptyUpdateUrlData, std::string());
+        id2, "2.0.0.0", &kNeverPingedData, kEmptyUpdateUrlData, std::string(),
+        false);
     AddParseResult(id2, "2.0.0.0", "http://localhost/e2_2.0.crx", &updates);
 
     EXPECT_CALL(delegate, IsExtensionPending(_)).WillRepeatedly(Return(false));
@@ -849,7 +852,8 @@ class ExtensionUpdaterTest : public testing::Test {
                               "1.0.0.0",
                               &kNeverPingedData,
                               kEmptyUpdateUrlData,
-                              std::string());
+                              std::string(),
+                              false);
       AddParseResult(*it, "1.1", "http://localhost/e1_1.1.crx", &updates);
     }
 
@@ -883,13 +887,13 @@ class ExtensionUpdaterTest : public testing::Test {
     scoped_ptr<ManifestFetchData> fetch4(new ManifestFetchData(kUpdateUrl, 0));
     ManifestFetchData::PingData zeroDays(0, 0, true);
     fetch1->AddExtension(
-        "1111", "1.0", &zeroDays, kEmptyUpdateUrlData, std::string());
+        "1111", "1.0", &zeroDays, kEmptyUpdateUrlData, std::string(), false);
     fetch2->AddExtension(
-        "2222", "2.0", &zeroDays, kEmptyUpdateUrlData, std::string());
+        "2222", "2.0", &zeroDays, kEmptyUpdateUrlData, std::string(), false);
     fetch3->AddExtension(
-        "3333", "3.0", &zeroDays, kEmptyUpdateUrlData, std::string());
+        "3333", "3.0", &zeroDays, kEmptyUpdateUrlData, std::string(), false);
     fetch4->AddExtension(
-        "4444", "4.0", &zeroDays, kEmptyUpdateUrlData, std::string());
+        "4444", "4.0", &zeroDays, kEmptyUpdateUrlData, std::string(), false);
 
     // This will start the first fetcher and queue the others. The next in queue
     // is started as each fetcher receives its response. Note that the fetchers
@@ -1020,7 +1024,7 @@ class ExtensionUpdaterTest : public testing::Test {
     scoped_ptr<ManifestFetchData> fetch(new ManifestFetchData(kUpdateUrl, 0));
     ManifestFetchData::PingData zeroDays(0, 0, true);
     fetch->AddExtension(
-        "1111", "1.0", &zeroDays, kEmptyUpdateUrlData, std::string());
+        "1111", "1.0", &zeroDays, kEmptyUpdateUrlData, std::string(), false);
 
     // This will start the first fetcher.
     downloader.StartUpdateCheck(fetch.Pass());
@@ -1048,7 +1052,7 @@ class ExtensionUpdaterTest : public testing::Test {
     // should not retry.
     fetch.reset(new ManifestFetchData(kUpdateUrl, 0));
     fetch->AddExtension(
-        "1111", "1.0", &zeroDays, kEmptyUpdateUrlData, std::string());
+        "1111", "1.0", &zeroDays, kEmptyUpdateUrlData, std::string(), false);
 
     // This will start the first fetcher.
     downloader.StartUpdateCheck(fetch.Pass());
@@ -1603,6 +1607,7 @@ class ExtensionUpdaterTest : public testing::Test {
     ExtensionUpdater::CheckParams params;
     updater.Start();
     updater.CheckNow(params);
+    content::RunAllBlockingPoolTasksUntilIdle();
 
     // Make the updater do manifest fetching, and note the urls it tries to
     // fetch.
@@ -1706,7 +1711,8 @@ class ExtensionUpdaterTest : public testing::Test {
                             extension->VersionString(),
                             &kNeverPingedData,
                             kEmptyUpdateUrlData,
-                            std::string());
+                            std::string(),
+                            false);
     UpdateManifest::Results results;
     results.daystart_elapsed_seconds = 750;
 
@@ -1904,6 +1910,7 @@ TEST_F(ExtensionUpdaterTest, TestNonAutoUpdateableLocations) {
   ExtensionUpdater::CheckParams params;
   updater.Start();
   updater.CheckNow(params);
+  content::RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(ExtensionUpdaterTest, TestUpdatingDisabledExtensions) {
@@ -1942,6 +1949,7 @@ TEST_F(ExtensionUpdaterTest, TestUpdatingDisabledExtensions) {
   ExtensionUpdater::CheckParams params;
   updater.Start();
   updater.CheckNow(params);
+  content::RunAllBlockingPoolTasksUntilIdle();
 }
 
 TEST_F(ExtensionUpdaterTest, TestManifestFetchesBuilderAddExtension) {
index 8ed4fe0..dafbdf8 100644 (file)
@@ -67,16 +67,24 @@ bool ManifestFetchData::AddExtension(const std::string& id,
                                      const std::string& version,
                                      const PingData* ping_data,
                                      const std::string& update_url_data,
-                                     const std::string& install_source) {
+                                     const std::string& install_source,
+                                     bool force_update) {
   if (extension_ids_.find(id) != extension_ids_.end()) {
     NOTREACHED() << "Duplicate extension id " << id;
     return false;
   }
 
+  if (force_update)
+    forced_updates_.insert(id);
+
+  // If we want to force an update, we send 0.0.0.0 as the installed version
+  // number.
+  const std::string installed_version = force_update ? "0.0.0.0" : version;
+
   // Compute the string we'd append onto the full_url_, and see if it fits.
   std::vector<std::string> parts;
   parts.push_back("id=" + id);
-  parts.push_back("v=" + version);
+  parts.push_back("v=" + installed_version);
   if (!install_source.empty())
     parts.push_back("installsource=" + install_source);
   parts.push_back("uc");
@@ -163,4 +171,8 @@ void ManifestFetchData::Merge(const ManifestFetchData& other) {
   request_ids_.insert(other.request_ids_.begin(), other.request_ids_.end());
 }
 
+bool ManifestFetchData::DidForceUpdate(const std::string& extension_id) const {
+  return forced_updates_.find(extension_id) != forced_updates_.end();
+}
+
 }  // namespace extensions
index a7eab99..36a77c8 100644 (file)
@@ -56,7 +56,8 @@ class ManifestFetchData {
                     const std::string& version,
                     const PingData* ping_data,
                     const std::string& update_url_data,
-                    const std::string& install_source);
+                    const std::string& install_source,
+                    bool force_update);
 
   const GURL& base_url() const { return base_url_; }
   const GURL& full_url() const { return full_url_; }
@@ -76,6 +77,9 @@ class ManifestFetchData {
   // to this ManifestFetchData).
   void Merge(const ManifestFetchData& other);
 
+  // Returns |true| if a given extension was forced to update.
+  bool DidForceUpdate(const std::string& extension_id) const;
+
  private:
   // The set of extension id's for this ManifestFetchData.
   std::set<std::string> extension_ids_;
@@ -96,6 +100,9 @@ class ManifestFetchData {
   // one ManifestFetchData.
   std::set<int> request_ids_;
 
+  // The set of extension IDs for which this fetch forced a CRX update.
+  std::set<std::string> forced_updates_;
+
   DISALLOW_COPY_AND_ASSIGN(ManifestFetchData);
 };
 
index 82bf26c..947068f 100644 (file)
@@ -207,6 +207,7 @@ MTPDeviceDelegateImplLinux::PendingTaskInfo::~PendingTaskInfo() {
 class MTPDeviceDelegateImplLinux::MTPFileNode {
  public:
   MTPFileNode(uint32 file_id,
+              const std::string& file_name,
               MTPFileNode* parent,
               FileIdToMTPFileNodeMap* file_id_to_node_map);
   ~MTPFileNode();
@@ -222,6 +223,7 @@ class MTPDeviceDelegateImplLinux::MTPFileNode {
   bool DeleteChild(uint32 file_id);
 
   uint32 file_id() const { return file_id_; }
+  const std::string& file_name() const { return file_name_; }
   MTPFileNode* parent() { return parent_; }
 
  private:
@@ -229,6 +231,8 @@ class MTPDeviceDelegateImplLinux::MTPFileNode {
   typedef base::ScopedPtrHashMap<std::string, MTPFileNode> ChildNodes;
 
   const uint32 file_id_;
+  const std::string file_name_;
+
   ChildNodes children_;
   MTPFileNode* const parent_;
   FileIdToMTPFileNodeMap* file_id_to_node_map_;
@@ -238,9 +242,11 @@ class MTPDeviceDelegateImplLinux::MTPFileNode {
 
 MTPDeviceDelegateImplLinux::MTPFileNode::MTPFileNode(
     uint32 file_id,
+    const std::string& file_name,
     MTPFileNode* parent,
     FileIdToMTPFileNodeMap* file_id_to_node_map)
     : file_id_(file_id),
+      file_name_(file_name),
       parent_(parent),
       file_id_to_node_map_(file_id_to_node_map) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@@ -272,7 +278,7 @@ void MTPDeviceDelegateImplLinux::MTPFileNode::EnsureChildExists(
 
   children_.set(
       name,
-      make_scoped_ptr(new MTPFileNode(id, this, file_id_to_node_map_)));
+      make_scoped_ptr(new MTPFileNode(id, name, this, file_id_to_node_map_)));
 }
 
 void MTPDeviceDelegateImplLinux::MTPFileNode::ClearNonexistentChildren(
@@ -309,7 +315,8 @@ MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux(
       task_in_progress_(false),
       device_path_(device_location),
       root_node_(new MTPFileNode(mtpd::kRootFileId,
-                                 NULL,
+                                 "",    // Root node has no name.
+                                 NULL,  // And no parent node.
                                  &file_id_to_node_map_)),
       weak_ptr_factory_(this) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@@ -328,6 +335,24 @@ void MTPDeviceDelegateImplLinux::GetFileInfo(
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(!file_path.empty());
+
+  // If a ReadDirectory operation is in progress, the file info may already be
+  // cached.
+  FileInfoCache::const_iterator it = file_info_cache_.find(file_path);
+  if (it != file_info_cache_.end()) {
+    // TODO(thestig): This code is repeated in several places. Combine them.
+    // e.g. c/b/media_galleries/win/mtp_device_operations_util.cc
+    const fileapi::DirectoryEntry& cached_file_entry = it->second;
+    base::File::Info info;
+    info.size = cached_file_entry.size;
+    info.is_directory = cached_file_entry.is_directory;
+    info.is_symbolic_link = false;
+    info.last_modified = cached_file_entry.last_modified_time;
+    info.creation_time = base::Time();
+
+    success_callback.Run(info);
+    return;
+  }
   base::Closure closure =
       base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
                  weak_ptr_factory_.GetWeakPtr(),
@@ -733,6 +758,17 @@ void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
   DCHECK(it != file_id_to_node_map_.end());
   MTPFileNode* dir_node = it->second;
 
+  // Traverse the MTPFileNode tree to reconstuct the full path for |dir_id|.
+  std::deque<std::string> dir_path_parts;
+  MTPFileNode* parent_node = dir_node;
+  while (parent_node->parent()) {
+    dir_path_parts.push_front(parent_node->file_name());
+    parent_node = parent_node->parent();
+  }
+  base::FilePath dir_path = device_path_;
+  for (size_t i = 0; i < dir_path_parts.size(); ++i)
+    dir_path = dir_path.Append(dir_path_parts[i]);
+
   fileapi::AsyncFileUtil::EntryList normalized_file_list;
   for (size_t i = 0; i < file_list.size(); ++i) {
     normalized_file_list.push_back(file_list[i]);
@@ -751,6 +787,9 @@ void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
     // Refresh the in memory tree.
     dir_node->EnsureChildExists(entry.name, file_id);
     child_nodes_seen_.insert(entry.name);
+
+    // Add to |file_info_cache_|.
+    file_info_cache_[dir_path.Append(entry.name)] = entry;
   }
 
   success_callback.Run(normalized_file_list, has_more);
@@ -760,6 +799,7 @@ void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
   // Last call, finish book keeping and continue with the next request.
   dir_node->ClearNonexistentChildren(child_nodes_seen_);
   child_nodes_seen_.clear();
+  file_info_cache_.clear();
 
   PendingRequestDone();
 }
index 44d390d..770c060 100644 (file)
@@ -60,6 +60,9 @@ class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
   // Maps file ids to file nodes.
   typedef std::map<uint32, MTPFileNode*> FileIdToMTPFileNodeMap;
 
+  // Maps file paths to file info.
+  typedef std::map<base::FilePath, fileapi::DirectoryEntry> FileInfoCache;
+
   // Should only be called by CreateMTPDeviceAsyncDelegate() factory call.
   // Defer the device initializations until the first file operation request.
   // Do all the initializations in EnsureInitAndRunTask() function.
@@ -278,6 +281,11 @@ class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
   // can return results over multiple callbacks, is in progress.
   std::set<std::string> child_nodes_seen_;
 
+  // A cache to store file metadata for file entries read during a ReadDirectory
+  // operation. Used to service incoming GetFileInfo calls for the duration of
+  // the ReadDirectory operation.
+  FileInfoCache file_info_cache_;
+
   // For callbacks that may run after destruction.
   base::WeakPtrFactory<MTPDeviceDelegateImplLinux> weak_ptr_factory_;
 
index 37683b0..69b2ec9 100644 (file)
@@ -443,11 +443,10 @@ void ChromeNetworkDelegate::OnResolveProxy(
 }
 
 void ChromeNetworkDelegate::OnProxyFallback(const net::ProxyServer& bad_proxy,
-                                            int net_error,
-                                            bool did_fallback) {
+                                            int net_error) {
   if (data_reduction_proxy_usage_stats_) {
     data_reduction_proxy_usage_stats_->RecordBypassEventHistograms(
-        bad_proxy, net_error, did_fallback);
+        bad_proxy, net_error);
   }
 }
 
@@ -584,9 +583,13 @@ void ChromeNetworkDelegate::OnCompleted(net::URLRequest* request,
       RecordContentLengthHistograms(received_content_length,
                                     original_content_length,
                                     freshness_lifetime);
-      if (data_reduction_proxy_enabled_ && data_reduction_proxy_usage_stats_) {
+      if (data_reduction_proxy_enabled_ &&
+          data_reduction_proxy_usage_stats_ &&
+          !proxy_config_getter_.is_null()) {
         data_reduction_proxy_usage_stats_->RecordBypassedBytesHistograms(
-            *request, *data_reduction_proxy_enabled_);
+            *request,
+            *data_reduction_proxy_enabled_,
+            proxy_config_getter_.Run());
       }
       DVLOG(2) << __FUNCTION__
           << " received content length: " << received_content_length
index 07e9af7..0431a66 100644 (file)
@@ -216,8 +216,7 @@ class ChromeNetworkDelegate : public net::NetworkDelegate {
       const net::ProxyService& proxy_service,
       net::ProxyInfo* result) OVERRIDE;
   virtual void OnProxyFallback(const net::ProxyServer& bad_proxy,
-                               int net_error,
-                               bool did_fallback) OVERRIDE;
+                               int net_error) OVERRIDE;
   virtual int OnBeforeSendHeaders(net::URLRequest* request,
                                   const net::CompletionCallback& callback,
                                   net::HttpRequestHeaders* headers) OVERRIDE;
index a01f5ee..f525388 100644 (file)
 #include "content/public/browser/browser_thread.h"
 #include "net/base/network_change_notifier.h"
 
+namespace chrome_browser_net {
+
 namespace {
 
 // Since looking up preferences and current network connection are presumably
 // both cheap, we do not cache them here.
-bool CanPrefetchAndPrerender(int network_prediction_options,
-                             bool network_prediction_enabled) {
+bool CanPrefetchAndPrerender(int network_prediction_options) {
   switch (network_prediction_options) {
-    case chrome_browser_net::NETWORK_PREDICTION_ALWAYS:
+    case NETWORK_PREDICTION_ALWAYS:
       return true;
-    case chrome_browser_net::NETWORK_PREDICTION_WIFI_ONLY:
-      return !net::NetworkChangeNotifier::IsConnectionCellular(
-          net::NetworkChangeNotifier::GetConnectionType());
-    case chrome_browser_net::NETWORK_PREDICTION_NEVER:
+    case NETWORK_PREDICTION_NEVER:
       return false;
-    case chrome_browser_net::NETWORK_PREDICTION_UNSET:
-      return network_prediction_enabled;
     default:
-      NOTREACHED() << "Unknown kNetworkPredictionOptions value.";
-      return false;
+      DCHECK_EQ(NETWORK_PREDICTION_WIFI_ONLY, network_prediction_options);
+      return !net::NetworkChangeNotifier::IsConnectionCellular(
+                 net::NetworkChangeNotifier::GetConnectionType());
   }
 }
 
-bool CanPreresolveAndPreconnect(int network_prediction_options,
-                                bool network_prediction_enabled) {
-  switch (network_prediction_options) {
-    case chrome_browser_net::NETWORK_PREDICTION_ALWAYS:
-      return true;
-    // DNS preresolution and TCP preconnect are performed even on cellular
-    // networks if the user setting is WIFI_ONLY.
-    case chrome_browser_net::NETWORK_PREDICTION_WIFI_ONLY:
-      return true;
-    case chrome_browser_net::NETWORK_PREDICTION_NEVER:
-      return false;
-    case chrome_browser_net::NETWORK_PREDICTION_UNSET:
-      return network_prediction_enabled;
-    default:
-      NOTREACHED() << "Unknown kNetworkPredictionOptions value.";
-      return false;
-  }
+bool CanPreresolveAndPreconnect(int network_prediction_options) {
+  // DNS preresolution and TCP preconnect are performed even on cellular
+  // networks if the user setting is WIFI_ONLY.
+  return network_prediction_options != NETWORK_PREDICTION_NEVER;
 }
 
 }  // namespace
 
-namespace chrome_browser_net {
-
 void RegisterPredictionOptionsProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterIntegerPref(
       prefs::kNetworkPredictionOptions,
-      chrome_browser_net::NETWORK_PREDICTION_UNSET,
+      NETWORK_PREDICTION_DEFAULT,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
@@ -81,8 +63,7 @@ void MigrateNetworkPredictionUserPrefs(PrefService* pref_service) {
   if (network_prediction_enabled->GetAsBoolean(&value)) {
     pref_service->SetInteger(
         prefs::kNetworkPredictionOptions,
-        value ? chrome_browser_net::NETWORK_PREDICTION_WIFI_ONLY
-              : chrome_browser_net::NETWORK_PREDICTION_NEVER);
+        value ? NETWORK_PREDICTION_WIFI_ONLY : NETWORK_PREDICTION_NEVER);
   }
 }
 
@@ -90,16 +71,14 @@ bool CanPrefetchAndPrerenderIO(ProfileIOData* profile_io_data) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   DCHECK(profile_io_data);
   return CanPrefetchAndPrerender(
-      profile_io_data->network_prediction_options()->GetValue(),
-      profile_io_data->network_prediction_enabled()->GetValue());
+      profile_io_data->network_prediction_options()->GetValue());
 }
 
 bool CanPrefetchAndPrerenderUI(PrefService* prefs) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK(prefs);
   return CanPrefetchAndPrerender(
-      prefs->GetInteger(prefs::kNetworkPredictionOptions),
-      prefs->GetBoolean(prefs::kNetworkPredictionEnabled));
+      prefs->GetInteger(prefs::kNetworkPredictionOptions));
 }
 
 bool CanPredictNetworkActionsUI(PrefService* prefs) {
@@ -110,16 +89,14 @@ bool CanPreresolveAndPreconnectIO(ProfileIOData* profile_io_data) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   DCHECK(profile_io_data);
   return CanPreresolveAndPreconnect(
-      profile_io_data->network_prediction_options()->GetValue(),
-      profile_io_data->network_prediction_enabled()->GetValue());
+      profile_io_data->network_prediction_options()->GetValue());
 }
 
 bool CanPreresolveAndPreconnectUI(PrefService* prefs) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK(prefs);
   return CanPreresolveAndPreconnect(
-      prefs->GetInteger(prefs::kNetworkPredictionOptions),
-      prefs->GetBoolean(prefs::kNetworkPredictionEnabled));
+      prefs->GetInteger(prefs::kNetworkPredictionOptions));
 }
 
 }  // namespace chrome_browser_net
index 49c33df..1fec4cc 100644 (file)
@@ -17,14 +17,11 @@ namespace chrome_browser_net {
 // Enum describing when to allow network predictions based on connection type.
 // The numerical value is stored in the prefs file, therefore the same enum
 // with the same order must be used by the platform-dependent components.
-// TODO(bnc): implement as per crbug.com/334602.
-// NETWORK_PREDICTION_UNSET means that the old preferences,
-// kNetworkPredictionEnabled and kAllowPrerender, should be observed.
 enum NetworkPredictionOptions {
   NETWORK_PREDICTION_ALWAYS,
   NETWORK_PREDICTION_WIFI_ONLY,
   NETWORK_PREDICTION_NEVER,
-  NETWORK_PREDICTION_UNSET,
+  NETWORK_PREDICTION_DEFAULT = NETWORK_PREDICTION_WIFI_ONLY,
 };
 
 void RegisterPredictionOptionsProfilePrefs(
index ca7cb26..30915df 100644 (file)
@@ -81,7 +81,6 @@ void data_reduction_proxy::DataReductionProxySettingsTestBase::ResetSettings(
 template <class C>
 void data_reduction_proxy::DataReductionProxySettingsTestBase::SetProbeResult(
     const std::string& test_url,
-    const std::string& warmup_test_url,
     const std::string& response,
     ProbeURLFetchResult result,
     bool success,
@@ -116,7 +115,6 @@ data_reduction_proxy::DataReductionProxySettingsTestBase::ResetSettings<
 template void
 data_reduction_proxy::DataReductionProxySettingsTestBase::SetProbeResult<
     DataReductionProxyChromeSettings>(const std::string& test_url,
-                                       const std::string& warmup_test_url,
                                        const std::string& response,
                                        ProbeURLFetchResult result,
                                        bool success,
index c5c50bf..4a8b5d3 100644 (file)
@@ -92,9 +92,6 @@ bool ChromePasswordManagerClient::IsAutomaticPasswordSavingEnabled() const {
 
 bool ChromePasswordManagerClient::IsPasswordManagerEnabledForCurrentPage()
     const {
-  if (EnabledForSyncSignin())
-    return true;
-
   DCHECK(web_contents());
   content::NavigationEntry* entry =
       web_contents()->GetController().GetLastCommittedEntry();
@@ -102,6 +99,14 @@ bool ChromePasswordManagerClient::IsPasswordManagerEnabledForCurrentPage()
     // TODO(gcasto): Determine if fix for crbug.com/388246 is relevant here.
     return true;
   }
+
+  // Disable the password manager for online password management.
+  if (IsURLPasswordWebsiteReauth(entry->GetURL()))
+    return false;
+
+  if (EnabledForSyncSignin())
+    return true;
+
   // Do not fill nor save password when a user is signing in for sync. This
   // is because users need to remember their password if they are syncing as
   // this is effectively their master password.
@@ -403,6 +408,26 @@ bool ChromePasswordManagerClient::LastLoadWasTransactionalReauthPage() const {
                                     &ignored_value);
 }
 
+bool ChromePasswordManagerClient::IsURLPasswordWebsiteReauth(
+    const GURL& url) const {
+  if (url.GetOrigin() != GaiaUrls::GetInstance()->gaia_url().GetOrigin())
+    return false;
+
+  // "rart" param signals this page is for transactional reauth.
+  std::string param_value;
+  if (!net::GetValueForKeyInQuery(url, "rart", &param_value))
+    return false;
+
+  // Check the "continue" param to see if this reauth page is for the passwords
+  // website.
+  param_value.clear();
+  if (!net::GetValueForKeyInQuery(url, "continue", &param_value))
+    return false;
+
+  return GURL(param_value).host() ==
+      GURL(chrome::kPasswordManagerAccountDashboardURL).host();
+}
+
 bool ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled() {
 #if !defined(USE_AURA)
   return false;
index 4fbed64..ccab0ed 100644 (file)
@@ -138,6 +138,10 @@ class ChromePasswordManagerClient
   // Google property.
   bool LastLoadWasTransactionalReauthPage() const;
 
+  // Returns true if |url| is the reauth page for accessing the password
+  // website.
+  bool IsURLPasswordWebsiteReauth(const GURL& url) const;
+
   // Sets |autofill_state_| based on experiment and flag values.
   void SetUpAutofillSyncState();
 
index 802bdce..157aaee 100644 (file)
@@ -266,3 +266,58 @@ TEST_F(ChromePasswordManagerClientTest, ShouldFilterAutofillResult) {
   NavigateAndCommit(GURL("https://accounts.google.com/Login"));
   EXPECT_TRUE(client->ShouldFilterAutofillResult(form));
 }
+
+TEST_F(ChromePasswordManagerClientTest,
+       IsPasswordManagerEnabledForCurrentPage) {
+  ChromePasswordManagerClient* client = GetClient();
+  NavigateAndCommit(
+      GURL("https://accounts.google.com/ServiceLogin?continue="
+           "https://passwords.google.com/settings&rart=123"));
+  EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
+
+  // Password site is inaccesible via HTTP, but because of HSTS the following
+  // link should still continue to https://passwords.google.com.
+  NavigateAndCommit(
+      GURL("https://accounts.google.com/ServiceLogin?continue="
+           "http://passwords.google.com/settings&rart=123"));
+  EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
+
+  // Specifying default port still passes.
+  NavigateAndCommit(
+      GURL("https://accounts.google.com/ServiceLogin?continue="
+           "https://passwords.google.com:443/settings&rart=123"));
+  EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
+
+  // Encoded URL is considered the same.
+  NavigateAndCommit(
+      GURL("https://accounts.google.com/ServiceLogin?continue="
+           "https://passwords.%67oogle.com/settings&rart=123"));
+  EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
+
+  // Fully qualified domain name is considered a different hostname by GURL.
+  // Ideally this would not be the case, but this quirk can be avoided by
+  // verification on the server. This test is simply documentation of this
+  // behavior.
+  NavigateAndCommit(
+      GURL("https://accounts.google.com/ServiceLogin?continue="
+           "https://passwords.google.com./settings&rart=123"));
+  EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
+
+  // Not a transactional reauth page.
+  NavigateAndCommit(
+      GURL("https://accounts.google.com/ServiceLogin?continue="
+           "https://passwords.google.com/settings"));
+  EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
+
+  // Should be enabled for other transactional reauth pages.
+  NavigateAndCommit(
+      GURL("https://accounts.google.com/ServiceLogin?continue="
+           "https://mail.google.com&rart=234"));
+  EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
+
+  // Reauth pages are only on accounts.google.com
+  NavigateAndCommit(
+      GURL("https://other.site.com/ServiceLogin?continue="
+           "https://passwords.google.com&rart=234"));
+  EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
+}
index ff2fdce..7d5633e 100644 (file)
@@ -729,9 +729,10 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
   second_observer.Wait();
   EXPECT_FALSE(second_prompt_observer->IsShowingPrompt());
 
-  // Verify that we sent a ping to Autofill saying that the original form
-  // was likely an account creation form since it has more than 2 text input
-  // fields and was used for the first time on a different form.
+  // Verify that we sent two pings to Autofill. One vote for of PASSWORD for
+  // the current form, and one vote for ACCOUNT_CREATION_PASSWORD on the
+  // original form since it has more than 2 text input fields and was used for
+  // the first time on a different form.
   base::HistogramBase* upload_histogram =
       base::StatisticsRecorder::FindHistogram(
           "PasswordGeneration.UploadStarted");
@@ -739,7 +740,7 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
   scoped_ptr<base::HistogramSamples> snapshot =
       upload_histogram->SnapshotSamples();
   EXPECT_EQ(0, snapshot->GetCount(0 /* failure */));
-  EXPECT_EQ(1, snapshot->GetCount(1 /* success */));
+  EXPECT_EQ(2, snapshot->GetCount(1 /* success */));
 }
 #endif
 
index 238fdd1..0d854e4 100644 (file)
@@ -142,6 +142,11 @@ void GetExpectedDefaultPolicy(PolicyMap* policy_map) {
                   POLICY_SCOPE_USER,
                   new base::StringValue("primary-only"),
                   NULL);
+  policy_map->Set(key::kEasyUnlockAllowed,
+                  POLICY_LEVEL_MANDATORY,
+                  POLICY_SCOPE_USER,
+                  new base::FundamentalValue(false),
+                  NULL);
 #endif
 }
 
@@ -178,6 +183,11 @@ void GetExpectedTestPolicy(PolicyMap* expected, const char* homepage) {
                 POLICY_SCOPE_USER,
                 new base::StringValue("primary-only"),
                 NULL);
+  expected->Set(key::kEasyUnlockAllowed,
+                POLICY_LEVEL_MANDATORY,
+                POLICY_SCOPE_USER,
+                new base::FundamentalValue(false),
+                NULL);
 #endif
 }
 
index c38147f..4b23f86 100644 (file)
@@ -19,17 +19,6 @@ bool IsPrefetchEnabled(content::ResourceContext* resource_context) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
 
   ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
-  DCHECK(io_data);
-
-  // TODO(bnc): Remove this condition once the new
-  // predictive preference is used on all platforms. See crbug.com/334602.
-  if (io_data->network_prediction_options()->GetValue() ==
-          chrome_browser_net::NETWORK_PREDICTION_UNSET &&
-      net::NetworkChangeNotifier::IsConnectionCellular(
-          net::NetworkChangeNotifier::GetConnectionType())) {
-    return false;
-  }
-
   return chrome_browser_net::CanPrefetchAndPrerenderIO(io_data) &&
          !DisableForFieldTrial();
 }
index bd8ba5b..0f371fc 100644 (file)
@@ -6,6 +6,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/net/prediction_options.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
+#include "net/base/network_change_notifier.h"
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_job.h"
 
+using chrome_browser_net::NetworkPredictionOptions;
 using content::BrowserThread;
+using net::NetworkChangeNotifier;
 
 namespace {
 
 const char kPrefetchPage[] = "files/prerender/simple_prefetch.html";
 
+class MockNetworkChangeNotifierWIFI : public NetworkChangeNotifier {
+ public:
+  virtual ConnectionType GetCurrentConnectionType() const OVERRIDE {
+    return NetworkChangeNotifier::CONNECTION_WIFI;
+  }
+};
+
+class MockNetworkChangeNotifier4G : public NetworkChangeNotifier {
+ public:
+  virtual ConnectionType GetCurrentConnectionType() const OVERRIDE {
+    return NetworkChangeNotifier::CONNECTION_4G;
+  }
+};
+
 class PrefetchBrowserTestBase : public InProcessBrowserTest {
  public:
-  explicit PrefetchBrowserTestBase(bool do_predictive_networking,
-                                   bool do_prefetch_field_trial)
-      : do_predictive_networking_(do_predictive_networking),
-        do_prefetch_field_trial_(do_prefetch_field_trial) {}
+  explicit PrefetchBrowserTestBase(bool disabled_via_field_trial)
+      : disabled_via_field_trial_(disabled_via_field_trial) {}
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    if (do_prefetch_field_trial_) {
+    if (disabled_via_field_trial_) {
       command_line->AppendSwitchASCII(switches::kForceFieldTrials,
                                       "Prefetch/ExperimentDisabled/");
-    } else {
-      command_line->AppendSwitchASCII(switches::kForceFieldTrials,
-                                      "Prefetch/ExperimentEnabled/");
     }
   }
 
-  virtual void SetUpOnMainThread() OVERRIDE {
-    browser()->profile()->GetPrefs()->SetBoolean(
-        prefs::kNetworkPredictionEnabled, do_predictive_networking_);
+  void SetPreference(NetworkPredictionOptions value) {
+    browser()->profile()->GetPrefs()->SetInteger(
+        prefs::kNetworkPredictionOptions, value);
   }
 
   bool RunPrefetchExperiment(bool expect_success, Browser* browser) {
-    CHECK(test_server()->Start());
     GURL url = test_server()->GetURL(kPrefetchPage);
 
     const base::string16 expected_title =
@@ -62,32 +74,17 @@ class PrefetchBrowserTestBase : public InProcessBrowserTest {
   }
 
  private:
-  bool do_predictive_networking_;
-  bool do_prefetch_field_trial_;
-};
-
-class PrefetchBrowserTestPredictionOnExpOn : public PrefetchBrowserTestBase {
- public:
-  PrefetchBrowserTestPredictionOnExpOn()
-      : PrefetchBrowserTestBase(true, true) {}
-};
-
-class PrefetchBrowserTestPredictionOnExpOff : public PrefetchBrowserTestBase {
- public:
-  PrefetchBrowserTestPredictionOnExpOff()
-      : PrefetchBrowserTestBase(true, false) {}
+  bool disabled_via_field_trial_;
 };
 
-class PrefetchBrowserTestPredictionOffExpOn : public PrefetchBrowserTestBase {
+class PrefetchBrowserTestPrediction : public PrefetchBrowserTestBase {
  public:
-  PrefetchBrowserTestPredictionOffExpOn()
-      : PrefetchBrowserTestBase(false, true) {}
+  PrefetchBrowserTestPrediction() : PrefetchBrowserTestBase(false) {}
 };
 
-class PrefetchBrowserTestPredictionOffExpOff : public PrefetchBrowserTestBase {
+class PrefetchBrowserTestPredictionDisabled : public PrefetchBrowserTestBase {
  public:
-  PrefetchBrowserTestPredictionOffExpOff()
-      : PrefetchBrowserTestBase(false, false) {}
+  PrefetchBrowserTestPredictionDisabled() : PrefetchBrowserTestBase(true) {}
 };
 
 // URLRequestJob (and associated handler) which hangs.
@@ -134,29 +131,59 @@ void CreateHangingRequestInterceptorOnIO(const GURL& url,
       url, never_respond_handler.Pass());
 }
 
-// Privacy option is on, experiment is on.  Prefetch should succeed.
-IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOn, PredOnExpOn) {
+// Prefetch is disabled via field experiment.  Prefetch should be dropped.
+IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionDisabled,
+                       ExperimentDisabled) {
+  CHECK(test_server()->Start());
+  EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
+  // Should not prefetch even if preference is ALWAYS.
+  SetPreference(NetworkPredictionOptions::NETWORK_PREDICTION_ALWAYS);
   EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
 }
 
-// Privacy option is on, experiment is off.  Prefetch should be dropped.
-IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOff, PredOnExpOff) {
-  EXPECT_TRUE(RunPrefetchExperiment(true, browser()));
-}
+// Prefetch should be allowed depending on preference and network type.
+IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPrediction, PreferenceWorks) {
+  CHECK(test_server()->Start());
+  // Set real NetworkChangeNotifier singleton aside.
+  scoped_ptr<NetworkChangeNotifier::DisableForTest> disable_for_test(
+      new NetworkChangeNotifier::DisableForTest);
+
+  // Preference defaults to WIFI_ONLY: prefetch when not on cellular.
+  {
+    scoped_ptr<NetworkChangeNotifier> mock(new MockNetworkChangeNotifierWIFI);
+    EXPECT_TRUE(RunPrefetchExperiment(true, browser()));
+  }
+  {
+    scoped_ptr<NetworkChangeNotifier> mock(new MockNetworkChangeNotifier4G);
+    EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
+  }
 
-// Privacy option is off, experiment is on.  Prefetch should be dropped.
-IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOffExpOn, PredOffExpOn) {
-  EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
-}
+  // Set preference to ALWAYS: always prefetch.
+  SetPreference(NetworkPredictionOptions::NETWORK_PREDICTION_ALWAYS);
+  {
+    scoped_ptr<NetworkChangeNotifier> mock(new MockNetworkChangeNotifierWIFI);
+    EXPECT_TRUE(RunPrefetchExperiment(true, browser()));
+  }
+  {
+    scoped_ptr<NetworkChangeNotifier> mock(new MockNetworkChangeNotifier4G);
+    EXPECT_TRUE(RunPrefetchExperiment(true, browser()));
+  }
 
-// Privacy option is off, experiment is off.  Prefetch should be dropped.
-IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOffExpOff, PredOffExpOff) {
-  EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
+  // Set preference to NEVER: never prefetch.
+  SetPreference(NetworkPredictionOptions::NETWORK_PREDICTION_NEVER);
+  {
+    scoped_ptr<NetworkChangeNotifier> mock(new MockNetworkChangeNotifierWIFI);
+    EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
+  }
+  {
+    scoped_ptr<NetworkChangeNotifier> mock(new MockNetworkChangeNotifier4G);
+    EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
+  }
 }
 
 // Bug 339909: When in incognito mode the browser crashed due to an
 // uninitialized preference member. Verify that it no longer does.
-IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOff, IncognitoTest) {
+IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPrediction, IncognitoTest) {
   Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile();
   Browser* incognito_browser = new Browser(
       Browser::CreateParams(incognito_profile, browser()->host_desktop_type()));
@@ -165,6 +192,7 @@ IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOff, IncognitoTest) {
   // WebContents for the incognito browser.
   ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
 
+  CHECK(test_server()->Start());
   EXPECT_TRUE(RunPrefetchExperiment(true, incognito_browser));
 }
 
@@ -173,8 +201,7 @@ IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOff, IncognitoTest) {
 // - if a prefetch is in progress, but the originating renderer is destroyed,
 //   that the pending prefetch request is cleaned up cleanly and does not
 //   result in a crash.
-IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionOnExpOff,
-                       PrefetchFromBrowser) {
+IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPrediction, PrefetchFromBrowser) {
   const GURL kHangingUrl("http://hanging-url.com");
   base::RunLoop loop_;
   BrowserThread::PostTask(BrowserThread::IO,
index 3b7b327..1861ac1 100644 (file)
@@ -82,6 +82,9 @@ bool IncognitoModePrefs::ShouldLaunchIncognito(
 
 // static
 bool IncognitoModePrefs::CanOpenBrowser(Profile* profile) {
+  if (profile->IsGuestSession())
+    return true;
+
   switch (GetAvailability(profile->GetPrefs())) {
     case IncognitoModePrefs::ENABLED:
       return true;
index ea4bba1..3627820 100644 (file)
@@ -238,8 +238,7 @@ struct PrerenderManager::NavigationRecord {
 
 PrerenderManager::PrerenderManager(Profile* profile,
                                    PrerenderTracker* prerender_tracker)
-    : enabled_(profile && profile->GetPrefs() &&
-          profile->GetPrefs()->GetBoolean(prefs::kNetworkPredictionEnabled)),
+    : enabled_(true),
       profile_(profile),
       prerender_tracker_(prerender_tracker),
       prerender_contents_factory_(PrerenderContents::CreateFactory()),
@@ -1862,24 +1861,9 @@ void PrerenderManager::RecordNetworkBytes(Origin origin,
 bool PrerenderManager::IsEnabled() const {
   DCHECK(CalledOnValidThread());
 
-  // TODO(bnc): remove conditional as per crbug.com/334602.
-  if (profile_ && profile_->GetPrefs() &&
-        profile_->GetPrefs()->GetInteger(prefs::kNetworkPredictionOptions) !=
-        chrome_browser_net::NETWORK_PREDICTION_UNSET) {
-    return chrome_browser_net::CanPrefetchAndPrerenderUI(profile_->GetPrefs());
-  }
-  // TODO(bnc): remove rest of method as per crbug.com/334602.
   if (!enabled_)
     return false;
-  for (std::list<const PrerenderCondition*>::const_iterator it =
-           prerender_conditions_.begin();
-       it != prerender_conditions_.end();
-       ++it) {
-    const PrerenderCondition* condition = *it;
-    if (!condition->CanPrerender())
-      return false;
-  }
-  return true;
+  return chrome_browser_net::CanPrefetchAndPrerenderUI(profile_->GetPrefs());
 }
 
 void PrerenderManager::AddProfileNetworkBytesIfEnabled(int64 bytes) {
index 21800ee..5c07d96 100644 (file)
@@ -16,6 +16,7 @@
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/utility_process_host.h"
 #include "content/public/browser/utility_process_host_client.h"
+#include "printing/emf_win.h"
 #include "printing/page_range.h"
 #include "printing/pdf_render_settings.h"
 
@@ -25,14 +26,12 @@ namespace {
 
 using content::BrowserThread;
 
-class FileHandlers {
+class FileHandlers
+    : public base::RefCountedThreadSafe<FileHandlers,
+                                        BrowserThread::DeleteOnFileThread> {
  public:
   FileHandlers() {}
 
-  ~FileHandlers() {
-    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-  }
-
   void Init(base::RefCountedMemory* data);
   bool IsValid();
 
@@ -40,6 +39,11 @@ class FileHandlers {
     return temp_dir_.path().AppendASCII("output.emf");
   }
 
+  base::FilePath GetEmfPagePath(int page_number) const {
+    return GetEmfPath().InsertBeforeExtensionASCII(
+        base::StringPrintf(".%d", page_number));
+  }
+
   base::FilePath GetPdfPath() const {
     return temp_dir_.path().AppendASCII("input.pdf");
   }
@@ -56,6 +60,11 @@ class FileHandlers {
   }
 
  private:
+  friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
+  friend class base::DeleteHelper<FileHandlers>;
+
+  ~FileHandlers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); }
+
   base::ScopedTempDir temp_dir_;
   base::File pdf_file_;
 };
@@ -67,20 +76,51 @@ void FileHandlers::Init(base::RefCountedMemory* data) {
     return;
   }
 
+  pdf_file_.Initialize(GetPdfPath(),
+                       base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
+                           base::File::FLAG_READ |
+                           base::File::FLAG_DELETE_ON_CLOSE);
   if (static_cast<int>(data->size()) !=
-      base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) {
+      pdf_file_.WriteAtCurrentPos(data->front_as<char>(), data->size())) {
+    pdf_file_.Close();
     return;
   }
-
-  // Reopen in read only mode.
-  pdf_file_.Initialize(GetPdfPath(),
-                       base::File::FLAG_OPEN | base::File::FLAG_READ);
+  pdf_file_.Seek(base::File::FROM_BEGIN, 0);
+  pdf_file_.Flush();
 }
 
 bool FileHandlers::IsValid() {
   return pdf_file_.IsValid();
 }
 
+// Modification of Emf to keep references to |FileHandlers|.
+// |FileHandlers| must be deleted after the last metafile is closed because
+// Emf holds files locked.
+// Ideally we want to use FLAG_DELETE_ON_CLOSE, but it requires large changes.
+// It's going to be done for crbug.com/408184
+class TempEmf : public Emf {
+ public:
+  explicit TempEmf(const scoped_refptr<FileHandlers>& files) : files_(files) {}
+  virtual ~TempEmf() {}
+
+  virtual bool SafePlayback(HDC hdc) const OVERRIDE {
+    bool result = Emf::SafePlayback(hdc);
+    TempEmf* this_mutable = const_cast<TempEmf*>(this);
+    // TODO(vitalybuka): Fix destruction of metafiles. For some reasons
+    // instances of Emf are not deleted. crbug.com/411683
+    // |files_| must be released as soon as possible to guarantee deletion.
+    // It's know that this Emf file is going to be played just once to
+    // a printer. So just release files here.
+    this_mutable->Close();
+    this_mutable->files_ = NULL;
+    return result;
+  }
+
+ private:
+  scoped_refptr<FileHandlers> files_;
+  DISALLOW_COPY_AND_ASSIGN(TempEmf);
+};
+
 // Converts PDF into EMF.
 // Class uses 3 threads: UI, IO and FILE.
 // Internal workflow is following:
@@ -125,7 +165,7 @@ class PdfToEmfUtilityProcessHostClient
       double scale_factor);
   void OnFilesReadyOnUIThread();
 
-  scoped_ptr<FileHandlers> files_;
+  scoped_refptr<FileHandlers> files_;
   printing::PdfRenderSettings settings_;
   PdfToEmfConverter::ResultCallback callback_;
   base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
@@ -138,8 +178,6 @@ PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient(
     : settings_(settings) {}
 
 PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() {
-  // Delete temp directory.
-  BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, files_.release());
 }
 
 void PdfToEmfUtilityProcessHostClient::Convert(
@@ -147,14 +185,12 @@ void PdfToEmfUtilityProcessHostClient::Convert(
     const PdfToEmfConverter::ResultCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   callback_ = callback;
-  CHECK(!files_);
-  files_.reset(new FileHandlers());
+  CHECK(!files_.get());
+  files_ = new FileHandlers();
   BrowserThread::PostTaskAndReply(
       BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(&FileHandlers::Init,
-                 base::Unretained(files_.get()),
-                 make_scoped_refptr(data)),
+      base::Bind(&FileHandlers::Init, files_, make_scoped_refptr(data)),
       base::Bind(&PdfToEmfUtilityProcessHostClient::OnFilesReadyOnUIThread,
                  this));
 }
@@ -248,19 +284,21 @@ void PdfToEmfUtilityProcessHostClient::RunCallbackOnUIThread(
     const std::vector<printing::PageRange>& page_ranges,
     double scale_factor) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  std::vector<base::FilePath> page_filenames;
+  ScopedVector<Metafile> pages;
   std::vector<printing::PageRange>::const_iterator iter;
   for (iter = page_ranges.begin(); iter != page_ranges.end(); ++iter) {
     for (int page_number = iter->from; page_number <= iter->to; ++page_number) {
-      page_filenames.push_back(files_->GetEmfPath().InsertBeforeExtensionASCII(
-          base::StringPrintf(".%d", page_number)));
+      scoped_ptr<TempEmf> metafile(new TempEmf(files_));
+      if (!metafile->InitFromFile(files_->GetEmfPagePath(page_number))) {
+        NOTREACHED() << "Invalid metafile";
+        metafile.reset();
+      }
+      pages.push_back(metafile.release());
     }
   }
+  files_ = NULL;
   if (!callback_.is_null()) {
-    BrowserThread::PostTask(
-        BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(callback_, scale_factor, page_filenames));
+    callback_.Run(scale_factor, &pages);
     callback_.Reset();
   }
 }
index 86afb05..0ad5a1a 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_vector.h"
 
 namespace base {
 class FilePath;
@@ -18,11 +19,14 @@ class PdfRenderSettings;
 
 namespace printing {
 
+class Metafile;
+
 class PdfToEmfConverter {
  public:
   // Callback for when the PDF is converted to an EMF.
-  typedef base::Callback<void(double /*scale_factor*/,
-                              const std::vector<base::FilePath>& /*emf_files*/)>
+  // Takes ownership of metafiles.
+  typedef base::Callback<
+      void(double /*scale_factor*/, ScopedVector<Metafile>* /*emf_files*/)>
       ResultCallback;
   virtual ~PdfToEmfConverter() {}
 
index 3c8c24f..c8e50d2 100644 (file)
@@ -16,7 +16,6 @@
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
 #include "chrome/browser/printing/print_view_manager.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/webplugininfo.h"
 #include "ui/web_dialogs/web_dialog_delegate.h"
-#include "ui/web_dialogs/web_dialog_web_contents_delegate.h"
 
-using content::NativeWebKeyboardEvent;
 using content::NavigationController;
 using content::WebContents;
 using content::WebUIMessageHandler;
-using ui::WebDialogDelegate;
-using ui::WebDialogWebContentsDelegate;
 
 namespace {
 
@@ -70,9 +65,8 @@ void EnableInternalPDFPluginForContents(WebContents* preview_dialog) {
       GURL(), pdf_plugin);
 }
 
-// WebDialogDelegate that specifies what the print preview dialog
-// will look like.
-class PrintPreviewDialogDelegate : public WebDialogDelegate {
+// A ui::WebDialogDelegate that specifies the print preview dialog appearance.
+class PrintPreviewDialogDelegate : public ui::WebDialogDelegate {
  public:
   explicit PrintPreviewDialogDelegate(WebContents* initiator);
   virtual ~PrintPreviewDialogDelegate();
@@ -167,44 +161,6 @@ bool PrintPreviewDialogDelegate::ShouldShowDialogTitle() const {
   return false;
 }
 
-// WebContentsDelegate that forwards shortcut keys in the print preview
-// renderer to the browser.
-class PrintPreviewWebContentDelegate : public WebDialogWebContentsDelegate {
- public:
-  PrintPreviewWebContentDelegate(Profile* profile, WebContents* initiator);
-  virtual ~PrintPreviewWebContentDelegate();
-
-  // Overridden from WebDialogWebContentsDelegate:
-  virtual void HandleKeyboardEvent(
-      WebContents* source,
-      const NativeWebKeyboardEvent& event) OVERRIDE;
-
- private:
-  WebContents* initiator_;
-
-  DISALLOW_COPY_AND_ASSIGN(PrintPreviewWebContentDelegate);
-};
-
-PrintPreviewWebContentDelegate::PrintPreviewWebContentDelegate(
-    Profile* profile,
-    WebContents* initiator)
-    : WebDialogWebContentsDelegate(profile, new ChromeWebContentsHandler),
-      initiator_(initiator) {}
-
-PrintPreviewWebContentDelegate::~PrintPreviewWebContentDelegate() {}
-
-void PrintPreviewWebContentDelegate::HandleKeyboardEvent(
-    WebContents* source,
-    const NativeWebKeyboardEvent& event) {
-  // Disabled on Mac due to http://crbug.com/112173
-#if !defined(OS_MACOSX)
-  Browser* current_browser = chrome::FindBrowserWithWebContents(initiator_);
-  if (!current_browser)
-    return;
-  current_browser->window()->HandleKeyboardEvent(event);
-#endif
-}
-
 }  // namespace
 
 namespace printing {
@@ -412,22 +368,14 @@ void PrintPreviewDialogController::OnNavEntryCommitted(
 WebContents* PrintPreviewDialogController::CreatePrintPreviewDialog(
     WebContents* initiator) {
   base::AutoReset<bool> auto_reset(&is_creating_print_preview_dialog_, true);
-  Profile* profile =
-      Profile::FromBrowserContext(initiator->GetBrowserContext());
-
-  // |web_dialog_ui_delegate| deletes itself in
-  // PrintPreviewDialogDelegate::OnDialogClosed().
-  WebDialogDelegate* web_dialog_delegate =
-      new PrintPreviewDialogDelegate(initiator);
-  // |web_dialog_delegate|'s owner is |constrained_delegate|.
-  PrintPreviewWebContentDelegate* pp_wcd =
-      new PrintPreviewWebContentDelegate(profile, initiator);
-  ConstrainedWebDialogDelegate* constrained_delegate =
-      CreateConstrainedWebDialog(profile,
-                                 web_dialog_delegate,
-                                 pp_wcd,
+
+  // The dialog delegates are deleted when the dialog is closed.
+  ConstrainedWebDialogDelegate* web_dialog_delegate =
+      CreateConstrainedWebDialog(initiator->GetBrowserContext(),
+                                 new PrintPreviewDialogDelegate(initiator),
                                  initiator);
-  WebContents* preview_dialog = constrained_delegate->GetWebContents();
+
+  WebContents* preview_dialog = web_dialog_delegate->GetWebContents();
   EnableInternalPDFPluginForContents(preview_dialog);
   PrintViewManager::CreateForWebContents(preview_dialog);
   extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
index 4e15b1d..ecd3c15 100644 (file)
@@ -133,7 +133,7 @@ void PrintViewManagerBase::OnDidGetDocumentCookie(int cookie) {
 void PrintViewManagerBase::OnPdfToEmfConverted(
     const PrintHostMsg_DidPrintPage_Params& params,
     double scale_factor,
-    const std::vector<base::FilePath>& emf_files) {
+    ScopedVector<Metafile>* emf_files) {
   if (!print_job_.get())
     return;
 
@@ -141,20 +141,23 @@ void PrintViewManagerBase::OnPdfToEmfConverted(
   if (!document)
     return;
 
-  for (size_t i = 0; i < emf_files.size(); ++i) {
-    scoped_ptr<printing::Emf> metafile(new printing::Emf);
-    if (!metafile->InitFromFile(emf_files[i])) {
-      NOTREACHED() << "Invalid metafile";
+  for (size_t i = 0; i < emf_files->size(); ++i) {
+    if (!(*emf_files)[i]) {
       web_contents()->Stop();
       return;
     }
+  }
+
+  for (size_t i = 0; i < emf_files->size(); ++i) {
     // Update the rendered document. It will send notifications to the listener.
     document->SetPage(i,
-                      metafile.release(),
+                      (*emf_files)[i],
                       scale_factor,
                       params.page_size,
                       params.content_area);
   }
+  // document->SetPage took ownership of all EMFs.
+  emf_files->weak_clear();
 
   ShouldQuitFromInnerMessageLoop();
 }
index ef48ed5..16b9bba 100644 (file)
@@ -23,6 +23,7 @@ class RenderViewHost;
 namespace printing {
 
 class JobEventDetails;
+class Metafile;
 class PdfToEmfConverter;
 class PrintJob;
 class PrintJobWorkerOwner;
@@ -135,7 +136,7 @@ class PrintViewManagerBase : public content::NotificationObserver,
   // Called on completion of converting the pdf to emf.
   void OnPdfToEmfConverted(const PrintHostMsg_DidPrintPage_Params& params,
                            double scale_factor,
-                           const std::vector<base::FilePath>& emf_file);
+                           ScopedVector<Metafile>* emf_files);
 #endif
 
   content::NotificationRegistrar registrar_;
index a68006b..010756c 100644 (file)
@@ -159,6 +159,7 @@ void GAIAInfoUpdateService::OnUsernameChanged(const std::string& username) {
   if (username.empty()) {
     // Unset the old user's GAIA info.
     cache.SetGAIANameOfProfileAtIndex(profile_index, base::string16());
+    cache.SetGAIAGivenNameOfProfileAtIndex(profile_index, base::string16());
     // The profile index may have changed.
     profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
     if (profile_index == std::string::npos)
index 209ba2a..6159efe 100644 (file)
@@ -124,8 +124,10 @@ void OffTheRecordProfileImpl::Init() {
   BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
       this);
 
-  DCHECK_NE(IncognitoModePrefs::DISABLED,
-            IncognitoModePrefs::GetAvailability(profile_->GetPrefs()));
+  // Guest profiles may always be OTR. Check IncognitoModePrefs otherwise.
+  DCHECK(profile_->IsGuestSession() ||
+         IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) !=
+             IncognitoModePrefs::DISABLED);
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
   UseSystemProxy();
index 0496675..ce6ec36 100644 (file)
@@ -63,6 +63,30 @@ jobject ProfileAndroid::GetLastUsedProfile(JNIEnv* env, jclass clazz) {
   return profile_android->obj_.obj();
 }
 
+base::android::ScopedJavaLocalRef<jobject> ProfileAndroid::GetOriginalProfile(
+    JNIEnv* env, jobject obj) {
+  ProfileAndroid* original_profile = ProfileAndroid::FromProfile(
+      profile_->GetOriginalProfile());
+  DCHECK(original_profile);
+  return original_profile->GetJavaObject();
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+ProfileAndroid::GetOffTheRecordProfile(JNIEnv* env, jobject obj) {
+  ProfileAndroid* otr_profile = ProfileAndroid::FromProfile(
+      profile_->GetOffTheRecordProfile());
+  DCHECK(otr_profile);
+  return otr_profile->GetJavaObject();
+}
+
+jboolean ProfileAndroid::HasOffTheRecordProfile(JNIEnv* env, jobject obj) {
+  return profile_->HasOffTheRecordProfile();
+}
+
+jboolean ProfileAndroid::IsOffTheRecord(JNIEnv* env, jobject obj) {
+  return profile_->IsOffTheRecord();
+}
+
 // static
 jobject GetLastUsedProfile(JNIEnv* env, jclass clazz) {
   return ProfileAndroid::GetLastUsedProfile(env, clazz);
@@ -74,7 +98,6 @@ ProfileAndroid::ProfileAndroid(Profile* profile)
   base::android::ScopedJavaLocalRef<jobject> jprofile =
       Java_Profile_create(env, reinterpret_cast<intptr_t>(this));
   obj_.Reset(env, jprofile.obj());
-
 }
 
 ProfileAndroid::~ProfileAndroid() {
index 0017b5b..8350afd 100644 (file)
@@ -23,6 +23,24 @@ class ProfileAndroid : public base::SupportsUserData::Data {
 
   static jobject GetLastUsedProfile(JNIEnv* env, jclass clazz);
 
+  // Return the original profile.
+  base::android::ScopedJavaLocalRef<jobject> GetOriginalProfile(
+      JNIEnv* env, jobject obj);
+
+  // Return the incognito profile.
+  //
+  // WARNING: This will create the OffTheRecord profile if it doesn't already
+  // exist. If this isn't what you want, you need to check
+  // HasOffTheRecordProfile() first.
+  base::android::ScopedJavaLocalRef<jobject> GetOffTheRecordProfile(
+      JNIEnv* env, jobject obj);
+
+  // Return whether an off the record profile exists.
+  jboolean HasOffTheRecordProfile(JNIEnv* env, jobject obj);
+
+  // Whether this profile is off the record.
+  jboolean IsOffTheRecord(JNIEnv* env, jobject obj);
+
   explicit ProfileAndroid(Profile* profile);
   virtual ~ProfileAndroid();
 
index 8aaa047..c5ba808 100644 (file)
@@ -169,13 +169,10 @@ ProfileInfoCache::ProfileInfoCache(PrefService* prefs,
     }
   }
 
-  // If needed, start downloading the high-res avatars.
-  if (switches::IsNewAvatarMenu()) {
-    for (size_t i = 0; i < GetNumberOfProfiles(); i++) {
-      DownloadHighResAvatar(GetAvatarIconIndexOfProfileAtIndex(i),
-                            GetPathOfProfileAtIndex(i));
-    }
-  }
+  // If needed, start downloading the high-res avatars and migrate any legacy
+  // profile names.
+  if (switches::IsNewAvatarMenu())
+    MigrateLegacyProfileNamesAndDownloadAvatars();
 }
 
 ProfileInfoCache::~ProfileInfoCache() {
@@ -1067,3 +1064,45 @@ void ProfileInfoCache::OnAvatarPictureSaved(
   delete avatar_images_downloads_in_progress_[file_name];
   avatar_images_downloads_in_progress_[file_name] = NULL;
 }
+
+void ProfileInfoCache::MigrateLegacyProfileNamesAndDownloadAvatars() {
+  DCHECK(switches::IsNewAvatarMenu());
+
+  // Only do this on desktop platforms.
+#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+  // Migrate any legacy profile names ("First user", "Default Profile") to
+  // new style default names ("Person 1"). The problem here is that every
+  // time you rename a profile, the ProfileInfoCache sorts itself, so
+  // whatever you were iterating through is no longer valid. We need to
+  // save a list of the profile paths (which thankfully do not change) that
+  // need to be renamed. We also can't pre-compute the new names, as they
+  // depend on the names of all the other profiles in the info cache, so they
+  // need to be re-computed after each rename.
+  std::vector<base::FilePath> profiles_to_rename;
+
+  const base::string16 default_profile_name = base::i18n::ToLower(
+      l10n_util::GetStringUTF16(IDS_DEFAULT_PROFILE_NAME));
+  const base::string16 default_legacy_profile_name = base::i18n::ToLower(
+      l10n_util::GetStringUTF16(IDS_LEGACY_DEFAULT_PROFILE_NAME));
+
+  for (size_t i = 0; i < GetNumberOfProfiles(); i++) {
+    // If needed, start downloading the high-res avatar for this profile.
+    DownloadHighResAvatar(GetAvatarIconIndexOfProfileAtIndex(i),
+                          GetPathOfProfileAtIndex(i));
+
+    base::string16 name = base::i18n::ToLower(GetNameOfProfileAtIndex(i));
+    if (name == default_profile_name || name == default_legacy_profile_name)
+      profiles_to_rename.push_back(GetPathOfProfileAtIndex(i));
+  }
+
+  // Rename the necessary profiles.
+  std::vector<base::FilePath>::const_iterator it;
+  for (it = profiles_to_rename.begin(); it != profiles_to_rename.end(); ++it) {
+    size_t profile_index = GetIndexOfProfileWithPath(*it);
+    SetProfileIsUsingDefaultNameAtIndex(profile_index, true);
+    // This will assign a new "Person %d" type name and re-sort the cache.
+    SetNameOfProfileAtIndex(profile_index, ChooseNameForNewProfile(
+        GetAvatarIconIndexOfProfileAtIndex(profile_index)));
+  }
+#endif
+}
index f8c4390..41fc3df 100644 (file)
@@ -206,6 +206,11 @@ class ProfileInfoCache : public ProfileInfoInterface,
   void OnAvatarPictureSaved(const std::string& file_name,
                             const base::FilePath& profile_path);
 
+  // Migrate any legacy profile names ("First user", "Default Profile") to
+  // new style default names ("Person 1"), and download and high-res avatars
+  // used by the profiles.
+  void MigrateLegacyProfileNamesAndDownloadAvatars();
+
   PrefService* prefs_;
   std::vector<std::string> sorted_keys_;
   base::FilePath user_data_dir_;
index ab25357..9fa123c 100644 (file)
@@ -590,4 +590,85 @@ TEST_F(ProfileInfoCacheTest, DownloadHighResAvatarTest) {
   EXPECT_TRUE(base::DeleteFile(icon_path, true));
   EXPECT_FALSE(base::PathExists(icon_path));
 }
+
+TEST_F(ProfileInfoCacheTest, MigrateLegacyProfileNamesWithNewAvatarMenu) {
+  switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
+  EXPECT_EQ(0U, GetCache()->GetNumberOfProfiles());
+
+  base::FilePath path_1 = GetProfilePath("path_1");
+  GetCache()->AddProfileToCache(path_1, ASCIIToUTF16("Default Profile"),
+                                base::string16(), 0, std::string());
+  base::FilePath path_2 = GetProfilePath("path_2");
+  GetCache()->AddProfileToCache(path_2, ASCIIToUTF16("First user"),
+                                base::string16(), 1, std::string());
+  base::string16 name_3 = ASCIIToUTF16("Lemonade");
+  base::FilePath path_3 = GetProfilePath("path_3");
+  GetCache()->AddProfileToCache(path_3, name_3,
+                                base::string16(), 2, std::string());
+  base::string16 name_4 = ASCIIToUTF16("Batman");
+  base::FilePath path_4 = GetProfilePath("path_4");
+  GetCache()->AddProfileToCache(path_4, name_4,
+                                base::string16(), 3, std::string());
+  base::string16 name_5 = ASCIIToUTF16("Person 2");
+  base::FilePath path_5 = GetProfilePath("path_5");
+  GetCache()->AddProfileToCache(path_5, name_5,
+                                base::string16(), 2, std::string());
+
+  EXPECT_EQ(5U, GetCache()->GetNumberOfProfiles());
+
+
+  ResetCache();
+
+  // Legacy profile names like "Default Profile" and "First user" should be
+  // migrated to "Person %n" type names.
+  EXPECT_EQ(ASCIIToUTF16("Person 1"), GetCache()->GetNameOfProfileAtIndex(
+      GetCache()->GetIndexOfProfileWithPath(path_1)));
+  EXPECT_EQ(ASCIIToUTF16("Person 3"), GetCache()->GetNameOfProfileAtIndex(
+      GetCache()->GetIndexOfProfileWithPath(path_2)));
+
+  // Other profile names should not be migrated even if they're the old
+  // default cartoon profile names.
+  EXPECT_EQ(name_3, GetCache()->GetNameOfProfileAtIndex(
+      GetCache()->GetIndexOfProfileWithPath(path_3)));
+  EXPECT_EQ(name_4, GetCache()->GetNameOfProfileAtIndex(
+      GetCache()->GetIndexOfProfileWithPath(path_4)));
+  EXPECT_EQ(name_5, GetCache()->GetNameOfProfileAtIndex(
+      GetCache()->GetIndexOfProfileWithPath(path_5)));
+}
 #endif
+
+TEST_F(ProfileInfoCacheTest,
+       DontMigrateLegacyProfileNamesWithoutNewAvatarMenu) {
+  EXPECT_EQ(0U, GetCache()->GetNumberOfProfiles());
+
+  base::string16 name_1 = ASCIIToUTF16("Default Profile");
+  base::FilePath path_1 = GetProfilePath("path_1");
+  GetCache()->AddProfileToCache(path_1, name_1,
+                                base::string16(), 0, std::string());
+  base::string16 name_2 = ASCIIToUTF16("First user");
+  base::FilePath path_2 = GetProfilePath("path_2");
+  GetCache()->AddProfileToCache(path_2, name_2,
+                                base::string16(), 1, std::string());
+  base::string16 name_3 = ASCIIToUTF16("Lemonade");
+  base::FilePath path_3 = GetProfilePath("path_3");
+  GetCache()->AddProfileToCache(path_3, name_3,
+                                base::string16(), 2, std::string());
+  base::string16 name_4 = ASCIIToUTF16("Batman");
+  base::FilePath path_4 = GetProfilePath("path_4");
+  GetCache()->AddProfileToCache(path_4, name_4,
+                                base::string16(), 3, std::string());
+  EXPECT_EQ(4U, GetCache()->GetNumberOfProfiles());
+
+  ResetCache();
+
+  // Profile names should have been preserved.
+  EXPECT_EQ(name_1, GetCache()->GetNameOfProfileAtIndex(
+      GetCache()->GetIndexOfProfileWithPath(path_1)));
+  EXPECT_EQ(name_2, GetCache()->GetNameOfProfileAtIndex(
+      GetCache()->GetIndexOfProfileWithPath(path_2)));
+  EXPECT_EQ(name_3, GetCache()->GetNameOfProfileAtIndex(
+      GetCache()->GetIndexOfProfileWithPath(path_3)));
+  EXPECT_EQ(name_4, GetCache()->GetNameOfProfileAtIndex(
+      GetCache()->GetIndexOfProfileWithPath(path_4)));
+}
+
index 9d410c5..bf18085 100644 (file)
@@ -695,6 +695,9 @@ void ProfileManager::ScheduleProfileForDeletion(
                          new_profile_name,
                          new_avatar_url,
                          std::string());
+
+      ProfileMetrics::LogProfileAddNewUser(
+          ProfileMetrics::ADD_NEW_USER_LAST_DELETED);
     } else {
       // On the Mac, the browser process is not killed when all browser windows
       // are closed, so just in case we are deleting the active profile, and no
index 1645dc1..6e47eb3 100644 (file)
@@ -1085,17 +1085,27 @@ TEST_F(ProfileManagerTest, ProfileDisplayNamePreservesSignedInName) {
   EXPECT_EQ(default_profile_name,
             profiles::GetAvatarNameForProfile(profile1->GetPath()));
 
-  // We should display the actual profile name for signed in profiles.
+  // For a signed in profile with a default name we still display
+  // IDS_SINGLE_PROFILE_DISPLAY_NAME.
   cache.SetUserNameOfProfileAtIndex(0, ASCIIToUTF16("user@gmail.com"));
   EXPECT_EQ(profile_name1, cache.GetNameOfProfileAtIndex(0));
-  EXPECT_EQ(profile_name1,
+  EXPECT_EQ(default_profile_name,
             profiles::GetAvatarNameForProfile(profile1->GetPath()));
 
+  // For a signed in profile with a non-default Gaia given name we display the
+  // Gaia given name.
+  cache.SetUserNameOfProfileAtIndex(0, ASCIIToUTF16("user@gmail.com"));
+  const base::string16 gaia_given_name(ASCIIToUTF16("given name"));
+  cache.SetGAIAGivenNameOfProfileAtIndex(0, gaia_given_name);
+  EXPECT_EQ(gaia_given_name, cache.GetNameOfProfileAtIndex(0));
+  EXPECT_EQ(gaia_given_name,
+      profiles::GetAvatarNameForProfile(profile1->GetPath()));
+
   // Multiple profiles means displaying the actual profile names.
   const base::string16 profile_name2 = cache.ChooseNameForNewProfile(1);
   Profile* profile2 = AddProfileToCache(profile_manager,
                                         "path_2", profile_name2);
-  EXPECT_EQ(profile_name1,
+  EXPECT_EQ(gaia_given_name,
             profiles::GetAvatarNameForProfile(profile1->GetPath()));
   EXPECT_EQ(profile_name2,
             profiles::GetAvatarNameForProfile(profile2->GetPath()));
@@ -1105,7 +1115,7 @@ TEST_F(ProfileManagerTest, ProfileDisplayNamePreservesSignedInName) {
                                               ProfileManager::CreateCallback());
   // Spin the message loop so that all the callbacks can finish running.
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(profile_name1,
+  EXPECT_EQ(gaia_given_name,
             profiles::GetAvatarNameForProfile(profile1->GetPath()));
 }
 #endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
index ffc59c8..611c62e 100644 (file)
@@ -33,10 +33,11 @@ class ProfileMetrics {
 
   // Enum for counting the ways users were added.
   enum ProfileAdd {
-    ADD_NEW_USER_ICON = 0,    // User adds new user from icon menu
-    ADD_NEW_USER_MENU,        // User adds new user from menu bar
-    ADD_NEW_USER_DIALOG,      // User adds new user from create-profile dialog
-    ADD_NEW_USER_MANAGER,     // User adds new user from User Manager
+    ADD_NEW_USER_ICON = 0,      // User adds new user from icon menu
+    ADD_NEW_USER_MENU,          // User adds new user from menu bar
+    ADD_NEW_USER_DIALOG,        // User adds new user from create-profile dialog
+    ADD_NEW_USER_MANAGER,       // User adds new user from User Manager
+    ADD_NEW_USER_LAST_DELETED,  // Auto-created after deleting last user
     NUM_PROFILE_ADD_METRICS
   };
 
index 8552cdf..864ac7e 100644 (file)
@@ -59,21 +59,19 @@ base::string16 GetAvatarNameForProfile(const base::FilePath& profile_path) {
     if (index == std::string::npos)
       return l10n_util::GetStringUTF16(IDS_SINGLE_PROFILE_DISPLAY_NAME);
 
-    // Using the --new-profile-management flag, there's a couple of rules
-    // about what the avatar button displays. If there's a single, local
-    // profile, with a default name (i.e. of the form Person %d), it should
-    // display IDS_SINGLE_PROFILE_DISPLAY_NAME. If this is a signed in profile,
-    // or the user has edited the profile name, or there are multiple profiles,
-    // it will return the actual name  of the profile.
+    // Using the --new-avatar-menu flag, there's a couple of rules about what
+    // the avatar button displays. If there's a single profile, with a default
+    // name (i.e. of the form Person %d) not manually set, it should display
+    // IDS_SINGLE_PROFILE_DISPLAY_NAME. Otherwise, it will return the actual
+    // name of the profile.
     base::string16 profile_name = cache.GetNameOfProfileAtIndex(index);
-    bool has_default_name = cache.ProfileIsUsingDefaultNameAtIndex(index);
+    bool has_default_name = cache.ProfileIsUsingDefaultNameAtIndex(index) &&
+        cache.IsDefaultProfileName(profile_name);
 
-    if (cache.GetNumberOfProfiles() == 1 && has_default_name &&
-        cache.GetUserNameOfProfileAtIndex(index).empty()) {
+    if (cache.GetNumberOfProfiles() == 1 && has_default_name)
       display_name = l10n_util::GetStringUTF16(IDS_SINGLE_PROFILE_DISPLAY_NAME);
-    } else {
+    else
       display_name = profile_name;
-    }
   }
   return display_name;
 }
@@ -93,15 +91,19 @@ base::string16 GetAvatarButtonTextForProfile(Profile* profile) {
 
 void UpdateProfileName(Profile* profile,
                        const base::string16& new_profile_name) {
-  PrefService* pref_service = profile->GetPrefs();
   ProfileInfoCache& cache =
       g_browser_process->profile_manager()->GetProfileInfoCache();
+  size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
+  if (profile_index == std::string::npos)
+    return;
+
+  if (new_profile_name == cache.GetNameOfProfileAtIndex(profile_index))
+    return;
 
   // This is only called when updating the profile name through the UI,
   // so we can assume the user has done this on purpose.
-  size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
-  if (profile_index != std::string::npos)
-    pref_service->SetBoolean(prefs::kProfileUsingDefaultName, false);
+  PrefService* pref_service = profile->GetPrefs();
+  pref_service->SetBoolean(prefs::kProfileUsingDefaultName, false);
 
   // Updating the profile preference will cause the cache to be updated for
   // this preference.
index a3610e2..b372b2a 100644 (file)
@@ -1712,7 +1712,8 @@ void RenderViewContextMenu::NotifyURLOpened(
     content::WebContents* new_contents) {
   RetargetingDetails details;
   details.source_web_contents = source_web_contents_;
-  details.source_render_frame_id = GetRenderFrameHost()->GetRoutingID();
+  // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
+  details.source_render_frame_id = render_frame_id_;
   details.target_url = url;
   details.target_web_contents = new_contents;
   details.not_yet_in_tabstrip = false;
index 90647dd..5759399 100644 (file)
@@ -387,8 +387,7 @@ cvox.KeySequence.prototype.isKeyModifierActive = function(keyEvent, modifier) {
       return (keyEvent.shiftKey || (keyEvent.keyCode == 16));
       break;
     case 'metaKey':
-      return (keyEvent.metaKey ||
-          (!cvox.ChromeVox.isChromeOS && keyEvent.keyCode == 91));
+      return (keyEvent.metaKey || (keyEvent.keyCode == 91));
       break;
     case 'searchKeyHeld':
       return ((cvox.ChromeVox.isChromeOS && keyEvent.keyCode == 91) ||
index 4a32569..fc7b750 100644 (file)
@@ -40,7 +40,7 @@
   "externally_connectable": {
     "ids": ["*"],
     "matches": [
-      "*://www.google.com/*/chrome/devices/goodies.html*"
+      "*://www.google.com/*chrome/devices/goodies.html*"
     ]
   }
 }
index 11d13b5..e9269ce 100644 (file)
@@ -25,7 +25,9 @@
   "permissions": [
     "alarms",
     "identity",
+    "identity.email",
     "chromeosInfoPrivate",
+    "fileSystem",
     "firstRunPrivate",
     "management",
     "metricsPrivate",
@@ -45,7 +47,6 @@
   "oauth2": {
     "client_id": "929143421683.apps.googleusercontent.com",
     "scopes": [
-        "https://www.googleapis.com/auth/userinfo.email",
         "https://www.googleapis.com/auth/supportcontent",
         "https://www.google.com/accounts/OAuthLogin"
     ]
       ],
       "title": "Open Help Article"
     },
+    "hts": {
+      "matches": [
+        "https://support.google.com/chromeos-gethelp/rts*",
+        "https://support.google.com/chromeos-gethelp/helpouts*"
+      ],
+      "title": "Contact Support"
+    },
     "home": {
       "matches": [
         "https://support.google.com/chromeos-gethelp",
index 43ab8d4..3764eab 100644 (file)
           "productId": 512
         },
         {
+          "vendorId": 4176,
+          "productId": 275
+        },
+        {
+          "vendorId": 4176,
+          "productId": 277
+        },
+        {
+          "vendorId": 4176,
+          "productId": 288
+        },
+        {
+          "vendorId": 4176,
+          "productId": 1025
+        },
+        {
           "vendorId": 9601,
           "productId": 61904
         },
index 09b3909..089ca15 100644 (file)
@@ -374,26 +374,29 @@ UsbGnubbyDevice.prototype.queueCommand = function(cid, cmd, data) {
 };
 
 /**
+ * @const
+ */
+UsbGnubbyDevice.WINUSB_VID_PIDS = [
+  {'vendorId': 4176, 'productId': 529}  // Yubico WinUSB
+];
+
+/**
  * @param {function(Array)} cb Enumerate callback
  */
 UsbGnubbyDevice.enumerate = function(cb) {
-  var permittedDevs;
   var numEnumerated = 0;
   var allDevs = [];
 
   function enumerated(devs) {
     allDevs = allDevs.concat(devs);
-    if (++numEnumerated == permittedDevs.length) {
+    if (++numEnumerated == UsbGnubbyDevice.WINUSB_VID_PIDS.length) {
       cb(allDevs);
     }
   }
 
-  GnubbyDevice.getPermittedUsbDevices(function(devs) {
-    permittedDevs = devs;
-    for (var i = 0; i < devs.length; i++) {
-      chrome.usb.getDevices(devs[i], enumerated);
-    }
-  });
+  for (var i = 0; i < UsbGnubbyDevice.WINUSB_VID_PIDS.length; i++) {
+    chrome.usb.getDevices(UsbGnubbyDevice.WINUSB_VID_PIDS[i], enumerated);
+  }
 };
 
 /**
index b64d43f..38c7143 100644 (file)
     "easyUnlockPrivate",
     "systemPrivate",
     "alarms",
-    "gcm"
+    "gcm",
+    "system.display",
+    "chromeosInfoPrivate",
+    "tabs"
   ],
 
   "app": {
index eec68a9..5b70596 100644 (file)
@@ -3,7 +3,7 @@
  * found in the LICENSE file. */
 
 body {
-  font-family: 'Noto Sans UI', 'Droid Sans Fallback', sans-serif;
+  font-family: 'Noto Sans UI', sans-serif;
   font-size: 12px;
 }
 
index 89d4bbf..34de5e7 100644 (file)
@@ -6,5 +6,26 @@
   "default_locale": "en",
   "manifest_version": 2,
   "content_security_policy": "default-src 'self'; img-src 'self' data:;",
+  "background": {
+    "scripts": [
+      "js/background-bundle.js"
+    ],
+    "persistent": false
+  },
+  "content_scripts": [
+    {
+      "js": ["js/content_script_head.js"],
+      "matches": ["https://support.google.com/chromebook/*"],
+      "run_at": "document_start"
+    },
+    {
+      "js": ["js/content_script_foot.js"],
+      "matches": ["https://support.google.com/chromebook/*"],
+      "run_at": "document_idle"
+    }
+  ],
+  "permissions": [
+    "storage"
+  ],
   "incognito": "split"
 }
index 2e2acd0..c3de096 100644 (file)
@@ -46,7 +46,10 @@ body.fakebox-disable #fakebox > input {
 }
 
 body.alternate-logo #logo {
-  background-image: url('images/white_google_logo.png@2x');
+  -webkit-mask-image: url('images/google_logo.png@2x');
+  -webkit-mask-repeat: no-repeat;
+  -webkit-mask-size: 100%;
+  background: #eee;
 }
 
 #fakebox {
@@ -61,7 +64,7 @@ body.alternate-logo #logo {
   font-size: 18px;
   height: 36px;
   line-height: 36px;
-  max-width: 620px;
+  max-width: 672px;
   position: relative;
   /* #fakebox width (here and below) should be 2px less than #mv-tiles
      to account for its border. */
@@ -103,12 +106,17 @@ body[dir=rtl] #fakebox > input {
   color: #bbb;
   font-family: arial, sans-serif;
   font-size: 16px;
-  height: 16px;
+  height: 100%;
   left: 9px;
   margin-top: 1px;
+  overflow: hidden;
   position: absolute;
+  text-align: initial;
+  text-overflow: ellipsis;
   vertical-align: middle;
-  visibility: hidden;
+  visibility: inherit;
+  white-space: nowrap;
+  width: calc(100% - 2 * 9px);
 }
 
 body[dir=rtl] #fakebox-text {
@@ -142,7 +150,7 @@ body[dir=rtl] #cursor {
 
 body.fakebox-drag-focused #fakebox-text,
 body.fakebox-focused #fakebox-text {
-  visibility: inherit;
+  visibility: hidden;
 }
 
 body.fakebox-drag-focused #cursor {
@@ -164,7 +172,7 @@ body.fakebox-focused #cursor {
 }
 
 .md #most-visited {
-  margin-top: 50px;
+  margin-top: 64px;
 }
 
 #mv-tiles {
@@ -183,8 +191,8 @@ body[dir=rtl] #mv-tiles {
 }
 
 .md #mv-tiles {
-  height: calc(2 * 126px);
-  line-height: 126px;
+  height: calc(2 * 146px);
+  line-height: 146px;
 }
 
 .mv-tile {
@@ -214,12 +222,12 @@ body[dir=rtl] #mv-tiles {
 }
 
 .md .mv-tile {
-  background: #f2f2f2;
+  background: rgb(242,242,242);
   border-radius: 1px;
-  height: 114px;
-  margin-left: 6px;
-  margin-right: 6px;
-  width: 146px;
+  height: 130px;
+  margin-left: 8px;
+  margin-right: 8px;
+  width: 156px;
 }
 
 .md .mv-page-ready {
@@ -228,7 +236,7 @@ body[dir=rtl] #mv-tiles {
 }
 
 .md.dark .mv-tile {
-  background: #333;
+  background: rgb(51,51,51);
 }
 
 .mv-tile-inner {
@@ -274,8 +282,8 @@ body[dir=rtl] #mv-tiles {
 .md .mv-mask {
   border-color: transparent;
   border-radius: 2px;
-  height: 112px;
-  width: 144px;
+  height: calc(130px - 2px);
+  width: calc(156px - 2px);
 }
 
 /* Styling border. */
@@ -288,45 +296,48 @@ body[dir=rtl] #mv-tiles {
 }
 
 .default-theme.classical .mv-page-ready:hover .mv-mask,
-.default-theme.classical .mv-page-ready:focus .mv-mask {
+.default-theme.classical .mv-page-ready .mv-focused ~ .mv-mask {
   border-color: #7f7f7f;
 }
 
 .default-theme.md.old-hover .mv-page-ready:hover .mv-mask,
-.default-theme.md.old-hover .mv-page-ready:focus .mv-mask {
+.default-theme.md.old-hover .mv-page-ready .mv-focused ~ .mv-mask {
   border-color: #999;
 }
 
 .default-theme.md.dark .mv-page-ready:hover .mv-mask,
-.default-theme.md.dark .mv-page-ready:focus .mv-mask,
-.default-theme.md.old-hover.dark .mv-page-ready:hover .mv-mask {
+.default-theme.md.dark .mv-page-ready .mv-focused ~ .mv-mask,
+.default-theme.md.old-hover.dark .mv-page-ready:hover .mv-mask,
+.default-theme.md.old-hover.dark .mv-page-ready .mv-focused ~ .mv-mask {
   border-color: #888;
 }
 
 /* Styling shadow. */
-.md .mv-page-ready .mv-mask {
+.default-theme.md .mv-page-ready .mv-mask {
   -webkit-transition: box-shadow 200ms, border 200ms;
 }
-.default-theme.md .mv-page-ready:hover .mv-mask {
-  box-shadow: 0 2px 8px rgba(0,0,0,0.3);
+
+.default-theme.md .mv-page-ready:hover .mv-mask,
+.default-theme.md .mv-page-ready .mv-focused ~ .mv-mask {
+  box-shadow: 0 1px 2px 0 rgba(0,0,0,0.1), 0 4px 8px 0 rgba(0,0,0,0.2);
 }
 
-.default-theme..md.dark .mv-page-ready:hover .mv-mask,
-.default-theme..md.old-hover .mv-page-ready:hover .mv-mask {
+.default-theme.md.dark .mv-page-ready:hover .mv-mask,
+.default-theme.md.old-hover .mv-page-ready:hover .mv-mask {
   box-shadow: none;
 }
 
 /* Styling background. */
-.classical .mv-page:focus .mv-mask {
+.classical .mv-page .mv-focused ~ .mv-mask {
   -webkit-transition: background-color 100ms ease-in-out;
   background: linear-gradient(rgba(255, 255, 255, 0),
     rgba(255, 255, 255, 0) 80%, rgba(255, 255, 255, 0.9));
   background-color: rgba(0, 0, 0, 0.35);
 }
 
-.md .mv-page:focus .mv-mask {
+.md .mv-page .mv-focused ~ .mv-mask {
   -webkit-transition: box-shadow 200ms, border 200ms,
-      background-color 100ms ease-in-out;
+      background-color 100ms ease-in-out;
   background: rgba(0, 0, 0, 0.3);
   border-color: rgba(0, 0, 0, 0.3);
 }
@@ -346,20 +357,20 @@ body[dir=rtl] #mv-tiles {
 .md .mv-title {
   bottom: auto;
   height: 15px;
-  left: 28px;
-  top: 7px;
-  width: 112px;
+  left: 32px;
+  top: 9px;
+  width: calc(156px - 32px - 4px);
 }
 
 @media (-webkit-min-device-pixel-ratio: 2) {
   .md .mv-title {
-    top: 6px;
+    top: 8px;
   }
 }
 
 body[dir=rtl] .md .mv-title {
   left: auto;
-  right: 28px;
+  right: 32px;
 }
 
 .mv-thumb {
@@ -389,10 +400,10 @@ body[dir=rtl] .md .mv-title {
 .md .mv-thumb,
 .md .mv-thumb-fallback {
   border-radius: 0;
-  height: 82px;
+  height: 94px;
   left: 4px;
-  top: 28px;
-  width: 138px;
+  top: 32px;
+  width: 148px;
 }
 
 body[dir=rtl] .md .mv-thumb,
@@ -402,30 +413,29 @@ body[dir=rtl] .md .mv-thumb-fallback {
 }
 
 .md .mv-thumb-fallback {
-  background: #fff;
-  padding: none;
+  background-color: #fff;
   position: absolute;
 }
 
 .md.dark .mv-thumb-fallback {
-  background: #555;
+  background-color: #555;
 }
 
 .md .mv-thumb-fallback .dot {
-  background: #f2f2f2;
-  border-radius: 16px;
+  background-color: #f2f2f2;
+  border-radius: 8px;
   display: block;
-  height: 32px;
+  height: 16px;
   left: 50%;
-  margin-left: -16px;
-  margin-top: -16px;
+  margin-left: -8px;
+  margin-top: -8px;
   position: absolute;
   top: 50%;
-  width: 32px;
+  width: 16px;
 }
 
 .md.dark .mv-thumb-fallback .dot {
-  background: #333;
+  background-color: #333;
 }
 
 .mv-x-hide .mv-x {
@@ -435,11 +445,8 @@ body[dir=rtl] .md .mv-thumb-fallback {
 /* An X button to blacklist a tile or hide the notification. */
 .mv-x {
   background-color: transparent;
-  background-image: url(images/close_2.png);
   border: none;
-  cursor: default;
-  height: 16px;
-  width: 16px;
+  cursor: pointer;
 }
 
 .mv-page .mv-x {
@@ -448,13 +455,20 @@ body[dir=rtl] .md .mv-thumb-fallback {
   position: absolute;
 }
 
-.mv-x:hover,
-#mv-notice-x:focus {
-  background-image: url(images/close_2_hover.png);
+.classical .mv-x {
+  background-image: url('images/close_2.png');
+  height: 16px;
+  width: 16px;
+}
+
+.classical .mv-x:hover,
+.classical #mv-notice-x:focus {
+  background-image: url('images/close_2_hover.png');
 }
 
-.mv-x:active {
-  background-image: url(images/close_2_active.png);
+.classical .mv-x:active,
+.classical #mv-notice-x:active {
+  background-image: url('images/close_2_active.png');
 }
 
 .classical .mv-page .mv-x {
@@ -462,30 +476,89 @@ body[dir=rtl] .md .mv-thumb-fallback {
   top: 2px;
 }
 
+body[dir=rtl] .classical .mv-page .mv-x {
+  left: 2px;
+  right: auto;
+}
+
+#mv-notice-x {
+  display: inline-block;
+  position: relative;
+}
+
+.md #mv-notice-x {
+  -webkit-transform: translate(0,-8px);
+}
+
 .md .mv-x {
-  background-color: rgba(187,187,187,0.8);
-  border-radius: 8px;
+  height: 32px;
+  width: 32px;
 }
 
-.md.dark .mv-x {
-  background-color: rgba(119,119,119,0.8);
+.md .mv-x .mv-x-inner {
+  -webkit-mask-image: -webkit-image-set(
+      url('images/close_3_mask.png') 1x,
+      url('images/close_3_mask.png@2x') 2x);
+  -webkit-mask-repeat: no-repeat;
+  -webkit-mask-size: 10px 10px;
+  background-color: rgba(90,90,90,0.7);
+  height: 10px;
+  left: 50%;
+  margin-left: -5px;
+  margin-top: -5px;
+  position: absolute;
+  top: 50%;
+  width: 10px;
 }
 
-.md .mv-page .mv-x {
-  right: 4px;
-  top: 5px;
+.md.dark .mv-x .mv-x-inner {
+  background-color: rgba(255,255,255,0.7);
 }
 
-body[dir=rtl] .classical .mv-page .mv-x {
-  left: 2px;
-  right: auto;
+.md .mv-x:hover .mv-x-inner,
+.md #mv-notice-x:focus .mv-x-inner {
+  background-color: rgb(90,90,90);
+}
+
+.md.dark .mv-x:hover .mv-x-inner,
+.md.dark #mv-notice-x:focus .mv-x-inner {
+  background-color: rgb(255,255,255);
+}
+
+.md .mv-x:active .mv-x-inner,
+.md #mv-notice-x:active .mv-x-inner {
+  background-color: rgb(66,133,244);
+}
+
+.md.dark .mv-x:active .mv-x-inner,
+.md.dark #mv-notice-x:active .mv-x-inner {
+  background-color: rgba(255,255,255,0.5);
+}
+
+.md .mv-page .mv-x {
+  /* background color needs to match .md .mv-tile */
+  background: linear-gradient(to right, transparent, rgb(242,242,242) 10%);
+  right: 0;
+  top: 0;
 }
 
 body[dir=rtl] .md .mv-page .mv-x {
-  left: 4px;
+  /* background color needs to match .md .mv-tile */
+  background: linear-gradient(to left, transparent, rgb(242,242,242) 10%);
+  left: 0;
   right: auto;
 }
 
+.md.dark .mv-page .mv-x {
+  /* background color needs to match .md.dark .mv-tile */
+  background: linear-gradient(to right, transparent, rgba(51,51,51,0.9) 30%);
+}
+
+body[dir=rtl] .md.dark .mv-page .mv-x {
+  /* background color needs to match .md.dark .mv-tile */
+  background: linear-gradient(to left, transparent, rgba(51,51,51,0.9) 30%);
+}
+
 .mv-page-ready:hover .mv-x {
   -webkit-transition-delay: 500ms;
   opacity: 1;
@@ -509,14 +582,22 @@ body[dir=rtl] .md .mv-page .mv-x {
 }
 
 .md .mv-favicon {
-  left: 6px;
-  top: 6px;
+  left: 8px;
+  top: 8px;
 }
 
 body[dir=rtl] .md .mv-favicon {
   left: auto;
-  right: 6px;
-  top: 6px;
+  right: 8px;
+  top: 8px;
+}
+
+.md .mv-favicon-fallback {
+  background-image: -webkit-image-set(
+      url('images/ntp_default_favicon.png') 1x,
+      url('images/ntp_default_favicon.png@2x') 2x);
+  background-repeat: no-repeat;
+  background-size: 16px 16px;
 }
 
 /* The notification shown when a tile is blacklisted. */
@@ -529,6 +610,10 @@ body[dir=rtl] .md .mv-favicon {
 
 #mv-notice span {
   cursor: default;
+  display: inline-block;
+  height: 16px;
+  line-height: 16px;
+  vertical-align: top;
 }
 
 /* Links in the notification. */
@@ -550,6 +635,10 @@ body[dir=rtl] .md .mv-favicon {
   color: #fff;
 }
 
+.default-theme.dark #mv-notice-links span {
+  color: #fff;
+}
+
 #mv-notice-links .mv-x {
   -webkit-margin-start: 8px;
   outline: none;
index 44e79bb..dd43063 100644 (file)
@@ -21,7 +21,7 @@
         <span id="mv-notice-links">
           <span id="mv-undo" tabIndex="1"></span>
           <span id="mv-restore" tabIndex="1"></span>
-          <button id="mv-notice-x" tabIndex="1" class="mv-x"></button>
+          <div id="mv-notice-x" tabIndex="1" class="mv-x"></div>
         </span>
       </div>
     </div>
index 26bf34e..c25fbb1 100644 (file)
@@ -28,6 +28,7 @@ var CLASSES = {
   ALTERNATE_LOGO: 'alternate-logo', // Shows white logo if required by theme
   BLACKLIST: 'mv-blacklist', // triggers tile blacklist animation
   BLACKLIST_BUTTON: 'mv-x',
+  BLACKLIST_BUTTON_INNER: 'mv-x-inner',
   DARK: 'dark',
   DEFAULT_THEME: 'default-theme',
   DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide',
@@ -38,6 +39,7 @@ var CLASSES = {
   FAKEBOX_DRAG_FOCUS: 'fakebox-drag-focused',
   FAVICON: 'mv-favicon',
   FAVICON_FALLBACK: 'mv-favicon-fallback',
+  FOCUSED: 'mv-focused',
   HIDE_BLACKLIST_BUTTON: 'mv-x-hide', // hides blacklist button during animation
   HIDE_FAKEBOX_AND_LOGO: 'hide-fakebox-logo',
   HIDE_NOTIFICATION: 'mv-notice-hide',
@@ -84,7 +86,6 @@ var IDS = {
  * @const
  */
 var KEYCODE = {
-  DELETE: 46,
   ENTER: 13
 };
 
@@ -167,19 +168,19 @@ var lastBlacklistedTile = null;
 
 
 /**
- * True if a page has been blacklisted and we're waiting on the
- * onmostvisitedchange callback. See onMostVisitedChange() for how this
- * is used.
- * @type {boolean}
+ * The iframe element which is currently keyboard focused, or null.
+ * @type {?Element}
  */
-var isBlacklisting = false;
+var focusedIframe = null;
 
 
 /**
- * Stores whether the current theme has a dark background.
+ * True if a page has been blacklisted and we're waiting on the
+ * onmostvisitedchange callback. See onMostVisitedChange() for how this
+ * is used.
  * @type {boolean}
  */
-var isBackgroundDark = false;
+var isBlacklisting = false;
 
 
 /**
@@ -268,6 +269,13 @@ var MOST_VISITED_THUMBNAIL_IFRAME = 'thumbnail.html';
 
 
 /**
+ * The color of the title in RRGGBBAA format.
+ * @type {?string}
+ */
+var titleColor = null;
+
+
+/**
  * Hide most visited tiles for at most this many milliseconds while painting.
  * @type {number}
  * @const
@@ -306,17 +314,19 @@ function Tile(elem, opt_innerElem, opt_titleElem, opt_thumbnailElem, opt_rid) {
 
 
 /**
- * Determines whether a theme should be considered to have dark background.
- * @param {ThemeBackgroundInfo} info Theme background information.
- * @return {boolean} Whether the theme has dark background.
+ * Heuristic to determine whether a theme should be considered to be dark, so
+ * the colors of various UI elements can be adjusted.
+ * @param {ThemeBackgroundInfo|undefined} info Theme background information.
+ * @return {boolean} Whether the theme is dark.
  * @private
  */
-function getIsBackgroundDark(info) {
-  if (info.imageUrl)
-    return true;
-  var rgba = info.backgroundColorRgba;
+function getIsThemeDark(info) {
+  if (!info)
+    return false;
+  // Heuristic: light text implies dark theme.
+  var rgba = info.textColorRgba;
   var luminance = 0.3 * rgba[0] + 0.59 * rgba[1] + 0.11 * rgba[2];
-  return luminance < 128;
+  return luminance >= 128;
 }
 
 
@@ -325,20 +335,37 @@ function getIsBackgroundDark(info) {
  * @private
  */
 function renderTheme() {
+  var fakeboxText = $(IDS.FAKEBOX_TEXT);
+  if (fakeboxText) {
+    fakeboxText.innerHTML = '';
+    if (NTP_DESIGN.showFakeboxHint &&
+        configData.translatedStrings.searchboxPlaceholder) {
+      fakeboxText.textContent =
+          configData.translatedStrings.searchboxPlaceholder;
+    }
+  }
+
   var info = ntpApiHandle.themeBackgroundInfo;
+  var isThemeDark = getIsThemeDark(info);
+  ntpContents.classList.toggle(CLASSES.DARK, isThemeDark);
   if (!info) {
-    isBackgroundDark = false;
+    titleColor = NTP_DESIGN.titleColor;
     return;
   }
 
-  isBackgroundDark = getIsBackgroundDark(info);
-  ntpContents.classList.toggle(CLASSES.DARK, isBackgroundDark);
+  if (!info.usingDefaultTheme && info.textColorRgba) {
+    titleColor = convertToRRGGBBAAColor(info.textColorRgba);
+  } else {
+    titleColor = isThemeDark ?
+        NTP_DESIGN.titleColorAgainstDark : NTP_DESIGN.titleColor;
+  }
 
   var background = [convertToRGBAColor(info.backgroundColorRgba),
                     info.imageUrl,
                     info.imageTiling,
                     info.imageHorizontalAlignment,
                     info.imageVerticalAlignment].join(' ').trim();
+
   document.body.style.background = background;
   document.body.classList.toggle(CLASSES.ALTERNATE_LOGO, info.alternateLogo);
   updateThemeAttribution(info.attributionUrl);
@@ -366,7 +393,6 @@ function onThemeChange() {
 function setCustomThemeStyle(opt_themeInfo) {
   var customStyleElement = $(IDS.CUSTOM_THEME_STYLE);
   var head = document.head;
-
   if (opt_themeInfo && !opt_themeInfo.usingDefaultTheme) {
     ntpContents.classList.remove(CLASSES.DEFAULT_THEME);
     var themeStyle =
@@ -387,7 +413,7 @@ function setCustomThemeStyle(opt_themeInfo) {
       '  border: 1px solid ' +
           convertToRGBAColor(opt_themeInfo.sectionBorderColorRgba) + ';' +
       '}' +
-      '.mv-page-ready:hover .mv-mask, .mv-page-ready:focus .mv-mask {' +
+      '.mv-page-ready:hover .mv-mask, .mv-page-ready .mv-focused ~ .mv-mask {' +
       '  border-color: ' +
           convertToRGBAColor(opt_themeInfo.headerColorRgba) + ';' +
       '}';
@@ -444,6 +470,19 @@ function setAttributionVisibility_(show) {
 
 
  /**
+ * Converts an Array of color components into RRGGBBAA format.
+ * @param {Array.<number>} color Array of rgba color components.
+ * @return {string} Color string in RRGGBBAA format.
+ * @private
+ */
+function convertToRRGGBBAAColor(color) {
+  return color.map(function(t) {
+    return ('0' + t.toString(16)).slice(-2);  // To 2-digit, 0-padded hex.
+  }).join('');
+}
+
+
+ /**
  * Converts an Array of color components into RGBA format "rgba(R,G,B,A)".
  * @param {Array.<number>} color Array of rgba color components.
  * @return {string} CSS color in RGBA format.
@@ -585,8 +624,6 @@ function renderAndShowTiles() {
 function getMostVisitedTitleIframeUrl(rid, position) {
   var url = 'chrome-search://most-visited/' +
       encodeURIComponent(MOST_VISITED_TITLE_IFRAME);
-  var titleColor = isBackgroundDark ? NTP_DESIGN.titleColorAgainstDark :
-      NTP_DESIGN.titleColor;
   var params = [
       'rid=' + encodeURIComponent(rid),
       'f=' + encodeURIComponent(NTP_DESIGN.fontFamily),
@@ -632,6 +669,11 @@ function getMostVisitedThumbnailIframeUrl(rid, position) {
 function createTile(page, position) {
   var tileElem = document.createElement('div');
   tileElem.classList.add(CLASSES.TILE);
+  // Prevent tile from being selected (and highlighted) when areas outside the
+  // <iframe>s are clicked.
+  tileElem.addEventListener('mousedown', function(e) {
+    e.preventDefault();
+  });
   var innerElem = createAndAppendElement(tileElem, 'div', CLASSES.TILE_INNER);
 
   if (page) {
@@ -646,13 +688,11 @@ function createTile(page, position) {
     // The click handler for navigating to the page identified by the RID.
     tileElem.addEventListener('click', navigateFunction);
 
-    // Make thumbnails tab-accessible.
-    tileElem.setAttribute('tabindex', '1');
-    registerKeyHandler(tileElem, KEYCODE.ENTER, navigateFunction);
-
     // The iframe which renders the page title.
     var titleElem = document.createElement('iframe');
-    titleElem.tabIndex = '-1';
+    // Enable tab navigation on the iframe, which will move the selection to the
+    // link element (which also has a tabindex).
+    titleElem.tabIndex = '0';
 
     // Why iframes have IDs:
     //
@@ -685,6 +725,7 @@ function createTile(page, position) {
     // The iframe which renders either a thumbnail or domain element.
     var thumbnailElem = document.createElement('iframe');
     thumbnailElem.tabIndex = '-1';
+    thumbnailElem.setAttribute('aria-hidden', 'true');
     // Keep this ID here. See comment above.
     thumbnailElem.id = 'thumb-' + rid;
     thumbnailElem.className = CLASSES.THUMBNAIL;
@@ -694,6 +735,8 @@ function createTile(page, position) {
     // The button used to blacklist this page.
     var blacklistButton = createAndAppendElement(
         innerElem, 'div', CLASSES.BLACKLIST_BUTTON);
+    createAndAppendElement(
+        blacklistButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER);
     var blacklistFunction = generateBlacklistFunction(rid);
     blacklistButton.addEventListener('click', blacklistFunction);
     blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip;
@@ -703,9 +746,6 @@ function createTile(page, position) {
     var maskElement = createAndAppendElement(
         innerElem, 'div', CLASSES.THUMBNAIL_MASK);
 
-    // When a tile is focused, have delete also blacklist the page.
-    registerKeyHandler(tileElem, KEYCODE.DELETE, blacklistFunction);
-
     // The page favicon, or a fallback.
     var favicon = createAndAppendElement(innerElem, 'div', CLASSES.FAVICON);
     if (page.faviconUrl) {
@@ -724,13 +764,14 @@ function createTile(page, position) {
  * Generates a function to be called when the page with the corresponding RID
  * is blacklisted.
  * @param {number} rid The RID of the page being blacklisted.
- * @return {function(Event)} A function which handles the blacklisting of the
+ * @return {function(Event=)} A function which handles the blacklisting of the
  *     page by updating state variables and notifying Chrome.
  */
 function generateBlacklistFunction(rid) {
   return function(e) {
     // Prevent navigation when the page is being blacklisted.
-    e.stopPropagation();
+    if (e)
+      e.stopPropagation();
 
     userInitiatedMostVisitedChange = true;
     isBlacklisting = true;
@@ -757,6 +798,7 @@ function showNotification() {
  */
 function hideNotification() {
   notification.classList.add(CLASSES.HIDE_NOTIFICATION);
+  notification.classList.remove(CLASSES.DELAYED_HIDE_NOTIFICATION);
 }
 
 
@@ -785,11 +827,11 @@ function onRestoreAll() {
 
 
 /**
- * Resizes elements because the number of tile columns may need to change in
- * response to resizing. Also shows or hides extra tiles tiles according to the
- * new width of the page.
+ * Recomputes the number of tile columns, and width of various contents based
+ * on the width of the window.
+ * @return {boolean} Whether the number of tile columns has changed.
  */
-function onResize() {
+function updateContentWidth() {
   var tileRequiredWidth = NTP_DESIGN.tileWidth + NTP_DESIGN.tileMargin;
   // If innerWidth is zero, then use the maximum snap size.
   var maxSnapSize = MAX_NUM_COLUMNS * tileRequiredWidth -
@@ -804,14 +846,28 @@ function onResize() {
   else if (newNumColumns > MAX_NUM_COLUMNS)
     newNumColumns = MAX_NUM_COLUMNS;
 
-  if (numColumnsShown != newNumColumns) {
-    numColumnsShown = newNumColumns;
-    var tilesContainerWidth = numColumnsShown * tileRequiredWidth;
-    tilesContainer.style.width = tilesContainerWidth + 'px';
-    if (fakebox) {
-      fakebox.style.width =  // -2 to account for border.
-          (tilesContainerWidth - NTP_DESIGN.tileMargin - 2) + 'px';
-    }
+  if (numColumnsShown === newNumColumns)
+    return false;
+
+  numColumnsShown = newNumColumns;
+  var tilesContainerWidth = numColumnsShown * tileRequiredWidth;
+  tilesContainer.style.width = tilesContainerWidth + 'px';
+  if (fakebox) {
+    // -2 to account for border.
+    var fakeboxWidth = (tilesContainerWidth - NTP_DESIGN.tileMargin - 2);
+    fakebox.style.width = fakeboxWidth + 'px';
+  }
+  return true;
+}
+
+
+/**
+ * Resizes elements because the number of tile columns may need to change in
+ * response to resizing. Also shows or hides extra tiles tiles according to the
+ * new width of the page.
+ */
+function onResize() {
+  if (updateContentWidth()) {
     // Render without clearing tiles.
     renderAndShowTiles();
   }
@@ -981,6 +1037,33 @@ function getEmbeddedSearchApiHandle() {
 
 
 /**
+ * Event handler for the focus changed and blacklist messages on link elements.
+ * Used to toggle visual treatment on the tiles (depending on the message).
+ * @param {Event} event Event received.
+ */
+function handlePostMessage(event) {
+  if (event.origin !== 'chrome-search://most-visited')
+    return;
+
+  if (event.data === 'linkFocused') {
+    var activeElement = document.activeElement;
+    if (activeElement.classList.contains(CLASSES.TITLE)) {
+      activeElement.classList.add(CLASSES.FOCUSED);
+      focusedIframe = activeElement;
+    }
+  } else if (event.data === 'linkBlurred') {
+    if (focusedIframe)
+      focusedIframe.classList.remove(CLASSES.FOCUSED);
+    focusedIframe = null;
+  } else if (event.data.indexOf('tileBlacklisted') === 0) {
+    var tilePosition = event.data.split(',')[1];
+    if (tilePosition)
+      generateBlacklistFunction(tiles[parseInt(tilePosition, 10)].rid)();
+  }
+}
+
+
+/**
  * Prepares the New Tab Page by adding listeners, rendering the current
  * theme, the most visited pages section, and Google-specific elements for a
  * Google-provided page.
@@ -1000,11 +1083,7 @@ function init() {
     var fakeboxHtml = [];
     fakeboxHtml.push('<input id="' + IDS.FAKEBOX_INPUT +
         '" autocomplete="off" tabindex="-1" aria-hidden="true">');
-    if (NTP_DESIGN.showFakeboxHint &&
-        configData.translatedStrings.searchboxPlaceholder) {
-      fakeboxHtml.push('<div id="' + IDS.FAKEBOX_TEXT + '">' +
-          configData.translatedStrings.searchboxPlaceholder + '</div>');
-    }
+    fakeboxHtml.push('<div id="' + IDS.FAKEBOX_TEXT + '"></div>');
     fakeboxHtml.push('<div id="cursor"></div>');
     fakebox.innerHTML = fakeboxHtml.join('');
 
@@ -1014,6 +1093,9 @@ function init() {
     document.body.classList.add(CLASSES.NON_GOOGLE_PAGE);
   }
 
+  // Hide notifications after fade out, so we can't focus on links via keyboard.
+  notification.addEventListener('webkitTransitionEnd', hideNotification);
+
   var notificationMessage = $(IDS.NOTIFICATION_MESSAGE);
   notificationMessage.textContent =
       configData.translatedStrings.thumbnailRemovedNotification;
@@ -1033,10 +1115,12 @@ function init() {
       configData.translatedStrings.attributionIntro;
 
   var notificationCloseButton = $(IDS.NOTIFICATION_CLOSE_BUTTON);
+  createAndAppendElement(
+      notificationCloseButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER);
   notificationCloseButton.addEventListener('click', hideNotification);
 
   window.addEventListener('resize', onResize);
-  onResize();
+  updateContentWidth();
 
   var topLevelHandle = getEmbeddedSearchApiHandle();
 
@@ -1098,6 +1182,8 @@ function init() {
     document.body.classList.add(CLASSES.RTL);
     $(IDS.TILES).dir = 'rtl';
   }
+
+  window.addEventListener('message', handlePostMessage);
 }
 
 
index ec8db73..7434209 100644 (file)
  * fontSize: Font size to use for the <iframe>s, in px.
  * tileWidth: The width of each suggestion tile, in px.
  * tileMargin: Spacing between successive tiles, in px.
- * titleColor: The RRGGBB color of title text.
- * titleColorAgainstDark: The RRGGBB color of title text against a dark theme.
+ * titleColor: The RRGGBBAA color of title text.
+ * titleColorAgainstDark: The RRGGBBAA color of title text against a dark theme.
  * titleTextAlign: (Optional) The alignment of title text. If unspecified, the
  *   default value is 'center'.
  * titleTextFade: (Optional) The number of pixels beyond which title
  *   text begins to fade. This overrides the default ellipsis style.
- * thumbnailTextColor: The RRGGBB color that thumbnail <iframe> may use to
+ * thumbnailTextColor: The RRGGBBAA color that thumbnail <iframe> may use to
  *   display text message in place of missing thumbnail.
  * thumbnailFallback: (Optional) A value in THUMBNAIL_FALLBACK to specify the
  *   thumbnail fallback strategy. If unassigned, then the thumbnail.html
@@ -63,13 +63,13 @@ function getNtpDesign(opt_name) {
       name: opt_name,
       fontFamily: 'arial, sans-serif',
       fontSize: 12,
-      tileWidth: 146,
-      tileMargin: 12,
-      titleColor: '000000',
-      titleColorAgainstDark: 'd2d2d2',
+      tileWidth: 156,
+      tileMargin: 16,
+      titleColor: '323232ff',
+      titleColorAgainstDark: 'd2d2d2ff',
       titleTextAlign: 'inherit',
-      titleTextFade: 112 - 24,  // 112px wide title with 24 pixel fade at end.
-      thumbnailTextColor: '777777',
+      titleTextFade: 122 - 36,  // 112px wide title with 32 pixel fade at end.
+      thumbnailTextColor: '323232ff',  // Unused.
       thumbnailFallback: THUMBNAIL_FALLBACK.DOT,
       showFakeboxHint: true
     };
@@ -80,11 +80,11 @@ function getNtpDesign(opt_name) {
       fontSize: 11,
       tileWidth: 140,
       tileMargin: 20,
-      titleColor: '777777',
-      titleColorAgainstDark: '777777',
+      titleColor: '777777ff',
+      titleColorAgainstDark: '777777ff',
       titleTextAlign: 'center',
       titleTextFade: null,  // Default to ellipsis.
-      thumbnailTextColor: '777777',
+      thumbnailTextColor: '777777ff',
       thumbnailFallback: null,  // Default to false.
       showFakeboxHint: false
     };
index 3a1a1ca..abe5dd0 100644 (file)
@@ -9,6 +9,7 @@ body {
 
 a {
   height: 100%;
+  position: relative;
   width: 100%;
 }
 
@@ -27,6 +28,13 @@ div {
   width: 90%;
 }
 
+span.blocker {
+  display: inline-block;
+  height: 100%;
+  position: absolute;
+  width: 100%;
+}
+
 img {
   height: 100%;
   width: 100%;
index 105f85a..e18efd6 100644 (file)
@@ -45,6 +45,10 @@ window.addEventListener('DOMContentLoaded', function() {
         var link = createMostVisitedLink(
             params, data.url, data.title, undefined, data.direction,
             data.provider);
+        // Use blocker to prevent context menu from showing image-related items.
+        var blocker = document.createElement('span');
+        blocker.className = 'blocker';
+        link.appendChild(blocker);
         link.appendChild(image);
         displayLink(link);
       };
index 91aa804..c957279 100644 (file)
@@ -123,20 +123,26 @@ function createMostVisitedLink(params, href, title, text, direction, provider) {
   link.href = href;
   link.title = title;
   link.target = '_top';
-  // Exclude links from the tab order.  The tabIndex is added to the thumbnail
-  // parent container instead.
-  link.tabIndex = '-1';
+  // Include links in the tab order.  The tabIndex is necessary for
+  // accessibility.
+  link.tabIndex = '0';
   if (text)
     link.textContent = text;
   link.addEventListener('mouseover', function() {
     var ntpApiHandle = chrome.embeddedSearch.newTabPage;
     ntpApiHandle.logEvent(NTP_LOGGING_EVENT_TYPE.NTP_MOUSEOVER);
   });
+  link.addEventListener('focus', function() {
+    window.parent.postMessage('linkFocused', DOMAIN_ORIGIN);
+  });
+  link.addEventListener('blur', function() {
+    window.parent.postMessage('linkBlurred', DOMAIN_ORIGIN);
+  });
 
   // Webkit's security policy prevents some Most Visited thumbnails from
   // working (those with schemes different from http and https). Therefore,
   // navigateContentWindow is being used in order to get all schemes working.
-  link.addEventListener('click', function handleNavigation(e) {
+  var navigateFunction = function handleNavigation(e) {
     var isServerSuggestion = 'url' in params;
 
     // Ping are only populated for server-side suggestions, never for MV.
@@ -155,6 +161,18 @@ function createMostVisitedLink(params, href, title, text, direction, provider) {
       ntpApiHandle.navigateContentWindow(href, getDispositionFromEvent(e));
     }
     // Else follow <a> normally, so transition type would be LINK.
+  };
+
+  link.addEventListener('click', navigateFunction);
+  link.addEventListener('keydown', function(event) {
+    if (event.keyCode == 46 /* DELETE */ ||
+        event.keyCode == 8 /* BACKSPACE */) {
+      event.preventDefault();
+      window.parent.postMessage('tileBlacklisted,' + params.pos, DOMAIN_ORIGIN);
+    } else if (event.keyCode == 13 /* ENTER */ ||
+               event.keyCode == 32 /* SPACE */) {
+      navigateFunction(event);
+    }
   });
 
   return link;
@@ -162,6 +180,38 @@ function createMostVisitedLink(params, href, title, text, direction, provider) {
 
 
 /**
+ * Returns the color to display string with, depending on whether title is
+ * displayed, the current theme, and URL parameters.
+ * @param {Object.<string, string>} params URL parameters specifying style.
+ * @param {boolean} isTitle if the style is for the Most Visited Title.
+ * @return {string} The color to use, in "rgba(#,#,#,#)" format.
+ */
+function getTextColor(params, isTitle) {
+  // 'RRGGBBAA' color format overrides everything.
+  if ('c' in params && params.c.match(/^[0-9A-Fa-f]{8}$/)) {
+    // Extract the 4 pairs of hex digits, map to number, then form rgba().
+    var t = params.c.match(/(..)(..)(..)(..)/).slice(1).map(function(s) {
+      return parseInt(s, 16);
+    });
+    return 'rgba(' + t[0] + ',' + t[1] + ',' + t[2] + ',' + t[3] / 255 + ')';
+  }
+
+  // For backward compatibility with server-side NTP, look at themes directly
+  // and use param.c for non-title or as fallback.
+  var apiHandle = chrome.embeddedSearch.newTabPage;
+  var themeInfo = apiHandle.themeBackgroundInfo;
+  var c = '#777';
+  if (isTitle && themeInfo && !themeInfo.usingDefaultTheme) {
+    // Read from theme directly
+    c = convertArrayToRGBAColor(themeInfo.textColorRgba) || c;
+  } else if ('c' in params) {
+    c = convertToHexColor(parseInt(params.c, 16)) || c;
+  }
+  return c;
+}
+
+
+/**
  * Decodes most visited styles from URL parameters.
  * - c: A hexadecimal number interpreted as a hex color code.
  * - f: font-family.
@@ -174,18 +224,10 @@ function createMostVisitedLink(params, href, title, text, direction, provider) {
  */
 function getMostVisitedStyles(params, isTitle) {
   var styles = {
-    color: '#777',
+    color: getTextColor(params, isTitle),  // Handles 'c' in params.
     fontFamily: '',
     fontSize: 11
   };
-  var apiHandle = chrome.embeddedSearch.newTabPage;
-  var themeInfo = apiHandle.themeBackgroundInfo;
-  if (isTitle && themeInfo && !themeInfo.usingDefaultTheme) {
-    styles.color = convertArrayToRGBAColor(themeInfo.textColorRgba) ||
-        styles.color;
-  } else if ('c' in params) {
-    styles.color = convertToHexColor(parseInt(params.c, 16)) || styles.color;
-  }
   if ('f' in params && /^[-0-9a-zA-Z ,]+$/.test(params.f))
     styles.fontFamily = params.f;
   if ('fs' in params && isFinite(parseInt(params.fs, 10)))
index bc945bf..960aa5f 100644 (file)
@@ -452,10 +452,13 @@ list:not([disabled]) > .network-group[selected] {
   -webkit-margin-start: 0.6em;
 }
 
-div[guestmode=true] #appearance-section,
-div[guestmode=true] #startup-section,
-div[guestmode=true] #searchBox,
-div[guestmode=true] #reset-profile-settings-section {
+div[guestmode=true] :-webkit-any(
+<if expr="not chromeos">
+    #searchBox,
+</if>
+    #appearance-section,
+    #startup-section,
+    #reset-profile-settings-section) {
   display: none;
 }
 
index 425c2f2..4e9c4ed 100644 (file)
   <section>
     <h3 id="voice-section-title" i18n-content="sectionTitleVoice" hidden></h3>
     <div id="voice-section-content">
-      <div id="hotword-search" hidden>
-        <div class="checkbox">
-          <span class="controlled-setting-with-label">
-            <input id="hotword-search-enable" pref="hotword.search_enabled_2"
-                metric="Options_HotwordCheckbox" type="checkbox" dialog-pref>
-            <span>
-              <label for="hotword-search-enable"
-                  i18n-values=".innerHTML:hotwordSearchEnable">
-              </label>
-              <span id="hotword-search-setting-indicator"
-                  pref="hotword.search_enabled_2" dialog-pref>
-              </span>
-            </span>
-          </span>
-        </div>
-      </div>
       <div id="hotword-always-on-search" hidden>
         <div class="checkbox">
           <span class="controlled-setting-with-label">
         </span>
       </div>
 </if>
+      <div id="hotword-search" hidden>
+        <div class="checkbox">
+          <span class="controlled-setting-with-label">
+            <input id="hotword-search-enable" pref="hotword.search_enabled_2"
+                metric="Options_HotwordCheckbox" type="checkbox" dialog-pref>
+            <span>
+              <label for="hotword-search-enable"
+                  i18n-values=".innerHTML:hotwordSearchEnable">
+              </label>
+              <span id="hotword-search-setting-indicator"
+                  pref="hotword.search_enabled_2" dialog-pref>
+              </span>
+            </span>
+          </span>
+        </div>
+      </div>
     </div>
   </section>
 <if expr="chromeos">
     </div>
   </section>
 </if>
-  <section id="reset-profile-settings-section" hidden>
+  <section id="reset-profile-settings-section">
     <h3 i18n-content="resetProfileSettingsSectionTitle"></h3>
     <div>
       <span class="settings-row" i18n-content="resetProfileSettingsDescription">
index 618c749..6a7618b 100644 (file)
@@ -1101,7 +1101,6 @@ cr.define('options', function() {
      * @private
      */
     showHotwordSection_: function(opt_enabled, opt_error) {
-      $('voice-section-title').hidden = false;
       $('hotword-search').hidden = false;
       $('hotword-search-setting-indicator').setError(opt_error);
       if (opt_enabled && opt_error)
@@ -1114,6 +1113,7 @@ cr.define('options', function() {
      * @private
      */
     showHotwordAlwaysOnSection_: function() {
+      $('voice-section-title').hidden = false;
       $('hotword-always-on-search').hidden = false;
       $('audio-logging').hidden = false;
     },
index 7447b52..0cdd12b 100644 (file)
@@ -1268,7 +1268,7 @@ cr.define('options.internet', function() {
           'prl-version',
           getActiveDictionaryValue(data, 'Cellular', 'PRLVersion'));
 
-      var family = getActiveDictionaryValue(data, 'Cellular', 'GSM');
+      var family = getActiveDictionaryValue(data, 'Cellular', 'Family');
       detailsPage.gsm = family == 'GSM';
       if (detailsPage.gsm) {
         $('iccid').textContent =
index 0d7d5f4..29159c4 100644 (file)
@@ -173,12 +173,12 @@ cr.define('options', function() {
         return;
       this.expanded_ = expanded;
       if (expanded) {
+        this.classList.add('show-items');
         var oldExpanded = this.list.expandedItem;
         this.list.expandedItem = this;
         this.updateItems_();
         if (oldExpanded)
           oldExpanded.expanded = false;
-        this.classList.add('show-items');
       } else {
         if (this.list.expandedItem == this) {
           this.list.expandedItem = null;
@@ -535,7 +535,6 @@ cr.define('options', function() {
       div.className = 'cookie-item';
       // Help out screen readers and such: this is a clickable thing.
       div.setAttribute('role', 'button');
-      div.tabIndex = 0;
       div.textContent = text;
       var apps = this.data.appsProtectingThis;
       if (apps)
index ab7a62c..2377e57 100644 (file)
@@ -116,6 +116,7 @@ list.cookie-list > .deletable-item[selected] .cookie-data {
   -webkit-margin-start: 14em;
   -webkit-padding-start: 7px;
   -webkit-transition: 150ms ease-in-out;
+  display: none;
   height: 0;
   opacity: 0;
   /* Make the cookie items wrap correctly. */
@@ -129,6 +130,7 @@ list.cookie-list > .deletable-item[selected] .cookie-data {
 }
 
 .show-items .cookie-items {
+  display: block;
   opacity: 1;
 }
 
index 39294a3..37dc71b 100644 (file)
@@ -1,5 +1,5 @@
 {
-  "x-version": 12,
+  "x-version": 13,
   "google-talk": {
     "mime_types": [
     ],
     ],
     "versions": [
       {
-        "version": "10.1.8",
+        "version": "10.1.11",
         "status": "requires_authorization",
-        "reference": "https://www.adobe.com/support/security/bulletins/apsb13-22.html"
+        "reference": "https://helpx.adobe.com/security/products/reader/apsb14-19.html"
       },
       {
         "version": "11",
         "status": "out_of_date"
       },
       {
-        "version": "11.0.5",
+        "version": "11.0.8",
         "status": "requires_authorization",
-        "reference": "https://www.adobe.com/support/security/bulletins/apsb13-25.html"
+        "reference": "https://helpx.adobe.com/security/products/reader/apsb14-19.html"
       }
     ],
     "lang": "en-US",
     "name": "Adobe Reader",
     "help_url": "https://support.google.com/chrome/?p=plugin_pdf",
-    "url": "http://www.adobe.com/support/downloads/detail.jsp?ftpID=5674",
+    "url": "https://get.adobe.com/reader/",
+    "displayurl": true,
     "group_name_matcher": "*Adobe Acrobat*"
   },
   "apple-quicktime": {
index 2e0d5d9..f5f9853 100644 (file)
@@ -64,6 +64,14 @@ cr.define('options', function() {
       Page.prototype.initializePage.call(this);
 
       var self = this;
+
+      // If 'profilesInfo' doesn't exist, it's forbidden to delete profile.
+      // So don't display the delete-profile checkbox.
+      if (!loadTimeData.valueExists('profilesInfo') &&
+          $('sync-setup-delete-profile')) {
+        $('sync-setup-delete-profile').hidden = true;
+      }
+
       $('basic-encryption-option').onchange =
           $('full-encryption-option').onchange = function() {
         self.onEncryptionRadioChanged_();
index c78fb69..cc1dd2e 100644 (file)
 .pod {
   box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
   height: 226px;
+  /* On non-retina desktop, the text is blurry if we use the scale3d()
+  inherited from user_pod_row.js */
+  transform: scale(0.9);
+}
+
+podrow[ncolumns='6'] .pod {
+  transform: scale(0.8);
 }
 
 .pod.faded {
 
 .pod.hovered:not(.focused) {
   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
-  opacity: 0.9;
 }
 
 .pod.focused {
   box-shadow: 0 16px 21px rgba(0, 0, 0, 0.2);
+  transform: scale(1) !important;
 }
 
 .pod.focused.locked {
@@ -136,6 +143,9 @@ html[dir=rtl] .main-pane {
 .action-box-area {
   background-color: #f5f5f5;
   height: 24px;
+  /* Because of crbug.com/406529, the text in the .name div is janky if there's
+  an opacity transition in this div. */
+  transition: none;
   width: 24px;
 }
 
@@ -158,3 +168,14 @@ html[dir=rtl] .main-pane {
 .action-box-area.active .action-box-button {
   border-top: 6px solid #4c4c4c;
 }
+
+.action-box-remove-user-warning .remove-warning-button {
+  height: 30px;
+}
+
+.action-box-remove-user-warning .remove-warning-button:focus {
+  /* Override the default blue border inherited from
+  button.custom-appearance:focus. */
+  border: 1px solid transparent !important;
+  box-shadow: inset 0 0 0 1px #fff;
+}
index 951144a..7685162 100644 (file)
@@ -388,8 +388,10 @@ void IncidentReportingService::OnProfileAdded(Profile* profile) {
 
   // Start a new report if this profile participates in safe browsing and there
   // are process-wide incidents.
-  if (safe_browsing_enabled && GetProfileContext(NULL))
+  if (safe_browsing_enabled && GetProfileContext(NULL) &&
+      GetProfileContext(NULL)->incidents.size()) {
     BeginReportProcessing();
+  }
 
   // TODO(grt): register for pref change notifications to start delayed analysis
   // and/or report processing if sb is currently disabled but subsequently
index e676110..dbe16fb 100644 (file)
@@ -802,6 +802,33 @@ TEST_F(IncidentReportingServiceTest, ProcessWideOneUploadAfterProfile) {
   ExpectTestIncidentUploaded(1);
 }
 
+TEST_F(IncidentReportingServiceTest, NoCollectionWithoutIncident) {
+  // Register a callback.
+  RegisterAnalysis(ON_DELAYED_ANALYSIS_NO_ACTION);
+
+  // Let all tasks run.
+  task_runner_->RunUntilIdle();
+
+  // Confirm that the callback was not run.
+  ASSERT_FALSE(DelayedAnalysisRan());
+
+  // No collection should have taken place.
+  ASSERT_FALSE(HasCollectedEnvironmentData());
+
+  // Add a profile that participates in safe browsing.
+  CreateProfile(
+      "profile1", SAFE_BROWSING_OPT_IN, ON_PROFILE_ADDITION_NO_ACTION);
+
+  // Let all tasks run.
+  task_runner_->RunUntilIdle();
+
+  // Confirm that the callback was run.
+  ASSERT_TRUE(DelayedAnalysisRan());
+
+  // Still no collection should have taken place.
+  ASSERT_FALSE(HasCollectedEnvironmentData());
+}
+
 // Tests that delayed analysis callbacks are called following the addition of a
 // profile that participates in safe browsing.
 TEST_F(IncidentReportingServiceTest, AnalysisAfterProfile) {
index a4c48eb..19528bb 100644 (file)
@@ -164,23 +164,27 @@ bool EnumRelocsCallback(const base::win::PEImage& mem_peimage,
   if (!AddrIsInCodeSection(address, mem_code_addr, code_size))
     return true;
 
-  UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.ModuleBaseRelocation", type);
-
   switch (type) {
-    case IMAGE_REL_BASED_HIGHLOW: {
-      AddBytesCorrectedByReloc(reinterpret_cast<uintptr_t>(address), state);
-      break;
-    }
-    case IMAGE_REL_BASED_ABSOLUTE:
+    case IMAGE_REL_BASED_ABSOLUTE:  // 0
       // Absolute type relocations are a noop, sometimes used to pad a section
       // of relocations.
       break;
-    default: {
+    case IMAGE_REL_BASED_HIGHLOW:  // 3
+      // The base relocation applies all 32 bits of the difference to the 32-bit
+      // field at offset.
+      AddBytesCorrectedByReloc(reinterpret_cast<uintptr_t>(address), state);
+      break;
+    case IMAGE_REL_BASED_DIR64:  // 10
+      // The base relocation applies the difference to the 64-bit field at
+      // offset.
+      // TODO(robertshield): Handle this type of reloc.
+      break;
+    default:
       // TODO(robertshield): Find a reliable description of the behaviour of the
       // remaining types of relocation and handle them.
+      UMA_HISTOGRAM_SPARSE_SLOWLY("SafeBrowsing.ModuleBaseRelocation", type);
       state->unknown_reloc_type = true;
       break;
-    }
   }
   return true;
 }
index 2029b51..faf6e5f 100644 (file)
@@ -59,9 +59,11 @@ const struct Resource{
   { "images/close_2_hover.png", IDR_CLOSE_2_H, "image/png" },
   { "images/close_2_active.png", IDR_CLOSE_2_P, "image/png" },
   { "images/close_2_white.png", IDR_CLOSE_2_MASK, "image/png" },
+  { "images/close_3_mask.png", IDR_CLOSE_3_MASK, "image/png" },
   { "images/google_logo.png", IDR_LOCAL_NTP_IMAGES_LOGO_PNG, "image/png" },
   { "images/white_google_logo.png",
     IDR_LOCAL_NTP_IMAGES_WHITE_LOGO_PNG, "image/png" },
+  { "images/ntp_default_favicon.png", IDR_NTP_DEFAULT_FAVICON, "image/png" },
 };
 
 // Strips any query parameters from the specified path.
index aceabcc..a79589a 100644 (file)
@@ -21,6 +21,7 @@
 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
 #include "chrome/common/url_constants.h"
 #include "components/suggestions/suggestions_service.h"
+#include "components/suggestions/suggestions_utils.h"
 #include "net/base/escape.h"
 #include "ui/base/l10n/time_format.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -126,7 +127,10 @@ void SuggestionsSource::StartDataRequest(
     return;
   }
 
+  // Since it's a debugging page, it's fine to specify that sync state is
+  // initialized.
   suggestions_service->FetchSuggestionsData(
+      INITIALIZED_ENABLED_HISTORY,
       base::Bind(&SuggestionsSource::OnSuggestionsAvailable,
                  weak_ptr_factory_.GetWeakPtr(), callback));
 }
index 13816fc..641f00c 100644 (file)
@@ -28,6 +28,7 @@ std::string GetIconURLForState(EasyUnlockScreenlockStateHandler::State state) {
     case EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED:
     case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY:
     case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE:
+    case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED:
       return "chrome://theme/IDR_EASY_UNLOCK_LOCKED";
     case EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING:
       return "chrome://theme/IDR_EASY_UNLOCK_SPINNER";
@@ -42,13 +43,18 @@ bool UseOpaqueIcon(EasyUnlockScreenlockStateHandler::State state) {
   return state == EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH ||
          state == EasyUnlockScreenlockStateHandler::STATE_NO_PHONE ||
          state == EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY ||
-         state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE;
+         state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE ||
+         state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED;
 }
 
 bool HasAnimation(EasyUnlockScreenlockStateHandler::State state) {
   return state == EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING;
 }
 
+bool HardlockOnClick(EasyUnlockScreenlockStateHandler::State state) {
+  return state != EasyUnlockScreenlockStateHandler::STATE_INACTIVE;
+}
+
 size_t GetTooltipResourceId(EasyUnlockScreenlockStateHandler::State state) {
   switch (state) {
     case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH:
@@ -64,14 +70,21 @@ size_t GetTooltipResourceId(EasyUnlockScreenlockStateHandler::State state) {
     case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY:
       return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_NOT_NEARBY;
     case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED:
-      // TODO(tbarzic): When hard lock is enabled change this to
-      // IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_INSTRUCTIONS.
-      return 0;
+      return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_INSTRUCTIONS;
+    case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED:
+      return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_UNSUPPORTED_ANDROID_VERSION;
     default:
       return 0;
   }
 }
 
+bool TooltipContainsDeviceType(EasyUnlockScreenlockStateHandler::State state) {
+  return state == EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED ||
+         state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE ||
+         state == EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH ||
+         state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED;
+}
+
 }  // namespace
 
 
@@ -99,10 +112,13 @@ void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) {
 
   state_ = new_state;
 
-  // If lock screen is not active, just cache the current state.
-  // The screenlock state will get refreshed in |ScreenDidLock|.
-  if (!screenlock_bridge_->IsLocked())
+  // If lock screen is not active or it forces offline password, just cache the
+  // current state. The screenlock state will get refreshed in |ScreenDidLock|.
+  if (!screenlock_bridge_->IsLocked() ||
+      screenlock_bridge_->lock_handler()->GetAuthType(user_email_) ==
+          ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD) {
     return;
+  }
 
   UpdateScreenlockAuthType();
 
@@ -115,7 +131,9 @@ void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) {
   }
   icon_options.SetIconAsResourceURL(icon_url);
 
-  UpdateTooltipOptions(&icon_options);
+  bool trial_run = IsTrialRun();
+
+  UpdateTooltipOptions(trial_run, &icon_options);
 
   if (UseOpaqueIcon(state_))
     icon_options.SetOpacity(kOpaqueIconOpacity);
@@ -125,6 +143,13 @@ void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) {
   if (HasAnimation(state_))
     icon_options.SetAnimation(kSpinnerResourceWidth, kSpinnerIntervalMs);
 
+  // Hardlocking is disabled in trial run.
+  if (!trial_run && HardlockOnClick(state_))
+    icon_options.SetHardlockOnClick();
+
+  if (trial_run && state_ == STATE_AUTHENTICATED)
+    MarkTrialRunComplete();
+
   screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_,
                                                             icon_options);
 }
@@ -140,16 +165,15 @@ void EasyUnlockScreenlockStateHandler::OnScreenDidUnlock() {
 }
 
 void EasyUnlockScreenlockStateHandler::UpdateTooltipOptions(
+    bool trial_run,
     ScreenlockBridge::UserPodCustomIconOptions* icon_options) {
-  bool show_tutorial = ShouldShowTutorial();
-
   size_t resource_id = 0;
   base::string16 device_name;
-  if (show_tutorial) {
+  if (trial_run && state_ == STATE_AUTHENTICATED) {
     resource_id = IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_TUTORIAL;
   } else {
     resource_id = GetTooltipResourceId(state_);
-    if (state_ == STATE_AUTHENTICATED || state_ == STATE_PHONE_UNLOCKABLE)
+    if (TooltipContainsDeviceType(state_))
       device_name = GetDeviceName();
   }
 
@@ -166,20 +190,17 @@ void EasyUnlockScreenlockStateHandler::UpdateTooltipOptions(
   if (tooltip.empty())
     return;
 
-  if (show_tutorial)
-    MarkTutorialShown();
-
-  icon_options->SetTooltip(tooltip, show_tutorial /* autoshow tooltip */);
+  icon_options->SetTooltip(
+      tooltip,
+      state_ == STATE_AUTHENTICATED && trial_run /* autoshow tooltip */);
 }
 
-bool EasyUnlockScreenlockStateHandler::ShouldShowTutorial() {
-  if (state_ != STATE_AUTHENTICATED)
-    return false;
+bool EasyUnlockScreenlockStateHandler::IsTrialRun() {
   return pref_service_ &&
          pref_service_->GetBoolean(prefs::kEasyUnlockShowTutorial);
 }
 
-void EasyUnlockScreenlockStateHandler::MarkTutorialShown() {
+void EasyUnlockScreenlockStateHandler::MarkTrialRunComplete() {
   if (!pref_service_)
     return;
   pref_service_->SetBoolean(prefs::kEasyUnlockShowTutorial, false);
@@ -195,6 +216,10 @@ base::string16 EasyUnlockScreenlockStateHandler::GetDeviceName() {
 }
 
 void EasyUnlockScreenlockStateHandler::UpdateScreenlockAuthType() {
+  if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) ==
+          ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD)
+    return;
+
   if (state_ == STATE_AUTHENTICATED) {
     screenlock_bridge_->lock_handler()->SetAuthType(
         user_email_,
index dc5c2cc..452687b 100644 (file)
@@ -38,6 +38,9 @@ class EasyUnlockScreenlockStateHandler : public ScreenlockBridge::Observer {
     // A phone eligible to unlock the device is found, but it's not close enough
     // to be allowed to unlock the device.
     STATE_PHONE_NOT_NEARBY,
+    // An Easy Unlock enabled phone is found, but it is not allowed to unlock
+    // the device because it does not support reporting it's lock screen state.
+    STATE_PHONE_UNSUPPORTED,
     // The device can be unlocked using Easy Unlock.
     STATE_AUTHENTICATED
   };
@@ -61,17 +64,20 @@ class EasyUnlockScreenlockStateHandler : public ScreenlockBridge::Observer {
   virtual void OnScreenDidLock() OVERRIDE;
   virtual void OnScreenDidUnlock() OVERRIDE;
 
+  // Updates icon's tooltip options.
+  // |trial_run|: Whether the trial Easy Unlock run is in progress.
   void UpdateTooltipOptions(
+      bool trial_run,
       ScreenlockBridge::UserPodCustomIconOptions* icon_options);
 
-  // Whether the tutorial message should be shown to the user. The message is
-  // shown only once, when the user encounters STATE_AUTHENTICATED for the first
-  // time (across sessions). After the tutorial message is shown,
-  // |MarkTutorialShown| should be called to prevent further tutorial message.
-  bool ShouldShowTutorial();
+  // Whether this is the first, trial Easy Unlock run. If this is the case, a
+  // tutorial message should be shown and hard-locking be disabled in
+  // Authenticated state. The trial run will be active if Easy Unlock never
+  // entered Authenticated state (across sessions).
+  bool IsTrialRun();
 
-  // Sets user preference that prevents showing of tutorial messages.
-  void MarkTutorialShown();
+  // Sets user preference that marks trial run completed.
+  void MarkTrialRunComplete();
 
   // Gets the name to be used for the device. The name depends on the device
   // type (example values: Chromebook and Chromebox).
index afbb94f..b9240aa 100644 (file)
@@ -131,7 +131,7 @@ void EasyUnlockService::RegisterProfilePrefs(
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterBooleanPref(
       prefs::kEasyUnlockShowTutorial,
-      false,
+      true,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterDictionaryPref(
       prefs::kEasyUnlockPairing,
@@ -290,7 +290,15 @@ void EasyUnlockService::Initialize() {
       base::Bind(&EasyUnlockService::OnPrefsChanged, base::Unretained(this)));
   OnPrefsChanged();
 
+#if defined(OS_CHROMEOS)
+  // Only start Bluetooth detection for ChromeOS since the feature is
+  // only offered on ChromeOS. Enabling this on non-ChromeOS platforms
+  // previously introduced a performance regression: http://crbug.com/404482
+  // Make sure not to reintroduce a performance regression if re-enabling on
+  // additional platforms.
+  // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
   bluetooth_detector_->Initialize();
+#endif  // defined(OS_CHROMEOS)
 }
 
 void EasyUnlockService::LoadApp() {
@@ -361,6 +369,9 @@ void EasyUnlockService::OnTurnOffFlowFinished(bool success) {
   ClearRemoteDevices();
   SetTurnOffFlowStatus(IDLE);
 
+  // Make sure lock screen state set by the extension gets reset.
+  screenlock_state_handler_.reset();
+
   if (GetComponentLoader(profile_)->Exists(extension_misc::kEasyUnlockAppId)) {
     extensions::ExtensionSystem* extension_system =
         extensions::ExtensionSystem::Get(profile_);
index 56c2910..4a95429 100644 (file)
@@ -37,7 +37,8 @@ ScreenlockBridge::UserPodCustomIconOptions::UserPodCustomIconOptions()
       animation_resource_width_(0u),
       animation_frame_length_ms_(0u),
       opacity_(100u),
-      autoshow_tooltip_(false) {
+      autoshow_tooltip_(false),
+      hardlock_on_click_(false) {
 }
 
 ScreenlockBridge::UserPodCustomIconOptions::~UserPodCustomIconOptions() {}
@@ -86,6 +87,10 @@ ScreenlockBridge::UserPodCustomIconOptions::ToDictionaryValue() const {
                           animation_frame_length_ms_);
     result->Set("animation", animation);
   }
+
+  if (hardlock_on_click_)
+    result->SetBoolean("hardlockOnClick", true);
+
   return result.Pass();
 }
 
@@ -130,6 +135,10 @@ void ScreenlockBridge::UserPodCustomIconOptions::SetTooltip(
   autoshow_tooltip_ = autoshow;
 }
 
+void ScreenlockBridge::UserPodCustomIconOptions::SetHardlockOnClick() {
+  hardlock_on_click_ = true;
+}
+
 // static
 std::string ScreenlockBridge::GetAuthenticatedUserEmail(Profile* profile) {
   // |profile| has to be a signed-in profile with SigninManager already
index 72cec43..5391ca3 100644 (file)
@@ -78,6 +78,10 @@ class ScreenlockBridge {
     // shown with the icon.
     void SetTooltip(const base::string16& tooltip, bool autoshow);
 
+    // If hardlock on click is set, clicking the icon in the screenlock will
+    // go to state where password is required for unlock.
+    void SetHardlockOnClick();
+
    private:
     std::string icon_resource_url_;
     scoped_ptr<gfx::Image> icon_image_;
@@ -95,6 +99,8 @@ class ScreenlockBridge {
     base::string16 tooltip_;
     bool autoshow_tooltip_;
 
+    bool hardlock_on_click_;
+
     DISALLOW_COPY_AND_ASSIGN(UserPodCustomIconOptions);
   };
 
@@ -108,6 +114,7 @@ class ScreenlockBridge {
       NUMERIC_PIN = 2,
       USER_CLICK = 3,
       EXPAND_THEN_USER_CLICK = 4,
+      FORCE_OFFLINE_PASSWORD = 5
     };
 
     // Displays |message| in a banner on the lock screen.
index 955a4b6..0769185 100644 (file)
@@ -761,6 +761,8 @@ void ProfileSyncService::OnGetTokenFailure(
   last_get_token_error_ = error;
   switch (error.state()) {
     case GoogleServiceAuthError::CONNECTION_FAILED:
+    case GoogleServiceAuthError::REQUEST_CANCELED:
+    case GoogleServiceAuthError::SERVICE_ERROR:
     case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
       // Transient error. Retry after some time.
       request_access_token_backoff_.InformOfRequest(false);
@@ -774,7 +776,6 @@ void ProfileSyncService::OnGetTokenFailure(
       NotifyObservers();
       break;
     }
-    case GoogleServiceAuthError::SERVICE_ERROR:
     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
       if (!sync_prefs_.SyncHasAuthError()) {
         sync_prefs_.SetSyncAuthError(true);
@@ -785,6 +786,9 @@ void ProfileSyncService::OnGetTokenFailure(
       // Fallthrough.
     }
     default: {
+      if (error.state() != GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
+        LOG(ERROR) << "Unexpected persistent error: " << error.ToString();
+      }
       // Show error to user.
       UpdateAuthErrorState(error);
     }
index c4bf4e7..71b8c4f 100644 (file)
@@ -206,10 +206,10 @@ IN_PROC_BROWSER_TEST_F(SyncAuthTest, InvalidGrant) {
             GetSyncService((0))->GetAuthError().state());
 }
 
-// Verify that ProfileSyncService ends up with an SERVICE_ERROR auth error when
+// Verify that ProfileSyncService retries after SERVICE_ERROR auth error when
 // an invalid_client error is returned by OAuth2TokenService with an
 // HTTP_BAD_REQUEST (400) response code.
-IN_PROC_BROWSER_TEST_F(SyncAuthTest, InvalidClient) {
+IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryInvalidClient) {
   ASSERT_TRUE(SetupSync());
   ASSERT_FALSE(AttemptToTriggerAuthError());
   GetFakeServer()->SetUnauthenticated();
@@ -218,13 +218,12 @@ IN_PROC_BROWSER_TEST_F(SyncAuthTest, InvalidClient) {
                          net::HTTP_BAD_REQUEST,
                          net::URLRequestStatus::SUCCESS);
   ASSERT_TRUE(AttemptToTriggerAuthError());
-  ASSERT_EQ(GoogleServiceAuthError::SERVICE_ERROR,
-            GetSyncService((0))->GetAuthError().state());
+  ASSERT_TRUE(GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
 }
 
-// Verify that ProfileSyncService ends up with a REQUEST_CANCELED auth error
-// when when OAuth2TokenService has encountered a URLRequestStatus of CANCELED.
-IN_PROC_BROWSER_TEST_F(SyncAuthTest, RequestCanceled) {
+// Verify that ProfileSyncService retries after REQUEST_CANCELED auth error
+// when OAuth2TokenService has encountered a URLRequestStatus of CANCELED.
+IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryRequestCanceled) {
   ASSERT_TRUE(SetupSync());
   ASSERT_FALSE(AttemptToTriggerAuthError());
   GetFakeServer()->SetUnauthenticated();
@@ -233,8 +232,7 @@ IN_PROC_BROWSER_TEST_F(SyncAuthTest, RequestCanceled) {
                          net::HTTP_INTERNAL_SERVER_ERROR,
                          net::URLRequestStatus::CANCELED);
   ASSERT_TRUE(AttemptToTriggerAuthError());
-  ASSERT_EQ(GoogleServiceAuthError::REQUEST_CANCELED,
-            GetSyncService((0))->GetAuthError().state());
+  ASSERT_TRUE(GetSyncService((0))->IsRetryingAccessTokenFetchForTest());
 }
 
 // Verify that ProfileSyncService fails initial sync setup during backend
index ad47041..bd447c2 100644 (file)
@@ -94,6 +94,11 @@ void ThumbnailListSource::StartDataRequest(
     int render_process_id,
     int render_frame_id,
     const content::URLDataSource::GotDataCallback& callback) {
+  if (!profile_->GetTopSites()) {
+    callback.Run(NULL);
+    return;
+  }
+
   profile_->GetTopSites()->GetMostVisitedURLs(
       base::Bind(&ThumbnailListSource::OnMostVisitedURLsAvailable,
                  weak_ptr_factory_.GetWeakPtr(),
index 8ce3153..8129eb2 100644 (file)
@@ -142,13 +142,6 @@ void WebsiteSettingsPopupAndroid::SetIdentityInfo(
 
     ScopedJavaLocalRef<jstring> description = ConvertUTF8ToJavaString(
         env, identity_info.identity_status_description);
-    Java_WebsiteSettingsPopup_addDescriptionSection(
-        env,
-        popup_jobject_.obj(),
-        icon_id,
-        ConvertUTF8ToJavaString(env, headline).obj(),
-        description.obj());
-
     base::string16 certificate_label =
         l10n_util::GetStringUTF16(IDS_PAGEINFO_CERT_INFO_BUTTON);
     Java_WebsiteSettingsPopup_addCertificateSection(
index 06eea7b..8d636f4 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/stringprintf.h"
+#include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/favicon/favicon_tab_helper.h"
 #include "chrome/browser/file_select_helper.h"
 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
@@ -17,6 +18,7 @@
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
+#include "chrome/browser/ui/zoom/zoom_controller.h"
 #include "chrome/common/extensions/chrome_extension_messages.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/render_view_host.h"
@@ -164,6 +166,10 @@ void ChromeAppDelegate::InitWebContents(content::WebContents* web_contents) {
   printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
 #endif  // defined(ENABLE_FULL_PRINTING)
 #endif  // defined(ENABLE_PRINTING)
+
+  // Kiosk app supports zooming.
+  if (chrome::IsRunningInForcedAppMode())
+    ZoomController::CreateForWebContents(web_contents);
 }
 
 content::WebContents* ChromeAppDelegate::OpenURLFromTab(
index cd912ec..bcd0c9a 100644 (file)
@@ -22,6 +22,9 @@ class PasswordGenerationPopupController : public AutofillPopupViewDelegate {
   // Spacing between the border of the popup and any text.
   static const int kHorizontalPadding = 10;
 
+  // Desired height of the password section.
+  static const int kPopupPasswordSectionHeight = 62;
+
   // Called by the view when the saved passwords link is clicked.
   virtual void OnSavedPasswordsLinkClicked() = 0;
 
index 6c22cb8..9f4cd9a 100644 (file)
@@ -9,8 +9,7 @@
 #include "base/logging.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
 #import "chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.h"
-#include "ui/base/cocoa/window_size_constants.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/size.h"
 
 namespace autofill {
 
@@ -36,8 +35,7 @@ void PasswordGenerationPopupViewBridge::Show() {
 }
 
 gfx::Size PasswordGenerationPopupViewBridge::GetPreferredSizeOfPasswordView() {
-  // TODO(gcasto): Implement this function.
-  return gfx::Size();
+  return gfx::Size(NSSizeToCGSize([view_ preferredSize]));
 }
 
 void PasswordGenerationPopupViewBridge::UpdateBoundsAndRedrawPopup() {
@@ -50,8 +48,7 @@ void PasswordGenerationPopupViewBridge::PasswordSelectionUpdated() {
 
 bool PasswordGenerationPopupViewBridge::IsPointInPasswordBounds(
     const gfx::Point& point) {
-  // TODO(gcasto): Implement this function.
-  return true;
+  return [view_ isPointInPasswordBounds:NSPointFromCGPoint(point.ToCGPoint())];
 }
 
 PasswordGenerationPopupView* PasswordGenerationPopupView::Create(
index e475161..35dd04f 100644 (file)
@@ -7,6 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
+#include "base/mac/scoped_nsobject.h"
 #include "chrome/browser/ui/autofill/password_generation_popup_controller.h"
 #import "chrome/browser/ui/cocoa/autofill/autofill_popup_base_view_cocoa.h"
 
@@ -23,9 +24,12 @@ class AutofillPopupController;
   // The cross-platform controller for this view.
   __weak autofill::PasswordGenerationPopupController* controller_;
 
-  __weak NSTextField* passwordField_;
-  __weak NSTextField* passwordSubtextField_;
-  __weak HyperlinkTextView* helpTextView_;
+  base::scoped_nsobject<NSView> passwordSection_;
+  base::scoped_nsobject<NSTextField> passwordField_;
+  base::scoped_nsobject<NSTextField> passwordTitleField_;
+  base::scoped_nsobject<NSImageView> keyIcon_;
+  base::scoped_nsobject<NSBox> divider_;
+  base::scoped_nsobject<HyperlinkTextView> helpTextView_;
 }
 
 // Designated initializer.
@@ -33,10 +37,17 @@ class AutofillPopupController;
     (autofill::PasswordGenerationPopupController*)controller
                    frame:(NSRect)frame;
 
+// Determines whether |point| falls inside the password section of the popup.
+// |point| needs to be in the popup's coordinate system.
+- (BOOL)isPointInPasswordBounds:(NSPoint)point;
+
 // Informs the view that its controller has been (or will imminently be)
 // destroyed.
 - (void)controllerDestroyed;
 
+// The preferred size for the popup.
+- (NSSize)preferredSize;
+
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_AUTOFILL_PASSWORD_GENERATION_POPUP_VIEW_COCOA_H_
index a8a85fd..a3db139 100644 (file)
@@ -4,6 +4,8 @@
 
 #import "chrome/browser/ui/cocoa/autofill/password_generation_popup_view_cocoa.h"
 
+#include <cmath>
+
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
@@ -14,6 +16,7 @@
 #import "chrome/browser/ui/cocoa/hyperlink_text_view.h"
 #import "chrome/browser/ui/cocoa/l10n_util.h"
 #include "components/autofill/core/browser/popup_item_ids.h"
+#include "grit/theme_resources.h"
 #include "skia/ext/skia_utils_mac.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/text_constants.h"
 
 using autofill::AutofillPopupView;
+using autofill::PasswordGenerationPopupController;
 using autofill::PasswordGenerationPopupView;
 using base::scoped_nsobject;
 
 namespace {
 
+// The height of the divider between the password and help sections, in pixels.
+const CGFloat kDividerHeight = 1;
+
+// The amount of whitespace, in pixels, between lines of text in the password
+// section.
+const CGFloat kPasswordSectionVerticalSeparation = 5;
+
 NSColor* DividerColor() {
   return gfx::SkColorToCalibratedNSColor(
       PasswordGenerationPopupView::kDividerColor);
@@ -65,30 +76,52 @@ NSColor* HelpLinkColor() {
   if (self = [super initWithDelegate:controller frame:frame]) {
     controller_ = controller;
 
-    passwordField_ = [self textFieldWithText:controller_->password()
-                                       color:[self nameColor]
-                                   alignment:NSLeftTextAlignment];
-    [self addSubview:passwordField_];
-
-    passwordSubtextField_ = [self textFieldWithText:controller_->SuggestedText()
-                                              color:[self subtextColor]
-                                          alignment:NSRightTextAlignment];
-    [self addSubview:passwordSubtextField_];
-
-    scoped_nsobject<HyperlinkTextView> helpTextView(
-        [[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
-    [helpTextView setMessage:base::SysUTF16ToNSString(controller_->HelpText())
-                    withFont:[self textFont]
-                messageColor:HelpTextColor()];
-    [helpTextView addLinkRange:controller_->HelpTextLinkRange().ToNSRange()
-                      withName:@""
-                     linkColor:HelpLinkColor()];
-    [helpTextView setDelegate:self];
-    [[helpTextView textContainer] setLineFragmentPadding:0.0f];
-    [helpTextView setVerticallyResizable:YES];
-    [self addSubview:helpTextView];
-    helpTextView_ = helpTextView.get();
-  }
+    passwordSection_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
+    [self addSubview:passwordSection_];
+
+    passwordField_.reset(
+        [[self textFieldWithText:controller_->password()
+                      attributes:[self passwordAttributes]] retain]);
+    [passwordSection_ addSubview:passwordField_];
+
+    passwordTitleField_.reset(
+        [[self textFieldWithText:controller_->SuggestedText()
+                      attributes:[self passwordTitleAttributes]] retain]);
+    [passwordSection_ addSubview:passwordTitleField_];
+
+    keyIcon_.reset([[NSImageView alloc] initWithFrame:NSZeroRect]);
+    NSImage* keyImage = ResourceBundle::GetSharedInstance()
+        .GetImageNamed(IDR_GENERATE_PASSWORD_KEY)
+        .ToNSImage();
+    [keyIcon_ setImage:keyImage];
+    [passwordSection_ addSubview:keyIcon_];
+
+    divider_.reset([[NSBox alloc] initWithFrame:NSZeroRect]);
+    [divider_ setBoxType:NSBoxCustom];
+    [divider_ setBorderType:NSLineBorder];
+    [divider_ setBorderColor:DividerColor()];
+    [self addSubview:divider_];
+
+    helpTextView_.reset([[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
+    [helpTextView_ setMessage:base::SysUTF16ToNSString(controller_->HelpText())
+                     withFont:[self textFont]
+                 messageColor:HelpTextColor()];
+    [helpTextView_ addLinkRange:controller_->HelpTextLinkRange().ToNSRange()
+                       withName:@""
+                      linkColor:HelpLinkColor()];
+    [helpTextView_ setDelegate:self];
+    [helpTextView_ setDrawsBackground:YES];
+    [helpTextView_ setBackgroundColor:HelpTextBackgroundColor()];
+    [helpTextView_
+        setTextContainerInset:NSMakeSize(controller_->kHorizontalPadding,
+                                         controller_->kHelpVerticalPadding)];
+    // Remove the underlining.
+    NSTextStorage* text = [helpTextView_ textStorage];
+    [text addAttribute:NSUnderlineStyleAttributeName
+                 value:@(NSUnderlineStyleNone)
+                 range:controller_->HelpTextLinkRange().ToNSRange()];
+    [self addSubview:helpTextView_];
+}
 
   return self;
 }
@@ -96,6 +129,8 @@ NSColor* HelpLinkColor() {
 #pragma mark NSView implementation:
 
 - (void)drawRect:(NSRect)dirtyRect {
+  [super drawRect:dirtyRect];
+
   // If the view is in the process of being destroyed, don't bother drawing.
   if (!controller_)
     return;
@@ -104,30 +139,119 @@ NSColor* HelpLinkColor() {
 
   if (controller_->password_selected()) {
     // Draw a highlight under the suggested password.
-    NSRect highlightBounds = [self passwordBounds];
+    NSRect highlightBounds = [passwordSection_ frame];
     [[self highlightColor] set];
     [NSBezierPath fillRect:highlightBounds];
   }
-
-  // Render the background of the help text.
-  [HelpTextBackgroundColor() set];
-  [NSBezierPath fillRect:[self helpBounds]];
-
-  // Render the divider.
-  [DividerColor() set];
-  [NSBezierPath fillRect:[self dividerBounds]];
 }
 
 #pragma mark Public API:
 
+- (NSSize)preferredSize {
+  const NSSize passwordTitleSize =
+      [base::SysUTF16ToNSString(controller_->SuggestedText())
+          sizeWithAttributes:@{ NSFontAttributeName : [self boldFont] }];
+  const NSSize passwordSize = [base::SysUTF16ToNSString(controller_->password())
+      sizeWithAttributes:@{ NSFontAttributeName : [self textFont] }];
+
+  CGFloat width =
+      autofill::kPopupBorderThickness +
+      controller_->kHorizontalPadding +
+      [[keyIcon_ image] size].width +
+      controller_->kHorizontalPadding +
+      std::max(passwordSize.width, passwordTitleSize.width) +
+      controller_->kHorizontalPadding +
+      autofill::kPopupBorderThickness;
+
+  width = std::max(width, (CGFloat)controller_->GetMinimumWidth());
+
+  CGFloat height =
+      autofill::kPopupBorderThickness +
+      controller_->kHelpVerticalPadding +
+      [self helpSizeForPopupWidth:width].height +
+      controller_->kHelpVerticalPadding +
+      autofill::kPopupBorderThickness;
+
+  if (controller_->display_password())
+    height += controller_->kPopupPasswordSectionHeight;
+
+  return NSMakeSize(width, height);
+}
+
 - (void)updateBoundsAndRedrawPopup {
-  [self positionView:passwordField_ inRect:[self passwordBounds]];
-  [self positionView:passwordSubtextField_ inRect:[self passwordBounds]];
-  [self positionView:helpTextView_ inRect:[self helpBounds]];
+  const CGFloat popupWidth = controller_->popup_bounds().width();
+  const CGFloat contentWidth =
+      popupWidth - (2 * autofill::kPopupBorderThickness);
+  const CGFloat contentHeight = controller_->popup_bounds().height() -
+                                (2 * autofill::kPopupBorderThickness);
+
+  if (controller_->display_password()) {
+    // The password can change while the bubble is shown: If the user has
+    // accepted the password and then selects the form again and starts deleting
+    // the password, the field will be initially invisible and then become
+    // visible.
+    [self updatePassword];
+
+    // Lay out the password section, which includes the key icon, the title, and
+    // the suggested password.
+    [passwordSection_
+        setFrame:NSMakeRect(autofill::kPopupBorderThickness,
+                            autofill::kPopupBorderThickness,
+                            contentWidth,
+                            controller_->kPopupPasswordSectionHeight)];
+
+    // The key icon falls to the left of the title and password.
+    const NSSize imageSize = [[keyIcon_ image] size];
+    const CGFloat keyX = controller_->kHorizontalPadding;
+    const CGFloat keyY =
+        std::ceil((controller_->kPopupPasswordSectionHeight / 2.0) -
+                  (imageSize.height / 2.0));
+    [keyIcon_ setFrame:{ NSMakePoint(keyX, keyY), imageSize }];
+
+    // The title and password fall to the right of the key icon and are centered
+    // vertically as a group with some padding in between.
+    [passwordTitleField_ sizeToFit];
+    [passwordField_ sizeToFit];
+    const CGFloat groupHeight = NSHeight([passwordField_ frame]) +
+                                kPasswordSectionVerticalSeparation +
+                                NSHeight([passwordTitleField_ frame]);
+    const CGFloat groupX =
+        NSMaxX([keyIcon_ frame]) + controller_->kHorizontalPadding;
+    const CGFloat groupY =
+        std::ceil((controller_->kPopupPasswordSectionHeight / 2.0) -
+                  (groupHeight / 2.0));
+    [passwordField_ setFrameOrigin:NSMakePoint(groupX, groupY)];
+    const CGFloat titleY = groupY +
+                           NSHeight([passwordField_ frame]) +
+                           kPasswordSectionVerticalSeparation;
+    [passwordTitleField_ setFrameOrigin:NSMakePoint(groupX, titleY)];
+
+    // Layout the divider, which falls immediately below the password section.
+    const CGFloat dividerX = autofill::kPopupBorderThickness;
+    const CGFloat dividerY = NSMaxY([passwordSection_ frame]);
+    NSRect dividerFrame =
+        NSMakeRect(dividerX, dividerY, contentWidth, kDividerHeight);
+    [divider_ setFrame:dividerFrame];
+  }
+
+  // Layout the help section beneath the divider (if applicable, otherwise
+  // beneath the border).
+  const CGFloat helpX = autofill::kPopupBorderThickness;
+  const CGFloat helpY = controller_->display_password()
+      ? NSMaxY([divider_ frame])
+      : autofill::kPopupBorderThickness;
+  const CGFloat helpHeight = contentHeight -
+                             NSHeight([passwordSection_ frame]) -
+                             NSHeight([divider_ frame]);
+  [helpTextView_ setFrame:NSMakeRect(helpX, helpY, contentWidth, helpHeight)];
 
   [super updateBoundsAndRedrawPopup];
 }
 
+- (BOOL)isPointInPasswordBounds:(NSPoint)point {
+  return NSPointInRect(point, [passwordSection_ frame]);
+}
+
 - (void)controllerDestroyed {
   controller_ = NULL;
   [super delegateDestroyed];
@@ -144,27 +268,45 @@ NSColor* HelpLinkColor() {
 
 #pragma mark Private helpers:
 
-- (NSTextField*)textFieldWithText:(const base::string16&)text
-                            color:(NSColor*)color
-                        alignment:(NSTextAlignment)alignment {
+- (void)updatePassword {
+  base::scoped_nsobject<NSMutableAttributedString> updatedPassword(
+      [[NSMutableAttributedString alloc]
+          initWithString:base::SysUTF16ToNSString(controller_->password())
+              attributes:[self passwordAttributes]]);
+  [passwordField_ setAttributedStringValue:updatedPassword];
+}
+
+- (NSDictionary*)passwordTitleAttributes {
   scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
       [[NSMutableParagraphStyle alloc] init]);
-  [paragraphStyle setAlignment:alignment];
+  [paragraphStyle setAlignment:NSLeftTextAlignment];
+  return @{
+    NSFontAttributeName : [self boldFont],
+    NSForegroundColorAttributeName : [self nameColor],
+    NSParagraphStyleAttributeName : paragraphStyle.autorelease()
+  };
+}
 
-  NSDictionary* textAttributes = @{
+- (NSDictionary*)passwordAttributes {
+  scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
+      [[NSMutableParagraphStyle alloc] init]);
+  [paragraphStyle setAlignment:NSLeftTextAlignment];
+  return @{
     NSFontAttributeName : [self textFont],
-    NSForegroundColorAttributeName : color,
-    NSParagraphStyleAttributeName : paragraphStyle
+    NSForegroundColorAttributeName : [self nameColor],
+    NSParagraphStyleAttributeName : paragraphStyle.autorelease()
   };
+}
 
+- (NSTextField*)textFieldWithText:(const base::string16&)text
+                       attributes:(NSDictionary*)attributes {
+  NSTextField* textField =
+      [[[NSTextField alloc] initWithFrame:NSZeroRect] autorelease];
   scoped_nsobject<NSAttributedString> attributedString(
       [[NSAttributedString alloc]
           initWithString:base::SysUTF16ToNSString(text)
-              attributes:textAttributes]);
-
-  NSTextField* textField =
-      [[[NSTextField alloc] initWithFrame:NSZeroRect] autorelease];
-  [textField setAttributedStringValue:attributedString];
+              attributes:attributes]);
+  [textField setAttributedStringValue:attributedString.autorelease()];
   [textField setEditable:NO];
   [textField setSelectable:NO];
   [textField setDrawsBackground:NO];
@@ -172,31 +314,25 @@ NSColor* HelpLinkColor() {
   return textField;
 }
 
-- (void)positionView:(NSView*)view inRect:(NSRect)bounds {
-  NSRect frame = NSInsetRect(bounds, controller_->kHorizontalPadding, 0);
-  [view setFrame:frame];
-
-  // Center the text vertically within the bounds.
-  NSSize delta = cocoa_l10n_util::WrapOrSizeToFit(view);
-  [view setFrameOrigin:
-      NSInsetRect(frame, 0, floor(-delta.height/2)).origin];
-}
-
-- (NSRect)passwordBounds {
-  return NSZeroRect;
-}
-
-- (NSRect)helpBounds {
-  return NSZeroRect;
+- (NSSize)helpSizeForPopupWidth:(CGFloat)width {
+  const CGFloat helpWidth = width -
+                            2 * controller_->kHorizontalPadding -
+                            2 * autofill::kPopupBorderThickness;
+  const NSSize size = NSMakeSize(helpWidth, MAXFLOAT);
+  NSRect textFrame = [base::SysUTF16ToNSString(controller_->HelpText())
+      boundingRectWithSize:size
+                   options:NSLineBreakByWordWrapping |
+                           NSStringDrawingUsesLineFragmentOrigin
+                attributes:@{ NSFontAttributeName : [self textFont] }];
+  return textFrame.size;
 }
 
-- (NSRect)dividerBounds {
-  return NSZeroRect;
+- (NSFont*)boldFont {
+  return [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]];
 }
 
 - (NSFont*)textFont {
-  return ResourceBundle::GetSharedInstance().GetFontList(
-      ResourceBundle::SmallFont).GetPrimaryFont().GetNativeFont();
+  return [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
 }
 
 @end
index 51b265a..fdbd89f 100644 (file)
@@ -135,6 +135,9 @@ class Command;
   // fullscreen mode.
   BOOL enteringFullscreen_;
 
+  // True when entering system fullscreen.
+  BOOL enteringSystemFullscreen_;
+
   // True between |-setPresentationMode:url:bubbleType:| and
   // |-windowDidEnterFullScreen:| to indicate that the window is in the process
   // of transitioning into fullscreen presentation mode.
index 808e3ba..0bf99da 100644 (file)
@@ -314,9 +314,23 @@ willPositionSheet:(NSWindow*)sheet
   maxY -= tabStripHeight;
   [tabStripView setFrame:NSMakeRect(0, maxY, width, tabStripHeight)];
 
+  // In Yosemite fullscreen, manually add the fullscreen controls to the tab
+  // strip.
+  BOOL isInAppKitFullscreen =
+      [self isInSystemFullscreen] || enteringSystemFullscreen_;
+  BOOL addControlsInFullscreen =
+      isInAppKitFullscreen && base::mac::IsOSYosemiteOrLater();
+
   // Set left indentation based on fullscreen mode status.
-  [tabStripController_ setLeftIndentForControls:(fullscreen ? 0 :
-      [[tabStripController_ class] defaultLeftIndentForControls])];
+  CGFloat leftIndent = 0;
+  if (!fullscreen || addControlsInFullscreen)
+    leftIndent = [[tabStripController_ class] defaultLeftIndentForControls];
+  [tabStripController_ setLeftIndentForControls:leftIndent];
+
+  if (addControlsInFullscreen)
+    [tabStripController_ addWindowControls];
+  else
+    [tabStripController_ removeWindowControls];
 
   // Lay out the icognito/avatar badge because calculating the indentation on
   // the right depends on it.
@@ -875,6 +889,7 @@ willPositionSheet:(NSWindow*)sheet
   BOOL mode = enteringPresentationMode_ ||
        browser_->fullscreen_controller()->IsWindowFullscreenForTabOrPending();
   enteringFullscreen_ = YES;
+  enteringSystemFullscreen_ = YES;
   [self setPresentationModeInternal:mode forceDropdown:NO];
 }
 
@@ -895,6 +910,7 @@ willPositionSheet:(NSWindow*)sheet
   if (notification)  // For System Fullscreen when non-nil.
     [self deregisterForContentViewResizeNotifications];
   enteringFullscreen_ = NO;
+  enteringSystemFullscreen_ = NO;
   enteringPresentationMode_ = NO;
 
   const CommandLine* command_line = CommandLine::ForCurrentProcess();
@@ -928,6 +944,7 @@ willPositionSheet:(NSWindow*)sheet
 - (void)windowDidFailToEnterFullScreen:(NSWindow*)window {
   [self deregisterForContentViewResizeNotifications];
   enteringFullscreen_ = NO;
+  enteringSystemFullscreen_ = NO;
   [self setPresentationModeInternal:NO forceDropdown:NO];
 
   // Force a relayout to try and get the window back into a reasonable state.
index 34a1195..87f757c 100644 (file)
@@ -46,7 +46,7 @@ void CocoaProfileTest::SetUp() {
 
   ASSERT_TRUE(profile_manager_.SetUp());
 
-  profile_ = profile_manager_.CreateTestingProfile("default");
+  profile_ = profile_manager_.CreateTestingProfile("Person 1");
   ASSERT_TRUE(profile_);
 
   // TODO(shess): These are needed in case someone creates a browser
index 9ec3864..615337c 100644 (file)
@@ -28,10 +28,8 @@ class ConstrainedWebDialogDelegateMac
  public:
   ConstrainedWebDialogDelegateMac(
       content::BrowserContext* browser_context,
-      WebDialogDelegate* delegate,
-      WebDialogWebContentsDelegate* tab_delegate)
-      : ConstrainedWebDialogDelegateBase(
-            browser_context, delegate, tab_delegate) {}
+      WebDialogDelegate* delegate)
+      : ConstrainedWebDialogDelegateBase(browser_context, delegate, NULL) {}
 
   // WebDialogWebContentsDelegate interface.
   virtual void CloseContents(WebContents* source) OVERRIDE {
@@ -58,7 +56,6 @@ class ConstrainedWebDialogDelegateViewMac :
   ConstrainedWebDialogDelegateViewMac(
       content::BrowserContext* browser_context,
       WebDialogDelegate* delegate,
-      WebDialogWebContentsDelegate* tab_delegate,
       content::WebContents* web_contents);
   virtual ~ConstrainedWebDialogDelegateViewMac() {}
 
@@ -102,11 +99,8 @@ class ConstrainedWebDialogDelegateViewMac :
 ConstrainedWebDialogDelegateViewMac::ConstrainedWebDialogDelegateViewMac(
     content::BrowserContext* browser_context,
     WebDialogDelegate* delegate,
-    WebDialogWebContentsDelegate* tab_delegate,
     content::WebContents* web_contents)
-    : impl_(new ConstrainedWebDialogDelegateMac(browser_context,
-                                                delegate,
-                                                tab_delegate)) {
+    : impl_(new ConstrainedWebDialogDelegateMac(browser_context, delegate)) {
   // Create a window to hold web_contents in the constrained sheet:
   gfx::Size size;
   delegate->GetDialogSize(&size);
@@ -128,11 +122,10 @@ ConstrainedWebDialogDelegateViewMac::ConstrainedWebDialogDelegateViewMac(
 ConstrainedWebDialogDelegate* CreateConstrainedWebDialog(
         content::BrowserContext* browser_context,
         WebDialogDelegate* delegate,
-        WebDialogWebContentsDelegate* tab_delegate,
         content::WebContents* web_contents) {
   // Deleted when the dialog closes.
   ConstrainedWebDialogDelegateViewMac* constrained_delegate =
       new ConstrainedWebDialogDelegateViewMac(
-          browser_context, delegate, tab_delegate, web_contents);
+          browser_context, delegate, web_contents);
   return constrained_delegate;
 }
index 7198d96..93ab5ec 100644 (file)
@@ -84,6 +84,7 @@ const CGFloat kProfileButtonHeight = 30;
 const int kBezelThickness = 3;  // Width of the bezel on an NSButton.
 const int kImageTitleSpacing = 10;
 const int kBlueButtonHeight = 30;
+const CGFloat kFocusRingLineWidth = 2;
 
 // Fixed size for embedded sign in pages as defined in Gaia.
 const CGFloat kFixedGaiaViewWidth = 360;
@@ -93,7 +94,7 @@ const CGFloat kFixedGaiaViewHeight = 440;
 const CGFloat kFixedAccountRemovalViewWidth = 280;
 
 // Fixed size for the switch user view.
-const int kFixedSwitchUserViewWidth = 280;
+const int kFixedSwitchUserViewWidth = 320;
 
 // The tag number for the primary account.
 const int kPrimaryProfileTag = -1;
@@ -229,7 +230,7 @@ NSView* BuildTitleCard(NSRect frame_rect,
   [container addSubview:button];
   [container addSubview:title_label];
   CGFloat height = std::max(NSMaxY([title_label frame]),
-                            NSMaxY([button frame])) + kSmallVerticalSpacing;
+                            NSMaxY([button frame])) + kVerticalSpacing;
   [container setFrameSize:NSMakeSize(NSWidth([container frame]), height)];
 
   return container.autorelease();
@@ -409,22 +410,34 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   return buttonSize;
 }
 
-@end
+- (NSFocusRingType)focusRingType {
+  // This is taken care of by the custom drawing code.
+  return NSFocusRingTypeNone;
+}
 
-// A custom button that has a transparent backround.
-@interface TransparentBackgroundButton : NSButton
-@end
+- (void)drawWithFrame:(NSRect)frame inView:(NSView *)controlView {
+  [super drawInteriorWithFrame:frame inView:controlView];
 
-@implementation TransparentBackgroundButton
-- (id)initWithFrame:(NSRect)frameRect {
-  if ((self = [super initWithFrame:frameRect])) {
-    [self setBordered:NO];
-    [self setFont:[NSFont labelFontOfSize:kTextFontSize]];
-    [self setButtonType:NSMomentaryChangeButton];
+  // Focus ring.
+  if ([self showsFirstResponder]) {
+    NSRect focusRingRect =
+        NSInsetRect(frame, kFocusRingLineWidth, kFocusRingLineWidth);
+    // TODO(noms): When we are targetting 10.7, we should change this to use
+    // -drawFocusRingMaskWithFrame instead.
+    [[[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:1] set];
+    NSBezierPath* path = [NSBezierPath bezierPathWithRect:focusRingRect];
+    [path setLineWidth:kFocusRingLineWidth];
+    [path stroke];
   }
-  return self;
 }
 
+@end
+
+// A custom image view that has a transparent backround.
+@interface TransparentBackgroundImageView : NSImageView
+@end
+
+@implementation TransparentBackgroundImageView
 - (void)drawRect:(NSRect)dirtyRect {
   NSColor* backgroundColor = [NSColor colorWithCalibratedWhite:1 alpha:0.6f];
   [backgroundColor setFill];
@@ -433,13 +446,31 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
 }
 @end
 
+@interface CustomCircleImageCell : NSButtonCell
+@end
+
+@implementation CustomCircleImageCell
+- (void)drawWithFrame:(NSRect)frame inView:(NSView *)controlView {
+  // Display everything as a circle that spans the entire control.
+  NSBezierPath* path = [NSBezierPath bezierPathWithOvalInRect:frame];
+  [path addClip];
+
+  [super drawImage:[self image] withFrame:frame inView:controlView];
+
+  // Focus ring.
+  if ([self showsFirstResponder]) {
+    [[[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:1] set];
+    [path setLineWidth:kFocusRingLineWidth];
+    [path stroke];
+  }
+}
+@end
+
 // A custom image control that shows a "Change" button when moused over.
-@interface EditableProfilePhoto : NSImageView {
+@interface EditableProfilePhoto : HoverImageButton {
  @private
   AvatarMenu* avatarMenu_;  // Weak; Owned by ProfileChooserController.
-  base::scoped_nsobject<TransparentBackgroundButton> changePhotoButton_;
-  // Used to display the "Change" button on hover.
-  ui::ScopedCrTrackingArea trackingArea_;
+  base::scoped_nsobject<TransparentBackgroundImageView> changePhotoImage_;
   ProfileChooserController* controller_;
 }
 
@@ -452,16 +483,6 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
 // Called when the "Change" button is clicked.
 - (void)editPhoto:(id)sender;
 
-// When hovering over the profile photo, show the "Change" button.
-- (void)mouseEntered:(NSEvent*)event;
-
-// When hovering away from the profile photo, hide the "Change" button.
-- (void)mouseExited:(NSEvent*)event;
-@end
-
-@interface EditableProfilePhoto (Private)
-// Create the "Change" avatar photo button.
-- (TransparentBackgroundButton*)changePhotoButtonWithRect:(NSRect)rect;
 @end
 
 @implementation EditableProfilePhoto
@@ -473,24 +494,29 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   if ((self = [super initWithFrame:frameRect])) {
     avatarMenu_ = avatarMenu;
     controller_ = controller;
-    [self setImage:CreateProfileImage(
-        profileIcon, kLargeImageSide).ToNSImage()];
 
-    // Add a tracking area so that we can show/hide the button when hovering.
-    trackingArea_.reset([[CrTrackingArea alloc]
-        initWithRect:[self bounds]
-             options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways
-               owner:self
-            userInfo:nil]);
-    [self addTrackingArea:trackingArea_.get()];
+    [self setBordered:NO];
+
+    base::scoped_nsobject<CustomCircleImageCell> cell(
+        [[CustomCircleImageCell alloc] init]);
+    [self setCell:cell.get()];
+
+    [self setDefaultImage:CreateProfileImage(
+        profileIcon, kLargeImageSide).ToNSImage()];
+    [self setImagePosition:NSImageOnly];
 
     NSRect bounds = NSMakeRect(0, 0, kLargeImageSide, kLargeImageSide);
     if (editingAllowed) {
-      changePhotoButton_.reset([self changePhotoButtonWithRect:bounds]);
-      [self addSubview:changePhotoButton_];
-
-      // Hide the button until the image is hovered over.
-      [changePhotoButton_ setHidden:YES];
+      [self setTarget:self];
+      [self setAction:@selector(editPhoto:)];
+      changePhotoImage_.reset([[TransparentBackgroundImageView alloc]
+          initWithFrame:bounds]);
+      [changePhotoImage_ setImage:ui::ResourceBundle::GetSharedInstance().
+          GetNativeImageNamed(IDR_ICON_PROFILES_EDIT_CAMERA).AsNSImage()];
+      [self addSubview:changePhotoImage_];
+
+      // Hide the image until the button is hovered over.
+      [changePhotoImage_ setHidden:YES];
     }
 
     // Set the image cell's accessibility strings to be the same as the
@@ -522,36 +548,15 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   return self;
 }
 
-- (void)drawRect:(NSRect)dirtyRect {
-  NSRect bounds = [self bounds];
-
-  // Display the profile picture as a circle.
-  NSBezierPath* path = [NSBezierPath bezierPathWithOvalInRect:bounds];
-  [path addClip];
-  [self.image drawAtPoint:bounds.origin
-                 fromRect:bounds
-                operation:NSCompositeSourceOver
-                 fraction:1.0];
-
-}
-
 - (void)editPhoto:(id)sender {
   avatarMenu_->EditProfile(avatarMenu_->GetActiveProfileIndex());
   [controller_
       postActionPerformed:ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE];
 }
 
-- (void)mouseEntered:(NSEvent*)event {
-  [changePhotoButton_ setHidden:NO];
-}
-
-- (void)mouseExited:(NSEvent*)event {
-  [changePhotoButton_ setHidden:YES];
-}
-
-// Make sure the element is focusable for accessibility.
-- (BOOL)canBecomeKeyView {
-  return YES;
+- (void)setHoverState:(HoverState)state {
+  [super setHoverState:state];
+  [changePhotoImage_ setHidden:([self hoverState] == kHoverStateNone)];
 }
 
 - (BOOL)accessibilityIsIgnored {
@@ -571,16 +576,6 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   [super accessibilityPerformAction:action];
 }
 
-- (TransparentBackgroundButton*)changePhotoButtonWithRect:(NSRect)rect {
-  TransparentBackgroundButton* button =
-      [[TransparentBackgroundButton alloc] initWithFrame:rect];
-  [button setImage:ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
-      IDR_ICON_PROFILES_EDIT_CAMERA).AsNSImage()];
-  [button setImagePosition:NSImageOnly];
-  [button setTarget:self];
-  [button setAction:@selector(editPhoto:)];
-  return button;
-}
 @end
 
 // A custom text control that turns into a textfield for editing when clicked.
@@ -772,6 +767,26 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
 }
 @end
 
+// A custom dummy button that is used to clear focus from the bubble's controls.
+@interface DummyWindowFocusButton : NSButton
+@end
+
+@implementation DummyWindowFocusButton
+// Ignore accessibility, as this is a placeholder button.
+- (BOOL)accessibilityIsIgnored {
+  return YES;
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+  return @[];
+}
+
+- (BOOL)canBecomeKeyView {
+  return false;
+}
+
+@end
+
 @interface ProfileChooserController ()
 // Builds the profile chooser view.
 - (NSView*)buildProfileChooserView;
@@ -1126,7 +1141,15 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   if (viewMode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER)
     tutorialMode_ = profiles::TUTORIAL_MODE_NONE;
 
+  // Add a dummy, empty element so that we don't initially display any
+  // focus rings.
+  NSButton* dummyFocusButton =
+      [[[DummyWindowFocusButton alloc] initWithFrame:NSZeroRect] autorelease];
+  [dummyFocusButton setNextKeyView:subView];
+  [[self window] makeFirstResponder:dummyFocusButton];
+
   [contentView addSubview:subView];
+  [contentView addSubview:dummyFocusButton];
   SetWindowSize([self window],
       NSMakeSize(NSWidth([subView frame]), NSHeight([subView frame])));
 }
@@ -1670,7 +1693,8 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
 - (NSButton*)createOtherProfileView:(int)itemIndex {
   const AvatarMenu::Item& item = avatarMenu_->GetItemAt(itemIndex);
 
-  NSRect rect = NSMakeRect(0, 0, kFixedMenuWidth, kBlueButtonHeight);
+  NSRect rect = NSMakeRect(
+      0, 0, kFixedMenuWidth, kBlueButtonHeight + kSmallVerticalSpacing);
   base::scoped_nsobject<BackgroundColorHoverButton> profileButton(
       [[BackgroundColorHoverButton alloc]
           initWithFrame:rect
@@ -1875,7 +1899,7 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   NSBox* separator = [self horizontalSeparatorWithFrame:
       NSMakeRect(0, yOffset, kFixedGaiaViewWidth, 0)];
   [container addSubview:separator];
-  yOffset = NSMaxY([separator frame]) + kSmallVerticalSpacing;
+  yOffset = NSMaxY([separator frame]) + kVerticalSpacing;
 
   NSView* titleView = BuildTitleCard(
       NSMakeRect(0, yOffset, kFixedGaiaViewWidth, 0),
@@ -1945,7 +1969,7 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   NSBox* separator = [self horizontalSeparatorWithFrame:
       NSMakeRect(0, yOffset, kFixedAccountRemovalViewWidth, 0)];
   [container addSubview:separator];
-  yOffset = NSMaxY([separator frame]) + kSmallVerticalSpacing;
+  yOffset = NSMaxY([separator frame]) + kVerticalSpacing;
 
   NSView* titleView = BuildTitleCard(
       NSMakeRect(0, yOffset, kFixedAccountRemovalViewWidth,0),
@@ -1985,7 +2009,7 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   yOffset = NSMaxY([disconnectButton frame]);
 
   NSBox* separator = [self horizontalSeparatorWithFrame:
-      NSMakeRect(0, yOffset, kFixedMenuWidth, 0)];
+      NSMakeRect(0, yOffset, kFixedSwitchUserViewWidth, 0)];
   [container addSubview:separator];
   yOffset = NSMaxY([separator frame]);
 
@@ -2001,7 +2025,7 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   yOffset = NSMaxY([addPersonButton frame]);
 
   separator = [self horizontalSeparatorWithFrame:
-      NSMakeRect(0, yOffset, kFixedMenuWidth, 0)];
+      NSMakeRect(0, yOffset, kFixedSwitchUserViewWidth, 0)];
   [container addSubview:separator];
   yOffset = NSMaxY([separator frame]);
 
@@ -2021,7 +2045,7 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   separator = [self horizontalSeparatorWithFrame:
       NSMakeRect(0, yOffset, kFixedSwitchUserViewWidth, 0)];
   [container addSubview:separator];
-  yOffset = NSMaxY([separator frame]) + kSmallVerticalSpacing;
+  yOffset = NSMaxY([separator frame]) + kVerticalSpacing;
 
   NSView* titleView = BuildTitleCard(
       NSMakeRect(0, yOffset, kFixedSwitchUserViewWidth,0),
@@ -2031,7 +2055,7 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver,
   [container addSubview:titleView];
   yOffset = NSMaxY([titleView frame]);
 
-  [container setFrameSize:NSMakeSize(kFixedAccountRemovalViewWidth, yOffset)];
+  [container setFrameSize:NSMakeSize(kFixedSwitchUserViewWidth, yOffset)];
   return container.autorelease();
 }
 
index e253775..d4fdeb0 100644 (file)
@@ -99,7 +99,7 @@ TEST_F(ProfileChooserControllerTest, InitialLayoutWithNewMenu) {
   StartProfileChooserController();
 
   NSArray* subviews = [[[controller() window] contentView] subviews];
-  ASSERT_EQ(1U, [subviews count]);
+  ASSERT_EQ(2U, [subviews count]);
   subviews = [[subviews objectAtIndex:0] subviews];
 
   // Three profiles means we should have one active card, one separator and
@@ -138,7 +138,7 @@ TEST_F(ProfileChooserControllerTest, InitialLayoutWithNewMenu) {
 
   // Profile icon.
   NSView* activeProfileImage = [activeCardSubviews objectAtIndex:2];
-  EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
+  EXPECT_TRUE([activeProfileImage isKindOfClass:[NSButton class]]);
 
   // Profile name.
   NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
@@ -166,7 +166,7 @@ TEST_F(ProfileChooserControllerTest, InitialLayoutWithFastUserSwitcher) {
   StartProfileChooserController();
 
   NSArray* subviews = [[[controller() window] contentView] subviews];
-  ASSERT_EQ(1U, [subviews count]);
+  ASSERT_EQ(2U, [subviews count]);
   subviews = [[subviews objectAtIndex:0] subviews];
 
   // Three profiles means we should have one active card and a
@@ -209,7 +209,7 @@ TEST_F(ProfileChooserControllerTest, InitialLayoutWithFastUserSwitcher) {
 
   // Profile icon.
   NSView* activeProfileImage = [activeCardSubviews objectAtIndex:2];
-  EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
+  EXPECT_TRUE([activeProfileImage isKindOfClass:[NSButton class]]);
 
   // Profile name.
   NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
@@ -240,7 +240,7 @@ TEST_F(ProfileChooserControllerTest, OtherProfilesSortedAlphabetically) {
   StartProfileChooserController();
 
   NSArray* subviews = [[[controller() window] contentView] subviews];
-  ASSERT_EQ(1U, [subviews count]);
+  ASSERT_EQ(2U, [subviews count]);
   subviews = [[subviews objectAtIndex:0] subviews];
   NSString* sortedNames[] = { @"Another Test",
                               @"New Profile",
@@ -272,7 +272,7 @@ TEST_F(ProfileChooserControllerTest,
   switches::EnableNewAvatarMenuForTesting(CommandLine::ForCurrentProcess());
   StartProfileChooserController();
   NSArray* subviews = [[[controller() window] contentView] subviews];
-  ASSERT_EQ(1U, [subviews count]);
+  ASSERT_EQ(2U, [subviews count]);
   subviews = [[subviews objectAtIndex:0] subviews];
   NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
   NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
@@ -301,7 +301,7 @@ TEST_F(ProfileChooserControllerTest,
 
   StartProfileChooserController();
   NSArray* subviews = [[[controller() window] contentView] subviews];
-  ASSERT_EQ(1U, [subviews count]);
+  ASSERT_EQ(2U, [subviews count]);
   subviews = [[subviews objectAtIndex:0] subviews];
   NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
   NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
@@ -323,7 +323,7 @@ TEST_F(ProfileChooserControllerTest,
 
   StartProfileChooserController();
   NSArray* subviews = [[[controller() window] contentView] subviews];
-  ASSERT_EQ(1U, [subviews count]);
+  ASSERT_EQ(2U, [subviews count]);
   subviews = [[subviews objectAtIndex:0] subviews];
   NSArray* activeCardSubviews = [[subviews objectAtIndex:2] subviews];
   NSArray* activeCardLinks = [[activeCardSubviews objectAtIndex:0] subviews];
@@ -358,7 +358,7 @@ TEST_F(ProfileChooserControllerTest, AccountManagementLayout) {
       profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT];
 
   NSArray* subviews = [[[controller() window] contentView] subviews];
-  ASSERT_EQ(1U, [subviews count]);
+  ASSERT_EQ(2U, [subviews count]);
   subviews = [[subviews objectAtIndex:0] subviews];
 
   // There should be one active card, one accounts container, two separators
@@ -435,7 +435,7 @@ TEST_F(ProfileChooserControllerTest, AccountManagementLayout) {
 
   // Profile icon.
   NSView* activeProfileImage = [activeCardSubviews objectAtIndex:2];
-  EXPECT_TRUE([activeProfileImage isKindOfClass:[NSImageView class]]);
+  EXPECT_TRUE([activeProfileImage isKindOfClass:[NSButton class]]);
 
   // Profile name.
   NSView* activeProfileName = [activeCardSubviews objectAtIndex:1];
index 6acd566..fa1d28e 100644 (file)
@@ -139,6 +139,10 @@ class WebContents;
 
   // Helper for performing tab selection as a result of dragging over a tab.
   scoped_ptr<HoverTabSelector> hoverTabSelector_;
+
+  // A container view for the window controls, which must be manually added in
+  // fullscreen in 10.10+.
+  base::scoped_nsobject<NSView> fullscreenWindowControls_;
 }
 
 @property(nonatomic) CGFloat leftIndentForControls;
@@ -248,6 +252,12 @@ class WebContents;
 // Returns the currently active TabContentsController.
 - (TabContentsController*)activeTabContentsController;
 
+// Adds traffic lights to the tab strip. Idempotent.
+- (void)addWindowControls;
+
+// Removes traffic lights from the tab strip. Idempotent.
+- (void)removeWindowControls;
+
 @end
 
 @interface TabStripController(TestingAPI)
index e8a76a1..9a0e525 100644 (file)
@@ -2172,6 +2172,56 @@ NSImage* Overlay(NSImage* ground, NSImage* overlay, CGFloat alpha) {
   return [tabContentsArray_ objectAtIndex:index];
 }
 
+- (void)addWindowControls {
+  if (!fullscreenWindowControls_) {
+    // Make the container view.
+    CGFloat height = NSHeight([tabStripView_ frame]);
+    NSRect frame = NSMakeRect(0, 0, [self leftIndentForControls], height);
+    fullscreenWindowControls_.reset([[NSView alloc] initWithFrame:frame]);
+    [fullscreenWindowControls_
+        setAutoresizingMask:NSViewMaxXMargin | NSViewHeightSizable];
+
+    // Add the traffic light buttons. The horizontal layout was determined by
+    // manual inspection on Yosemite.
+    CGFloat closeButtonX = 11;
+    CGFloat miniButtonX = 31;
+    CGFloat zoomButtonX = 51;
+
+    NSUInteger styleMask = [[tabStripView_ window] styleMask];
+    NSButton* closeButton = [NSWindow standardWindowButton:NSWindowCloseButton
+                                              forStyleMask:styleMask];
+
+    // Vertically center the buttons in the tab strip.
+    CGFloat buttonY = floor((height - NSHeight([closeButton bounds])) / 2);
+    [closeButton setFrameOrigin:NSMakePoint(closeButtonX, buttonY)];
+    [fullscreenWindowControls_ addSubview:closeButton];
+
+    NSButton* miniaturizeButton =
+        [NSWindow standardWindowButton:NSWindowMiniaturizeButton
+                          forStyleMask:styleMask];
+    [miniaturizeButton setFrameOrigin:NSMakePoint(miniButtonX, buttonY)];
+    [miniaturizeButton setEnabled:NO];
+    [fullscreenWindowControls_ addSubview:miniaturizeButton];
+
+    NSButton* zoomButton =
+        [NSWindow standardWindowButton:NSWindowZoomButton
+                          forStyleMask:styleMask];
+    [fullscreenWindowControls_ addSubview:zoomButton];
+    [zoomButton setFrameOrigin:NSMakePoint(zoomButtonX, buttonY)];
+  }
+
+  if (![permanentSubviews_ containsObject:fullscreenWindowControls_]) {
+    [self addSubviewToPermanentList:fullscreenWindowControls_];
+    [self regenerateSubviewList];
+  }
+}
+
+- (void)removeWindowControls {
+  if (fullscreenWindowControls_)
+    [permanentSubviews_ removeObject:fullscreenWindowControls_];
+  [self regenerateSubviewList];
+}
+
 - (void)themeDidChangeNotification:(NSNotification*)notification {
   [self setNewTabImages];
 }
index dee3a1c..5e826d6 100644 (file)
@@ -28,7 +28,7 @@
 namespace {
 
 // Hardcoded value for the secure version of Acrobat Reader.
-const char kSecureVersion[] = "11.0.7.79";
+const char kSecureVersion[] = "11.0.8.4";
 
 const char kAdobeReaderIdentifier[] = "adobe-reader";
 const char kPdfMimeType[] = "application/pdf";
@@ -94,10 +94,13 @@ AdobeReaderPluginInfo GetReaderPlugin(
       reader_info.is_enabled = plugin_status != PluginPrefs::POLICY_DISABLED;
     }
 
-    PluginMetadata::SecurityStatus security_status =
+    // Adobe Reader will likely always come up as "requires_authorization".
+    // See http://crbug.com/311655.
+    PluginMetadata::SecurityStatus security_stat =
         plugin_metadata->GetSecurityStatus(plugins[i]);
     reader_info.is_secure =
-        security_status == PluginMetadata::SECURITY_STATUS_UP_TO_DATE;
+        security_stat == PluginMetadata::SECURITY_STATUS_UP_TO_DATE ||
+        security_stat == PluginMetadata::SECURITY_STATUS_REQUIRES_AUTHORIZATION;
 
     reader_info.plugin_info = plugins[i];
     break;
index 56455fa..8ccf1fb 100644 (file)
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/views/apps/shaped_app_window_targeter.h"
 #include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h"
 #include "chrome/browser/ui/views/frame/taskbar_decorator.h"
+#include "chrome/browser/ui/zoom/zoom_controller.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_switches.h"
 #include "extensions/common/extension.h"
@@ -271,6 +272,11 @@ void ChromeNativeAppWindowViews::InitializeDefaultWindow(
              arraysize(kAppWindowAcceleratorMap) +
                  arraysize(kAppWindowKioskAppModeAcceleratorMap));
 
+  // Ensure there is a ZoomController in kiosk mode, otherwise the processing
+  // of the accelerators will cause a crash.
+  DCHECK(!is_kiosk_app_mode ||
+         ZoomController::FromWebContents(web_view()->GetWebContents()));
+
   for (std::map<ui::Accelerator, int>::const_iterator iter =
            accelerator_table.begin();
        iter != accelerator_table.end(); ++iter) {
index 2979d42..3c836b2 100644 (file)
@@ -25,7 +25,6 @@ namespace {
 // The amount of whitespace that is present when there is no padding. Used
 // to get the proper spacing in the help section.
 const int kHelpVerticalOffset = 5;
-const int kPasswordSectionHeight = 62;
 
 // Wrapper around just the text portions of the generation UI (password and
 // prompting text).
@@ -173,7 +172,8 @@ gfx::Size PasswordGenerationPopupViewViews::GetPreferredSizeOfPasswordView() {
   int height = kPopupBorderThickness;
   if (controller_->display_password()) {
     // Add divider height as well.
-    height += kPasswordSectionHeight + 1;
+    height +=
+        PasswordGenerationPopupController::kPopupPasswordSectionHeight + 1;
   }
   int width = controller_->GetMinimumWidth();
   int popup_width = width - 2 * kPopupBorderThickness;
@@ -217,7 +217,10 @@ void PasswordGenerationPopupViewViews::Layout() {
     // it), but it can't change the other way around.
     CreatePasswordView();
     password_view_->SetBounds(
-        kPopupBorderThickness, y, popup_width, kPasswordSectionHeight);
+        kPopupBorderThickness,
+        y,
+        popup_width,
+        PasswordGenerationPopupController::kPopupPasswordSectionHeight);
     divider_bounds_ =
         gfx::Rect(kPopupBorderThickness, password_view_->bounds().bottom(),
                   popup_width, 1);
index 402385d..8e9a3cf 100644 (file)
@@ -5,7 +5,10 @@
 #include "chrome/browser/ui/webui/constrained_web_dialog_delegate_base.h"
 
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/views/constrained_window_views.h"
+#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
 #include "ui/web_dialogs/web_dialog_delegate.h"
 #include "ui/web_dialogs/web_dialog_ui.h"
 
-#if defined(USE_AURA)
-#include "content/public/browser/render_widget_host_view.h"
-#include "ui/aura/client/focus_change_observer.h"
-#include "ui/aura/client/focus_client.h"
+namespace {
+
+class WebDialogWebContentsDelegateViews
+    : public ui::WebDialogWebContentsDelegate {
+ public:
+  WebDialogWebContentsDelegateViews(content::BrowserContext* browser_context,
+                                    content::WebContents* initiator,
+                                    views::WebView* web_view)
+      : ui::WebDialogWebContentsDelegate(browser_context,
+                                         new ChromeWebContentsHandler()),
+        initiator_(initiator),
+        web_view_(web_view) {
+  }
+  virtual ~WebDialogWebContentsDelegateViews() {}
+
+  // ui::WebDialogWebContentsDelegate:
+  virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE {
+    // Ensure the WebView is focused when its WebContents is focused.
+    web_view_->RequestFocus();
+  }
+  virtual void HandleKeyboardEvent(
+      content::WebContents* source,
+      const content::NativeWebKeyboardEvent& event) OVERRIDE {
+    // Forward shortcut keys in dialog to the browser. http://crbug.com/104586
+    // Disabled on Mac due to http://crbug.com/112173
+#if !defined(OS_MACOSX)
+    Browser* current_browser = chrome::FindBrowserWithWebContents(initiator_);
+    if (!current_browser)
+      return;
+    current_browser->window()->HandleKeyboardEvent(event);
 #endif
+  }
 
-using ui::WebDialogDelegate;
-using ui::WebDialogWebContentsDelegate;
+ private:
+  content::WebContents* initiator_;
+  views::WebView* web_view_;
 
-namespace {
+  DISALLOW_COPY_AND_ASSIGN(WebDialogWebContentsDelegateViews);
+};
 
 class ConstrainedWebDialogDelegateViews
     : public ConstrainedWebDialogDelegateBase {
  public:
   ConstrainedWebDialogDelegateViews(content::BrowserContext* context,
-                                    WebDialogDelegate* delegate,
-                                    WebDialogWebContentsDelegate* tab_delegate,
+                                    ui::WebDialogDelegate* delegate,
+                                    content::WebContents* web_contents,
                                     views::WebView* view)
-      : ConstrainedWebDialogDelegateBase(context, delegate, tab_delegate),
+      : ConstrainedWebDialogDelegateBase(context, delegate,
+            new WebDialogWebContentsDelegateViews(context, web_contents, view)),
         view_(view) {}
 
   virtual ~ConstrainedWebDialogDelegateViews() {}
 
-  // WebDialogWebContentsDelegate:
+  // ui::WebDialogWebContentsDelegate:
   virtual void CloseContents(content::WebContents* source) OVERRIDE {
     view_->GetWidget()->Close();
   }
@@ -65,44 +98,6 @@ class ConstrainedWebDialogDelegateViews
   DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateViews);
 };
 
-#if defined(USE_AURA)
-// TODO(msw): Make this part of WebView? Modify various WebContentsDelegates?
-class WebViewFocusHelper : public aura::client::FocusChangeObserver {
- public:
-  explicit WebViewFocusHelper(views::WebView* web_view)
-      : web_view_(web_view),
-        window_(NULL),
-        focus_client_(NULL) {
-    if (web_view_ && web_view_->web_contents()) {
-      content::RenderWidgetHostView* host_view =
-          web_view_->web_contents()->GetRenderWidgetHostView();
-      window_ = host_view ? host_view->GetNativeView() : NULL;
-    }
-    focus_client_ = window_ ? aura::client::GetFocusClient(window_) : NULL;
-    if (focus_client_)
-      focus_client_->AddObserver(this);
-  }
-
-  virtual ~WebViewFocusHelper() {
-    if (focus_client_)
-      focus_client_->RemoveObserver(this);
-  }
-
-  virtual void OnWindowFocused(aura::Window* gained_focus,
-                               aura::Window* lost_focus) OVERRIDE {
-    if (gained_focus == window_ && !web_view_->HasFocus())
-      web_view_->RequestFocus();
-  }
-
- private:
-  views::WebView* web_view_;
-  aura::Window* window_;
-  aura::client::FocusClient* focus_client_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebViewFocusHelper);
-};
-#endif
-
 class ConstrainedWebDialogDelegateViewViews
     : public views::WebView,
       public ConstrainedWebDialogDelegate,
@@ -110,21 +105,21 @@ class ConstrainedWebDialogDelegateViewViews
  public:
   ConstrainedWebDialogDelegateViewViews(
       content::BrowserContext* browser_context,
-      WebDialogDelegate* delegate,
-      WebDialogWebContentsDelegate* tab_delegate)
+      ui::WebDialogDelegate* delegate,
+      content::WebContents* web_contents)
       : views::WebView(browser_context),
         impl_(new ConstrainedWebDialogDelegateViews(browser_context, delegate,
-                                                    tab_delegate, this)) {
+                                                    web_contents, this)) {
     SetWebContents(GetWebContents());
     AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
   }
   virtual ~ConstrainedWebDialogDelegateViewViews() {}
 
   // ConstrainedWebDialogDelegate:
-  virtual const WebDialogDelegate* GetWebDialogDelegate() const OVERRIDE {
+  virtual const ui::WebDialogDelegate* GetWebDialogDelegate() const OVERRIDE {
     return impl_->GetWebDialogDelegate();
   }
-  virtual WebDialogDelegate* GetWebDialogDelegate() OVERRIDE {
+  virtual ui::WebDialogDelegate* GetWebDialogDelegate() OVERRIDE {
     return impl_->GetWebDialogDelegate();
   }
   virtual void OnDialogCloseFromWebUI() OVERRIDE {
@@ -191,17 +186,8 @@ class ConstrainedWebDialogDelegateViewViews
     return gfx::Size();
   }
 
-  void OnShow() {
-#if defined(USE_AURA)
-  web_view_focus_helper_.reset(new WebViewFocusHelper(this));
-#endif
-  }
-
  private:
   scoped_ptr<ConstrainedWebDialogDelegateViews> impl_;
-#if defined(USE_AURA)
-  scoped_ptr<WebViewFocusHelper> web_view_focus_helper_;
-#endif
 
   DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateViewViews);
 };
@@ -210,13 +196,11 @@ class ConstrainedWebDialogDelegateViewViews
 
 ConstrainedWebDialogDelegate* CreateConstrainedWebDialog(
     content::BrowserContext* browser_context,
-    WebDialogDelegate* delegate,
-    WebDialogWebContentsDelegate* tab_delegate,
+    ui::WebDialogDelegate* delegate,
     content::WebContents* web_contents) {
   ConstrainedWebDialogDelegateViewViews* dialog =
       new ConstrainedWebDialogDelegateViewViews(
-          browser_context, delegate, tab_delegate);
+          browser_context, delegate, web_contents);
   ShowWebModalDialogViews(dialog, web_contents);
-  dialog->OnShow();
   return dialog;
 }
index f4783b3..1f23944 100644 (file)
@@ -11,6 +11,8 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/web_modal/popup_manager.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/events/event_constants.h"
@@ -358,7 +360,6 @@ void DesktopMediaListView::OnSourceThumbnailChanged(int index) {
 DesktopMediaPickerDialogView::DesktopMediaPickerDialogView(
     content::WebContents* parent_web_contents,
     gfx::NativeWindow context,
-    gfx::NativeWindow parent_window,
     DesktopMediaPickerViews* parent,
     const base::string16& app_name,
     const base::string16& target_name,
@@ -384,26 +385,25 @@ DesktopMediaPickerDialogView::DesktopMediaPickerDialogView(
       GetMediaListViewHeightForRows(1), GetMediaListViewHeightForRows(2));
   AddChildView(scroll_view_);
 
-  // If |parent_web_contents| is set, the picker will be shown modal to the
-  // web contents. Otherwise, a new dialog widget inside |parent_window| will be
-  // created for the picker. Note that |parent_window| may also be NULL if
-  // parent web contents is not set. In this case the picker will be parented
-  // by a root window.
+  // If |parent_web_contents| is set and it's not a background page then the
+  // picker will be shown modal to the web contents. Otherwise the picker is
+  // shown in a separate window.
   views::Widget* widget = NULL;
-  if (parent_web_contents)
+  bool modal_dialog =
+      parent_web_contents &&
+      !parent_web_contents->GetDelegate()->IsNeverVisible(parent_web_contents);
+  if (modal_dialog) {
     widget = CreateWebModalDialogViews(this, parent_web_contents);
-  else
-    widget = DialogDelegate::CreateDialogWidget(this, context, parent_window);
+  } else {
+    widget = DialogDelegate::CreateDialogWidget(this, context, NULL);
+  }
 
-  // DesktopMediaList needs to know the ID of the picker window which
-  // matches the ID it gets from the OS. Depending on the OS and configuration
-  // we get this ID differently.
+  // If the picker is not modal to the calling web contents then it is displayed
+  // in its own top-level window, so in that case it needs to be filtered out of
+  // the list of top-level windows available for capture, and to achieve that
+  // the Id is passed to DesktopMediaList.
   DesktopMediaID::Id dialog_window_id = 0;
-
-  // If there is |parent_window| or |parent_web_contents|, the picker window
-  // is embedded in the parent and does not have its own native window id, so we
-  // do not filter in that case.
-  if (!parent_window && !parent_web_contents) {
+  if (!modal_dialog) {
 #if defined(USE_ASH)
     if (chrome::IsNativeWindowInAsh(widget->GetNativeWindow())) {
       dialog_window_id =
@@ -420,7 +420,7 @@ DesktopMediaPickerDialogView::DesktopMediaPickerDialogView(
 
   list_view_->StartUpdating(dialog_window_id);
 
-  if (parent_web_contents) {
+  if (modal_dialog) {
     web_modal::PopupManager* popup_manager =
         web_modal::PopupManager::FromWebContents(parent_web_contents);
     popup_manager->ShowModalDialog(GetWidget()->GetNativeView(),
@@ -555,8 +555,7 @@ void DesktopMediaPickerViews::Show(content::WebContents* web_contents,
                                    const DoneCallback& done_callback) {
   callback_ = done_callback;
   dialog_ = new DesktopMediaPickerDialogView(
-      web_contents, context, parent, this, app_name, target_name,
-      media_list.Pass());
+      web_contents, context, this, app_name, target_name, media_list.Pass());
 }
 
 void DesktopMediaPickerViews::NotifyDialogResult(DesktopMediaID source) {
index 50f8239..0bb9a5b 100644 (file)
@@ -108,7 +108,6 @@ class DesktopMediaPickerDialogView : public views::DialogDelegateView {
  public:
   DesktopMediaPickerDialogView(content::WebContents* parent_web_contents,
                                gfx::NativeWindow context,
-                               gfx::NativeWindow parent_window,
                                DesktopMediaPickerViews* parent,
                                const base::string16& app_name,
                                const base::string16& target_name,
index 268435d..511493d 100644 (file)
@@ -46,8 +46,8 @@ class DesktopMediaPickerViewsTest : public testing::Test {
 
     picker_views_.reset(new DesktopMediaPickerViews());
     picker_views_->Show(NULL,
-                        NULL,
                         parent_widget_->GetNativeWindow(),
+                        NULL,
                         app_name,
                         app_name,
                         media_list.PassAs<DesktopMediaList>(),
index cbfbb4b..f80d824 100644 (file)
@@ -113,52 +113,6 @@ const gfx::Tween::Type kHideTweenType = gfx::Tween::FAST_OUT_LINEAR_IN;
 // by 1 px.
 const int kSearchButtonInset = 1;
 
-// Given a containing |height| and a |base_font_list|, shrinks the font size
-// until the font list will fit within |height| while having its cap height
-// vertically centered.  Returns the correctly-sized font list.
-//
-// The expected layout:
-//   +--------+-----------------------------------------------+------------+
-//   |        | y offset                                      | space      |
-//   |        +--------+-------------------+------------------+ above      |
-//   |        |        |                   | internal leading | cap height |
-//   | box    | font   | ascent (baseline) +------------------+------------+
-//   | height | height |                   | cap height                    |
-//   |        |        |-------------------+------------------+------------+
-//   |        |        | descent (height - baseline)          | space      |
-//   |        +--------+--------------------------------------+ below      |
-//   |        | space at bottom                               | cap height |
-//   +--------+-----------------------------------------------+------------+
-// Goal:
-//     center of box height == center of cap height
-//     (i.e. space above cap height == space below cap height)
-// Restrictions:
-//     y offset >= 0
-//     space at bottom >= 0
-//     (i.e. Entire font must be visible inside the box.)
-gfx::FontList GetLargestFontListWithHeightBound(
-    const gfx::FontList& base_font_list,
-    int height) {
-  gfx::FontList font_list = base_font_list;
-  for (int font_size = font_list.GetFontSize(); font_size > 1; --font_size) {
-    const int internal_leading =
-        font_list.GetBaseline() - font_list.GetCapHeight();
-    // Some platforms don't support getting the cap height, and simply return
-    // the entire font ascent from GetCapHeight().  Centering the ascent makes
-    // the font look too low, so if GetCapHeight() returns the ascent, center
-    // the entire font height instead.
-    const int space =
-        height - ((internal_leading != 0) ?
-                  font_list.GetCapHeight() : font_list.GetHeight());
-    const int y_offset = space / 2 - internal_leading;
-    const int space_at_bottom = height - (y_offset + font_list.GetHeight());
-    if ((y_offset >= 0) && (space_at_bottom >= 0))
-      break;
-    font_list = font_list.DeriveWithSizeDelta(-1);
-  }
-  return font_list;
-}
-
 int GetEditLeadingInternalSpace() {
   // The textfield has 1 px of whitespace before the text in the RTL case only.
   return base::i18n::IsRTL() ? 1 : 0;
@@ -281,16 +235,15 @@ void LocationBarView::Init() {
   // Shrink large fonts to make them fit.
   // TODO(pkasting): Stretch the location bar instead in this case.
   const int location_height = GetInternalHeight(true);
-  font_list = GetLargestFontListWithHeightBound(font_list, location_height);
+  font_list = font_list.DeriveWithHeightUpperBound(location_height);
 
   // Determine the font for use inside the bubbles.  The bubble background
   // images have 1 px thick edges, which we don't want to overlap.
   const int kBubbleInteriorVerticalPadding = 1;
   const int bubble_vertical_padding =
       (kBubblePadding + kBubbleInteriorVerticalPadding) * 2;
-  const gfx::FontList bubble_font_list(
-      GetLargestFontListWithHeightBound(
-          font_list, location_height - bubble_vertical_padding));
+  const gfx::FontList bubble_font_list(font_list.DeriveWithHeightUpperBound(
+      location_height - bubble_vertical_padding));
 
   const SkColor background_color =
       GetColor(ToolbarModel::NONE, LocationBarView::BACKGROUND);
index 2fe40ae..2e3647c 100644 (file)
@@ -61,6 +61,12 @@ NewAvatarButton::NewAvatarButton(
       gfx::ShadowValue(gfx::Point(), 1.0f, SK_ColorDKGRAY)));
   SetTextSubpixelRenderingEnabled(false);
 
+  // The largest text height that fits in the button. If the font list height
+  // is larger than this, it will be shrunk to match it.
+  // TODO(noms): Calculate this constant algorithmically.
+  const int kDisplayFontHeight = 15;
+  SetFontList(GetFontList().DeriveWithHeightUpperBound(kDisplayFontHeight));
+
   ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
   if (button_style == THEMED_BUTTON) {
     const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_NORMAL);
@@ -142,6 +148,11 @@ void NewAvatarButton::OnProfileNameChanged(
   UpdateAvatarButtonAndRelayoutParent();
 }
 
+void NewAvatarButton::OnProfileAvatarChanged(
+      const base::FilePath& profile_path) {
+  UpdateAvatarButtonAndRelayoutParent();
+}
+
 void NewAvatarButton::OnProfileSupervisedUserIdChanged(
       const base::FilePath& profile_path) {
   UpdateAvatarButtonAndRelayoutParent();
index 76e3ac1..917a696 100644 (file)
@@ -46,6 +46,8 @@ class NewAvatarButton : public views::MenuButton,
   virtual void OnProfileNameChanged(
       const base::FilePath& profile_path,
       const base::string16& old_profile_name) OVERRIDE;
+  virtual void OnProfileAvatarChanged(
+      const base::FilePath& profile_path) OVERRIDE;
   virtual void OnProfileSupervisedUserIdChanged(
       const base::FilePath& profile_path) OVERRIDE;
 
index 752dc66..5cfbdd4 100644 (file)
@@ -71,9 +71,11 @@ const int kButtonHeight = 32;
 const int kFixedGaiaViewHeight = 440;
 const int kFixedGaiaViewWidth = 360;
 const int kFixedAccountRemovalViewWidth = 280;
-const int kFixedSwitchUserViewWidth = 280;
+const int kFixedSwitchUserViewWidth = 320;
 const int kLargeImageSide = 88;
 
+const int kVerticalSpacing = 16;
+
 // Creates a GridLayout with a single column. This ensures that all the child
 // views added get auto-expanded to fill the full width of the bubble.
 views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) {
@@ -420,8 +422,9 @@ class TitleCard : public views::View {
     AddChildView(title_label_);
   }
 
-  // Creates a new view that has the |title_card| with padding at the top, an
-  // edge-to-edge separator below, and the specified |view| at the bottom.
+  // Creates a new view that has the |title_card| with horizontal padding at the
+  // top, an edge-to-edge separator below, and the specified |view| at the
+  // bottom.
   static views::View* AddPaddedTitleCard(views::View* view,
                                          TitleCard* title_card,
                                          int width) {
@@ -440,9 +443,9 @@ class TitleCard : public views::View {
     layout->AddColumnSet(1)->AddColumn(views::GridLayout::FILL,
         views::GridLayout::FILL, 0,views::GridLayout::FIXED, width, width);
 
-    layout->StartRowWithPadding(1, 0, 0, views::kButtonVEdgeMarginNew);
+    layout->StartRowWithPadding(1, 0, 0, kVerticalSpacing);
     layout->AddView(title_card);
-    layout->StartRowWithPadding(1, 1, 0, views::kRelatedControlVerticalSpacing);
+    layout->StartRowWithPadding(1, 1, 0, kVerticalSpacing);
     layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
 
     layout->StartRow(1, 1);
index 828b916..e77f642 100644 (file)
@@ -164,7 +164,6 @@ BrowserActionsContainer::BrowserActionsContainer(
     // the Chrome menu.
     if (!overflow_experiment) {
       chevron_ = new ChevronMenuButton(NULL, base::string16(), this, false);
-      chevron_->SetBorder(views::Border::NullBorder());
       chevron_->EnableCanvasFlippingForRTLUI(true);
       chevron_->SetAccessibleName(
           l10n_util::GetStringUTF16(IDS_ACCNAME_EXTENSIONS_CHEVRON));
index b5370d3..70499ac 100644 (file)
@@ -228,11 +228,8 @@ void CertificateViewerDialog::Show(WebContents* web_contents,
                                    gfx::NativeWindow parent) {
   // TODO(bshe): UI tweaks needed for Aura HTML Dialog, such as adding padding
   // on the title for Aura ConstrainedWebDialogUI.
-  dialog_ = CreateConstrainedWebDialog(
-      web_contents->GetBrowserContext(),
-      this,
-      NULL,
-      web_contents);
+  dialog_ = CreateConstrainedWebDialog(web_contents->GetBrowserContext(), this,
+                                       web_contents);
 }
 
 NativeWebContentsModalDialog
index b3d8efb..d359bf7 100644 (file)
@@ -8,6 +8,7 @@
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/sys_info.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
@@ -34,6 +35,18 @@ DemoModeDetector::~DemoModeDetector() {
 // Public methods.
 
 void DemoModeDetector::InitDetection() {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableDemoMode))
+    return;
+
+  if (base::SysInfo::IsRunningOnChromeOS()) {
+    std::string track;
+    // We're running on an actual device; if we cannot find our release track
+    // value or if the track contains "testimage", don't start demo mode.
+    if (!base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_TRACK", &track) ||
+        track.find("testimage") != std::string::npos)
+      return;
+  }
+
   if (IsDerelict())
     StartIdleDetection();
   else
index e298ce8..04b1c32 100644 (file)
@@ -113,8 +113,7 @@ void HIDDetectionScreenHandler::Show() {
     show_on_init_ = true;
     return;
   }
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableDemoMode))
-    core_oobe_actor_->InitDemoModeDetection();
+  core_oobe_actor_->InitDemoModeDetection();
   input_service_proxy_.AddObserver(this);
   UpdateDevices();
 
index 34a690d..4b75020 100644 (file)
@@ -370,6 +370,32 @@ scoped_ptr<base::ListValue> GetUILanguageList(
   return languages_list.Pass();
 }
 
+std::string FindMostRelevantLocale(
+    const std::vector<std::string>& most_relevant_language_codes,
+    const base::ListValue& available_locales,
+    const std::string& fallback_locale) {
+  for (std::vector<std::string>::const_iterator most_relevant_it =
+          most_relevant_language_codes.begin();
+       most_relevant_it != most_relevant_language_codes.end();
+       ++most_relevant_it) {
+    for (base::ListValue::const_iterator available_it =
+             available_locales.begin();
+         available_it != available_locales.end(); ++available_it) {
+      base::DictionaryValue* dict;
+      std::string available_locale;
+      if (!(*available_it)->GetAsDictionary(&dict) ||
+          !dict->GetString("value", &available_locale)) {
+        NOTREACHED();
+        continue;
+      }
+      if (available_locale == *most_relevant_it)
+        return *most_relevant_it;
+    }
+  }
+
+  return fallback_locale;
+}
+
 scoped_ptr<base::ListValue> GetAcceptLanguageList() {
   // Collect the language codes from the supported accept-languages.
   const std::string app_locale = g_browser_process->GetApplicationLocale();
@@ -457,13 +483,13 @@ void GetKeyboardLayoutsForLocale(
 
   // Resolve |locale| on a background thread, then continue on the current
   // thread.
+  std::string (*get_application_locale)(const std::string&, bool) =
+      &l10n_util::GetApplicationLocale;
   base::PostTaskAndReplyWithResult(
       background_task_runner,
       FROM_HERE,
-      base::Bind(&l10n_util::GetApplicationLocale,
-                 locale),
-      base::Bind(&GetKeyboardLayoutsForResolvedLocale,
-                 callback));
+      base::Bind(get_application_locale, locale, false /* set_icu_locale */),
+      base::Bind(&GetKeyboardLayoutsForResolvedLocale, callback));
 }
 
 scoped_ptr<base::DictionaryValue> GetCurrentKeyboardLayout() {
index aa9f4fb..3ea1e96 100644 (file)
@@ -37,6 +37,14 @@ scoped_ptr<base::ListValue> GetUILanguageList(
     const std::vector<std::string>* most_relevant_language_codes,
     const std::string& selected);
 
+// Returns the most first entry of |most_relevant_language_codes| that is
+// actually available (present in |available_locales|). If none of the entries
+// are present in |available_locales|, returns the |fallback_locale|.
+std::string FindMostRelevantLocale(
+    const std::vector<std::string>& most_relevant_language_codes,
+    const base::ListValue& available_locales,
+    const std::string& fallback_locale);
+
 // Return a list of supported accept languages. The listed languages can be used
 // in the Accept-Language header. The return value will look like:
 // [{'code': 'fi', 'displayName': 'Finnish', 'nativeDisplayName': 'suomi'}, ...]
index 86e3d92..6e9be46 100644 (file)
@@ -129,6 +129,39 @@ TEST_F(L10nUtilTest, GetUILanguageList) {
   VerifyOnlyUILanguages(*list);
 }
 
+TEST_F(L10nUtilTest, FindMostRelevantLocale) {
+  base::ListValue available_locales;
+  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
+  dict->SetString("value", "de");
+  available_locales.Append(dict.release());
+  dict.reset(new base::DictionaryValue);
+  dict->SetString("value", "fr");
+  available_locales.Append(dict.release());
+  dict.reset(new base::DictionaryValue);
+  dict->SetString("value", "en-GB");
+  available_locales.Append(dict.release());
+
+  std::vector<std::string> most_relevant_language_codes;
+  EXPECT_EQ("en-US", FindMostRelevantLocale(most_relevant_language_codes,
+                                            available_locales,
+                                            "en-US"));
+
+  most_relevant_language_codes.push_back("xx");
+  EXPECT_EQ("en-US", FindMostRelevantLocale(most_relevant_language_codes,
+                                            available_locales,
+                                            "en-US"));
+
+  most_relevant_language_codes.push_back("fr");
+  EXPECT_EQ("fr", FindMostRelevantLocale(most_relevant_language_codes,
+                                         available_locales,
+                                         "en-US"));
+
+  most_relevant_language_codes.push_back("de");
+  EXPECT_EQ("fr", FindMostRelevantLocale(most_relevant_language_codes,
+                                         available_locales,
+                                         "en-US"));
+}
+
 void InitStartupCustomizationDocumentForTesting(const std::string& manifest) {
   StartupCustomizationDocument::GetInstance()->LoadManifestFromString(manifest);
   StartupCustomizationDocument::GetInstance()->Init(
index 47cb912..0fd28b9 100644 (file)
@@ -6,11 +6,9 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/command_line.h"
 #include "base/memory/weak_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/sys_info.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
@@ -24,7 +22,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/chromeos_switches.h"
 #include "chromeos/ime/extension_ime_util.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_state_handler.h"
@@ -129,17 +126,6 @@ void NetworkScreenHandler::Show() {
                                 true,
                                 chromeos::network_handler::ErrorCallback());
   ShowScreen(OobeUI::kScreenOobeNetwork, NULL);
-
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableDemoMode))
-    return;
-  if (base::SysInfo::IsRunningOnChromeOS()) {
-    std::string track;
-    // We're running on an actual device; if we cannot find our release track
-    // value or if the track contains "testimage", don't start demo mode.
-    if (!base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_TRACK", &track) ||
-        track.find("testimage") != std::string::npos)
-      return;
-  }
   core_oobe_actor_->InitDemoModeDetection();
 }
 
index 138e06f..615a30b 100644 (file)
@@ -762,6 +762,7 @@ void SigninScreenHandler::RegisterMessages() {
   AddCallback("updateOfflineLogin",
               &SigninScreenHandler::HandleUpdateOfflineLogin);
   AddCallback("focusPod", &SigninScreenHandler::HandleFocusPod);
+  AddCallback("hardlockPod", &SigninScreenHandler::HandleHardlockPod);
   AddCallback("retrieveAuthenticatedUserEmail",
               &SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail);
   AddCallback("getPublicSessionKeyboardLayouts",
@@ -946,6 +947,10 @@ void SigninScreenHandler::SetAuthType(
     const std::string& username,
     ScreenlockBridge::LockHandler::AuthType auth_type,
     const base::string16& initial_value) {
+  if (delegate_->GetAuthType(username) ==
+          ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD)
+    return;
+
   delegate_->SetAuthType(username, auth_type);
 
   CallJS("login.AccountPickerScreen.setAuthType",
@@ -1302,6 +1307,13 @@ void SigninScreenHandler::HandleFocusPod(const std::string& user_id) {
   WallpaperManager::Get()->SetUserWallpaperDelayed(user_id);
 }
 
+void SigninScreenHandler::HandleHardlockPod(const std::string& user_id) {
+  SetAuthType(user_id,
+              ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD,
+              base::string16());
+  HideUserPodCustomIcon(user_id);
+}
+
 void SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail(
     double attempt_token) {
   // TODO(antrim) : move GaiaSigninScreen dependency to GaiaSigninScreen.
index 86d4dda..4656185 100644 (file)
@@ -370,6 +370,7 @@ class SigninScreenHandler
   void HandleUpdateOfflineLogin(bool offline_login_active);
   void HandleShowSupervisedUserCreationScreen();
   void HandleFocusPod(const std::string& user_id);
+  void HandleHardlockPod(const std::string& user_id);
   void HandleLaunchKioskApp(const std::string& app_id, bool diagnostic_mode);
   void HandleRetrieveAuthenticatedUserEmail(double attempt_token);
   void HandleGetPublicSessionKeyboardLayouts(const std::string& user_id,
index 98a6af6..de28f1a 100644 (file)
@@ -82,15 +82,10 @@ class ConstrainedWebDialogUI : public content::WebUIController {
 // |browser_context| is used to construct the constrained HTML dialog's
 //                   WebContents.
 // |delegate| controls the behavior of the dialog.
-// |tab_delegate| is optional, pass one in to use a custom
-//                WebDialogWebContentsDelegate with the dialog, or NULL to
-//                use the default one. The dialog takes ownership of
-//                |tab_delegate|.
 // |overshadowed| is the tab being overshadowed by the dialog.
 ConstrainedWebDialogDelegate* CreateConstrainedWebDialog(
     content::BrowserContext* browser_context,
     ui::WebDialogDelegate* delegate,
-    ui::WebDialogWebContentsDelegate* tab_delegate,
     content::WebContents* overshadowed);
 
 #endif  // CHROME_BROWSER_UI_WEBUI_CONSTRAINED_WEB_DIALOG_UI_H_
index ba8e0e5..e0405bb 100644 (file)
@@ -64,10 +64,7 @@ IN_PROC_BROWSER_TEST_F(ConstrainedWebDialogBrowserTest, BasicTest) {
   ASSERT_TRUE(web_contents);
 
   ConstrainedWebDialogDelegate* dialog_delegate =
-      CreateConstrainedWebDialog(browser()->profile(),
-                                 delegate,
-                                 NULL,
-                                 web_contents);
+      CreateConstrainedWebDialog(browser()->profile(), delegate, web_contents);
   ASSERT_TRUE(dialog_delegate);
   EXPECT_TRUE(dialog_delegate->GetNativeDialog());
   EXPECT_TRUE(IsShowingWebContentsModalDialog(web_contents));
@@ -84,10 +81,7 @@ IN_PROC_BROWSER_TEST_F(ConstrainedWebDialogBrowserTest,
   ASSERT_TRUE(web_contents);
 
   ConstrainedWebDialogDelegate* dialog_delegate =
-      CreateConstrainedWebDialog(browser()->profile(),
-                                 delegate,
-                                 NULL,
-                                 web_contents);
+      CreateConstrainedWebDialog(browser()->profile(), delegate, web_contents);
   ASSERT_TRUE(dialog_delegate);
   scoped_ptr<WebContents> new_tab(dialog_delegate->GetWebContents());
   ASSERT_TRUE(new_tab.get());
index 0979c10..5e4468b 100644 (file)
@@ -457,6 +457,10 @@ void ManageProfileHandler::RequestHasProfileShortcuts(
   if (profile_index == std::string::npos)
     return;
 
+  // Don't show the add/remove desktop shortcut button in the single user case.
+  if (cache.GetNumberOfProfiles() <= 1)
+    return;
+
   const base::FilePath profile_path =
       cache.GetPathOfProfileAtIndex(profile_index);
   ProfileShortcutManager* shortcut_manager =
index cc787ef..fbbc35f 100644 (file)
@@ -153,8 +153,7 @@ void ProfileSigninConfirmationDialog::Close() const {
 
 void ProfileSigninConfirmationDialog::Show(bool prompt) {
   prompt_for_new_profile_ = prompt;
-  dialog_delegate_ =
-      CreateConstrainedWebDialog(profile_, this, NULL, web_contents_);
+  dialog_delegate_ = CreateConstrainedWebDialog(profile_, this, web_contents_);
 }
 
 ui::ModalType ProfileSigninConfirmationDialog::GetDialogModalType() const {
index c8104f7..4314bc0 100644 (file)
@@ -257,6 +257,10 @@ void UserManagerScreenHandler::SetAuthType(
     const std::string& user_email,
     ScreenlockBridge::LockHandler::AuthType auth_type,
     const base::string16& auth_value) {
+  if (GetAuthType(user_email) ==
+          ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD)
+    return;
+
   user_auth_type_map_[user_email] = auth_type;
   web_ui()->CallJavascriptFunction(
       "login.AccountPickerScreen.setAuthType",
@@ -430,6 +434,16 @@ void UserManagerScreenHandler::HandleAttemptUnlock(
   GetScreenlockRouter(email)->OnAuthAttempted(GetAuthType(email), "");
 }
 
+void UserManagerScreenHandler::HandleHardlockUserPod(
+    const base::ListValue* args) {
+  std::string email;
+  CHECK(args->GetString(0, &email));
+  SetAuthType(email,
+              ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD,
+              base::string16());
+  HideUserPodCustomIcon(email);
+}
+
 void UserManagerScreenHandler::OnClientLoginSuccess(
     const ClientLoginResult& result) {
   chrome::SetLocalAuthCredentials(authenticating_profile_index_,
index 8339d61..1e7d1b6 100644 (file)
@@ -63,6 +63,7 @@ class UserManagerScreenHandler : public content::WebUIMessageHandler,
   void HandleLaunchUser(const base::ListValue* args);
   void HandleRemoveUser(const base::ListValue* args);
   void HandleAttemptUnlock(const base::ListValue* args);
+  void HandleHardlockUserPod(const base::ListValue* args);
 
   // Handle GAIA auth results.
   virtual void OnClientLoginSuccess(const ClientLoginResult& result) OVERRIDE;
index f6fe31a..a2c691c 100644 (file)
             '../printing/printing.gyp:printing_java',
             '../sync/sync.gyp:sync_java',
             '../third_party/android_tools/android_tools.gyp:android_support_v7_appcompat_javalib',
+            '../third_party/android_tools/android_tools.gyp:android_support_v13_javalib',
             '../third_party/guava/guava.gyp:guava_javalib',
             '../ui/android/ui_android.gyp:ui_java',
           ],
index 3a5452e..6addb3f 100644 (file)
@@ -269,7 +269,9 @@ void ComputeBuiltInPlugins(std::vector<content::PepperPluginInfo>* plugins) {
       widevine_cdm.is_out_of_process = true;
       widevine_cdm.path = path;
       widevine_cdm.name = kWidevineCdmDisplayName;
-      widevine_cdm.description = kWidevineCdmDescription;
+      widevine_cdm.description = kWidevineCdmDescription +
+                                 std::string(" (version: ") +
+                                 WIDEVINE_CDM_VERSION_STRING + ")";
       widevine_cdm.version = WIDEVINE_CDM_VERSION_STRING;
       content::WebPluginMimeType widevine_cdm_mime_type(
           kWidevineCdmPluginMimeType,
index 84a83ef..21cb6fb 100644 (file)
@@ -61,6 +61,8 @@ const char kChannel[] = "channel";
 
 const char kActiveURL[] = "url-chunk";
 
+const char kFontKeyName[] = "font_key_name";
+
 const char kSwitch[] = "switch-%" PRIuS;
 const char kNumSwitches[] = "num-switches";
 
@@ -144,6 +146,7 @@ size_t RegisterChromeCrashKeys() {
     // base/:
     { "dm-usage", kSmallSize },
     // content/:
+    { kFontKeyName, kSmallSize},
     { "ppapi_path", kMediumSize },
     { "subresource_url", kLargeSize },
 #if defined(OS_CHROMEOS)
index 1615623..1f439ec 100644 (file)
       "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80",  // http://crbug.com/396117
       "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE",  // http://crbug.com/396117
       "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB",  // http://crbug.com/396117
-      "307E96539209F95A1A8740C713E6998A73657D96"   // http://crbug.com/396117
+      "307E96539209F95A1A8740C713E6998A73657D96",  // http://crbug.com/396117
+      "4F25792AF1AA7483936DE29C07806F203C7170A0",  // http://crbug.com/407693
+      "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
+      "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
+      "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/407693
     ]
   }],
   "browser_action": {
index a951be2..0d1947c 100644 (file)
       ]
     }
   ],
-  "app.window.shape": {
-    "channel": "stable",
-    "extension_types": ["platform_app"]
-  },
+  "app.window.shape": [
+    {
+      "channel": "dev",
+      "extension_types": ["platform_app"]
+    },
+    {
+      "channel": "stable",
+      "extension_types": ["platform_app"],
+      "whitelist": [
+        "0F42756099D914A026DADFA182871C015735DD95",  // http://crbug.com/323773
+        "2D22CDB6583FD0A13758AEBE8B15E45208B4E9A7",
+        "E7E2461CE072DF036CF9592740196159E2D7C089",  // http://crbug.com/356200
+        "A74A4D44C7CFCD8844830E6140C8D763E12DD8F3",
+        "312745D9BF916161191143F6490085EEA0434997",
+        "53041A2FA309EECED01FFC751E7399186E860B2C",
+        "EBA908206905323CECE6DC4B276A58A0F4AC573F",
+        "2775E568AC98F9578791F1EAB65A1BF5F8CEF414",
+        "4AA3C5D69A4AECBD236CAD7884502209F0F5C169",
+        "E410CDAB2C6E6DD408D731016CECF2444000A912",
+        "9E930B2B5EABA6243AE6C710F126E54688E8FAF6",
+        "FAFE8EFDD2D6AE2EEB277AFEB91C870C79064D9E",  // http://crbug.com/327507
+        "3B52D273A271D4E2348233E322426DBAE854B567",
+        "5DF6ADC8708DF59FCFDDBF16AFBFB451380C2059",
+        "1037DEF5F6B06EA46153AD87B6C5C37440E3F2D1",
+        "F5815DAFEB8C53B078DD1853B2059E087C42F139",
+        "6A08EFFF9C16E090D6DCC7EC55A01CADAE840513",
+        "C32D6D93E12F5401DAA3A723E0C3CC5F25429BA4",  // http://crbug.com/354258
+        "9099782647D39C778E15C8C6E0D23C88F5CDE170",
+        "B7D5B52D1E5B106288BD7F278CAFA5E8D76108B0",
+        "89349DBAA2C4022FB244AA50182AB60934EB41EE",
+        "CB593E510640572A995CB1B6D41BD85ED51E63F8",
+        "1AD1AC86C87969CD3434FA08D99DBA6840AEA612",
+        "9C2EA21D7975BDF2B3C01C3A454EE44854067A6D",
+        "D2C488C80C3C90C3E01A991112A05E37831E17D0",
+        "6EEC061C0E74B46C7B5BE2EEFA49436368F4988F",
+        "8B344D9E8A4C505EF82A0DBBC25B8BD1F984E777",
+        "E06AFCB1EB0EFD237824CC4AC8FDD3D43E8BC868",
+        "F76F43EFFF56BF17A9868A5243F339BA28746632",  // http://crbug.com/386324
+        "C6EA52B92F80878515F94137020F01519357E5B5",
+        "E466389F058ABD73FF6FDD06F768A351FCBF8532",
+        "40063F1CF7B68BA847A26FA6620DDF156171D23C",
+        "A6FD8E15353CF1F5C3D0A7B20E1D10AEA4DD3E6A",
+        "57AC4D9E6BD8A2D0A70056B5FAC2378CAA588912",
+        "02037314DA4D913640DCF0E296A7D01F4FD793EC",
+        "B6EC0809BC63E10B431C5E4AA3645232CA86B2A5",
+        "48CA541313139786F056DBCB504A1025CFF5D2E3",
+        "05106136AE7F08A3C181D4648E5438350B1D2B4F"
+      ]
+    }
+  ],
   "audio": [
     {
       "channel": "dev",
         "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB",
         "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE",  // http://crbug.com/335729
         "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80",  // http://crbug.com/335729
-        "307E96539209F95A1A8740C713E6998A73657D96"   // http://crbug.com/335729
+        "307E96539209F95A1A8740C713E6998A73657D96",  // http://crbug.com/335729
+        "4F25792AF1AA7483936DE29C07806F203C7170A0",  // http://crbug.com/407693
+        "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
+        "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
+        "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/407693
       ]
     }
   ],
         "4FE45FA56EF6A25FDE8C302C44045CA9CE8A605A",  // http://crbug.com/320952
         "3D14248405B8A59043420AAC160077C99E7788A9",  // http://crbug.com/398585
         "A6C87307BBE5886CC5F1393025000E2FE8060BF2",  // http://crbug.com/398585
-        "3407516021EA3669C0EC8E65E6B9837E5A521B9C"   // http://crbug.com/398585
+        "3407516021EA3669C0EC8E65E6B9837E5A521B9C",  // http://crbug.com/398585
+        "0F585FB1D0FDFBEBCE1FEB5E9DFFB6DA476B8C9B",  // http://crbug.com/405800
+        "2D22CDB6583FD0A13758AEBE8B15E45208B4E9A7",  // http://crbug.com/405800
+        "A07A5B743CD82A1C2579DB77D353C98A23201EEF",  // http://crbug.com/405800
+        "0F42756099D914A026DADFA182871C015735DD95"   // http://crbug.com/405800
       ]
     }
   ],
       "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80",  // http://crbug.com/387169
       "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE",  // http://crbug.com/387169
       "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB",  // http://crbug.com/387169
-      "307E96539209F95A1A8740C713E6998A73657D96"  // http://crbug.com/387169
+      "307E96539209F95A1A8740C713E6998A73657D96",  // http://crbug.com/387169
+      "4F25792AF1AA7483936DE29C07806F203C7170A0",  // http://crbug.com/407693
+      "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
+      "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
+      "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/407693
     ]
   },
   "bookmarkManagerPrivate": {
       "FA01E0B81978950F2BC5A50512FD769725F57510",  // Beta
       "B11A93E7E5B541F8010245EBDE2C74647D6C14B9",  // Canary
       "F155646B5D1CA545F7E1E4E20D573DFDD44C2540",  // Google Cast Beta
-      "16CA7A47AAE4BE49B1E75A6B960C3875E945B264"   // Google Cast Stable
+      "16CA7A47AAE4BE49B1E75A6B960C3875E945B264",  // Google Cast Stable
+      "4F25792AF1AA7483936DE29C07806F203C7170A0",  // http://crbug.com/407693
+      "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
+      "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
+      "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/407693
     ]
   },
   "clipboardRead": {
         "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80",  // http://crbug.com/389230
         "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE",  // http://crbug.com/389230
         "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB",  // http://crbug.com/389230
-        "307E96539209F95A1A8740C713E6998A73657D96"   // http://crbug.com/389230
+        "307E96539209F95A1A8740C713E6998A73657D96",  // http://crbug.com/389230
+        "4F25792AF1AA7483936DE29C07806F203C7170A0",  // http://crbug.com/407693
+        "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
+        "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
+        "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/407693
       ]
     }
   ],
       "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE",  // http://crbug.com/293683
       "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578",  // http://crbug.com/234235
       "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB",  // http://crbug.com/234235
-      "307E96539209F95A1A8740C713E6998A73657D96"   // http://crbug.com/329690
+      "307E96539209F95A1A8740C713E6998A73657D96",  // http://crbug.com/329690
+      "4F25792AF1AA7483936DE29C07806F203C7170A0",  // http://crbug.com/407693
+      "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
+      "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
+      "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/407693
     ]
   },
   "fileBrowserHandler": {
       "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80",  // http://crbug.com/389230
       "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE",  // http://crbug.com/389230
       "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB",  // http://crbug.com/389230
-      "307E96539209F95A1A8740C713E6998A73657D96"   // http://crbug.com/389230
+      "307E96539209F95A1A8740C713E6998A73657D96",  // http://crbug.com/389230
+      "4F25792AF1AA7483936DE29C07806F203C7170A0",  // http://crbug.com/407693
+      "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
+      "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
+      "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/407693
     ]
   },
   "location": [
       "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB",  // http://crbug.com/234235
       "307E96539209F95A1A8740C713E6998A73657D96",  // http://crbug.com/329690
       "A291B26E088FA6BA53FFD72F0916F06EBA7C585A",  // http://crbug.com/341258
-      "D7986543275120831B39EF28D1327552FC343960"   // http://crbug.com/329088
+      "D7986543275120831B39EF28D1327552FC343960",  // http://crbug.com/329088
+      "4F25792AF1AA7483936DE29C07806F203C7170A0",  // http://crbug.com/407693
+      "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
+      "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
+      "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/407693
     ]
   },
   "webcamPrivate": {
       "16CA7A47AAE4BE49B1E75A6B960C3875E945B264",  // Google Cast Stable
       "7AE714FFD394E073F0294CFA134C9F91DB5FBAA4",  // CCD Development
       "C7DA3A55C2355F994D3FDDAD120B426A0DF63843",  // CCD Testing
-      "75E3CFFFC530582C583E4690EF97C70B9C8423B7"   // CCD Release
+      "75E3CFFFC530582C583E4690EF97C70B9C8423B7",  // CCD Release
+      "4F25792AF1AA7483936DE29C07806F203C7170A0",  // http://crbug.com/407693
+      "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
+      "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
+      "81986D4F846CEDDDB962643FA501D1780DD441BB"   // http://crbug.com/407693
     ]
   },
   "notificationProvider": {
index 1648853..5a33e5e 100644 (file)
@@ -40,6 +40,9 @@
     // A phone eligible to unlock the device is detected, but it's not close
     // enough to be allowed to unlock the device.
     PHONE_NOT_NEARBY,
+    // A phone eligible to unlock the device is detected, but it is not allowed
+    // to unlock the device because it does not report its lock screen state.
+    PHONE_UNSUPPORTED,
     // The devie can be unlocked using Easy Unlock.
     AUTHENTICATED
   };
     static void seekBluetoothDeviceByAddress(DOMString deviceAddress,
                                              optional EmptyCallback callback);
 
+    // Connects the socket to a remote Bluetooth device over an insecure
+    // connection, i.e. a connection that requests no bonding and no
+    // man-in-the-middle protection. Other than the reduced security setting,
+    // behaves identically to the chrome.bluetoothSocket.connect() function.
+    // |socketId|: The socket identifier, as issued by the
+    //     chrome.bluetoothSocket API.
+    // |deviceAddress|: The Bluetooth address of the device to connect to.
+    // |uuid|: The UUID of the service to connect to.
+    // |callback|: Called when the connect attempt is complete.
+    static void connectToBluetoothServiceInsecurely(long socketId,
+                                                    DOMString deviceAddress,
+                                                    DOMString uuid,
+                                                    EmptyCallback callback);
+
     // Updates the screenlock state to reflect the Easy Unlock app state.
     static void updateScreenlockState(State state,
                                       optional EmptyCallback callback);
index 5efd19a..cadfd55 100644 (file)
@@ -239,9 +239,6 @@ dictionary ProfileInfo {
   // TODO(hirono): Remove the property because of the design change of
   // multi-profile suuport.
   boolean isCurrentProfile;
-
-  // Image set of profile image.
-  ImageSet? profileImage;
 };
 
 // Mounted disk volume metadata.
index 0f69175..6ebc580 100644 (file)
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Use <code>chrome.pushMessaging</code> to enable apps and extensions to
-// receive message data sent through
+// The <code>chrome.pushMessaging</code> API is deprecated since Chrome 38,
+// and will no longer be supported in Chrome 41.
+// Switch to <code>$(ref:gcm chrome.gcm)</code> to take advantage of
 // <a href="cloudMessaging.html">Google Cloud Messaging</a>.
+[deprecated="Use $(ref:gcm chrome.gcm) API"]
 namespace pushMessaging {
 
   dictionary Message {
@@ -31,6 +33,7 @@ namespace pushMessaging {
     // to trigger push messages back to the app or extension.
     // If the interactive flag is set, we will ask the user to log in
     // when they are not already logged in.
+    [deprecated="Use $(ref:gcm chrome.gcm) API"]
     static void getChannelId(optional boolean interactive,
                              ChannelIdCallback callback);
   };
@@ -38,6 +41,7 @@ namespace pushMessaging {
   interface Events {
     // Fired when a push message has been received.
     // |message| : The details associated with the message.
+    [deprecated="Use $(ref:gcm chrome.gcm) API"]
     static void onMessage(Message message);
   };
 };
index 72bd150..70b492a 100644 (file)
@@ -38,3 +38,9 @@ document.querySelector('#cancel').addEventListener('click', function(e) {
     chrome.desktopCapture.cancelChooseDesktopMedia(pending_request_id);
   }
 });
+
+document.querySelector('#startFromBackgroundPage')
+    .addEventListener('click', function(e) {
+      chrome.runtime.sendMessage(
+          {}, function(response) { console.log(response.farewell); });
+    });
index 6d17ac4..c1574a5 100644 (file)
@@ -10,3 +10,11 @@ chrome.app.runtime.onLaunched.addListener(function() {
     }
   });
 });
+
+chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
+  chrome.desktopCapture.chooseDesktopMedia(
+      ["screen", "window"],
+      function(id) {
+        sendResponse({"id": id});
+      });
+});
index 57b3d37..f8db183 100644 (file)
 </head>
 <body>
   <video id="video" autoplay></video>
-  <p><button id="start">Start</button><button id="cancel">Cancel</button></p>
+  <p>
+    <button id="start">Start</button>
+    <button id="cancel">Cancel</button>
+    <button id="startFromBackgroundPage">Start from background page</button>
+  </p>
   <script src="app.js"></script>
 </body>
 </html>
index b717ff3..619f532 100644 (file)
@@ -2,8 +2,9 @@
 <h1>Google Cloud Messaging for Chrome V1</h1>
 
 <p class="note">
-Google Cloud Messaging for Chrome V1 will be legacy soon.
-Use the new <a href="cloudMessaging">Google Cloud Messaging API</a>.
+Google Cloud Messaging for Chrome V1 is deprecated since Chrome 38.
+It will be removed in Chrome 41.
+Use the new <a href="cloudMessaging">Google Cloud Messaging</a>.
 </p>
 
 <p>
@@ -116,14 +117,13 @@ to use the push messaging service
     </ul>
   </li>
   <li>Set up your app or extension to use the service:
-       <ul>
-         <li>Add the permission to the manifest.</li>
-         <li>Include a call to <code>getChannelId</code>
-      for any user who is to receive a message.</li>
-         <li>Register a handler to receive the
-         <code>onMessage</code> event.</li>    
-       </ul>
-   </li>
+    <ul>
+      <li>Add the permission to the manifest.</li>
+      <li>Include a call to <code>getChannelId</code>
+        for any user who is to receive a message.</li>
+      <li>Register a handler to receive the <code>onMessage</code> event.</li>
+    </ul>
+  </li>
   <li>Publish your app in the Chrome Web Store. </li>
   <li>Use refresh token to get a valid access token.</li>
   <li>Send message to user.</li>
index ef0e74f..302ce46 100644 (file)
@@ -1,8 +1,14 @@
 <meta name="doc-family" content="apps">
 <h1>API Reference for GCM service</h1>
 
+<p class="note">
+This document explains sending messages to chrome.pushMessaging API, which is
+deprecated since Chrome 38. The API will be removed in Chrome 41.
+Use the new <a href="cloudMessaging">Google Cloud Messaging</a>.
+</p>
+
 <p>
-The <a href="cloudMessaging">Google Cloud Messaging for Chrome</a> service
+The <a href="cloudMessagingV1">Google Cloud Messaging for Chrome</a> service
 sends messages to users of a Chrome App.
 The service handles all aspects of queueing and delivering messages.
 To use the service,
index 6fc6246..f3d24cd 100644 (file)
@@ -68,8 +68,6 @@
                </dict>
                <key>^Versions/@VERSION_REGEX@/</key>
                <dict>
-                       <key>nested</key>
-                       <true/>
                        <key>weight</key>
                        <real>20</real>
                </dict>
                        <key>weight</key>
                        <real>30</real>
                </dict>
+               <key>^Versions/@VERSION_REGEX@/.+/Resources/.+\.lproj/</key>
+               <dict>
+                       <key>optional</key>
+                       <true/>
+                       <key>weight</key>
+                       <real>30</real>
+               </dict>
+               <key>^Versions/@VERSION_REGEX@/.+/Resources Disabled/</key>
+               <dict>
+                       <key>omit</key>
+                       <true/>
+                       <key>weight</key>
+                       <real>40</real>
+               </dict>
                <key>/\.DS_Store$</key>
                <dict>
                        <key>omit</key>
index 48a4e32..cdf264b 100644 (file)
@@ -27,7 +27,8 @@ const wchar_t kSfxMultiFail[] = L"-multifail";
 
 const wchar_t* const kChannels[] = {
   installer::kChromeChannelBeta,
-  installer::kChromeChannelDev
+  installer::kChromeChannelDev,
+  installer::kChromeChannelStableExplicit
 };
 
 const wchar_t* const kModifiers[] = {
@@ -168,7 +169,11 @@ bool ChannelInfo::GetChannelName(std::wstring* channel_name) const {
              *const* end = &kChannels[arraysize(kChannels)]; scan != end;
          ++scan) {
       if (value_.find(*scan) != std::wstring::npos) {
-        channel_name->assign(*scan);
+        // Report channels with "stable" in them as stable (empty string).
+        if (*scan == installer::kChromeChannelStableExplicit)
+          channel_name->erase();
+        else
+          channel_name->assign(*scan);
         return true;
       }
     }
index d08f2c3..71d908b 100644 (file)
@@ -50,6 +50,16 @@ TEST(ChannelInfoTest, Channels) {
   EXPECT_TRUE(ci.GetChannelName(&channel));
   EXPECT_EQ(kChannelDev, channel);
 
+  ci.set_value(L"x64-dev");
+  EXPECT_TRUE(ci.GetChannelName(&channel));
+  EXPECT_EQ(kChannelDev, channel);
+  ci.set_value(L"x64-beta");
+  EXPECT_TRUE(ci.GetChannelName(&channel));
+  EXPECT_EQ(kChannelBeta, channel);
+  ci.set_value(L"x64-stable");
+  EXPECT_TRUE(ci.GetChannelName(&channel));
+  EXPECT_EQ(kChannelStable, channel);
+
   ci.set_value(L"fuzzy");
   EXPECT_FALSE(ci.GetChannelName(&channel));
 }
index 67df18e..82404b5 100644 (file)
@@ -263,6 +263,7 @@ const wchar_t kChromeChannelCanary[] = L"canary";
 const wchar_t kChromeChannelDev[] = L"dev";
 const wchar_t kChromeChannelBeta[] = L"beta";
 const wchar_t kChromeChannelStable[] = L"";
+const wchar_t kChromeChannelStableExplicit[] = L"stable";
 
 const size_t kMaxAppModelIdLength = 64U;
 
index da54a38..2bc9f3e 100644 (file)
@@ -256,6 +256,7 @@ extern const wchar_t kChromeChannelCanary[];
 extern const wchar_t kChromeChannelDev[];
 extern const wchar_t kChromeChannelBeta[];
 extern const wchar_t kChromeChannelStable[];
+extern const wchar_t kChromeChannelStableExplicit[];
 
 extern const size_t kMaxAppModelIdLength;
 
index 23e8fba..8a4c07a 100644 (file)
@@ -1,3 +1,4 @@
 include_rules = [
   "+chrome/grit",  # For generated headers.
+  "+sandbox/win/src",
 ]
index 96cd0d1..b976448 100644 (file)
@@ -32,6 +32,7 @@
 #include "content/public/common/sandbox_init.h"
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "printing/emf_win.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
 
 namespace {
 
@@ -49,6 +50,13 @@ class ServiceSandboxedProcessLauncherDelegate
     *exposed_dir = exposed_dir_;
   }
 
+  virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
+                              bool* success) OVERRIDE {
+    // Service process may run as windows service and it fails to create a
+    // window station.
+    policy->SetAlternateDesktop(false);
+  }
+
  private:
   base::FilePath exposed_dir_;
 };
@@ -72,6 +80,7 @@ enum ServiceUtilityProcessHostEvent {
   SERVICE_UTILITY_SEMANTIC_CAPS_REQUEST,
   SERVICE_UTILITY_SEMANTIC_CAPS_SUCCEEDED,
   SERVICE_UTILITY_SEMANTIC_CAPS_FAILED,
+  SERVICE_UTILITY_FAILED_TO_START,
   SERVICE_UTILITY_EVENT_MAX,
 };
 }  // namespace
@@ -179,6 +188,9 @@ bool ServiceUtilityProcessHost::StartProcess(
                               SERVICE_UTILITY_EVENT_MAX);
     return true;
   }
+  UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
+                            SERVICE_UTILITY_FAILED_TO_START,
+                            SERVICE_UTILITY_EVENT_MAX);
   return false;
 }
 
index 32f032e..65423d5 100644 (file)
@@ -49,65 +49,6 @@ function waitForVisitDesktopMenu(windowId, profileId, waitMode) {
   });
 }
 
-testcase.multiProfileBadge = function() {
-  var appId;
-  StepsRunner.run([
-    function() {
-      setupAndWaitUntilReady(null, RootPath.DOWNLOADS, this.next);
-    },
-    // Add all users.
-    function(inAppId) {
-      appId = inAppId;
-      chrome.test.sendMessage(JSON.stringify({name: 'addAllUsers'}),
-                              this.next);
-    },
-    // Get the badge element.
-    function(json) {
-      chrome.test.assertTrue(JSON.parse(json));
-      waitForElement(appId, '#profile-badge').then(this.next);
-    },
-    // Verify no badge image is shown yet.  Move to other deskop.
-    function(element) {
-      chrome.test.assertTrue(element.hidden, 'Badge hidden initially');
-      callRemoteTestUtil('visitDesktop',
-                         appId,
-                         ['bob@invalid.domain'],
-                         this.next);
-    },
-    // Get the badge element again.
-    function(result) {
-      chrome.test.assertTrue(result);
-      waitForElement(appId, '#profile-badge:not([hidden])').then(this.next);
-    },
-    // Verify an image source is filled. Go back to the original desktop
-    function(element) {
-      callRemoteTestUtil('queryAllElements',
-                         appId,
-                         ['#profile-badge',
-                          null,
-                          ['background']]).then(this.next);
-    },
-    function(elements) {
-      chrome.test.assertTrue(
-          elements[0].styles.background.indexOf('data:image') !== -1,
-          'Badge shown after moving desktop');
-      callRemoteTestUtil('visitDesktop',
-                         appId,
-                         ['alice@invalid.domain'],
-                         this.next);
-    },
-    // Wait for #profile-badge element to disappear.
-    function(result) {
-      chrome.test.assertTrue(result);
-      waitForElementLost(appId, '#profile-badge:not([hidden])').then(this.next);
-    },
-    // The image is gone.
-    function(result) {
-      checkIfNoErrorsOccured(this.next);
-    }
-  ]);
-};
-
 testcase.multiProfileVisitDesktopMenu = function() {
   var appId;
   StepsRunner.run([
index e4922aa..316103b 100644 (file)
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/nacl/nacl_browsertest_util.h"
+#include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/web_contents.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
+#include "net/url_request/url_request.h"
 
 using net::test_server::BasicHttpResponse;
 using net::test_server::EmbeddedTestServer;
 using net::test_server::HttpRequest;
 using net::test_server::HttpResponse;
 
+void TestDispatcherHostDelegate::RequestBeginning(
+    net::URLRequest* request,
+    content::ResourceContext* resource_context,
+    content::AppCacheService* appcache_service,
+    content::ResourceType resource_type,
+    int child_id,
+    int route_id,
+    ScopedVector<content::ResourceThrottle>* throttles) {
+  // This checks the same condition as the one for PNaCl in
+  // AppendComponentUpdaterThrottles.
+  if (resource_type == content::RESOURCE_TYPE_OBJECT) {
+    const net::HttpRequestHeaders& headers = request->extra_request_headers();
+    std::string accept_headers;
+    if (headers.GetHeader("Accept", &accept_headers)) {
+      if (accept_headers.find("application/x-pnacl") != std::string::npos)
+        found_pnacl_header_ = true;
+    }
+  }
+}
+
 PnaclHeaderTest::PnaclHeaderTest() : noncors_loads_(0), cors_loads_(0) {}
 
 PnaclHeaderTest::~PnaclHeaderTest() {}
@@ -41,6 +63,7 @@ void PnaclHeaderTest::StartServer() {
 void PnaclHeaderTest::RunLoadTest(const std::string& url,
                                   int expected_noncors,
                                   int expected_cors) {
+  content::ResourceDispatcherHost::Get()->SetDelegate(&test_delegate_);
   StartServer();
   LoadTestMessageHandler handler;
   content::JavascriptTestObserver observer(
@@ -57,12 +80,17 @@ void PnaclHeaderTest::RunLoadTest(const std::string& url,
   base::ScopedPathOverride component_dir(chrome::DIR_PNACL_COMPONENT);
 
   ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL(url));
+
   // Wait until the NMF and pexe are also loaded, not just the HTML.
   // Do this by waiting till the LoadTestMessageHandler responds.
   EXPECT_TRUE(observer.Run()) << handler.error_message();
+
+  // Now check the expectations.
   EXPECT_TRUE(handler.test_passed()) << "Test failed.";
   EXPECT_EQ(expected_noncors, noncors_loads_);
   EXPECT_EQ(expected_cors, cors_loads_);
+
+  content::ResourceDispatcherHost::Get()->SetDelegate(NULL);
 }
 
 scoped_ptr<HttpResponse> PnaclHeaderTest::WatchForPexeFetch(
@@ -81,14 +109,14 @@ scoped_ptr<HttpResponse> PnaclHeaderTest::WatchForPexeFetch(
   if (absolute_url.path().find(".pexe") == std::string::npos)
     return scoped_ptr<HttpResponse>();
 
-  // For pexe files, check for the special Accept header.
-  // This must match whatever is in:
-  // ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
+  // For pexe files, check for the special Accept header,
+  // along with the expected ResourceType of the URL request.
   EXPECT_NE(0U, request.headers.count("Accept"));
   std::map<std::string, std::string>::const_iterator it =
       request.headers.find("Accept");
   EXPECT_NE(std::string::npos, it->second.find("application/x-pnacl"));
   EXPECT_NE(std::string::npos, it->second.find("*/*"));
+  EXPECT_TRUE(test_delegate_.found_pnacl_header());
 
   // Also make sure that other headers like CORS-related headers
   // are preserved when injecting the special Accept header.
index 9134925..e698b46 100644 (file)
@@ -8,6 +8,8 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
+#include "content/public/common/resource_type.h"
 
 namespace base {
 class FilePath;
@@ -20,6 +22,32 @@ class HttpResponse;
 }
 }
 
+using content::ResourceDispatcherHostDelegate;
+
+class TestDispatcherHostDelegate : public ResourceDispatcherHostDelegate {
+ public:
+  explicit TestDispatcherHostDelegate()
+      : ResourceDispatcherHostDelegate(), found_pnacl_header_(false) {}
+
+  virtual ~TestDispatcherHostDelegate() {}
+
+  virtual void RequestBeginning(
+      net::URLRequest* request,
+      content::ResourceContext* resource_context,
+      content::AppCacheService* appcache_service,
+      content::ResourceType resource_type,
+      int child_id,
+      int route_id,
+      ScopedVector<content::ResourceThrottle>* throttles) OVERRIDE;
+
+  bool found_pnacl_header() const { return found_pnacl_header_; }
+
+ private:
+  bool found_pnacl_header_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDispatcherHostDelegate);
+};
+
 class PnaclHeaderTest : public InProcessBrowserTest {
  public:
   PnaclHeaderTest();
@@ -40,6 +68,7 @@ class PnaclHeaderTest : public InProcessBrowserTest {
 
   int noncors_loads_;
   int cors_loads_;
+  TestDispatcherHostDelegate test_delegate_;
   DISALLOW_COPY_AND_ASSIGN(PnaclHeaderTest);
 };
 
index 824a9e9..bf1b1a2 100644 (file)
@@ -36,7 +36,6 @@ const wchar_t* g_troublesome_dlls[kTroublesomeDllsMaxCount] = {
                                         // See crbug.com/379218.
   L"activedetect64.dll",                // Lenovo One Key Theater.
   L"bitguard.dll",                      // Unknown (suspected malware).
-  L"cespy.dll",                         // CovenantEyes.
   L"chrmxtn.dll",                       // Unknown (keystroke logger).
   L"cplushook.dll",                     // Unknown (suspected malware).
   L"datamngr.dll",                      // Unknown (suspected adware).
index c5fe549..b3aabae 100644 (file)
@@ -13,7 +13,8 @@
 namespace chromeos {
 
 FakeSessionManagerClient::FakeSessionManagerClient()
-    : start_device_wipe_call_count_(0),
+    : first_boot_(false),
+      start_device_wipe_call_count_(0),
       notify_lock_screen_shown_call_count_(0),
       notify_lock_screen_dismissed_call_count_(0) {
 }
@@ -135,7 +136,7 @@ void FakeSessionManagerClient::SetFlagsForUser(
 void FakeSessionManagerClient::GetServerBackedStateKeys(
     const StateKeysCallback& callback) {
   base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(callback, server_backed_state_keys_));
+      FROM_HERE, base::Bind(callback, server_backed_state_keys_, first_boot_));
 }
 
 const std::string& FakeSessionManagerClient::device_policy() const {
index 2f4bb9a..f408b51 100644 (file)
@@ -85,6 +85,8 @@ class FakeSessionManagerClient : public SessionManagerClient {
     server_backed_state_keys_ = state_keys;
   }
 
+  void set_first_boot(bool first_boot) { first_boot_ = first_boot; }
+
   int start_device_wipe_call_count() const {
     return start_device_wipe_call_count_;
   }
@@ -106,6 +108,7 @@ class FakeSessionManagerClient : public SessionManagerClient {
   ObserverList<Observer> observers_;
   SessionManagerClient::ActiveSessionsMap user_sessions_;
   std::vector<std::string> server_backed_state_keys_;
+  bool first_boot_;
 
   int start_device_wipe_call_count_;
   int notify_lock_screen_shown_call_count_;
index b3ddad7..56dc850 100644 (file)
@@ -525,6 +525,7 @@ class SessionManagerClientImpl : public SessionManagerClient {
   void OnGetServerBackedStateKeys(const StateKeysCallback& callback,
                                   dbus::Response* response) {
     std::vector<std::string> state_keys;
+    bool first_run = false;
     if (!response) {
       LOG(ERROR) << "Failed to call "
                  << login_manager::kSessionManagerStartSession;
@@ -547,10 +548,14 @@ class SessionManagerClientImpl : public SessionManagerClient {
               std::string(reinterpret_cast<const char*>(data), size));
         }
       }
+      if (!reader.PopBool(&first_run)) {
+        // TODO(tnagel): After 2014-11-19 turn this warning into an error.
+        LOG(WARNING) << "Chrome OS is too old. Defaulting to first_run=false.";
+      }
     }
 
     if (!callback.is_null())
-      callback.Run(state_keys);
+      callback.Run(state_keys, first_run);
   }
 
 
@@ -713,7 +718,7 @@ class SessionManagerClientStubImpl : public SessionManagerClient {
       state_keys.push_back(crypto::SHA256HashString(base::IntToString(i)));
 
     if (!callback.is_null())
-      callback.Run(state_keys);
+      callback.Run(state_keys, false);
   }
 
  private:
index d4c0706..b007bee 100644 (file)
@@ -168,13 +168,16 @@ class CHROMEOS_EXPORT SessionManagerClient : public DBusClient {
   virtual void SetFlagsForUser(const std::string& username,
                                const std::vector<std::string>& flags) = 0;
 
-  typedef base::Callback<void(const std::vector<std::string>& state_keys)>
-      StateKeysCallback;
+  typedef base::Callback<void(const std::vector<std::string>& state_keys,
+                              bool first_boot)> StateKeysCallback;
 
   // Get the currently valid server-backed state keys for the device.
   // Server-backed state keys are opaque, device-unique, time-dependent,
   // client-determined identifiers that are used for keying state in the cloud
-  // for the device to retrieve after a device factory reset.
+  // for the device to retrieve after a device factory reset. The |first_boot|
+  // parameter indicates if this is the very first boot of the device after
+  // being assembled (even a "factory reset" will not trigger this again) in
+  // which case doing the enrollment check makes no sense.
   //
   // The state keys are returned asynchronously via |callback|. The callback
   // will be invoked with an empty state key vector in case of errors.
index 57777c8..80ad335 100644 (file)
@@ -117,6 +117,8 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
   // updated to match.
   InsertDataListValues(&values, &labels, &icons, &ids);
 
+// Temporarily disabled. See http://crbug.com/408695
+#if 0
 #if defined(OS_MACOSX) && !defined(OS_IOS)
   if (values.empty() &&
       manager_->ShouldShowAccessAddressBookSuggestion(query_form_,
@@ -130,6 +132,7 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
     EmitHistogram(SHOWED_ACCESS_ADDRESS_BOOK_ENTRY);
   }
 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+#endif
 
   if (values.empty()) {
     // No suggestions, any popup currently showing is obsolete.
index 26816f8..b8d824b 100644 (file)
@@ -138,20 +138,15 @@ void DeterminePossibleFieldTypesForUpload(
     AutofillField* field = submitted_form->field(i);
     ServerFieldTypeSet matching_types;
 
-    // If it's a password field, set the type directly.
-    if (field->form_control_type == "password") {
-      matching_types.insert(PASSWORD);
-    } else {
-      base::string16 value;
-      base::TrimWhitespace(field->value, base::TRIM_ALL, &value);
-      for (std::vector<AutofillProfile>::const_iterator it = profiles.begin();
-           it != profiles.end(); ++it) {
-        it->GetMatchingTypes(value, app_locale, &matching_types);
-      }
-      for (std::vector<CreditCard>::const_iterator it = credit_cards.begin();
-            it != credit_cards.end(); ++it) {
-        it->GetMatchingTypes(value, app_locale, &matching_types);
-      }
+    base::string16 value;
+    base::TrimWhitespace(field->value, base::TRIM_ALL, &value);
+    for (std::vector<AutofillProfile>::const_iterator it = profiles.begin();
+         it != profiles.end(); ++it) {
+      it->GetMatchingTypes(value, app_locale, &matching_types);
+    }
+    for (std::vector<CreditCard>::const_iterator it = credit_cards.begin();
+         it != credit_cards.end(); ++it) {
+      it->GetMatchingTypes(value, app_locale, &matching_types);
     }
 
     if (matching_types.empty())
@@ -813,17 +808,14 @@ void AutofillManager::UploadFormData(const FormStructure& submitted_form) {
 
   ServerFieldTypeSet non_empty_types;
   personal_data_->GetNonEmptyTypes(&non_empty_types);
-  // Always add PASSWORD to |non_empty_types| so that if |submitted_form|
-  // contains a password field it will be uploaded to the server. If
-  // |submitted_form| doesn't contain a password field, there is no side
-  // effect from adding PASSWORD to |non_empty_types|.
-  non_empty_types.insert(PASSWORD);
 
   download_manager_->StartUploadRequest(submitted_form, was_autofilled,
                                         non_empty_types);
 }
 
-bool AutofillManager::UploadPasswordGenerationForm(const FormData& form) {
+bool AutofillManager::UploadPasswordForm(
+    const FormData& form,
+    const ServerFieldType& password_type) {
   FormStructure form_structure(form);
 
   if (!ShouldUploadForm(form_structure))
@@ -832,8 +824,6 @@ bool AutofillManager::UploadPasswordGenerationForm(const FormData& form) {
   if (!form_structure.ShouldBeCrowdsourced())
     return false;
 
-  // TODO(gcasto): Check that PasswordGeneration is enabled?
-
   // Find the first password field to label. We don't try to label anything
   // else.
   bool found_password_field = false;
@@ -842,7 +832,7 @@ bool AutofillManager::UploadPasswordGenerationForm(const FormData& form) {
 
     ServerFieldTypeSet types;
     if (!found_password_field && field->form_control_type == "password") {
-      types.insert(ACCOUNT_CREATION_PASSWORD);
+      types.insert(password_type);
       found_password_field = true;
     } else {
       types.insert(UNKNOWN_TYPE);
@@ -853,7 +843,7 @@ bool AutofillManager::UploadPasswordGenerationForm(const FormData& form) {
 
   // Only one field type should be present.
   ServerFieldTypeSet available_field_types;
-  available_field_types.insert(ACCOUNT_CREATION_PASSWORD);
+  available_field_types.insert(password_type);
 
   // Force uploading as these events are relatively rare and we want to make
   // sure to receive them. It also makes testing easier if these requests
index 72454ed..d2ff660 100644 (file)
@@ -156,15 +156,17 @@ class AutofillManager : public AutofillDownloadManager::Observer {
   void OnSetDataList(const std::vector<base::string16>& values,
                      const std::vector<base::string16>& labels);
 
-  // Try and upload |form|. This differs from OnFormSubmitted() in a few ways.
+  // Try to label password fields and upload |form|. This differs from
+  // OnFormSubmitted() in a few ways.
   //   - This function will only label the first <input type="password"> field
-  //     as ACCOUNT_CREATION_PASSWORD. Other fields will stay unlabeled, as they
+  //     as |password_type|. Other fields will stay unlabeled, as they
   //     should have been labeled during the upload for OnFormSubmitted().
   //   - This function does not assume that |form| is being uploaded during
   //     the same browsing session as it was originally submitted (as we may
   //     not have the necessary information to classify the form at that time)
   //     so it bypasses the cache and doesn't log the same quality UMA metrics.
-  bool UploadPasswordGenerationForm(const FormData& form);
+  bool UploadPasswordForm(const FormData& form,
+                          const ServerFieldType& pasword_type);
 
   // Resets cache.
   virtual void Reset();
index 83d8173..b720ae4 100644 (file)
@@ -13,7 +13,7 @@ namespace autofill {
 
 namespace {
 
-const int kPickleVersion = 1;
+const int kPickleVersion = 2;
 
 bool ReadGURL(PickleIterator* iter, GURL* url) {
   std::string spec;
@@ -48,6 +48,11 @@ bool DeserializeFormFieldDataVector(PickleIterator* iter,
   return true;
 }
 
+void LogDeserializationError(int version) {
+  DVLOG(1) << "Could not deserialize version " << version
+             << " FormData from pickle.";
+}
+
 }  // namespace
 
 FormData::FormData()
@@ -113,24 +118,36 @@ void SerializeFormData(const FormData& form_data, Pickle* pickle) {
 bool DeserializeFormData(PickleIterator* iter, FormData* form_data) {
   int version;
   if (!iter->ReadInt(&version)) {
-    LOG(ERROR) << "Bad pickle of FormData, no version present";
+    DVLOG(1) << "Bad pickle of FormData, no version present";
     return false;
   }
 
   switch (version) {
     case 1: {
+      base::string16 method;
       if (!iter->ReadString16(&form_data->name) ||
+          !iter->ReadString16(&method) ||
           !ReadGURL(iter, &form_data->origin) ||
           !ReadGURL(iter, &form_data->action) ||
           !iter->ReadBool(&form_data->user_submitted) ||
           !DeserializeFormFieldDataVector(iter, &form_data->fields)) {
-        LOG(ERROR) << "Could not deserialize FormData from pickle";
+        LogDeserializationError(version);
         return false;
       }
       break;
     }
+    case 2:
+      if (!iter->ReadString16(&form_data->name) ||
+          !ReadGURL(iter, &form_data->origin) ||
+          !ReadGURL(iter, &form_data->action) ||
+          !iter->ReadBool(&form_data->user_submitted) ||
+          !DeserializeFormFieldDataVector(iter, &form_data->fields)) {
+        LogDeserializationError(version);
+        return false;
+      }
+      break;
     default: {
-      LOG(ERROR) << "Unknown FormData pickle version " << version;
+      DVLOG(1) << "Unknown FormData pickle version " << version;
       return false;
     }
   }
index 73d8256..4f57129 100644 (file)
@@ -6,8 +6,45 @@
 
 #include "base/pickle.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/form_field_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+
+// This function serializes the form data into the pickle in version one format.
+// It should always be possible to deserialize it using DeserializeFormData(),
+// even when version changes. See kPickleVersion in form_data.cc.
+void SerializeInVersion1Format(const autofill::FormData& form_data,
+                               Pickle* pickle) {
+  pickle->WriteInt(1);
+  pickle->WriteString16(form_data.name);
+  base::string16 method(base::ASCIIToUTF16("POST"));
+  pickle->WriteString16(method);
+  pickle->WriteString(form_data.origin.spec());
+  pickle->WriteString(form_data.action.spec());
+  pickle->WriteBool(form_data.user_submitted);
+  pickle->WriteInt(static_cast<int>(form_data.fields.size()));
+  for (size_t i = 0; i < form_data.fields.size(); ++i) {
+    SerializeFormFieldData(form_data.fields[i], pickle);
+  }
+}
+
+// This function serializes the form data into the pickle in incorrect format
+// (no version number).
+void SerializeIncorrectFormat(const autofill::FormData& form_data,
+                               Pickle* pickle) {
+  pickle->WriteString16(form_data.name);
+  pickle->WriteString(form_data.origin.spec());
+  pickle->WriteString(form_data.action.spec());
+  pickle->WriteBool(form_data.user_submitted);
+  pickle->WriteInt(static_cast<int>(form_data.fields.size()));
+  for (size_t i = 0; i < form_data.fields.size(); ++i) {
+    SerializeFormFieldData(form_data.fields[i], pickle);
+  }
+}
+
+}
+
 namespace autofill {
 
 TEST(FormDataTest, SerializeAndDeserialize) {
@@ -53,4 +90,88 @@ TEST(FormDataTest, SerializeAndDeserialize) {
   EXPECT_EQ(actual, data);
 }
 
+TEST(FormDataTest, Serialize_v1_Deserialize_vCurrent) {
+  FormData data;
+  data.name = base::ASCIIToUTF16("name");
+  data.origin = GURL("origin");
+  data.action = GURL("action");
+  data.user_submitted = true;
+
+  FormFieldData field_data;
+  field_data.label = base::ASCIIToUTF16("label");
+  field_data.name = base::ASCIIToUTF16("name");
+  field_data.value = base::ASCIIToUTF16("value");
+  field_data.form_control_type = "password";
+  field_data.autocomplete_attribute = "off";
+  field_data.max_length = 200;
+  field_data.is_autofilled = true;
+  field_data.is_checked = true;
+  field_data.is_checkable = true;
+  field_data.is_focusable = true;
+  field_data.should_autocomplete = false;
+  field_data.text_direction = base::i18n::RIGHT_TO_LEFT;
+  field_data.option_values.push_back(base::ASCIIToUTF16("First"));
+  field_data.option_values.push_back(base::ASCIIToUTF16("Second"));
+  field_data.option_contents.push_back(base::ASCIIToUTF16("First"));
+  field_data.option_contents.push_back(base::ASCIIToUTF16("Second"));
+
+  data.fields.push_back(field_data);
+
+  // Change a few fields.
+  field_data.max_length = 150;
+  field_data.option_values.push_back(base::ASCIIToUTF16("Third"));
+  field_data.option_contents.push_back(base::ASCIIToUTF16("Third"));
+  data.fields.push_back(field_data);
+
+  Pickle pickle;
+  SerializeInVersion1Format(data, &pickle);
+
+  PickleIterator iter(pickle);
+  FormData actual;
+  EXPECT_TRUE(DeserializeFormData(&iter, &actual));
+
+  EXPECT_EQ(actual, data);
+}
+
+TEST(FormDataTest, SerializeIncorrectFormatAndDeserialize) {
+  FormData data;
+  data.name = base::ASCIIToUTF16("name");
+  data.origin = GURL("origin");
+  data.action = GURL("action");
+  data.user_submitted = true;
+
+  FormFieldData field_data;
+  field_data.label = base::ASCIIToUTF16("label");
+  field_data.name = base::ASCIIToUTF16("name");
+  field_data.value = base::ASCIIToUTF16("value");
+  field_data.form_control_type = "password";
+  field_data.autocomplete_attribute = "off";
+  field_data.max_length = 200;
+  field_data.is_autofilled = true;
+  field_data.is_checked = true;
+  field_data.is_checkable = true;
+  field_data.is_focusable = true;
+  field_data.should_autocomplete = false;
+  field_data.text_direction = base::i18n::RIGHT_TO_LEFT;
+  field_data.option_values.push_back(base::ASCIIToUTF16("First"));
+  field_data.option_values.push_back(base::ASCIIToUTF16("Second"));
+  field_data.option_contents.push_back(base::ASCIIToUTF16("First"));
+  field_data.option_contents.push_back(base::ASCIIToUTF16("Second"));
+
+  data.fields.push_back(field_data);
+
+  // Change a few fields.
+  field_data.max_length = 150;
+  field_data.option_values.push_back(base::ASCIIToUTF16("Third"));
+  field_data.option_contents.push_back(base::ASCIIToUTF16("Third"));
+  data.fields.push_back(field_data);
+
+  Pickle pickle;
+  SerializeIncorrectFormat(data, &pickle);
+
+  PickleIterator iter(pickle);
+  FormData actual;
+  EXPECT_FALSE(DeserializeFormData(&iter, &actual));
+}
+
 }  // namespace autofill
index 72c4f90..0b60a77 100644 (file)
@@ -206,40 +206,6 @@ void AddTokenToRequest(ReportRequest* request, const AudioToken& token) {
   signals->set_observed_time_millis(base::Time::Now().ToJsTime());
 }
 
-OptInStateFilter* CreateOptedInOrOutFilter() {
-  OptInStateFilter* filter = new OptInStateFilter;
-  filter->add_allowed_opt_in_state(copresence::OPTED_IN);
-  filter->add_allowed_opt_in_state(copresence::OPTED_OUT);
-  return filter;
-}
-
-void AllowOptedOutMessages(ReportRequest* request) {
-  // TODO(ckehoe): Collapse this pattern into ProcessPublish()
-  // and ProcessSubscribe() methods.
-
-  if (request->has_manage_messages_request()) {
-    RepeatedPtrField<PublishedMessage>* messages = request
-        ->mutable_manage_messages_request()->mutable_message_to_publish();
-    for (int i = 0; i < messages->size(); ++i) {
-      PublishedMessage* message = messages->Mutable(i);
-      if (!message->has_opt_in_state_filter())
-        message->set_allocated_opt_in_state_filter(CreateOptedInOrOutFilter());
-    }
-  }
-
-  if (request->has_manage_subscriptions_request()) {
-    RepeatedPtrField<Subscription>* subscriptions =
-        request->mutable_manage_subscriptions_request()->mutable_subscription();
-    for (int i = 0; i < subscriptions->size(); ++i) {
-      Subscription* subscription = subscriptions->Mutable(i);
-      if (!subscription->has_opt_in_state_filter()) {
-        subscription->set_allocated_opt_in_state_filter(
-            CreateOptedInOrOutFilter());
-      }
-    }
-  }
-}
-
 }  // namespace
 
 // Public methods
@@ -306,7 +272,25 @@ void RpcHandler::SendReportRequest(scoped_ptr<ReportRequest> request,
 
   AddPlayingTokens(request.get());
 
-  AllowOptedOutMessages(request.get());
+  // TODO(ckehoe): Currently the server supports only BROADCAST_AND_SCAN.
+  // Remove this once b/16715253 is fixed.
+  if (request->has_manage_messages_request()) {
+    RepeatedPtrField<PublishedMessage>* messages = request
+        ->mutable_manage_messages_request()->mutable_message_to_publish();
+    for (int i = 0; i < messages->size(); ++i) {
+      messages->Mutable(i)->mutable_token_exchange_strategy()
+          ->set_broadcast_scan_configuration(BROADCAST_AND_SCAN);
+    }
+  }
+  if (request->has_manage_subscriptions_request()) {
+    RepeatedPtrField<Subscription>* subscriptions =
+        request->mutable_manage_subscriptions_request()->mutable_subscription();
+    for (int i = 0; i < subscriptions->size(); ++i) {
+      subscriptions->Mutable(i)->mutable_token_exchange_strategy()
+          ->set_broadcast_scan_configuration(BROADCAST_AND_SCAN);
+    }
+  }
+
   SendServerRequest(kReportRequestRpcName,
                     app_id,
                     request.Pass(),
index 962f8d9..b8d6b9b 100644 (file)
@@ -256,39 +256,6 @@ TEST_F(RpcHandlerTest, GetDeviceCapabilities) {
 }
 #endif
 
-TEST_F(RpcHandlerTest, AllowOptedOutMessages) {
-  // Request with no filter specified.
-  scoped_ptr<ReportRequest> report(new ReportRequest);
-  report->mutable_manage_messages_request()->add_message_to_publish()
-      ->set_id("message");
-  report->mutable_manage_subscriptions_request()->add_subscription()
-      ->set_id("subscription");
-  rpc_handler_.SendReportRequest(report.Pass());
-  const OptInStateFilter& filter =
-      GetMessagesPublished().Get(0).opt_in_state_filter();
-  ASSERT_EQ(2, filter.allowed_opt_in_state_size());
-  EXPECT_EQ(OPTED_IN, filter.allowed_opt_in_state(0));
-  EXPECT_EQ(OPTED_OUT, filter.allowed_opt_in_state(1));
-  EXPECT_EQ(2, GetSubscriptionsSent().Get(0).opt_in_state_filter()
-      .allowed_opt_in_state_size());
-
-  // Request with filters already specified.
-  report.reset(new ReportRequest);
-  report->mutable_manage_messages_request()->add_message_to_publish()
-      ->mutable_opt_in_state_filter()->add_allowed_opt_in_state(OPTED_IN);
-  report->mutable_manage_subscriptions_request()->add_subscription()
-      ->mutable_opt_in_state_filter()->add_allowed_opt_in_state(OPTED_OUT);
-  rpc_handler_.SendReportRequest(report.Pass());
-  const OptInStateFilter& publish_filter =
-      GetMessagesPublished().Get(0).opt_in_state_filter();
-  ASSERT_EQ(1, publish_filter.allowed_opt_in_state_size());
-  EXPECT_EQ(OPTED_IN, publish_filter.allowed_opt_in_state(0));
-  const OptInStateFilter& subscription_filter =
-      GetSubscriptionsSent().Get(0).opt_in_state_filter();
-  ASSERT_EQ(1, subscription_filter.allowed_opt_in_state_size());
-  EXPECT_EQ(OPTED_OUT, subscription_filter.allowed_opt_in_state(0));
-}
-
 TEST_F(RpcHandlerTest, CreateRequestHeader) {
   SetDeviceId("CreateRequestHeader Device ID");
   rpc_handler_.SendReportRequest(make_scoped_ptr(new ReportRequest),
index 1074783..3088e08 100644 (file)
@@ -12,6 +12,7 @@
 #include "base/time/time.h"
 #include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
 #include "net/base/host_port_pair.h"
+#include "net/proxy/proxy_config.h"
 #include "net/proxy/proxy_info.h"
 #include "net/proxy/proxy_retry_info.h"
 #include "net/proxy/proxy_server.h"
@@ -366,6 +367,21 @@ bool DataReductionProxyParams::IsDataReductionProxyEligible(
   return IsDataReductionProxy(result.proxy_server().host_port_pair(), NULL);
 }
 
+bool DataReductionProxyParams::IsBypassedByDataReductionProxyLocalRules(
+    const net::URLRequest& request,
+    const net::ProxyConfig& data_reduction_proxy_config) const {
+  DCHECK(request.context());
+  DCHECK(request.context()->proxy_service());
+  net::ProxyInfo result;
+  data_reduction_proxy_config.proxy_rules().Apply(
+      request.url(), &result);
+  if (!result.proxy_server().is_valid())
+    return true;
+  if (result.proxy_server().is_direct())
+    return true;
+  return !IsDataReductionProxy(result.proxy_server().host_port_pair(), NULL);
+}
+
 std::string DataReductionProxyParams::GetDefaultDevOrigin() const {
 #if defined(DATA_REDUCTION_DEV_HOST)
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
@@ -400,9 +416,14 @@ bool DataReductionProxyParams::AreProxiesBypassed(
   if (retry_map.size() == 0)
     return false;
 
-  if (is_https && alt_allowed_) {
-    return ArePrimaryAndFallbackBypassed(
-        retry_map, ssl_origin_, GURL(), min_retry_delay);
+  // If the request is https, consider only the ssl proxy.
+  if (is_https) {
+    if (alt_allowed_) {
+      return ArePrimaryAndFallbackBypassed(
+          retry_map, ssl_origin_, GURL(), min_retry_delay);
+    }
+    NOTREACHED();
+    return false;
   }
 
   if (allowed_ && ArePrimaryAndFallbackBypassed(
@@ -423,34 +444,41 @@ bool DataReductionProxyParams::ArePrimaryAndFallbackBypassed(
     const GURL& primary,
     const GURL& fallback,
     base::TimeDelta* min_retry_delay) const {
-  net::ProxyRetryInfoMap::const_iterator found = retry_map.find(
-      net::ProxyServer(primary.SchemeIs(url::kHttpsScheme) ?
-          net::ProxyServer::SCHEME_HTTPS : net::ProxyServer::SCHEME_HTTP,
-          net::HostPortPair::FromURL(primary)).ToURI());
-
-  if (found == retry_map.end())
-    return false;
-
-  base::TimeDelta min_delay = found->second.current_delay;
-  if (!fallback_allowed_ || !fallback.is_valid()) {
-    if (min_retry_delay != NULL)
-      *min_retry_delay = min_delay;
-    return true;
+  net::ProxyRetryInfoMap::const_iterator found = retry_map.end();
+  if (min_retry_delay)
+    *min_retry_delay = base::TimeDelta::Max();
+
+  // Look for the primary proxy in the retry map. This must be done before
+  // looking for the fallback in order to assign |min_retry_delay| if the
+  // primary proxy has a shorter delay.
+  if (!fallback_allowed_ || !fallback.is_valid() || min_retry_delay) {
+    found = retry_map.find(
+        net::ProxyServer(primary.SchemeIs(url::kHttpsScheme) ?
+            net::ProxyServer::SCHEME_HTTPS :
+            net::ProxyServer::SCHEME_HTTP,
+        net::HostPortPair::FromURL(primary)).ToURI());
+    if (found != retry_map.end() && min_retry_delay) {
+      *min_retry_delay = found->second.current_delay;
+    }
   }
 
-  found = retry_map.find(
-      net::ProxyServer(fallback.SchemeIs(url::kHttpsScheme) ?
-          net::ProxyServer::SCHEME_HTTPS : net::ProxyServer::SCHEME_HTTP,
-          net::HostPortPair::FromURL(fallback)).ToURI());
-
-  if (found == retry_map.end())
-    return false;
+  if (fallback_allowed_ && fallback.is_valid()) {
+    // If fallback is allowed, only the fallback proxy needs to be on the retry
+    // map to know if there was a bypass. We can reset found and forget if the
+    // primary was on the retry map.
+    found = retry_map.find(
+        net::ProxyServer(fallback.SchemeIs(url::kHttpsScheme) ?
+                             net::ProxyServer::SCHEME_HTTPS :
+                             net::ProxyServer::SCHEME_HTTP,
+                         net::HostPortPair::FromURL(fallback)).ToURI());
+    if (found != retry_map.end() &&
+        min_retry_delay &&
+        *min_retry_delay > found->second.current_delay) {
+      *min_retry_delay = found->second.current_delay;
+    }
+  }
 
-  if (min_delay > found->second.current_delay)
-    min_delay = found->second.current_delay;
-  if (min_retry_delay != NULL)
-    *min_retry_delay = min_delay;
-  return true;
+  return found != retry_map.end();
 }
 
 std::string DataReductionProxyParams::GetDefaultOrigin() const {
index 6517845..9059047 100644 (file)
@@ -19,6 +19,7 @@ class TimeDelta;
 }
 
 namespace net {
+class ProxyConfig;
 class URLRequest;
 }
 
@@ -130,6 +131,13 @@ class DataReductionProxyParams {
   // list.
   virtual bool IsDataReductionProxyEligible(const net::URLRequest* request);
 
+  // Returns true if this request would be bypassed by the data request proxy
+  // based on applying the |data_reduction_proxy_config| param rules to the
+  // request URL.
+  bool IsBypassedByDataReductionProxyLocalRules(
+      const net::URLRequest& request,
+      const net::ProxyConfig& data_reduction_proxy_config) const;
+
   // Checks if all configured data reduction proxies are in the retry map.
   // Returns true if the request is bypassed by all configured data reduction
   // proxies and returns the bypass delay in delay_seconds (if not NULL). If
index 69a9ab6..9a5681d 100644 (file)
@@ -704,7 +704,7 @@ TEST_F(DataReductionProxyParamsTest, AreProxiesBypassed) {
       { // proxy flags
         false,
         false,
-        false,
+        true,
         // is https request
         true,
         // proxies in retry map
@@ -714,11 +714,11 @@ TEST_F(DataReductionProxyParamsTest, AreProxiesBypassed) {
         false,
         true,
         // expected result
-        false,
+        true,
       },
       { // proxy flags
-        false,
-        false,
+        true,
+        true,
         true,
         // is https request
         true,
@@ -733,30 +733,45 @@ TEST_F(DataReductionProxyParamsTest, AreProxiesBypassed) {
       },
       { // proxy flags
         true,
-        true,
-        true,
+        false,
+        false,
         // is https request
-        true,
+        false,
         // proxies in retry map
+        true,
         false,
         false,
         false,
         false,
-        true,
         // expected result
         true,
       },
       { // proxy flags
         true,
-        false,
+        true,
         false,
         // is https request
         false,
         // proxies in retry map
+        false,
+        true,
+        false,
+        false,
+        false,
+        // expected result
+        true,
+      },
+      { // proxy flags
+        false,
+        true,
         true,
+        // is https request
+        false,
+        // proxies in retry map
         false,
         false,
         false,
+        true,
         false,
         // expected result
         true,
index 09f5d2c..a2ca75d 100644 (file)
@@ -240,11 +240,6 @@ void DataReductionProxySettings::OnURLFetchComplete(
     const net::URLFetcher* source) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  // The purpose of sending a request for the warmup URL is to warm the
-  // connection to the data_reduction_proxy. The result is ignored.
-  if (source == warmup_fetcher_.get())
-    return;
-
   DCHECK(source == fetcher_.get());
   net::URLRequestStatus status = source->GetStatus();
   if (status.status() == net::URLRequestStatus::FAILED) {
@@ -351,7 +346,6 @@ void DataReductionProxySettings::OnIPAddressChanged() {
     if (DisableIfVPN())
       return;
     ProbeWhetherDataReductionProxyIsAvailable();
-    WarmProxyConnection();
   }
 }
 
@@ -407,7 +401,6 @@ void DataReductionProxySettings::MaybeActivateDataReductionProxy(
   // Check if the proxy has been restricted explicitly by the carrier.
   if (enabled_by_user_ && !disabled_on_vpn_) {
     ProbeWhetherDataReductionProxyIsAvailable();
-    WarmProxyConnection();
   }
 }
 
@@ -566,18 +559,6 @@ void DataReductionProxySettings::ProbeWhetherDataReductionProxyIsAvailable() {
   fetcher_->Start();
 }
 
-net::URLFetcher* DataReductionProxySettings::GetURLFetcherForWarmup() {
-  return GetBaseURLFetcher(params_->warmup_url(), net::LOAD_DISABLE_CACHE);
-}
-
-void DataReductionProxySettings::WarmProxyConnection() {
-  net::URLFetcher* fetcher = GetURLFetcherForWarmup();
-  if (!fetcher)
-    return;
-  warmup_fetcher_.reset(fetcher);
-  warmup_fetcher_->Start();
-}
-
 bool DataReductionProxySettings::DisableIfVPN() {
   net::NetworkInterfaceList network_interfaces;
   GetNetworkList(&network_interfaces, 0);
index 804023b..7a1348c 100644 (file)
@@ -184,10 +184,6 @@ class DataReductionProxySettings
   // Virtual for testing.
   virtual net::URLFetcher* GetURLFetcherForAvailabilityCheck();
 
-  // Returns a fetcher to warm up the connection to the data reduction proxy.
-  // Virtual for testing.
-  virtual net::URLFetcher* GetURLFetcherForWarmup();
-
   // Virtualized for unit test support.
   virtual PrefService* GetOriginalProfilePrefs();
   virtual PrefService* GetLocalStatePrefs();
@@ -284,9 +280,6 @@ class DataReductionProxySettings
   // failure.
   void ProbeWhetherDataReductionProxyIsAvailable();
 
-  // Warms the connection to the data reduction proxy.
-  void WarmProxyConnection();
-
   // Disables use of the data reduction proxy on VPNs. Returns true if the
   // data reduction proxy has been disabled.
   bool DisableIfVPN();
@@ -301,7 +294,6 @@ class DataReductionProxySettings
   bool unreachable_;
 
   scoped_ptr<net::URLFetcher> fetcher_;
-  scoped_ptr<net::URLFetcher> warmup_fetcher_;
 
   BooleanPrefMember spdy_proxy_auth_enabled_;
   BooleanPrefMember data_reduction_proxy_alternative_enabled_;
index 7cf609a..42c4ca3 100644 (file)
@@ -20,7 +20,6 @@ using testing::Return;
 namespace {
 
 const char kProbeURLWithOKResponse[] = "http://ok.org/";
-const char kWarmupURLWithNoContentResponse[] = "http://warm.org/";
 
 const char kProxy[] = "proxy";
 
@@ -143,7 +142,6 @@ void DataReductionProxySettingsTestBase::ResetSettings(bool allowed,
       .Times(AnyNumber())
       .WillRepeatedly(Return(&pref_service_));
   EXPECT_CALL(*settings, GetURLFetcherForAvailabilityCheck()).Times(0);
-  EXPECT_CALL(*settings, GetURLFetcherForWarmup()).Times(0);
   EXPECT_CALL(*settings, LogProxyState(_, _, _)).Times(0);
   settings_.reset(settings);
   configurator_.reset(new TestDataReductionProxyConfig());
@@ -162,7 +160,6 @@ DataReductionProxySettingsTestBase::ResetSettings<DataReductionProxySettings>(
 template <class C>
 void DataReductionProxySettingsTestBase::SetProbeResult(
     const std::string& test_url,
-    const std::string& warmup_test_url,
     const std::string& response,
     ProbeURLFetchResult result,
     bool success,
@@ -171,7 +168,6 @@ void DataReductionProxySettingsTestBase::SetProbeResult(
       static_cast<MockDataReductionProxySettings<C>*>(settings_.get());
   if (0 == expected_calls) {
     EXPECT_CALL(*settings, GetURLFetcherForAvailabilityCheck()).Times(0);
-    EXPECT_CALL(*settings, GetURLFetcherForWarmup()).Times(0);
     EXPECT_CALL(*settings, RecordProbeURLFetchResult(_)).Times(0);
   } else {
     EXPECT_CALL(*settings, RecordProbeURLFetchResult(result)).Times(1);
@@ -184,15 +180,6 @@ void DataReductionProxySettingsTestBase::SetProbeResult(
             success ? net::HTTP_OK : net::HTTP_INTERNAL_SERVER_ERROR,
             success ? net::URLRequestStatus::SUCCESS :
                       net::URLRequestStatus::FAILED)));
-    EXPECT_CALL(*settings, GetURLFetcherForWarmup())
-        .Times(expected_calls)
-        .WillRepeatedly(Return(new net::FakeURLFetcher(
-            GURL(warmup_test_url),
-            settings,
-            "",
-            success ? net::HTTP_NO_CONTENT : net::HTTP_INTERNAL_SERVER_ERROR,
-                success ? net::URLRequestStatus::SUCCESS :
-                          net::URLRequestStatus::FAILED)));
   }
 }
 
@@ -200,7 +187,6 @@ void DataReductionProxySettingsTestBase::SetProbeResult(
 template void
 DataReductionProxySettingsTestBase::SetProbeResult<DataReductionProxySettings>(
     const std::string& test_url,
-    const std::string& warmup_test_url,
     const std::string& response,
     ProbeURLFetchResult result,
     bool success,
@@ -220,7 +206,6 @@ void DataReductionProxySettingsTestBase::CheckProxyConfigs(
 void DataReductionProxySettingsTestBase::CheckProbe(
     bool initially_enabled,
     const std::string& probe_url,
-    const std::string& warmup_url,
     const std::string& response,
     bool request_succeeded,
     bool expected_enabled,
@@ -232,7 +217,6 @@ void DataReductionProxySettingsTestBase::CheckProbe(
     settings_->enabled_by_user_ = true;
   settings_->restricted_by_carrier_ = false;
   SetProbeResult(probe_url,
-                 warmup_url,
                  response,
                  FetchResult(initially_enabled,
                              request_succeeded && (response == "OK")),
@@ -247,13 +231,11 @@ void DataReductionProxySettingsTestBase::CheckProbe(
 
 void DataReductionProxySettingsTestBase::CheckProbeOnIPChange(
     const std::string& probe_url,
-    const std::string& warmup_url,
     const std::string& response,
     bool request_succeeded,
     bool expected_restricted,
     bool expected_fallback_restricted) {
   SetProbeResult(probe_url,
-                 warmup_url,
                  response,
                  FetchResult(!settings_->restricted_by_carrier_,
                              request_succeeded && (response == "OK")),
@@ -270,7 +252,6 @@ void DataReductionProxySettingsTestBase::CheckOnPrefChange(
     bool managed) {
   // Always have a sucessful probe for pref change tests.
   SetProbeResult(kProbeURLWithOKResponse,
-                 kWarmupURLWithNoContentResponse,
                  "OK",
                  FetchResult(enabled, true),
                  true,
@@ -290,7 +271,6 @@ void DataReductionProxySettingsTestBase::CheckInitDataReductionProxy(
     bool enabled_at_startup) {
   base::MessageLoopForUI loop;
   SetProbeResult(kProbeURLWithOKResponse,
-                 kWarmupURLWithNoContentResponse,
                  "OK",
                  FetchResult(enabled_at_startup, true),
                  true,
index eb8ef0e..3cd6fdb 100644 (file)
@@ -69,7 +69,6 @@ class MockDataReductionProxySettings : public C {
           TestDataReductionProxyParams::HAS_EVERYTHING &
           ~TestDataReductionProxyParams::HAS_DEV_ORIGIN)) {}
   MOCK_METHOD0(GetURLFetcherForAvailabilityCheck, net::URLFetcher*());
-  MOCK_METHOD0(GetURLFetcherForWarmup, net::URLFetcher*());
   MOCK_METHOD0(GetOriginalProfilePrefs, PrefService*());
   MOCK_METHOD0(GetLocalStatePrefs, PrefService*());
   MOCK_METHOD3(LogProxyState, void(
@@ -126,13 +125,11 @@ class DataReductionProxySettingsTestBase : public testing::Test {
 
   template <class C> void SetProbeResult(
       const std::string& test_url,
-      const std::string& warmup_test_url,
       const std::string& response,
       ProbeURLFetchResult state,
       bool success,
       int expected_calls);
   virtual void SetProbeResult(const std::string& test_url,
-                              const std::string& warmup_test_url,
                               const std::string& response,
                               ProbeURLFetchResult result,
                               bool success,
@@ -143,14 +140,12 @@ class DataReductionProxySettingsTestBase : public testing::Test {
                          bool expected_fallback_restricted);
   void CheckProbe(bool initially_enabled,
                   const std::string& probe_url,
-                  const std::string& warmup_url,
                   const std::string& response,
                   bool request_success,
                   bool expected_enabled,
                   bool expected_restricted,
                   bool expected_fallback_restricted);
   void CheckProbeOnIPChange(const std::string& probe_url,
-                            const std::string& warmup_url,
                             const std::string& response,
                             bool request_success,
                             bool expected_enabled,
@@ -187,14 +182,12 @@ class ConcreteDataReductionProxySettingsTest
   }
 
   virtual void SetProbeResult(const std::string& test_url,
-                              const std::string& warmup_test_url,
                               const std::string& response,
                               ProbeURLFetchResult result,
                               bool success,
                               int expected_calls) OVERRIDE {
     return DataReductionProxySettingsTestBase::SetProbeResult<C>(
         test_url,
-        warmup_test_url,
         response,
         result,
         success,
index 9e77071..a192d9a 100644 (file)
@@ -23,7 +23,6 @@ namespace {
 const char kProbeURLWithOKResponse[] = "http://ok.org/";
 const char kProbeURLWithBadResponse[] = "http://bad.org/";
 const char kProbeURLWithNoResponse[] = "http://no.org/";
-const char kWarmupURLWithNoContentResponse[] = "http://warm.org/";
 
 }  // namespace
 
@@ -239,7 +238,6 @@ TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
   // Request succeeded but with bad response, expect proxy to be restricted.
   CheckProbe(true,
              kProbeURLWithBadResponse,
-             kWarmupURLWithNoContentResponse,
              "Bad",
              true,
              true,
@@ -248,7 +246,6 @@ TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
   // Request succeeded with valid response, expect proxy to be unrestricted.
   CheckProbe(true,
              kProbeURLWithOKResponse,
-             kWarmupURLWithNoContentResponse,
              "OK",
              true,
              true,
@@ -257,7 +254,6 @@ TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
   // Request failed, expect proxy to be enabled but restricted.
   CheckProbe(true,
              kProbeURLWithNoResponse,
-             kWarmupURLWithNoContentResponse,
              "",
              false,
              true,
@@ -267,7 +263,6 @@ TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
   // state.
   CheckProbe(false,
              kProbeURLWithOKResponse,
-             kWarmupURLWithNoContentResponse,
              "OK",
              true,
              false,
@@ -291,28 +286,24 @@ TEST_F(DataReductionProxySettingsTest, TestOnIPAddressChanged) {
   // IP address change triggers a probe that succeeds. Proxy remains
   // unrestricted.
   CheckProbeOnIPChange(kProbeURLWithOKResponse,
-                       kWarmupURLWithNoContentResponse,
                        "OK",
                        true,
                        false,
                        false);
   // IP address change triggers a probe that fails. Proxy is restricted.
   CheckProbeOnIPChange(kProbeURLWithBadResponse,
-                       kWarmupURLWithNoContentResponse,
                        "Bad",
                        true,
                        true,
                        false);
   // IP address change triggers a probe that fails. Proxy remains restricted.
   CheckProbeOnIPChange(kProbeURLWithBadResponse,
-                       kWarmupURLWithNoContentResponse,
                        "Bad",
                        true,
                        true,
                        false);
   // IP address change triggers a probe that succeeds. Proxy is unrestricted.
   CheckProbeOnIPChange(kProbeURLWithOKResponse,
-                       kWarmupURLWithNoContentResponse,
                        "OK",
                        true,
                        false,
@@ -343,7 +334,6 @@ TEST_F(DataReductionProxySettingsTest, TestOnIPAddressChanged) {
                             0  /* network prefix */
                             ));
   CheckProbeOnIPChange(kProbeURLWithOKResponse,
-                       kWarmupURLWithNoContentResponse,
                        "OK",
                        true,
                        false,
index 1f5bd77..bdbb9bf 100644 (file)
@@ -161,8 +161,24 @@ void DataReductionProxyUsageStats::SetBypassType(
 
 void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
     net::URLRequest& request,
-    const BooleanPrefMember& data_reduction_proxy_enabled) {
+    const BooleanPrefMember& data_reduction_proxy_enabled,
+    const net::ProxyConfig& data_reduction_proxy_config) {
   int64 content_length = request.received_response_content_length();
+
+  if (data_reduction_proxy_enabled.GetValue()) {
+  LOG(WARNING) << "managed pac: " << (!data_reduction_proxy_config.Equals(
+          request.context()->proxy_service()->config()) ? "true" : "false");
+  }
+
+  if (data_reduction_proxy_enabled.GetValue() &&
+      !data_reduction_proxy_config.Equals(
+          request.context()->proxy_service()->config())) {
+    RecordBypassedBytes(last_bypass_type_,
+                        DataReductionProxyUsageStats::MANAGED_PROXY_CONFIG,
+                        content_length);
+    return;
+  }
+
   if (data_reduction_proxy_params_->WasDataReductionProxyUsed(&request, NULL)) {
     RecordBypassedBytes(last_bypass_type_,
                         DataReductionProxyUsageStats::NOT_BYPASSED,
@@ -179,7 +195,8 @@ void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
   }
 
   if (data_reduction_proxy_enabled.GetValue() &&
-      !data_reduction_proxy_params_->IsDataReductionProxyEligible(&request)) {
+      data_reduction_proxy_params_->IsBypassedByDataReductionProxyLocalRules(
+          request, data_reduction_proxy_config)) {
     RecordBypassedBytes(last_bypass_type_,
                         DataReductionProxyUsageStats::LOCAL_BYPASS_RULES,
                         content_length);
@@ -187,11 +204,6 @@ void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
   }
 
   if (triggering_request_) {
-    RecordBypassedBytes(last_bypass_type_,
-                        DataReductionProxyUsageStats::TRIGGERING_REQUEST,
-                        content_length);
-    triggering_request_ = false;
-
     // We only record when audio or video triggers a bypass. We don't care
     // about audio and video bypassed as collateral damage.
     std::string mime_type;
@@ -203,7 +215,14 @@ void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
       RecordBypassedBytes(last_bypass_type_,
                           DataReductionProxyUsageStats::AUDIO_VIDEO,
                           content_length);
+      return;
     }
+
+    RecordBypassedBytes(last_bypass_type_,
+                        DataReductionProxyUsageStats::TRIGGERING_REQUEST,
+                        content_length);
+    triggering_request_ = false;
+    return;
   }
 
   if (last_bypass_type_ != BYPASS_EVENT_TYPE_MAX) {
@@ -223,8 +242,7 @@ void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
 
 void DataReductionProxyUsageStats::RecordBypassEventHistograms(
     const net::ProxyServer& bypassed_proxy,
-    int net_error,
-    bool did_fallback) const {
+    int net_error) const {
   DataReductionProxyTypeInfo data_reduction_proxy_info;
   if (bypassed_proxy.is_valid() && !bypassed_proxy.is_direct() &&
       data_reduction_proxy_params_->IsDataReductionProxy(
@@ -266,6 +284,11 @@ void DataReductionProxyUsageStats::RecordBypassedBytes(
           "DataReductionProxy.BypassedBytes.LocalBypassRules",
           content_length);
       break;
+    case DataReductionProxyUsageStats::MANAGED_PROXY_CONFIG:
+      UMA_HISTOGRAM_COUNTS(
+          "DataReductionProxy.BypassedBytes.ManagedProxyConfig",
+          content_length);
+      break;
     case DataReductionProxyUsageStats::AUDIO_VIDEO:
       if (last_bypass_type_ == BYPASS_EVENT_TYPE_SHORT) {
         UMA_HISTOGRAM_COUNTS(
index d73db4b..33fd29e 100644 (file)
@@ -55,23 +55,24 @@ class DataReductionProxyUsageStats
   // cause the current bypass.
   void SetBypassType(DataReductionProxyBypassType type);
 
-  // Given the |content_length| and associated |request|, records the
-  // number of bypassed bytes for that |request| into UMAs based on bypass type.
-  // |data_reduction_proxy_enabled| tells us the state of the
-  // kDataReductionProxyEnabled preference.
+  // Given |data_reduction_proxy_enabled|, a |request|, and the
+  // |data_reduction_proxy_config| records the number of bypassed bytes for that
+  // |request| into UMAs based on bypass type. |data_reduction_proxy_enabled|
+  // tells us the state of the kDataReductionProxyEnabled preference.
   void RecordBypassedBytesHistograms(
       net::URLRequest& request,
-      const BooleanPrefMember& data_reduction_proxy_enabled);
+      const BooleanPrefMember& data_reduction_proxy_enabled,
+      const net::ProxyConfig& data_reduction_proxy_config);
 
   void RecordBypassEventHistograms(const net::ProxyServer& bypassed_proxy,
-                                   int net_error,
-                                   bool did_fallback) const;
+                                   int net_error) const;
 
  private:
   enum BypassedBytesType {
     NOT_BYPASSED = 0,         /* Not bypassed. */
     SSL,                      /* Bypass due to SSL. */
     LOCAL_BYPASS_RULES,       /* Bypass due to client-side bypass rules. */
+    MANAGED_PROXY_CONFIG,     /* Bypass due to managed config. */
     AUDIO_VIDEO,              /* Audio/Video bypass. */
     TRIGGERING_REQUEST,       /* Triggering request bypass. */
     NETWORK_ERROR,            /* Network error. */
index b324b20..9ef1911 100644 (file)
               'domain_reliability/baked_in_configs/redirector_gvt1_com.json',
               'domain_reliability/baked_in_configs/s0_2mdn_net.json',
               'domain_reliability/baked_in_configs/ssl_gstatic_com.json',
+              'domain_reliability/baked_in_configs/star_admob_com.json',
+              'domain_reliability/baked_in_configs/star_doubleclick_net.json',
+              'domain_reliability/baked_in_configs/star_g_doubleclick_net.json',
+              'domain_reliability/baked_in_configs/star_ggpht_com.json',
+              'domain_reliability/baked_in_configs/star_google_cn.json',
+              'domain_reliability/baked_in_configs/star_google_co_uk.json',
+              'domain_reliability/baked_in_configs/star_google_com.json',
+              'domain_reliability/baked_in_configs/star_google_com_au.json',
+              'domain_reliability/baked_in_configs/star_google_de.json',
+              'domain_reliability/baked_in_configs/star_google_fr.json',
+              'domain_reliability/baked_in_configs/star_google_it.json',
+              'domain_reliability/baked_in_configs/star_google_jp.json',
+              'domain_reliability/baked_in_configs/star_google_org.json',
+              'domain_reliability/baked_in_configs/star_google_ru.json',
+              'domain_reliability/baked_in_configs/star_googleadservices_com.json',
+              'domain_reliability/baked_in_configs/star_googleapis_com.json',
+              'domain_reliability/baked_in_configs/star_googlesyndication_com.json',
+              'domain_reliability/baked_in_configs/star_googleusercontent_com.json',
+              'domain_reliability/baked_in_configs/star_googlevideo_com.json',
+              'domain_reliability/baked_in_configs/star_gstatic_com.json',
+              'domain_reliability/baked_in_configs/star_gvt1_com.json',
+              'domain_reliability/baked_in_configs/star_youtube_com.json',
+              'domain_reliability/baked_in_configs/star_ytimg_com.json',
               'domain_reliability/baked_in_configs/t0_gstatic_com.json',
               'domain_reliability/baked_in_configs/t1_gstatic_com.json',
               'domain_reliability/baked_in_configs/t2_gstatic_com.json',
index 937fce5..56f7aae 100755 (executable)
@@ -18,9 +18,12 @@ import sys
 # Chrome, to ensure incorrect ones are not added accidentally. Subdomains of
 # whitelist entries are also allowed (e.g. maps.google.com, ssl.gstatic.com).
 DOMAIN_WHITELIST = ('2mdn.net', 'admob.com', 'doubleclick.net', 'ggpht.com',
-                    'google.com', 'googleadservices.com', 'googleapis.com',
-                    'googlesyndication.com', 'googleusercontent.com',
-                    'googlevideo.com', 'gstatic.com', 'gvt1.com', 'youtube.com')
+                    'google.cn', 'google.co.uk', 'google.com', 'google.com.au',
+                    'google.de', 'google.fr', 'google.it', 'google.jp',
+                    'google.org', 'google.ru', 'googleadservices.com',
+                    'googleapis.com', 'googlesyndication.com',
+                    'googleusercontent.com', 'googlevideo.com', 'gstatic.com',
+                    'gvt1.com', 'youtube.com', 'ytimg.com')
 
 
 CC_HEADER = """// Copyright (C) 2014 The Chromium Authors. All rights reserved.
index 59f2773..d66613a 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "accounts-google-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "accounts.google.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 0c452a9..e042c4a 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "ad-doubleclick-net-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "ad.doubleclick.net",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 496da86..6f442ea 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "apis-google-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "apis.google.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 5b9af1d..1de2ce7 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "c-admob-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "c.admob.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
diff --git a/src/components/domain_reliability/baked_in_configs/clients2_google_com.json b/src/components/domain_reliability/baked_in_configs/clients2_google_com.json
new file mode 100644 (file)
index 0000000..18982df
--- /dev/null
@@ -0,0 +1,27 @@
+{
+  "config_version": "clients2-google-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "clients2.google.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "clients2-google-com-domainreliability",
+      "url_patterns": ["http*://clients2.google.com/domainreliability/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 0.50
+    },
+    {
+      "resource_name": "clients2-google-com-other",
+      "url_patterns": ["http*://clients2.google.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
index 7eacd17..2cb1e82 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "csi-gstatic-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "csi.gstatic.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index d0610f1..4a33380 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "ddm-google-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "ddm.google.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 31e926f..555d0ca 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "docs-google-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "docs.google.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 0bbd3d6..7f9de68 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "drive-google-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "drive.google.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index e67ea06..287ebea 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "e-admob-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "e.admob.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 5aea525..cb43d9a 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "fonts-googleapis-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "fonts.googleapis.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index ba5d6f6..4b1fb5d 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "googleads4-g-doubleclick-net-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "googleads4.g.doubleclick.net",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index a04fd23..78cbf19 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "googleads-g-doubleclick-net-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "googleads.g.doubleclick.net",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index ff10091..f2f9c82 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "gstatic-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "gstatic.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index cfcb290..db1b206 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "lh3-ggpht-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "lh3.ggpht.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 9a7fb2a..c645f27 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "lh4-ggpht-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "lh4.ggpht.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index a44d3e3..85e93f9 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "lh5-ggpht-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "lh5.ggpht.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index c6eb890..fbdd314 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "lh6-ggpht-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "lh6.ggpht.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 95f9d13..d876cc5 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "mail-google-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "mail.google.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 5fa79a6..12c2be0 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "media-admob-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "media.admob.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 26ed9a1..747cc64 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "pagead2-googlesyndication-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "pagead2.googlesyndication.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 4d7bcd6..a6a918f 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "partner-googleadservices-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "partner.googleadservices.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 07a2ab9..9bcf189 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "pubads-g-doubleclick-net-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "pubads.g.doubleclick.net",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index cffa94c..19f6ea5 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "redirector-googlevideo-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "redirector.googlevideo.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 7865ead..427bdd2 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "s0-2mdn-net-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "s0.2mdn.net",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index ea16028..8abf57a 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "ssl-gstatic-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "ssl.gstatic.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
diff --git a/src/components/domain_reliability/baked_in_configs/star_admob_com.json b/src/components/domain_reliability/baked_in_configs/star_admob_com.json
new file mode 100644 (file)
index 0000000..b0e513d
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-admob-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.admob.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-admob-com-other",
+      "url_patterns": ["http*://*.admob.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_doubleclick_net.json b/src/components/domain_reliability/baked_in_configs/star_doubleclick_net.json
new file mode 100644 (file)
index 0000000..f1e3617
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-doubleclick-net-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.doubleclick.net",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-doubleclick-net-other",
+      "url_patterns": ["http*://*.doubleclick.net/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_g_doubleclick_net.json b/src/components/domain_reliability/baked_in_configs/star_g_doubleclick_net.json
new file mode 100644 (file)
index 0000000..7e6cbd6
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-g-doubleclick-net-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.g.doubleclick.net",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-g-doubleclick-net-other",
+      "url_patterns": ["http*://*.g.doubleclick.net/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_ggpht_com.json b/src/components/domain_reliability/baked_in_configs/star_ggpht_com.json
new file mode 100644 (file)
index 0000000..9085235
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-ggpht-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.ggpht.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-ggpht-com-other",
+      "url_patterns": ["http*://*.ggpht.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_cn.json b/src/components/domain_reliability/baked_in_configs/star_google_cn.json
new file mode 100644 (file)
index 0000000..332ebb0
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-cn-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.cn",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-cn-other",
+      "url_patterns": ["http*://*.google.cn/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_co_uk.json b/src/components/domain_reliability/baked_in_configs/star_google_co_uk.json
new file mode 100644 (file)
index 0000000..292d1e2
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-co-uk-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.co.uk",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-co-uk-other",
+      "url_patterns": ["http*://*.google.co.uk/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_com.json b/src/components/domain_reliability/baked_in_configs/star_google_com.json
new file mode 100644 (file)
index 0000000..f017e91
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-com-other",
+      "url_patterns": ["http*://*.google.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_com_au.json b/src/components/domain_reliability/baked_in_configs/star_google_com_au.json
new file mode 100644 (file)
index 0000000..ac2d17d
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-com-au-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.com.au",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-com-au-other",
+      "url_patterns": ["http*://*.google.com.au/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_de.json b/src/components/domain_reliability/baked_in_configs/star_google_de.json
new file mode 100644 (file)
index 0000000..37ad7f7
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-de-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.de",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-de-other",
+      "url_patterns": ["http*://*.google.de/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_fr.json b/src/components/domain_reliability/baked_in_configs/star_google_fr.json
new file mode 100644 (file)
index 0000000..6d26930
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-fr-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.fr",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-fr-other",
+      "url_patterns": ["http*://*.google.fr/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_it.json b/src/components/domain_reliability/baked_in_configs/star_google_it.json
new file mode 100644 (file)
index 0000000..3561d0a
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-it-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.it",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-it-other",
+      "url_patterns": ["http*://*.google.it/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_jp.json b/src/components/domain_reliability/baked_in_configs/star_google_jp.json
new file mode 100644 (file)
index 0000000..b5d34c4
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-jp-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.jp",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-jp-other",
+      "url_patterns": ["http*://*.google.jp/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_org.json b/src/components/domain_reliability/baked_in_configs/star_google_org.json
new file mode 100644 (file)
index 0000000..8ac9b30
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-org-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.org",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-org-other",
+      "url_patterns": ["http*://*.google.org/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_google_ru.json b/src/components/domain_reliability/baked_in_configs/star_google_ru.json
new file mode 100644 (file)
index 0000000..566b091
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-google-ru-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.google.ru",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-google-ru-other",
+      "url_patterns": ["http*://*.google.ru/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_googleadservices_com.json b/src/components/domain_reliability/baked_in_configs/star_googleadservices_com.json
new file mode 100644 (file)
index 0000000..e170a5b
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-googleadservices-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.googleadservices.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-googleadservices-com-other",
+      "url_patterns": ["http*://*.googleadservices.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_googleapis_com.json b/src/components/domain_reliability/baked_in_configs/star_googleapis_com.json
new file mode 100644 (file)
index 0000000..fee1665
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-googleapis-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.googleapis.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-googleapis-com-other",
+      "url_patterns": ["http*://*.googleapis.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_googlesyndication_com.json b/src/components/domain_reliability/baked_in_configs/star_googlesyndication_com.json
new file mode 100644 (file)
index 0000000..e269f3e
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-googlesyndication-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.googlesyndication.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-googlesyndication-com-other",
+      "url_patterns": ["http*://*.googlesyndication.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_googleusercontent_com.json b/src/components/domain_reliability/baked_in_configs/star_googleusercontent_com.json
new file mode 100644 (file)
index 0000000..f59251b
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-googleusercontent-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.googleusercontent.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-googleusercontent-com-other",
+      "url_patterns": ["http*://*.googleusercontent.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_googlevideo_com.json b/src/components/domain_reliability/baked_in_configs/star_googlevideo_com.json
new file mode 100644 (file)
index 0000000..d749c17
--- /dev/null
@@ -0,0 +1,33 @@
+{
+  "config_version": "star-googlevideo-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.googlevideo.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-googlevideo-com-redirector",
+      "url_patterns": ["http*://redirector.googlevideo.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    },
+    {
+      "resource_name": "star-googlevideo-com-rname",
+      "url_patterns": ["http*://r*.googlevideo.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    },
+    {
+      "resource_name": "star-googlevideo-com-other",
+      "url_patterns": ["http*://*.googlevideo.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_gstatic_com.json b/src/components/domain_reliability/baked_in_configs/star_gstatic_com.json
new file mode 100644 (file)
index 0000000..f83986d
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-gstatic-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.gstatic.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-gstatic-com-other",
+      "url_patterns": ["http*://*.gstatic.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_gvt1_com.json b/src/components/domain_reliability/baked_in_configs/star_gvt1_com.json
new file mode 100644 (file)
index 0000000..0022c18
--- /dev/null
@@ -0,0 +1,39 @@
+{
+  "config_version": "star-gvt1-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.gvt1.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-gvt1-com-domain-reliability",
+      "url_patterns": ["http*://domain-reliability.gvt1.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 0.50
+    },
+    {
+      "resource_name": "star-gvt1-com-redirector",
+      "url_patterns": ["http*://redirector.gvt1.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    },
+    {
+      "resource_name": "star-gvt1-com-rname",
+      "url_patterns": ["http*://r*.gvt1.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    },
+    {
+      "resource_name": "star-gvt1-com-other",
+      "url_patterns": ["http*://*.gvt1.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_youtube_com.json b/src/components/domain_reliability/baked_in_configs/star_youtube_com.json
new file mode 100644 (file)
index 0000000..b74bbd1
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-youtube-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.youtube.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-youtube-com-other",
+      "url_patterns": ["http*://*.youtube.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
diff --git a/src/components/domain_reliability/baked_in_configs/star_ytimg_com.json b/src/components/domain_reliability/baked_in_configs/star_ytimg_com.json
new file mode 100644 (file)
index 0000000..df4e2c0
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "config_version": "star-ytimg-com-v1",
+  "config_valid_until": 1425168000.0,
+  "monitored_domain": "*.ytimg.com",
+  "collectors": [
+    {
+      "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
+    }
+  ],
+  "monitored_resources": [
+    {
+      "resource_name": "star-ytimg-com-other",
+      "url_patterns": ["http*://*.ytimg.com/*"],
+      "success_sample_rate": 0.05,
+      "failure_sample_rate": 1.00
+    }
+  ]
+}
index 3963b3d..c852545 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "t0-gstatic-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "t0.gstatic.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 39f3ac3..91b54f4 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "t1-gstatic-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "t1.gstatic.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 83c7ff4..ae5c2ad 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "t2-gstatic-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "t2.gstatic.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 0c6095e..5e8dd2f 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "t3-gstatic-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "t3.gstatic.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index bb47961..6092b5f 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "themes-googleusercontent-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "themes.googleusercontent.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 78011ad..793c612 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "www-google-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "www.google.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 755bd78..203ce51 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "www-googleadservices-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "www.googleadservices.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index cec78b9..e7d3150 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "www-gstatic-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "www.gstatic.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 7669f3f..fd70e91 100644 (file)
@@ -1,10 +1,13 @@
 {
   "config_version": "www-youtube-com-v1",
-  "config_valid_until": 1413331200.0,
+  "config_valid_until": 1425168000.0,
   "monitored_domain": "www.youtube.com",
   "collectors": [
     {
       "upload_url": "https://clients2.google.com/domainreliability/upload"
+    },
+    {
+      "upload_url": "https://beacons.gvt2.com/domainreliability/upload"
     }
   ],
   "monitored_resources": [
index 5090ad1..36c9272 100644 (file)
@@ -1699,6 +1699,7 @@ void StreamPexe(PP_Instance instance,
   url_request.addHTTPHeaderField(
       blink::WebString::fromUTF8("Accept"),
       blink::WebString::fromUTF8("application/x-pnacl, */*"));
+  url_request.setRequestContext(blink::WebURLRequest::RequestContextObject);
   downloader->Load(url_request);
 }
 
index 6033da6..dfe94a3 100644 (file)
@@ -540,6 +540,13 @@ void PasswordFormManager::SaveAsNewLogin(bool reset_preferred_login) {
     return;
   }
 
+  // Upload credentials the first time they are saved. This data is used
+  // by password generation to help determine account creation sites.
+  // Blacklisted credentials will never be used, so don't upload a vote for
+  // them.
+  if (!pending_credentials_.blacklisted_by_user)
+    UploadPasswordForm(pending_credentials_.form_data, autofill::PASSWORD);
+
   pending_credentials_.date_created = Time::Now();
   SanitizePossibleUsernames(&pending_credentials_);
   password_store->AddLogin(pending_credentials_);
@@ -700,19 +707,28 @@ void PasswordFormManager::CheckForAccountCreationForm(
     if (!pending.form_data.fields.empty() &&
         pending_structure.FormSignature() !=
             observed_structure.FormSignature()) {
-      autofill::AutofillManager* autofill_manager =
-          driver_->GetAutofillManager();
-      if (autofill_manager) {
-        // Note that this doesn't guarantee that the upload succeeded, only that
-        // |pending.form_data| is considered uploadable.
-        bool success =
-            autofill_manager->UploadPasswordGenerationForm(pending.form_data);
-        UMA_HISTOGRAM_BOOLEAN("PasswordGeneration.UploadStarted", success);
-      }
+      UploadPasswordForm(pending.form_data,
+                         autofill::ACCOUNT_CREATION_PASSWORD);
     }
   }
 }
 
+void PasswordFormManager::UploadPasswordForm(
+    const autofill::FormData& form_data,
+    const autofill::ServerFieldType& password_type) {
+  autofill::AutofillManager* autofill_manager =
+      driver_->GetAutofillManager();
+  if (!autofill_manager)
+    return;
+
+  // Note that this doesn't guarantee that the upload succeeded, only that
+  // |form_data| is considered uploadable.
+  bool success =
+      autofill_manager->UploadPasswordForm(
+          form_data, autofill::ACCOUNT_CREATION_PASSWORD);
+  UMA_HISTOGRAM_BOOLEAN("PasswordGeneration.UploadStarted", success);
+}
+
 int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
   DCHECK_EQ(state_, MATCHING_PHASE);
   // For scoring of candidate login data:
index 0b69c6c..a4fa82e 100644 (file)
@@ -11,6 +11,7 @@
 #include "build/build_config.h"
 
 #include "base/stl_util.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/password_manager_driver.h"
 #include "components/password_manager/core/browser/password_store.h"
@@ -263,6 +264,11 @@ class PasswordFormManager : public PasswordStoreConsumer {
   // duplicates.
   void SanitizePossibleUsernames(autofill::PasswordForm* form);
 
+  // Helper function to delegate uploading to the AutofillManager.
+  virtual void UploadPasswordForm(
+      const autofill::FormData& form_data,
+      const autofill::ServerFieldType& password_type);
+
   // Set of PasswordForms from the DB that best match the form
   // being managed by this. Use a map instead of vector, because we most
   // frequently require lookups by username value in IsNewLogin.
index 77b7d4c..a0a3c4b 100644 (file)
@@ -88,7 +88,7 @@ class TestPasswordManagerClient : public StubPasswordManagerClient {
 
   TestingPrefServiceSimple prefs_;
   PasswordStore* password_store_;
-  MockPasswordManagerDriver driver_;
+  testing::NiceMock<MockPasswordManagerDriver> driver_;
 };
 
 class TestPasswordManager : public PasswordManager {
@@ -112,6 +112,20 @@ class TestPasswordManager : public PasswordManager {
   mutable autofill::PasswordFormMap best_matches_;
 };
 
+class MockPasswordFormManager : public PasswordFormManager {
+ public:
+  MockPasswordFormManager(PasswordManager* manager,
+                          PasswordManagerClient* client,
+                          PasswordManagerDriver* driver,
+                          const autofill::PasswordForm& observed_form,
+                          bool ssl_valid)
+      : PasswordFormManager(manager, client, driver, observed_form, ssl_valid)
+  {}
+
+  MOCK_METHOD2(UploadPasswordForm, void(const autofill::FormData&,
+                                        const autofill::ServerFieldType&));
+};
+
 }  // namespace
 
 class PasswordFormManagerTest : public testing::Test {
@@ -146,9 +160,9 @@ class PasswordFormManagerTest : public testing::Test {
   }
 
   void InitializeMockStore() {
-    if (!mock_store_) {
-      mock_store_ = new MockPasswordStore();
-      ASSERT_TRUE(mock_store_);
+    if (!mock_store_.get()) {
+      mock_store_ = new testing::NiceMock<MockPasswordStore>();
+      ASSERT_TRUE(mock_store_.get());
     }
   }
 
@@ -207,7 +221,7 @@ class PasswordFormManagerTest : public testing::Test {
  private:
   PasswordForm observed_form_;
   PasswordForm saved_match_;
-  scoped_refptr<MockPasswordStore> mock_store_;
+  scoped_refptr<testing::NiceMock<MockPasswordStore> > mock_store_;
   TestPasswordManagerClient client_;
 };
 
@@ -1088,4 +1102,123 @@ TEST_F(PasswordFormManagerTest, CorrectlyUpdatePasswordsWithSameUsername) {
   password_store->Shutdown();
 }
 
+TEST_F(PasswordFormManagerTest, UploadFormData_NewPassword) {
+  InitializeMockStore();
+  TestPasswordManagerClient client_with_store(mock_store());
+  TestPasswordManager password_manager(&client_with_store);
+  EXPECT_CALL(*client_with_store.GetMockDriver(), IsOffTheRecord())
+      .WillRepeatedly(Return(false));
+
+  PasswordForm form(*observed_form());
+
+  autofill::FormFieldData field;
+  field.label = ASCIIToUTF16("full_name");
+  field.name = ASCIIToUTF16("full_name");
+  field.form_control_type = "text";
+  form.form_data.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Email");
+  field.name = ASCIIToUTF16("Email");
+  field.form_control_type = "text";
+  form.form_data.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("password");
+  field.name = ASCIIToUTF16("password");
+  field.form_control_type = "password";
+  form.form_data.fields.push_back(field);
+
+  // For newly saved passwords, upload a vote for autofill::PASSWORD.
+  MockPasswordFormManager form_manager(&password_manager,
+                                       &client_with_store,
+                                       client_with_store.GetDriver(),
+                                       form,
+                                       false);
+  SimulateMatchingPhase(&form_manager, RESULT_NO_MATCH);
+
+  PasswordForm form_to_save(form);
+  form_to_save.preferred = true;
+  form_to_save.username_value = ASCIIToUTF16("username");
+  form_to_save.password_value = ASCIIToUTF16("1234");
+
+  EXPECT_CALL(form_manager, UploadPasswordForm(_, autofill::PASSWORD)).Times(1);
+  form_manager.ProvisionallySave(
+      form_to_save,
+      PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+  form_manager.Save();
+  Mock::VerifyAndClearExpectations(&form_manager);
+
+  // Do not upload a vote if the user is blacklisting the form.
+  MockPasswordFormManager blacklist_form_manager(&password_manager,
+                                                 &client_with_store,
+                                                 client_with_store.GetDriver(),
+                                                 form,
+                                                 false);
+  SimulateMatchingPhase(&blacklist_form_manager, RESULT_NO_MATCH);
+
+  EXPECT_CALL(blacklist_form_manager,
+              UploadPasswordForm(_, autofill::PASSWORD)).Times(0);
+  blacklist_form_manager.PermanentlyBlacklist();
+  Mock::VerifyAndClearExpectations(&blacklist_form_manager);
+}
+
+TEST_F(PasswordFormManagerTest, UploadFormData_AccountCreationPassword) {
+  InitializeMockStore();
+  TestPasswordManagerClient client_with_store(mock_store());
+  TestPasswordManager password_manager(&client_with_store);
+  EXPECT_CALL(*client_with_store.GetMockDriver(), IsOffTheRecord())
+      .WillRepeatedly(Return(false));
+
+  PasswordForm form(*observed_form());
+
+  autofill::FormFieldData field;
+  field.label = ASCIIToUTF16("Email");
+  field.name = ASCIIToUTF16("Email");
+  field.form_control_type = "text";
+  form.form_data.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("password");
+  field.name = ASCIIToUTF16("password");
+  field.form_control_type = "password";
+  form.form_data.fields.push_back(field);
+
+  MockPasswordFormManager form_manager(&password_manager,
+                                       &client_with_store,
+                                       client_with_store.GetDriver(),
+                                       form,
+                                       false);
+  std::vector<PasswordForm*> result;
+  result.push_back(CreateSavedMatch(false));
+
+  field.label = ASCIIToUTF16("full_name");
+  field.name = ASCIIToUTF16("full_name");
+  field.form_control_type = "text";
+  result[0]->form_data.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Email");
+  field.name = ASCIIToUTF16("Email");
+  field.form_control_type = "text";
+  result[0]->form_data.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("password");
+  field.name = ASCIIToUTF16("password");
+  field.form_control_type = "password";
+  result[0]->form_data.fields.push_back(field);
+
+  PasswordForm form_to_save(form);
+  form_to_save.preferred = true;
+  form_to_save.username_value = result[0]->username_value;
+  form_to_save.password_value = result[0]->password_value;
+
+  SimulateFetchMatchingLoginsFromPasswordStore(&form_manager);
+  SimulateResponseFromPasswordStore(&form_manager, result);
+
+  EXPECT_CALL(form_manager,
+              UploadPasswordForm(_,
+                                 autofill::ACCOUNT_CREATION_PASSWORD)).Times(1);
+  form_manager.ProvisionallySave(
+      form_to_save,
+      PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+  form_manager.Save();
+}
+
 }  // namespace password_manager
index d0f33a0..d0f3c17 100644 (file)
 
       If you disable this setting, users will not be allowed to use EasyUnlock.
 
-      If this policy is left not set, EasyUnlock is allowed if the requirements for the feature are satified.
-      ''',
+      If this policy is left not set, the default is not allowed for enterprise-managed users and allowed for non-managed users.''',
     },
     {
       'name': 'SessionLocales',
       'name': 'BrowserGuestModeEnabled',
       'type': 'main',
       'schema': { 'type': 'boolean' },
-      'supported_on': ['chrome.*:39-'],
+      'supported_on': ['chrome.*:38-'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': False,
index aa47c91..5cfa2d8 100644 (file)
@@ -161,9 +161,9 @@ RenderViewContextMenuBase::RenderViewContextMenuBase(
       source_web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
       browser_context_(source_web_contents_->GetBrowserContext()),
       menu_model_(this),
+      render_frame_id_(render_frame_host->GetRoutingID()),
       command_executed_(false),
-      render_process_id_(render_frame_host->GetProcess()->GetID()),
-      render_frame_id_(render_frame_host->GetRoutingID()) {
+      render_process_id_(render_frame_host->GetProcess()->GetID()) {
 }
 
 RenderViewContextMenuBase::~RenderViewContextMenuBase() {
index 5452f1e..db6c175 100644 (file)
@@ -166,6 +166,9 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
 
   ui::SimpleMenuModel menu_model_;
 
+  // Renderer's frame id.
+  int render_frame_id_;
+
   // Our observers.
   mutable ObserverList<RenderViewContextMenuObserver> observers_;
 
@@ -180,7 +183,6 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
 
   // The RenderFrameHost's IDs.
   int render_process_id_;
-  int render_frame_id_;
 
   scoped_ptr<ToolkitDelegate> toolkit_delegate_;
 
index 0dae348..f4820ec 100644 (file)
@@ -31,6 +31,8 @@
         'suggestions/suggestions_service.h',
         'suggestions/suggestions_store.cc',
         'suggestions/suggestions_store.h',
+        'suggestions/suggestions_utils.cc',
+        'suggestions/suggestions_utils.h',
       ],
       'variables': {
         'proto_in_dir': 'suggestions/proto',
index 1fe2ff9..d505c40 100644 (file)
@@ -13,6 +13,8 @@ static_library("suggestions") {
     "suggestions_service.h",
     "suggestions_store.cc",
     "suggestions_store.h",
+    "suggestions_utils.cc",
+    "suggestions_utils.h",
   ]
 
   deps = [
index db1e3fc..b12aae1 100644 (file)
@@ -156,8 +156,25 @@ bool SuggestionsService::IsControlGroup() {
 }
 
 void SuggestionsService::FetchSuggestionsData(
+    SyncState sync_state,
     SuggestionsService::ResponseCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  if (sync_state == NOT_INITIALIZED_ENABLED) {
+    // Sync is not initialized yet, but enabled. Serve previously cached
+    // suggestions if available.
+    waiting_requestors_.push_back(callback);
+    ServeFromCache();
+    return;
+  } else if (sync_state == SYNC_OR_HISTORY_SYNC_DISABLED) {
+    // Cancel any ongoing request (and the timeout closure). We must no longer
+    // interact with the server.
+    pending_request_.reset(NULL);
+    pending_timeout_closure_.reset(NULL);
+    suggestions_store_->ClearSuggestions();
+    callback.Run(SuggestionsProfile());
+    DispatchRequestsAndClear(SuggestionsProfile(), &waiting_requestors_);
+    return;
+  }
 
   FetchSuggestionsDataNoTimeout(callback);
 
@@ -170,21 +187,6 @@ void SuggestionsService::FetchSuggestionsData(
       base::TimeDelta::FromMilliseconds(request_timeout_ms_));
 }
 
-void SuggestionsService::FetchSuggestionsDataNoTimeout(
-    SuggestionsService::ResponseCallback callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (pending_request_.get()) {
-    // Request already exists, so just add requestor to queue.
-    waiting_requestors_.push_back(callback);
-    return;
-  }
-
-  // Form new request.
-  DCHECK(waiting_requestors_.empty());
-  waiting_requestors_.push_back(callback);
-  IssueRequest(suggestions_url_);
-}
-
 void SuggestionsService::GetPageThumbnail(
     const GURL& url,
     base::Callback<void(const GURL&, const SkBitmap*)> callback) {
@@ -235,6 +237,33 @@ void SuggestionsService::RegisterProfilePrefs(
   BlacklistStore::RegisterProfilePrefs(registry);
 }
 
+void SuggestionsService::SetDefaultExpiryTimestamp(
+    SuggestionsProfile* suggestions, int64 default_timestamp_usec) {
+  for (int i = 0; i < suggestions->suggestions_size(); ++i) {
+    ChromeSuggestion* suggestion = suggestions->mutable_suggestions(i);
+    // Do not set expiry if the server has already provided a more specific
+    // expiry time for this suggestion.
+    if (!suggestion->has_expiry_ts()) {
+      suggestion->set_expiry_ts(default_timestamp_usec);
+    }
+  }
+}
+
+void SuggestionsService::FetchSuggestionsDataNoTimeout(
+    SuggestionsService::ResponseCallback callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (pending_request_.get()) {
+    // Request already exists, so just add requestor to queue.
+    waiting_requestors_.push_back(callback);
+    return;
+  }
+
+  // Form new request.
+  DCHECK(waiting_requestors_.empty());
+  waiting_requestors_.push_back(callback);
+  IssueRequest(suggestions_url_);
+}
+
 void SuggestionsService::IssueRequest(const GURL& url) {
   pending_request_.reset(CreateSuggestionsRequest(url));
   pending_request_->Start();
@@ -330,18 +359,6 @@ void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) {
   ScheduleBlacklistUpload(true);
 }
 
-void SuggestionsService::SetDefaultExpiryTimestamp(
-    SuggestionsProfile* suggestions, int64 default_timestamp_usec) {
-  for (int i = 0; i < suggestions->suggestions_size(); ++i) {
-    ChromeSuggestion* suggestion = suggestions->mutable_suggestions(i);
-    // Do not set expiry if the server has already provided a more specific
-    // expiry time for this suggestion.
-    if (!suggestion->has_expiry_ts()) {
-      suggestion->set_expiry_ts(default_timestamp_usec);
-    }
-  }
-}
-
 void SuggestionsService::Shutdown() {
   // Cancel pending request and timeout closure, then serve existing requestors
   // from cache.
index 3aa03a0..e495f7f 100644 (file)
@@ -19,6 +19,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/suggestions/image_manager.h"
 #include "components/suggestions/proto/suggestions.pb.h"
+#include "components/suggestions/suggestions_utils.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "ui/gfx/image/image_skia.h"
 #include "url/gurl.h"
@@ -64,16 +65,20 @@ class SuggestionsService : public KeyedService, public net::URLFetcherDelegate {
   // Whether the user is part of a control group.
   static bool IsControlGroup();
 
-  // Request suggestions data, which will be passed to |callback|. Initiates a
-  // fetch request unless a pending one exists. To prevent multiple requests,
-  // we place all |callback|s in a queue and update them simultaneously when
-  // fetch request completes. Also posts a task to execute OnRequestTimeout
-  // if the request hasn't completed in a given amount of time.
-  void FetchSuggestionsData(ResponseCallback callback);
-
-  // Similar to FetchSuggestionsData but doesn't post a task to execute
-  // OnDelaySinceFetch.
-  void FetchSuggestionsDataNoTimeout(ResponseCallback callback);
+  // Request suggestions data, which will be passed to |callback|. |sync_state|
+  // will influence the behavior of this function (see SyncState definition).
+  //
+  // |sync_state| must be specified based on the current state of the system
+  // (see suggestions::GetSyncState). Callers should call this function again if
+  // sync state changes.
+  //
+  // If state allows for a network request, it is initiated unless a pending one
+  // exists. To prevent multiple requests, all |callback|s are placed in a queue
+  // and are updated simultaneously when the fetch completes. Also posts a task
+  // to execute OnRequestTimeout if the request hasn't completed in a given
+  // amount of time.
+  void FetchSuggestionsData(SyncState sync_state,
+                            ResponseCallback callback);
 
   // Retrieves stored thumbnail for website |url| asynchronously. Calls
   // |callback| with Bitmap pointer if found, and NULL otherwise.
@@ -97,10 +102,15 @@ class SuggestionsService : public KeyedService, public net::URLFetcherDelegate {
   void SetDefaultExpiryTimestamp(SuggestionsProfile* suggestions,
                                  int64 timestamp_usec);
  private:
+  friend class SuggestionsServiceTest;
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, BlacklistURLFails);
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, FetchSuggestionsData);
   FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, UpdateBlacklistDelay);
 
+  // Similar to FetchSuggestionsData but doesn't post a task to execute
+  // OnDelaySinceFetch.
+  void FetchSuggestionsDataNoTimeout(ResponseCallback callback);
+
   // Issue a request.
   void IssueRequest(const GURL& url);
 
index 819e92b..a4d6058 100644 (file)
@@ -18,6 +18,7 @@
 #include "components/suggestions/image_manager.h"
 #include "components/suggestions/proto/suggestions.pb.h"
 #include "components/suggestions/suggestions_store.h"
+#include "components/suggestions/suggestions_utils.h"
 #include "components/variations/entropy_provider.h"
 #include "components/variations/variations_associated_data.h"
 #include "net/http/http_response_headers.h"
@@ -326,6 +327,7 @@ TEST_F(SuggestionsServiceTest, FetchSuggestionsDataRequestError) {
 
   // Send the request. Empty data will be returned to the callback.
   suggestions_service->FetchSuggestionsData(
+      INITIALIZED_ENABLED_HISTORY,  // Normal mode.
       base::Bind(&SuggestionsServiceTest::ExpectEmptySuggestionsProfile,
                  base::Unretained(this)));
 
@@ -361,6 +363,7 @@ TEST_F(SuggestionsServiceTest, FetchSuggestionsDataResponseNotOK) {
 
   // Send the request. Empty data will be returned to the callback.
   suggestions_service->FetchSuggestionsData(
+      INITIALIZED_ENABLED_HISTORY,  // Normal mode.
       base::Bind(&SuggestionsServiceTest::ExpectEmptySuggestionsProfile,
                  base::Unretained(this)));
 
@@ -371,6 +374,62 @@ TEST_F(SuggestionsServiceTest, FetchSuggestionsDataResponseNotOK) {
   EXPECT_EQ(1, suggestions_empty_data_count_);
 }
 
+TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncDisabled) {
+  // Field trial enabled with a specific suggestions URL.
+  EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
+                   kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
+  scoped_ptr<SuggestionsService> suggestions_service(
+      CreateSuggestionsServiceWithMocks());
+  EXPECT_TRUE(suggestions_service != NULL);
+
+  // Set up expectations on the SuggestionsStore.
+  EXPECT_CALL(*mock_suggestions_store_, ClearSuggestions());
+
+  // Send the request. Cache is cleared and empty data will be returned to the
+  // callback.
+  suggestions_service->FetchSuggestionsData(
+      SYNC_OR_HISTORY_SYNC_DISABLED,
+      base::Bind(&SuggestionsServiceTest::ExpectEmptySuggestionsProfile,
+                 base::Unretained(this)));
+
+  // Wait for posted task to complete.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Ensure that ExpectEmptySuggestionsProfile ran once.
+  EXPECT_EQ(1, suggestions_empty_data_count_);
+}
+
+TEST_F(SuggestionsServiceTest, FetchSuggestionsDataSyncNotInitializedEnabled) {
+  // Field trial enabled with a specific suggestions URL.
+  EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
+                   kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
+  scoped_ptr<SuggestionsService> suggestions_service(
+      CreateSuggestionsServiceWithMocks());
+  EXPECT_TRUE(suggestions_service != NULL);
+  scoped_ptr<SuggestionsProfile> suggestions_profile(
+      CreateSuggestionsProfile());
+
+  // Expectations.
+  EXPECT_CALL(*mock_suggestions_store_, LoadSuggestions(_))
+      .WillOnce(DoAll(SetArgPointee<0>(*suggestions_profile), Return(true)));
+  EXPECT_CALL(*mock_thumbnail_manager_,
+              Initialize(EqualsProto(*suggestions_profile)));
+  EXPECT_CALL(*mock_blacklist_store_, FilterSuggestions(_));
+
+  // Send the request. In this state, cached data will be returned to the
+  // caller.
+  suggestions_service->FetchSuggestionsData(
+      NOT_INITIALIZED_ENABLED,
+      base::Bind(&SuggestionsServiceTest::CheckSuggestionsData,
+                 base::Unretained(this)));
+
+  // Wait for posted task to complete.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Ensure that CheckSuggestionsData ran once.
+  EXPECT_EQ(1, suggestions_data_check_count_);
+}
+
 TEST_F(SuggestionsServiceTest, BlacklistURL) {
   EnableFieldTrial(kFakeSuggestionsURL, kFakeSuggestionsCommonParams,
                    kFakeBlacklistPath, kFakeBlacklistUrlParam, false);
diff --git a/src/components/suggestions/suggestions_utils.cc b/src/components/suggestions/suggestions_utils.cc
new file mode 100644 (file)
index 0000000..9c32791
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/suggestions/suggestions_utils.h"
+
+namespace suggestions {
+
+SyncState GetSyncState(bool sync_enabled,
+                       bool sync_initialized,
+                       bool history_sync_enabled) {
+  if (!sync_enabled)
+    return SYNC_OR_HISTORY_SYNC_DISABLED;
+
+  if (!sync_initialized)
+    return NOT_INITIALIZED_ENABLED;
+
+  return history_sync_enabled ?
+      INITIALIZED_ENABLED_HISTORY : SYNC_OR_HISTORY_SYNC_DISABLED;
+}
+
+}  // namespace suggestions
diff --git a/src/components/suggestions/suggestions_utils.h b/src/components/suggestions/suggestions_utils.h
new file mode 100644 (file)
index 0000000..eedef03
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUGGESTIONS_SUGGESTIONS_UTILS_H_
+#define COMPONENTS_SUGGESTIONS_SUGGESTIONS_UTILS_H_
+
+namespace suggestions {
+
+// Establishes the different sync states that users of SuggestionsService can
+// specify. There are three different concepts in the sync service: initialized,
+// sync enabled and history sync enabled.
+enum SyncState {
+  // State: Sync service is not initialized, yet not disabled. History sync
+  //     state is unknown (since not initialized).
+  // Behavior: Does not issue a server request, but serves from cache if
+  //     available.
+  NOT_INITIALIZED_ENABLED,
+
+  // State: Sync service is initialized, sync is enabled and history sync is
+  //     enabled.
+  // Behavior: Update suggestions from the server. Serve from cache on timeout.
+  INITIALIZED_ENABLED_HISTORY,
+
+  // State: Sync service is disabled or history sync is disabled.
+  // Behavior: Do not issue a server request. Clear the cache. Serve empty
+  //     suggestions.
+  SYNC_OR_HISTORY_SYNC_DISABLED,
+};
+
+// Users of SuggestionsService should always use this function to get SyncState.
+SyncState GetSyncState(bool sync_enabled,
+                       bool sync_initialized,
+                       bool history_sync_enabled);
+
+}  // namespace suggestions
+
+#endif  // COMPONENTS_SUGGESTIONS_SUGGESTIONS_UTILS_H_
index 3914819..fd50a75 100644 (file)
@@ -421,8 +421,10 @@ void UserManagerBase::SaveUserDisplayEmail(const std::string& user_id,
   DCHECK(task_runner_->RunsTasksOnCurrentThread());
 
   User* user = FindUserAndModify(user_id);
-  if (!user)
+  if (!user) {
+    LOG(ERROR) << "User not found: " << user_id;
     return;  // Ignore if there is no such user.
+  }
 
   user->set_display_email(display_email);
 
index cb317f4..c84e2b2 100644 (file)
@@ -620,9 +620,9 @@ void ContentViewCoreImpl::ShowPastePopup(int x_dip, int y_dip) {
   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
   if (obj.is_null())
     return;
-  Java_ContentViewCore_showPastePopup(env, obj.obj(),
-                                      static_cast<jint>(x_dip),
-                                      static_cast<jint>(y_dip));
+  Java_ContentViewCore_showPastePopupWithFeedback(env, obj.obj(),
+                                                  static_cast<jint>(x_dip),
+                                                  static_cast<jint>(y_dip));
 }
 
 void ContentViewCoreImpl::GetScaledContentBitmap(
index 06590fa..00d9ad0 100644 (file)
@@ -16,6 +16,7 @@
 #include "content/public/browser/android/compositor.h"
 #include "content/public/browser/android/content_view_layer_renderer.h"
 #include "content/public/browser/android/layer_tree_build_helper.h"
+#include "content/public/browser/android/ui_resource_provider.h"
 #include "jni/ContentViewRenderView_jni.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/size.h"
@@ -70,6 +71,7 @@ void ContentViewRenderView::SetLayerTreeBuildHelper(JNIEnv* env,
   LayerTreeBuildHelper* build_helper =
       reinterpret_cast<LayerTreeBuildHelper*>(native_build_helper);
   layer_tree_build_helper_.reset(build_helper);
+  InitCompositor();
 }
 // static
 static jlong Init(JNIEnv* env,
@@ -120,6 +122,12 @@ void ContentViewRenderView::SurfaceChanged(JNIEnv* env, jobject obj,
 void ContentViewRenderView::SetOverlayVideoMode(
     JNIEnv* env, jobject obj, bool enabled) {
   compositor_->SetHasTransparentBackground(enabled);
+  SetNeedsComposite(env, obj);
+}
+
+void ContentViewRenderView::SetNeedsComposite(JNIEnv* env, jobject obj) {
+  if (compositor_)
+    compositor_->SetNeedsComposite();
 }
 
 void ContentViewRenderView::Layout() {
@@ -136,4 +144,11 @@ void ContentViewRenderView::InitCompositor() {
   if (!compositor_)
     compositor_.reset(Compositor::Create(this, root_window_));
 }
+
+jlong ContentViewRenderView::GetUIResourceProvider(JNIEnv* env,
+                                                   jobject obj) {
+  if (!compositor_)
+    return 0;
+  return reinterpret_cast<intptr_t>(&compositor_->GetUIResourceProvider());
+}
 }  // namespace content
index 2f1bcc1..cc8fe80 100644 (file)
@@ -19,6 +19,7 @@ class Layer;
 namespace content {
 class Compositor;
 class LayerTreeBuildHelper;
+class UIResourceProvider;
 
 class ContentViewRenderView : public CompositorClient {
  public:
@@ -41,6 +42,11 @@ class ContentViewRenderView : public CompositorClient {
                       jint format, jint width, jint height, jobject surface);
   jboolean Composite(JNIEnv* env, jobject obj);
   void SetOverlayVideoMode(JNIEnv* env, jobject obj, bool enabled);
+  void SetNeedsComposite(JNIEnv* env, jobject obj);
+
+  // TODO(yusufo): Remove this once the compositor code is
+  // refactored to use a unified system.
+  jlong GetUIResourceProvider(JNIEnv* env, jobject obj);
 
   // CompositorClient implementation
   virtual void Layout() OVERRIDE;
index af50011..e624e9b 100644 (file)
@@ -44,38 +44,41 @@ scoped_ptr<gpu::GLInProcessContext> CreateOffscreenContext(
       attributes, &in_process_attribs);
   in_process_attribs.lose_context_when_out_of_memory = true;
 
-  scoped_ptr<gpu::GLInProcessContext> context(
-      gpu::GLInProcessContext::Create(NULL /* service */,
-                                      NULL /* surface */,
-                                      true /* is_offscreen */,
-                                      gfx::kNullAcceleratedWidget,
-                                      gfx::Size(1, 1),
-                                      NULL /* share_context */,
-                                      false /* share_resources */,
-                                      in_process_attribs,
-                                      gpu_preference));
+  scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create(
+      NULL /* service */,
+      NULL /* surface */,
+      true /* is_offscreen */,
+      gfx::kNullAcceleratedWidget,
+      gfx::Size(1, 1),
+      NULL /* share_context */,
+      false /* share_resources */,
+      in_process_attribs,
+      gpu_preference,
+      gpu::GLInProcessContextSharedMemoryLimits()));
   return context.Pass();
 }
 
 scoped_ptr<gpu::GLInProcessContext> CreateContext(
     scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
-    gpu::GLInProcessContext* share_context) {
+    gpu::GLInProcessContext* share_context,
+    const gpu::GLInProcessContextSharedMemoryLimits& mem_limits) {
   const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
   gpu::gles2::ContextCreationAttribHelper in_process_attribs;
   WebGraphicsContext3DImpl::ConvertAttributes(
       GetDefaultAttribs(), &in_process_attribs);
   in_process_attribs.lose_context_when_out_of_memory = true;
 
-  scoped_ptr<gpu::GLInProcessContext> context(
-      gpu::GLInProcessContext::Create(service,
-                                      NULL /* surface */,
-                                      false /* is_offscreen */,
-                                      gfx::kNullAcceleratedWidget,
-                                      gfx::Size(1, 1),
-                                      share_context,
-                                      false /* share_resources */,
-                                      in_process_attribs,
-                                      gpu_preference));
+  scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create(
+      service,
+      NULL /* surface */,
+      false /* is_offscreen */,
+      gfx::kNullAcceleratedWidget,
+      gfx::Size(1, 1),
+      share_context,
+      false /* share_resources */,
+      in_process_attribs,
+      gpu_preference,
+      mem_limits));
   return context.Pass();
 }
 
@@ -184,10 +187,16 @@ scoped_refptr<cc::ContextProvider> SynchronousCompositorFactoryImpl::
     CreateOnscreenContextProviderForCompositorThread() {
   DCHECK(service_);
 
-  if (!share_context_.get())
-    share_context_ = CreateContext(service_, NULL);
+  if (!share_context_.get()) {
+    share_context_ = CreateContext(
+        service_, NULL, gpu::GLInProcessContextSharedMemoryLimits());
+  }
+  gpu::GLInProcessContextSharedMemoryLimits mem_limits;
+  // This is half of what RenderWidget uses because synchronous compositor
+  // pipeline is only one frame deep.
+  mem_limits.mapped_memory_reclaim_limit = 6 * 1024 * 1024;
   return webkit::gpu::ContextProviderInProcess::Create(
-      WrapContext(CreateContext(service_, share_context_.get())),
+      WrapContext(CreateContext(service_, share_context_.get(), mem_limits)),
       "Child-Compositor");
 }
 
@@ -223,11 +232,6 @@ void SynchronousCompositorFactoryImpl::CompositorReleasedHardwareDraw() {
   base::AutoLock lock(num_hardware_compositor_lock_);
   DCHECK_GT(num_hardware_compositors_, 0u);
   num_hardware_compositors_--;
-  if (num_hardware_compositors_ == 0) {
-    // Nullify the video_context_provider_ now so that it is not null only if
-    // there is at least 1 hardware compositor
-    video_context_provider_ = NULL;
-  }
 }
 
 bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
@@ -237,18 +241,23 @@ bool SynchronousCompositorFactoryImpl::CanCreateMainThreadContext() {
 
 scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
 SynchronousCompositorFactoryImpl::TryCreateStreamTextureFactory() {
-  scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
-      context_provider;
-  // This check only guarantees the main thread context is created after
-  // a compositor did successfully initialize hardware draw in the past.
-  // When all compositors have released hardware draw, main thread context
-  // creation is guaranteed to fail.
-  if (CanCreateMainThreadContext() && !video_context_provider_) {
+  // Always fail creation even if |video_context_provider_| is not NULL.
+  // This is to avoid synchronous calls that may deadlock. Setting
+  // |video_context_provider_| to null is also not safe since it makes
+  // synchronous destruction uncontrolled and possibly deadlock.
+  if (!CanCreateMainThreadContext()) {
+    return
+        scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>();
+  }
+
+  if (!video_context_provider_) {
     DCHECK(service_);
     DCHECK(share_context_.get());
 
     video_context_provider_ = new VideoContextProvider(
-        CreateContext(service_, share_context_.get()));
+        CreateContext(service_,
+                      share_context_.get(),
+                      gpu::GLInProcessContextSharedMemoryLimits()));
   }
   return video_context_provider_;
 }
index 74ccaa2..ca63276 100644 (file)
@@ -56,6 +56,7 @@ GinJavaBridgeDispatcherHost::GinJavaBridgeDispatcherHost(
 }
 
 GinJavaBridgeDispatcherHost::~GinJavaBridgeDispatcherHost() {
+  DCHECK(pending_replies_.empty());
 }
 
 void GinJavaBridgeDispatcherHost::RenderFrameCreated(
@@ -70,6 +71,15 @@ void GinJavaBridgeDispatcherHost::RenderFrameCreated(
 
 void GinJavaBridgeDispatcherHost::RenderFrameDeleted(
     RenderFrameHost* render_frame_host) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+  if (reply_msg != NULL) {
+    base::ListValue result;
+    result.Append(base::Value::CreateNullValue());
+    IPC::WriteParam(reply_msg, result);
+    IPC::WriteParam(reply_msg, kGinJavaBridgeRenderFrameDeleted);
+    render_frame_host->Send(reply_msg);
+  }
   RemoveHolder(render_frame_host,
                GinJavaBoundObject::ObjectMap::iterator(&objects_),
                objects_.size());
@@ -352,17 +362,6 @@ bool GinJavaBridgeDispatcherHost::IsValidRenderFrameHost(
   return helper->rfh_found();
 }
 
-void GinJavaBridgeDispatcherHost::SendReply(
-    RenderFrameHost* render_frame_host,
-    IPC::Message* reply_msg) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (IsValidRenderFrameHost(render_frame_host)) {
-    render_frame_host->Send(reply_msg);
-  } else {
-    delete reply_msg;
-  }
-}
-
 void GinJavaBridgeDispatcherHost::OnGetMethods(
     RenderFrameHost* render_frame_host,
     GinJavaBoundObject::ObjectID object_id,
@@ -381,22 +380,26 @@ void GinJavaBridgeDispatcherHost::OnGetMethods(
     render_frame_host->Send(reply_msg);
     return;
   }
+  DCHECK(!HasPendingReply(render_frame_host));
+  pending_replies_[render_frame_host] = reply_msg;
   base::PostTaskAndReplyWithResult(
       g_background_thread.Get().message_loop()->message_loop_proxy(),
       FROM_HERE,
       base::Bind(&GinJavaBoundObject::GetMethodNames, object),
       base::Bind(&GinJavaBridgeDispatcherHost::SendMethods,
                  AsWeakPtr(),
-                 render_frame_host,
-                 reply_msg));
+                 render_frame_host));
 }
 
 void GinJavaBridgeDispatcherHost::SendMethods(
     RenderFrameHost* render_frame_host,
-    IPC::Message* reply_msg,
     const std::set<std::string>& method_names) {
+  IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+  if (!reply_msg) {
+    return;
+  }
   IPC::WriteParam(reply_msg, method_names);
-  SendReply(render_frame_host, reply_msg);
+  render_frame_host->Send(reply_msg);
 }
 
 void GinJavaBridgeDispatcherHost::OnHasMethod(
@@ -413,22 +416,26 @@ void GinJavaBridgeDispatcherHost::OnHasMethod(
     render_frame_host->Send(reply_msg);
     return;
   }
+  DCHECK(!HasPendingReply(render_frame_host));
+  pending_replies_[render_frame_host] = reply_msg;
   base::PostTaskAndReplyWithResult(
       g_background_thread.Get().message_loop()->message_loop_proxy(),
       FROM_HERE,
       base::Bind(&GinJavaBoundObject::HasMethod, object, method_name),
       base::Bind(&GinJavaBridgeDispatcherHost::SendHasMethodReply,
                  AsWeakPtr(),
-                 render_frame_host,
-                 reply_msg));
+                 render_frame_host));
 }
 
 void GinJavaBridgeDispatcherHost::SendHasMethodReply(
     RenderFrameHost* render_frame_host,
-    IPC::Message* reply_msg,
     bool result) {
+  IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+  if (!reply_msg) {
+    return;
+  }
   IPC::WriteParam(reply_msg, result);
-  SendReply(render_frame_host, reply_msg);
+  render_frame_host->Send(reply_msg);
 }
 
 void GinJavaBridgeDispatcherHost::OnInvokeMethod(
@@ -449,6 +456,8 @@ void GinJavaBridgeDispatcherHost::OnInvokeMethod(
     render_frame_host->Send(reply_msg);
     return;
   }
+  DCHECK(!HasPendingReply(render_frame_host));
+  pending_replies_[render_frame_host] = reply_msg;
   scoped_refptr<GinJavaMethodInvocationHelper> result =
       new GinJavaMethodInvocationHelper(
           make_scoped_ptr(new GinJavaBoundObjectDelegate(object))
@@ -466,32 +475,37 @@ void GinJavaBridgeDispatcherHost::OnInvokeMethod(
               &GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult,
               AsWeakPtr(),
               render_frame_host,
-              reply_msg,
               result));
 }
 
 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult(
     RenderFrameHost* render_frame_host,
-    IPC::Message* reply_msg,
     scoped_refptr<GinJavaMethodInvocationHelper> result) {
   if (result->HoldsPrimitiveResult()) {
+    IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+    if (!reply_msg) {
+      return;
+    }
     IPC::WriteParam(reply_msg, result->GetPrimitiveResult());
     IPC::WriteParam(reply_msg, result->GetInvocationError());
-    SendReply(render_frame_host, reply_msg);
+    render_frame_host->Send(reply_msg);
   } else {
-    ProcessMethodInvocationObjectResult(render_frame_host, reply_msg, result);
+    ProcessMethodInvocationObjectResult(render_frame_host, result);
   }
 }
 
 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationObjectResult(
     RenderFrameHost* render_frame_host,
-    IPC::Message* reply_msg,
     scoped_refptr<GinJavaMethodInvocationHelper> result) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
   if (!IsValidRenderFrameHost(render_frame_host)) {
-    delete reply_msg;
+    // In this case, we must've already sent the reply when the render frame
+    // was destroyed.
+    DCHECK(!HasPendingReply(render_frame_host));
     return;
   }
+
   base::ListValue wrapped_result;
   if (!result->GetObjectResult().is_null()) {
     GinJavaBoundObject::ObjectID returned_object_id;
@@ -504,10 +518,15 @@ void GinJavaBridgeDispatcherHost::ProcessMethodInvocationObjectResult(
                                      render_frame_host);
     }
     wrapped_result.Append(
-        GinJavaBridgeValue::CreateObjectIDValue(returned_object_id).release());
+        GinJavaBridgeValue::CreateObjectIDValue(
+            returned_object_id).release());
   } else {
     wrapped_result.Append(base::Value::CreateNullValue());
   }
+  IPC::Message* reply_msg = TakePendingReply(render_frame_host);
+  if (!reply_msg) {
+    return;
+  }
   IPC::WriteParam(reply_msg, wrapped_result);
   IPC::WriteParam(reply_msg, result->GetInvocationError());
   render_frame_host->Send(reply_msg);
@@ -527,4 +546,28 @@ void GinJavaBridgeDispatcherHost::OnObjectWrapperDeleted(
   }
 }
 
+IPC::Message* GinJavaBridgeDispatcherHost::TakePendingReply(
+    RenderFrameHost* render_frame_host) {
+  if (!IsValidRenderFrameHost(render_frame_host)) {
+    DCHECK(!HasPendingReply(render_frame_host));
+    return NULL;
+  }
+
+  PendingReplyMap::iterator it = pending_replies_.find(render_frame_host);
+  // There may be no pending reply if we're called from RenderFrameDeleted and
+  // we already sent the reply through the regular route.
+  if (it == pending_replies_.end()) {
+    return NULL;
+  }
+
+  IPC::Message* reply_msg = it->second;
+  pending_replies_.erase(it);
+  return reply_msg;
+}
+
+bool GinJavaBridgeDispatcherHost::HasPendingReply(
+    RenderFrameHost* render_frame_host) const {
+  return pending_replies_.find(render_frame_host) != pending_replies_.end();
+}
+
 }  // namespace content
index 615c2b0..48fcbb5 100644 (file)
@@ -76,20 +76,15 @@ class GinJavaBridgeDispatcherHost
                               GinJavaBoundObject::ObjectID object_id);
 
   bool IsValidRenderFrameHost(RenderFrameHost* render_frame_host);
-  void SendReply(RenderFrameHost* render_frame_host, IPC::Message* reply_msg);
   void SendMethods(RenderFrameHost* render_frame_host,
-                   IPC::Message* reply_msg,
                    const std::set<std::string>& method_names);
   void SendHasMethodReply(RenderFrameHost* render_frame_host,
-                          IPC::Message* reply_msg,
                           bool result);
   void ProcessMethodInvocationResult(
       RenderFrameHost* render_frame_host,
-      IPC::Message* reply_msg,
       scoped_refptr<GinJavaMethodInvocationHelper> result);
   void ProcessMethodInvocationObjectResult(
       RenderFrameHost* render_frame_host,
-      IPC::Message* reply_msg,
       scoped_refptr<GinJavaMethodInvocationHelper> result);
   GinJavaBoundObject::ObjectID AddObject(
       const base::android::JavaRef<jobject>& object,
@@ -101,6 +96,8 @@ class GinJavaBridgeDispatcherHost
   void RemoveHolder(RenderFrameHost* holder,
                     const GinJavaBoundObject::ObjectMap::iterator& from,
                     size_t count);
+  bool HasPendingReply(RenderFrameHost* render_frame_host) const;
+  IPC::Message* TakePendingReply(RenderFrameHost* render_frame_host);
 
   // Every time a GinJavaBoundObject backed by a real Java object is
   // created/destroyed, we insert/remove a strong ref to that Java object into
@@ -114,6 +111,13 @@ class GinJavaBridgeDispatcherHost
   typedef std::map<std::string, GinJavaBoundObject::ObjectID> NamedObjectMap;
   NamedObjectMap named_objects_;
 
+  // Keep track of pending calls out to Java such that we can send a synchronous
+  // reply to the renderer waiting on the response should the RenderFrame be
+  // destroyed while the reply is pending.
+  // Only used on the UI thread.
+  typedef std::map<RenderFrameHost*, IPC::Message*> PendingReplyMap;
+  PendingReplyMap pending_replies_;
+
   DISALLOW_COPY_AND_ASSIGN(GinJavaBridgeDispatcherHost);
 };
 
index 80c1c43..81f12fc 100644 (file)
@@ -45,6 +45,7 @@ SkBitmap CreateOverscrollGlowLBitmap(const gfx::Size& screen_size) {
     LOG(FATAL) << " Failed to allocate bitmap of size " << bounds.width() << "x"
                << bounds.height();
   }
+  glow_bitmap.eraseColor(SK_ColorTRANSPARENT);
 
   SkCanvas canvas(glow_bitmap);
   canvas.clipRect(SkRect::MakeXYWH(0, 0, bounds.width(), bounds.height()));
index f0c9c8f..86c0867 100644 (file)
@@ -107,7 +107,7 @@ void RenderViewDevToolsAgentHost::OnCancelPendingNavigation(
 
 RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost(RenderViewHost* rvh)
     : render_view_host_(NULL),
-      overrides_handler_(new RendererOverridesHandler(this)),
+      overrides_handler_(new RendererOverridesHandler()),
       tracing_handler_(
           new DevToolsTracingHandler(DevToolsTracingHandler::Renderer)),
       power_handler_(new DevToolsPowerHandler()),
@@ -254,8 +254,8 @@ void RenderViewDevToolsAgentHost::AboutToNavigateRenderView(
   if (!render_view_host_)
     return;
 
-  if (render_view_host_ == dest_rvh && static_cast<RenderViewHostImpl*>(
-          render_view_host_)->render_view_termination_status() ==
+  if (render_view_host_ == dest_rvh &&
+          render_view_host_->render_view_termination_status() ==
               base::TERMINATION_STATUS_STILL_RUNNING)
     return;
   ReattachToRenderViewHost(dest_rvh);
@@ -342,10 +342,10 @@ void RenderViewDevToolsAgentHost::Observe(int type,
 
 void RenderViewDevToolsAgentHost::SetRenderViewHost(RenderViewHost* rvh) {
   DCHECK(!render_view_host_);
-  render_view_host_ = rvh;
+  render_view_host_ = static_cast<RenderViewHostImpl*>(rvh);
 
   WebContentsObserver::Observe(WebContents::FromRenderViewHost(rvh));
-  overrides_handler_->OnRenderViewHostChanged();
+  overrides_handler_->SetRenderViewHost(render_view_host_);
 
   registrar_.Add(
       this,
@@ -360,6 +360,7 @@ void RenderViewDevToolsAgentHost::ClearRenderViewHost() {
       content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
       content::Source<RenderWidgetHost>(render_view_host_));
   render_view_host_ = NULL;
+  overrides_handler_->ClearRenderViewHost();
 }
 
 void RenderViewDevToolsAgentHost::DisconnectWebContents() {
index b1f3e07..5a9d5b4 100644 (file)
@@ -26,6 +26,7 @@ class DevToolsPowerHandler;
 class DevToolsTracingHandler;
 class RendererOverridesHandler;
 class RenderViewHost;
+class RenderViewHostImpl;
 
 #if defined(OS_ANDROID)
 class PowerSaveBlockerImpl;
@@ -96,7 +97,7 @@ class CONTENT_EXPORT RenderViewDevToolsAgentHost
   void InnerOnClientAttached();
   void InnerClientDetachedFromRenderer();
 
-  RenderViewHost* render_view_host_;
+  RenderViewHostImpl* render_view_host_;
   scoped_ptr<RendererOverridesHandler> overrides_handler_;
   scoped_ptr<DevToolsTracingHandler> tracing_handler_;
   scoped_ptr<DevToolsPowerHandler> power_handler_;
index d700dee..b068a85 100644 (file)
@@ -67,9 +67,8 @@ static int kCaptureRetryLimit = 2;
 
 }  // namespace
 
-RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
-    : agent_(agent),
-      has_last_compositor_frame_metadata_(false),
+RendererOverridesHandler::RendererOverridesHandler()
+    : has_last_compositor_frame_metadata_(false),
       capture_retry_count_(0),
       weak_factory_(this) {
   RegisterCommandHandler(
@@ -151,9 +150,8 @@ RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
 RendererOverridesHandler::~RendererOverridesHandler() {}
 
 void RendererOverridesHandler::OnClientDetached() {
-  RenderViewHostImpl* host = GetRenderViewHostImpl();
-  if (screencast_command_ && host)
-    host->SetTouchEventEmulationEnabled(false, false);
+  if (screencast_command_ && host_)
+    host_->SetTouchEventEmulationEnabled(false, false);
   screencast_command_ = NULL;
 }
 
@@ -172,12 +170,17 @@ void RendererOverridesHandler::OnVisibilityChanged(bool visible) {
   NotifyScreencastVisibility(visible);
 }
 
-void RendererOverridesHandler::OnRenderViewHostChanged() {
-  RenderViewHostImpl* host = GetRenderViewHostImpl();
+void RendererOverridesHandler::SetRenderViewHost(
+    RenderViewHostImpl* host) {
+  host_ = host;
   if (screencast_command_ && host)
     host->SetTouchEventEmulationEnabled(true, true);
 }
 
+void RendererOverridesHandler::ClearRenderViewHost() {
+  host_ = NULL;
+}
+
 bool RendererOverridesHandler::OnSetTouchEventEmulationEnabled() {
   return screencast_command_.get() != NULL;
 }
@@ -188,14 +191,13 @@ void RendererOverridesHandler::InnerSwapCompositorFrame() {
     return;
   }
 
-  RenderViewHost* host = GetRenderViewHostImpl();
-  if (!host->GetView())
+  if (!host_ || !host_->GetView())
     return;
 
   last_frame_time_ = base::TimeTicks::Now();
 
   RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
-      host->GetView());
+      host_->GetView());
   // TODO(vkuzkokov): do not use previous frame metadata.
   cc::CompositorFrameMetadata& metadata = last_compositor_frame_metadata_;
 
@@ -270,8 +272,7 @@ RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
       devtools::DOM::setFileInputFiles::kParamFiles;
   if (!params || !params->GetList(param, &file_list))
     return command->InvalidParamResponse(param);
-  RenderViewHost* host = GetRenderViewHostImpl();
-  if (!host)
+  if (!host_)
     return NULL;
 
   for (size_t i = 0; i < file_list->GetSize(); ++i) {
@@ -279,7 +280,7 @@ RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
     if (!file_list->GetString(i, &file))
       return command->InvalidParamResponse(param);
     ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
-        host->GetProcess()->GetID(), base::FilePath(file));
+        host_->GetProcess()->GetID(), base::FilePath(file));
   }
   return NULL;
 }
@@ -290,14 +291,14 @@ RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::ClearBrowserCache(
     scoped_refptr<DevToolsProtocol::Command> command) {
-  GetContentClient()->browser()->ClearCache(GetRenderViewHostImpl());
+  GetContentClient()->browser()->ClearCache(host_);
   return command->SuccessResponse(NULL);
 }
 
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::ClearBrowserCookies(
     scoped_refptr<DevToolsProtocol::Command> command) {
-  GetContentClient()->browser()->ClearCookies(GetRenderViewHostImpl());
+  GetContentClient()->browser()->ClearCookies(host_);
   return command->SuccessResponse(NULL);
 }
 
@@ -307,9 +308,8 @@ RendererOverridesHandler::ClearBrowserCookies(
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageDisable(
     scoped_refptr<DevToolsProtocol::Command> command) {
-  RenderViewHostImpl* host = GetRenderViewHostImpl();
-  if (screencast_command_ && host)
-    host->SetTouchEventEmulationEnabled(false, false);
+  if (screencast_command_ && host_)
+    host_->SetTouchEventEmulationEnabled(false, false);
   screencast_command_ = NULL;
   return NULL;
 }
@@ -331,7 +331,10 @@ RendererOverridesHandler::PageHandleJavaScriptDialog(
     prompt_override_ptr = NULL;
   }
 
-  WebContents* web_contents = agent_->GetWebContents();
+  if (!host_)
+    return command->InternalErrorResponse("Could not connect to view");
+
+  WebContents* web_contents = WebContents::FromRenderViewHost(host_);
   if (web_contents) {
     JavaScriptDialogManager* manager =
         web_contents->GetDelegate()->GetJavaScriptDialogManager();
@@ -356,7 +359,10 @@ RendererOverridesHandler::PageNavigate(
   if (!gurl.is_valid())
     return command->InternalErrorResponse("Cannot navigate to invalid URL");
 
-  WebContents* web_contents = agent_->GetWebContents();
+  if (!host_)
+    return command->InternalErrorResponse("Could not connect to view");
+
+  WebContents* web_contents = WebContents::FromRenderViewHost(host_);
   if (web_contents) {
     web_contents->GetController()
         .LoadURL(gurl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
@@ -370,7 +376,10 @@ RendererOverridesHandler::PageNavigate(
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageReload(
     scoped_refptr<DevToolsProtocol::Command> command) {
-  WebContents* web_contents = agent_->GetWebContents();
+  if (!host_)
+    return command->InternalErrorResponse("Could not connect to view");
+
+  WebContents* web_contents = WebContents::FromRenderViewHost(host_);
   if (web_contents) {
     // Override only if it is crashed.
     if (!web_contents->IsCrashed())
@@ -385,7 +394,9 @@ RendererOverridesHandler::PageReload(
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageGetNavigationHistory(
     scoped_refptr<DevToolsProtocol::Command> command) {
-  WebContents* web_contents = agent_->GetWebContents();
+  if (!host_)
+    return command->InternalErrorResponse("Could not connect to view");
+  WebContents* web_contents = WebContents::FromRenderViewHost(host_);
   if (web_contents) {
     base::DictionaryValue* result = new base::DictionaryValue();
     NavigationController& controller = web_contents->GetController();
@@ -425,7 +436,10 @@ RendererOverridesHandler::PageNavigateToHistoryEntry(
     return command->InvalidParamResponse(param);
   }
 
-  WebContents* web_contents = agent_->GetWebContents();
+  if (!host_)
+    return command->InternalErrorResponse("Could not connect to view");
+
+  WebContents* web_contents = WebContents::FromRenderViewHost(host_);
   if (web_contents) {
     NavigationController& controller = web_contents->GetController();
     for (int i = 0; i != controller.GetEntryCount(); ++i) {
@@ -442,11 +456,10 @@ RendererOverridesHandler::PageNavigateToHistoryEntry(
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageCaptureScreenshot(
     scoped_refptr<DevToolsProtocol::Command> command) {
-  RenderViewHostImpl* host = GetRenderViewHostImpl();
-  if (!host->GetView())
-    return command->InternalErrorResponse("Unable to access the view");
+  if (!host_ || !host_->GetView())
+    return command->InternalErrorResponse("Could not connect to view");
 
-  host->GetSnapshotFromBrowser(
+  host_->GetSnapshotFromBrowser(
       base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
           weak_factory_.GetWeakPtr(), command));
   return command->AsyncResponsePromise();
@@ -490,15 +503,16 @@ scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageStartScreencast(
     scoped_refptr<DevToolsProtocol::Command> command) {
   screencast_command_ = command;
-  RenderViewHostImpl* host = GetRenderViewHostImpl();
-  host->SetTouchEventEmulationEnabled(true, true);
-  bool visible = !host->is_hidden();
+  if (!host_)
+    return command->InternalErrorResponse("Could not connect to view");
+  host_->SetTouchEventEmulationEnabled(true, true);
+  bool visible = !host_->is_hidden();
   NotifyScreencastVisibility(visible);
   if (visible) {
     if (has_last_compositor_frame_metadata_)
       InnerSwapCompositorFrame();
     else
-      host->Send(new ViewMsg_ForceRedraw(host->GetRoutingID(), 0));
+      host_->Send(new ViewMsg_ForceRedraw(host_->GetRoutingID(), 0));
   }
   return command->SuccessResponse(NULL);
 }
@@ -508,9 +522,8 @@ RendererOverridesHandler::PageStopScreencast(
     scoped_refptr<DevToolsProtocol::Command> command) {
   last_frame_time_ = base::TimeTicks();
   screencast_command_ = NULL;
-  RenderViewHostImpl* host = GetRenderViewHostImpl();
-  if (host)
-    host->SetTouchEventEmulationEnabled(false, false);
+  if (host_)
+    host_->SetTouchEventEmulationEnabled(false, false);
   return command->SuccessResponse(NULL);
 }
 
@@ -801,10 +814,11 @@ RendererOverridesHandler::PageQueryUsageAndQuota(
       weak_factory_.GetWeakPtr(),
       command);
 
-  scoped_refptr<quota::QuotaManager> quota_manager = GetRenderViewHostImpl()
-                                                         ->GetProcess()
-                                                         ->GetStoragePartition()
-                                                         ->GetQuotaManager();
+  if (!host_)
+    return command->InternalErrorResponse("Could not connect to view");
+
+  scoped_refptr<quota::QuotaManager> quota_manager =
+      host_->GetProcess()->GetStoragePartition()->GetQuotaManager();
 
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
@@ -954,17 +968,14 @@ RendererOverridesHandler::InputEmulateTouchFromMouseEvent(
         devtools::Input::emulateTouchFromMouseEvent::kParamButton);
   }
 
-  RenderViewHost* host = GetRenderViewHostImpl();
+  if (!host_)
+    return command->InternalErrorResponse("Could not connect to view");
+
   if (event->type == WebInputEvent::MouseWheel)
-    host->ForwardWheelEvent(wheel_event);
+    host_->ForwardWheelEvent(wheel_event);
   else
-    host->ForwardMouseEvent(mouse_event);
+    host_->ForwardMouseEvent(mouse_event);
   return command->SuccessResponse(NULL);
 }
 
-RenderViewHostImpl* RendererOverridesHandler::GetRenderViewHostImpl() {
-  return static_cast<RenderViewHostImpl*>(
-      agent_->GetWebContents()->GetRenderViewHost());
-}
-
 }  // namespace content
index 4f5076e..774a683 100644 (file)
@@ -23,7 +23,6 @@ class Message;
 
 namespace content {
 
-class DevToolsAgentHost;
 class DevToolsTracingHandler;
 class RenderViewHostImpl;
 
@@ -33,13 +32,14 @@ class RenderViewHostImpl;
 class CONTENT_EXPORT RendererOverridesHandler
     : public DevToolsProtocol::Handler {
  public:
-  explicit RendererOverridesHandler(DevToolsAgentHost* agent);
+  RendererOverridesHandler();
   virtual ~RendererOverridesHandler();
 
   void OnClientDetached();
   void OnSwapCompositorFrame(const cc::CompositorFrameMetadata& frame_metadata);
   void OnVisibilityChanged(bool visible);
-  void OnRenderViewHostChanged();
+  void SetRenderViewHost(RenderViewHostImpl* host);
+  void ClearRenderViewHost();
   bool OnSetTouchEventEmulationEnabled();
 
  private:
@@ -102,9 +102,7 @@ class CONTENT_EXPORT RendererOverridesHandler
   scoped_refptr<DevToolsProtocol::Response> InputEmulateTouchFromMouseEvent(
       scoped_refptr<DevToolsProtocol::Command> command);
 
-  RenderViewHostImpl* GetRenderViewHostImpl();
-
-  DevToolsAgentHost* agent_;
+  RenderViewHostImpl* host_;
   scoped_refptr<DevToolsProtocol::Command> screencast_command_;
   bool has_last_compositor_frame_metadata_;
   cc::CompositorFrameMetadata last_compositor_frame_metadata_;
index 93db051..b60a55f 100644 (file)
@@ -1179,7 +1179,7 @@ std::vector<base::string16> IndexedDBBackingStore::GetDatabaseNames(
     // Decode database id (in iterator value).
     int64 database_id = 0;
     StringPiece valueSlice(it->Value());
-    if (!DecodeVarInt(&valueSlice, &database_id) || !valueSlice.empty()) {
+    if (!DecodeInt(&valueSlice, &database_id) || !valueSlice.empty()) {
       INTERNAL_CONSISTENCY_ERROR_UNTESTED(GET_DATABASE_NAMES);
       continue;
     }
index cee89b1..643889d 100644 (file)
@@ -218,6 +218,7 @@ static std::string CreateBlobData(
   uuid = base::GenerateGUID();
   scoped_refptr<webkit_blob::BlobData> blob_data =
       new webkit_blob::BlobData(uuid);
+  blob_data->set_content_type(base::UTF16ToUTF8(blob_info.type()));
   blob_data->AppendFile(
       blob_info.file_path(), 0, blob_info.size(), blob_info.last_modified());
   scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle(
index a493d52..dcb1081 100644 (file)
@@ -54,7 +54,7 @@
 // <0, 0, 0, 100, database id>
 //   => Existence implies the database id is in the free list
 //      [DatabaseFreeListKey]
-// <0, 0, 0, 201, origin, database name> => Database id [DatabaseNameKey]
+// <0, 0, 0, 201, origin, database name> => Database id (int) [DatabaseNameKey]
 //
 //
 // Database metadata: [DatabaseMetaDataKey]
index c8bbe26..030be1c 100644 (file)
@@ -265,6 +265,15 @@ void BrowserMediaPlayerManager::PauseVideo() {
   Send(new MediaPlayerMsg_PauseVideo(RoutingID()));
 }
 
+void BrowserMediaPlayerManager::ReleaseAllMediaPlayers() {
+  for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
+      it != players_.end(); ++it) {
+    if ((*it)->player_id() == fullscreen_player_id_)
+      fullscreen_player_is_released_ = true;
+    (*it)->Release();
+  }
+}
+
 void BrowserMediaPlayerManager::OnSeekComplete(
     int player_id,
     const base::TimeDelta& current_time) {
index 5f3fae5..fe78b8e 100644 (file)
@@ -70,6 +70,9 @@ class CONTENT_EXPORT BrowserMediaPlayerManager
   // Pauses all video players manages by this class.
   void PauseVideo();
 
+  // Stops and releases every media managed by this class.
+  void ReleaseAllMediaPlayers();
+
   // media::MediaPlayerManager overrides.
   virtual void OnTimeUpdate(
       int player_id, base::TimeDelta current_time) OVERRIDE;
index 930b752..246ab1b 100644 (file)
@@ -15,6 +15,7 @@
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/desktop_media_id.h"
+#include "content/public/browser/power_save_blocker.h"
 #include "media/base/video_util.h"
 #include "third_party/libyuv/include/libyuv/scale_argb.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_and_cursor_composer.h"
@@ -124,6 +125,10 @@ class DesktopCaptureDevice::Core : public webrtc::DesktopCapturer::Callback {
 
   scoped_ptr<webrtc::BasicDesktopFrame> black_frame_;
 
+  // TODO(jiayl): Remove power_save_blocker_ when there is an API to keep the
+  // screen from sleeping for the drive-by web.
+  scoped_ptr<PowerSaveBlocker> power_save_blocker_;
+
   DISALLOW_COPY_AND_ASSIGN(Core);
 };
 
@@ -164,6 +169,10 @@ void DesktopCaptureDevice::Core::AllocateAndStart(
   // This capturer always outputs ARGB, non-interlaced.
   capture_format_.pixel_format = media::PIXEL_FORMAT_ARGB;
 
+  power_save_blocker_.reset(PowerSaveBlocker::Create(
+      PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+      "DesktopCaptureDevice is running").release());
+
   desktop_capturer_->Start(this);
 
   CaptureFrameAndScheduleNext();
index 4939b62..700b027 100644 (file)
@@ -14,6 +14,7 @@
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
 #include "content/common/gpu/client/gl_helper.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/power_save_blocker.h"
 #include "media/base/video_util.h"
 #include "media/video/capture/video_capture_types.h"
 #include "skia/ext/image_operations.h"
@@ -174,6 +175,10 @@ class DesktopVideoCaptureMachine
   gfx::Point cursor_hot_point_;
   SkBitmap scaled_cursor_bitmap_;
 
+  // TODO(jiayl): Remove power_save_blocker_ when there is an API to keep the
+  // screen from sleeping for the drive-by web.
+  scoped_ptr<PowerSaveBlocker> power_save_blocker_;
+
   DISALLOW_COPY_AND_ASSIGN(DesktopVideoCaptureMachine);
 };
 
@@ -213,6 +218,10 @@ bool DesktopVideoCaptureMachine::Start(
   if (desktop_window_->GetHost())
     desktop_window_->GetHost()->compositor()->AddObserver(this);
 
+  power_save_blocker_.reset(PowerSaveBlocker::Create(
+      PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+      "DesktopCaptureDevice is running").release());
+
   // Starts timer.
   timer_.Start(FROM_HERE, oracle_proxy_->min_capture_period(),
                base::Bind(&DesktopVideoCaptureMachine::Capture, AsWeakPtr(),
@@ -224,6 +233,7 @@ bool DesktopVideoCaptureMachine::Start(
 
 void DesktopVideoCaptureMachine::Stop(const base::Closure& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  power_save_blocker_.reset();
 
   // Stop observing compositor and window events.
   if (desktop_window_) {
index 81a3529..aad9f7a 100644 (file)
@@ -146,7 +146,7 @@ void CompositingIOSurfaceLayerHelper::DisplayIfNeededAndAck() {
 }
 
 void CompositingIOSurfaceLayerHelper::TimerFired() {
-  SetNeedsDisplayAndDisplayAndAck();
+  DisplayIfNeededAndAck();
 }
 
 void CompositingIOSurfaceLayerHelper::BeginPumpingFrames() {
index 3ca74a2..59272be 100644 (file)
@@ -559,7 +559,6 @@ scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface(
 
 void CompositorImpl::OnLostResources() {
   client_->DidLoseResources();
-  ui_resource_provider_.UIResourcesAreInvalid();
 }
 
 void CompositorImpl::ScheduleComposite() {
index 8193fb1..d538048 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "content/browser/renderer_host/input/touch_selection_controller.h"
 
+#include "base/auto_reset.h"
 #include "base/logging.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 
@@ -12,7 +13,7 @@ namespace content {
 TouchSelectionController::TouchSelectionController(
     TouchSelectionControllerClient* client)
     : client_(client),
-      last_input_event_type_(INPUT_EVENT_TYPE_NONE),
+      response_pending_input_event_(INPUT_EVENT_TYPE_NONE),
       start_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
       start_visible_(false),
       end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
@@ -38,8 +39,11 @@ void TouchSelectionController::OnSelectionBoundsChanged(
     const gfx::RectF& end_rect,
     TouchHandleOrientation end_orientation,
     bool end_visible) {
-  if (!activate_selection_automatically_ && !activate_insertion_automatically_)
+  if (!activate_selection_automatically_ &&
+      !activate_insertion_automatically_) {
+    DCHECK_EQ(INPUT_EVENT_TYPE_NONE, response_pending_input_event_);
     return;
+  }
 
   if (start_rect_ == start_rect && end_rect_ == end_rect &&
       start_orientation_ == start_orientation &&
@@ -54,6 +58,14 @@ void TouchSelectionController::OnSelectionBoundsChanged(
   end_orientation_ = end_orientation;
   end_visible_ = end_visible;
 
+  // Ensure that |response_pending_input_event_| is cleared after the method
+  // completes, while also making its current value available for the duration
+  // of the call.
+  InputEventType causal_input_event = response_pending_input_event_;
+  response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
+  base::AutoReset<InputEventType> auto_reset_response_pending_input_event(
+      &response_pending_input_event_, causal_input_event);
+
   const bool is_selection_dragging =
       is_selection_active_ && (start_selection_handle_->is_dragging() ||
                                end_selection_handle_->is_dragging());
@@ -117,14 +129,14 @@ bool TouchSelectionController::WillHandleTouchEvent(
 }
 
 void TouchSelectionController::OnLongPressEvent() {
-  last_input_event_type_ = LONG_PRESS;
+  response_pending_input_event_ = LONG_PRESS;
   ShowSelectionHandlesAutomatically();
   ShowInsertionHandleAutomatically();
   ResetCachedValuesIfInactive();
 }
 
 void TouchSelectionController::OnTapEvent() {
-  last_input_event_type_ = TAP;
+  response_pending_input_event_ = TAP;
   activate_selection_automatically_ = false;
   DeactivateSelection();
   ShowInsertionHandleAutomatically();
@@ -132,7 +144,7 @@ void TouchSelectionController::OnTapEvent() {
 }
 
 void TouchSelectionController::HideAndDisallowShowingAutomatically() {
-  last_input_event_type_ = INPUT_EVENT_TYPE_NONE;
+  response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
   DeactivateInsertion();
   DeactivateSelection();
   activate_insertion_automatically_ = false;
@@ -248,7 +260,7 @@ void TouchSelectionController::ShowSelectionHandlesAutomatically() {
 void TouchSelectionController::OnInsertionChanged() {
   DeactivateSelection();
 
-  if (last_input_event_type_ == TAP && selection_empty_) {
+  if (response_pending_input_event_ == TAP && selection_empty_) {
     HideAndDisallowShowingAutomatically();
     return;
   }
@@ -324,8 +336,12 @@ void TouchSelectionController::ActivateSelection() {
     end_selection_handle_->SetOrientation(end_orientation_);
   }
 
-  if (!is_selection_active_) {
+  // As a long press received while a selection is already active may trigger
+  // an entirely new selection, notify the client but avoid sending an
+  // intervening SELECTION_CLEARED update to avoid unnecessary state changes.
+  if (!is_selection_active_ || response_pending_input_event_ == LONG_PRESS) {
     is_selection_active_ = true;
+    response_pending_input_event_ = INPUT_EVENT_TYPE_NONE;
     client_->OnSelectionEvent(SELECTION_SHOWN, GetStartPosition());
   }
 }
index 4ef75bd..c2b2059 100644 (file)
@@ -117,7 +117,7 @@ class CONTENT_EXPORT TouchSelectionController : public TouchHandleClient {
 
   TouchSelectionControllerClient* const client_;
 
-  InputEventType last_input_event_type_;
+  InputEventType response_pending_input_event_;
 
   gfx::RectF start_rect_;
   TouchHandleOrientation start_orientation_;
index 6389c38..f14860c 100644 (file)
@@ -478,6 +478,25 @@ TEST_F(TouchSelectionControllerTest, SelectionBasic) {
   EXPECT_EQ(gfx::PointF(), GetLastEventAnchor());
 }
 
+TEST_F(TouchSelectionControllerTest, SelectionRepeatedLongPress) {
+  gfx::RectF start_rect(5, 5, 0, 10);
+  gfx::RectF end_rect(50, 5, 0, 10);
+  bool visible = true;
+
+  controller().OnLongPressEvent();
+  ChangeSelection(start_rect, visible, end_rect, visible);
+  EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+  EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+
+  // A long press triggering a new selection should re-send the SELECTION_SHOWN
+  // event notification.
+  start_rect.Offset(10, 10);
+  controller().OnLongPressEvent();
+  ChangeSelection(start_rect, visible, end_rect, visible);
+  EXPECT_EQ(SELECTION_SHOWN, GetLastEventType());
+  EXPECT_EQ(start_rect.bottom_left(), GetLastEventAnchor());
+}
+
 TEST_F(TouchSelectionControllerTest, SelectionDragged) {
   base::TimeTicks event_time = base::TimeTicks::Now();
   controller().OnLongPressEvent();
index 2dcc56d..1f9c26d 100644 (file)
 #include "media/audio/audio_manager_base.h"
 #include "media/base/audio_bus.h"
 
+namespace {
+
+void LogMessage(int stream_id, const std::string& msg, bool add_prefix) {
+  std::ostringstream oss;
+  oss << "[stream_id=" << stream_id << "] ";
+  if (add_prefix)
+    oss << "AIRH::";
+  oss << msg;
+  content::MediaStreamManager::SendMessageToNativeLog(oss.str());
+  DVLOG(1) << oss.str();
+}
+
+}
+
 namespace content {
 
 struct AudioInputRendererHost::AudioEntry {
@@ -133,8 +147,10 @@ void AudioInputRendererHost::DoCompleteCreation(
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   AudioEntry* entry = LookupByController(controller);
-  if (!entry)
+  if (!entry) {
+    NOTREACHED() << "AudioInputController is invalid.";
     return;
+  }
 
   if (!PeerHandle()) {
     NOTREACHED() << "Renderer process handle is invalid.";
@@ -176,6 +192,10 @@ void AudioInputRendererHost::DoCompleteCreation(
     return;
   }
 
+  LogMessage(entry->stream_id,
+             "DoCompleteCreation => IPC channel and stream are now open",
+             true);
+
   Send(new AudioInputMsg_NotifyStreamCreated(entry->stream_id,
       foreign_memory_handle, foreign_socket_handle,
       entry->shared_memory.requested_size(),
@@ -187,29 +207,40 @@ void AudioInputRendererHost::DoSendRecordingMessage(
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // TODO(henrika): See crbug.com/115262 for details on why this method
   // should be implemented.
+  AudioEntry* entry = LookupByController(controller);
+  if (!entry) {
+    NOTREACHED() << "AudioInputController is invalid.";
+    return;
+  }
+  LogMessage(entry->stream_id,
+             "DoSendRecordingMessage => stream is now started",
+             true);
 }
 
 void AudioInputRendererHost::DoHandleError(
     media::AudioInputController* controller,
     media::AudioInputController::ErrorCode error_code) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  // Log all errors even it is ignored later.
-  MediaStreamManager::SendMessageToNativeLog(
-      base::StringPrintf("AudioInputController error: %d", error_code));
+  AudioEntry* entry = LookupByController(controller);
+  if (!entry) {
+    NOTREACHED() << "AudioInputController is invalid.";
+    return;
+  }
 
   // This is a fix for crbug.com/357501. The error can be triggered when closing
   // the lid on Macs, which causes more problems than it fixes.
   // Also, in crbug.com/357569, the goal is to remove usage of the error since
   // it was added to solve a crash on Windows that no longer can be reproduced.
   if (error_code == media::AudioInputController::NO_DATA_ERROR) {
-    DVLOG(1) << "AudioInputRendererHost@" << this << "::DoHandleError: "
-             << "NO_DATA_ERROR ignored.";
+    // TODO(henrika): it might be possible to do something other than just
+    // logging when we detect many NO_DATA_ERROR calls for a stream.
+    LogMessage(entry->stream_id, "AIC => NO_DATA_ERROR", false);
     return;
   }
 
-  AudioEntry* entry = LookupByController(controller);
-  if (!entry)
-    return;
+  std::ostringstream oss;
+  oss << "AIC reports error_code=" << error_code;
+  LogMessage(entry->stream_id, oss.str(), false);
 
   audio_log_->OnError(entry->stream_id);
   DeleteEntryOnError(entry, AUDIO_INPUT_CONTROLLER_ERROR);
@@ -219,15 +250,13 @@ void AudioInputRendererHost::DoLog(media::AudioInputController* controller,
                                    const std::string& message) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   AudioEntry* entry = LookupByController(controller);
-  if (!entry)
+  if (!entry) {
+    NOTREACHED() << "AudioInputController is invalid.";
     return;
+  }
 
   // Add stream ID and current audio level reported by AIC to native log.
-  std::string log_string =
-      base::StringPrintf("[stream_id=%d] ", entry->stream_id);
-  log_string += message;
-  MediaStreamManager::SendMessageToNativeLog(log_string);
-  DVLOG(1) << log_string;
+  LogMessage(entry->stream_id, message, false);
 }
 
 bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message) {
@@ -250,10 +279,10 @@ void AudioInputRendererHost::OnCreateStream(
     const AudioInputHostMsg_CreateStream_Config& config) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  DVLOG(1) << "AudioInputRendererHost@" << this
-           << "::OnCreateStream(stream_id=" << stream_id
-           << ", render_view_id=" << render_view_id
-           << ", session_id=" << session_id << ")";
+  std::ostringstream oss;
+  oss << "[stream_id=" << stream_id << "] "
+      << "AIRH::OnCreateStream(render_view_id=" << render_view_id
+      << ", session_id=" << session_id << ")";
   DCHECK_GT(render_view_id, 0);
 
   // media::AudioParameters is validated in the deserializer.
@@ -287,6 +316,7 @@ void AudioInputRendererHost::OnCreateStream(
 
     device_id = info->device.id;
     device_name = info->device.name;
+    oss << ": device_name=" << device_name;
   }
 
   // Create a new AudioEntry structure.
@@ -350,21 +380,24 @@ void AudioInputRendererHost::OnCreateStream(
 
   // Set the initial AGC state for the audio input stream. Note that, the AGC
   // is only supported in AUDIO_PCM_LOW_LATENCY mode.
-  if (config.params.format() == media::AudioParameters::AUDIO_PCM_LOW_LATENCY)
+  if (config.params.format() == media::AudioParameters::AUDIO_PCM_LOW_LATENCY) {
     entry->controller->SetAutomaticGainControl(config.automatic_gain_control);
+    oss << ", AGC=" << config.automatic_gain_control;
+  }
+
+  MediaStreamManager::SendMessageToNativeLog(oss.str());
+  DVLOG(1) << oss.str();
 
   // Since the controller was created successfully, create an entry and add it
   // to the map.
   entry->stream_id = stream_id;
   audio_entries_.insert(std::make_pair(stream_id, entry.release()));
-
-  MediaStreamManager::SendMessageToNativeLog(
-      "Audio input stream created successfully. Device name: " + device_name);
   audio_log_->OnCreated(stream_id, audio_params, device_id);
 }
 
 void AudioInputRendererHost::OnRecordStream(int stream_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  LogMessage(stream_id, "OnRecordStream", true);
 
   AudioEntry* entry = LookupById(stream_id);
   if (!entry) {
@@ -378,6 +411,7 @@ void AudioInputRendererHost::OnRecordStream(int stream_id) {
 
 void AudioInputRendererHost::OnCloseStream(int stream_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  LogMessage(stream_id, "OnCloseStream", true);
 
   AudioEntry* entry = LookupById(stream_id);
 
@@ -400,8 +434,10 @@ void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
 
 void AudioInputRendererHost::SendErrorMessage(
     int stream_id, ErrorCode error_code) {
-  MediaStreamManager::SendMessageToNativeLog(
-      base::StringPrintf("AudioInputRendererHost error: %d", error_code));
+  std::string err_msg =
+      base::StringPrintf("SendErrorMessage(error_code=%d)", error_code);
+  LogMessage(stream_id, err_msg, true);
+
   Send(new AudioInputMsg_NotifyStreamStateChanged(
       stream_id, media::AudioInputIPCDelegate::kError));
 }
@@ -419,6 +455,7 @@ void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (!entry->pending_close) {
+    LogMessage(entry->stream_id, "CloseAndDeleteStream", true);
     entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
                                         this, entry));
     entry->pending_close = true;
@@ -428,6 +465,7 @@ void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
 
 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  LogMessage(entry->stream_id, "DeleteEntry => stream is now closed", true);
 
   // Delete the entry when this method goes out of scope.
   scoped_ptr<AudioEntry> entry_deleter(entry);
index 117fbe8..6a78f6c 100644 (file)
@@ -60,18 +60,20 @@ void AudioInputSyncWriter::Write(const media::AudioBus* data,
   if (last_write_time_.is_null()) {
     // This is the first time Write is called.
     base::TimeDelta interval = base::Time::Now() - creation_time_;
-    oss << "Audio input data received for the first time: delay = "
-        << interval.InMilliseconds() << "ms.";
+    oss << "AISW::Write => audio input data received for the first time: delay "
+           "= " << interval.InMilliseconds() << "ms";
 
   } else {
     base::TimeDelta interval = base::Time::Now() - last_write_time_;
     if (interval > kLogDelayThreadhold) {
-      oss << "Audio input data delay unexpectedly long: delay = "
-          << interval.InMilliseconds() << "ms.";
+      oss << "AISW::Write => audio input data delay unexpectedly long: delay = "
+          << interval.InMilliseconds() << "ms";
     }
   }
-  if (!oss.str().empty())
+  if (!oss.str().empty()) {
     MediaStreamManager::SendMessageToNativeLog(oss.str());
+    DVLOG(1) << oss.str();
+  }
 
   last_write_time_ = base::Time::Now();
 #endif
index 3daacca..ffc906e 100644 (file)
@@ -9,12 +9,32 @@
 #include "base/command_line.h"
 #include "base/memory/shared_memory.h"
 #include "base/metrics/histogram.h"
+#include "base/strings/stringprintf.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/public/common/content_switches.h"
 #include "media/audio/audio_buffers_state.h"
 #include "media/audio/audio_parameters.h"
 
 using media::AudioBus;
 
+namespace {
+
+// Used to log if any audio glitches have been detected during an audio session.
+// Elements in this enum should not be added, deleted or rearranged.
+enum AudioGlitchResult {
+  AUDIO_RENDERER_NO_AUDIO_GLITCHES = 0,
+  AUDIO_RENDERER_AUDIO_GLITCHES = 1,
+  AUDIO_RENDERER_AUDIO_GLITCHES_MAX = AUDIO_RENDERER_AUDIO_GLITCHES
+};
+
+void LogAudioGlitchResult(AudioGlitchResult result) {
+  UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererAudioGlitches",
+                            result,
+                            AUDIO_RENDERER_AUDIO_GLITCHES_MAX + 1);
+}
+
+}  // namespace
+
 namespace content {
 
 AudioSyncReader::AudioSyncReader(base::SharedMemory* shared_memory,
@@ -47,6 +67,18 @@ AudioSyncReader::~AudioSyncReader() {
       100.0 * renderer_missed_callback_count_ / renderer_callback_count_;
   UMA_HISTOGRAM_PERCENTAGE(
       "Media.AudioRendererMissedDeadline", percentage_missed);
+
+  // Add more detailed information regarding detected audio glitches where
+  // a non-zero value of |renderer_missed_callback_count_| is added to the
+  // AUDIO_RENDERER_AUDIO_GLITCHES bin.
+  renderer_missed_callback_count_ > 0 ?
+      LogAudioGlitchResult(AUDIO_RENDERER_AUDIO_GLITCHES) :
+      LogAudioGlitchResult(AUDIO_RENDERER_NO_AUDIO_GLITCHES);
+  std::string log_string =
+      base::StringPrintf("ASR: number of detected audio glitches=%d",
+                         static_cast<int>(renderer_missed_callback_count_));
+  MediaStreamManager::SendMessageToNativeLog(log_string);
+  DVLOG(1) << log_string;
 }
 
 // media::AudioOutputController::SyncReader implementations.
index 399244e..516af83 100644 (file)
@@ -1238,6 +1238,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
     switches::kDisableWebRtcHWDecoding,
     switches::kDisableWebRtcHWEncoding,
     switches::kEnableWebRtcHWVp8Encoding,
+    switches::kEnableWebRtcHWH264Encoding,
 #endif
     switches::kLowEndDeviceMode,
 #if defined(OS_ANDROID)
index df99c91..4b36126 100644 (file)
@@ -235,6 +235,8 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
 }
 
 RenderWidgetHostImpl::~RenderWidgetHostImpl() {
+  if (view_weak_)
+    view_weak_->RenderWidgetHostGone();
   SetView(NULL);
 
   GpuSurfaceTracker::Get()->RemoveSurface(surface_id_);
@@ -310,6 +312,10 @@ RenderWidgetHostImpl* RenderWidgetHostImpl::From(RenderWidgetHost* rwh) {
 }
 
 void RenderWidgetHostImpl::SetView(RenderWidgetHostViewBase* view) {
+  if (view)
+    view_weak_ = view->GetWeakPtr();
+  else
+    view_weak_.reset();
   view_ = view;
 
   GpuSurfaceTracker::Get()->SetSurfaceHandle(
@@ -1206,7 +1212,7 @@ void RenderWidgetHostImpl::RendererExited(base::TerminationStatus status,
   // We need to at least make sure that the RenderProcessHost is notified about
   // the |is_hidden_| change, so that the renderer will have correct visibility
   // set when respawned.
-  if (!is_hidden_) {
+  if (is_hidden_) {
     process_->WidgetRestored();
     is_hidden_ = false;
   }
@@ -1218,7 +1224,8 @@ void RenderWidgetHostImpl::RendererExited(base::TerminationStatus status,
     GpuSurfaceTracker::Get()->SetSurfaceHandle(surface_id_,
                                                gfx::GLSurfaceHandle());
     view_->RenderProcessGone(status, exit_code);
-    view_ = NULL;  // The View should be deleted by RenderProcessGone.
+    view_ = NULL; // The View should be deleted by RenderProcessGone.
+    view_weak_.reset();
   }
 
   // Reconstruct the input router to ensure that it has fresh state for a new
index 80f0596..a47e9d7 100644 (file)
@@ -562,6 +562,12 @@ class CONTENT_EXPORT RenderWidgetHostImpl
   // doing so).
   RenderWidgetHostViewBase* view_;
 
+  // A weak pointer to the view. The above pointer should be weak, but changing
+  // that to be weak causes crashes on Android.
+  // TODO(ccameron): Fix this.
+  // http://crbug.com/404828
+  base::WeakPtr<RenderWidgetHostViewBase> view_weak_;
+
   // true if a renderer has once been valid. We use this flag to display a sad
   // tab only when we lose our renderer and not if a paint occurs during
   // initialization.
index f0e072f..c65276a 100644 (file)
@@ -1420,4 +1420,18 @@ TEST_F(RenderWidgetHostTest, RendererExitedResetsInputRouter) {
   ASSERT_FALSE(host_->input_router()->HasPendingEvents());
 }
 
+// Regression test for http://crbug.com/401859.
+TEST_F(RenderWidgetHostTest, RendererExitedResetsIsHidden) {
+  // RendererExited will delete the view.
+  host_->SetView(new TestView(host_.get()));
+  host_->WasHidden();
+
+  ASSERT_TRUE(host_->is_hidden());
+  host_->RendererExited(base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
+  ASSERT_FALSE(host_->is_hidden());
+
+  // Make sure the input router is in a fresh state.
+  ASSERT_FALSE(host_->input_router()->HasPendingEvents());
+}
+
 }  // namespace content
index 613fca9..49ae253 100644 (file)
@@ -106,7 +106,14 @@ void CopyFromCompositingSurfaceFinished(
   TRACE_EVENT0(
       "cc", "RenderWidgetHostViewAndroid::CopyFromCompositingSurfaceFinished");
   bitmap_pixels_lock.reset();
-  release_callback->Run(0, false);
+  uint32 sync_point = 0;
+  if (result) {
+    GLHelper* gl_helper =
+        ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
+    sync_point = gl_helper->InsertSyncPoint();
+  }
+  bool lost_resource = sync_point == 0;
+  release_callback->Run(sync_point, lost_resource);
   UMA_HISTOGRAM_TIMES(kAsyncReadBackString,
                       base::TimeTicks::Now() - start_time);
   callback.Run(result, *bitmap);
@@ -228,7 +235,7 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
     RenderWidgetHostImpl* widget_host,
     ContentViewCoreImpl* content_view_core)
     : host_(widget_host),
-      needs_begin_frame_(false),
+      outstanding_vsync_requests_(0),
       is_showing_(!widget_host->is_hidden()),
       content_view_core_(NULL),
       ime_adapter_android_(this),
@@ -242,7 +249,6 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid(
       gesture_text_selector_(this),
       touch_scrolling_(false),
       potentially_active_fling_count_(0),
-      flush_input_requested_(false),
       accelerated_surface_route_id_(0),
       using_synchronous_compositor_(SynchronousCompositorImpl::FromID(
                                         widget_host->GetProcess()->GetID(),
@@ -305,10 +311,9 @@ void RenderWidgetHostViewAndroid::WasShown() {
 
   host_->WasShown(ui::LatencyInfo());
 
-  if (content_view_core_ && !using_synchronous_compositor_) {
-    content_view_core_->GetWindowAndroid()->AddObserver(this);
-    content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
-    observing_root_window_ = true;
+  if (content_view_core_) {
+    StartObservingRootWindow();
+    RequestVSyncUpdate(BEGIN_FRAME);
   }
 }
 
@@ -322,10 +327,7 @@ void RenderWidgetHostViewAndroid::WasHidden() {
   // utilization.
   host_->WasHidden();
 
-  if (content_view_core_ && !using_synchronous_compositor_) {
-    content_view_core_->GetWindowAndroid()->RemoveObserver(this);
-    observing_root_window_ = false;
-  }
+  StopObservingRootWindow();
 }
 
 void RenderWidgetHostViewAndroid::WasResized() {
@@ -597,15 +599,13 @@ void RenderWidgetHostViewAndroid::OnDidChangeBodyBackgroundColor(
 }
 
 void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame(bool enabled) {
-  if (enabled == needs_begin_frame_)
-    return;
-
+  DCHECK(!using_synchronous_compositor_);
   TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrame",
                "enabled", enabled);
-  if (content_view_core_ && enabled)
-    content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
-
-  needs_begin_frame_ = enabled;
+  if (enabled)
+    RequestVSyncUpdate(PERSISTENT_BEGIN_FRAME);
+  else
+    outstanding_vsync_requests_ &= ~PERSISTENT_BEGIN_FRAME;
 }
 
 void RenderWidgetHostViewAndroid::OnStartContentIntent(
@@ -1208,6 +1208,64 @@ void RenderWidgetHostViewAndroid::RemoveLayers() {
     overscroll_effect_->Disable();
 }
 
+void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32 requests) {
+  // The synchronous compositor does not requre BeginFrame messages.
+  if (using_synchronous_compositor_)
+    requests &= FLUSH_INPUT;
+
+  bool should_request_vsync = !outstanding_vsync_requests_ && requests;
+  outstanding_vsync_requests_ |= requests;
+  // Note that if we're not currently observing the root window, outstanding
+  // vsync requests will be pushed if/when we resume observing in
+  // |StartObservingRootWindow()|.
+  if (observing_root_window_ && should_request_vsync)
+    content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+}
+
+void RenderWidgetHostViewAndroid::StartObservingRootWindow() {
+  DCHECK(content_view_core_);
+  if (observing_root_window_)
+    return;
+
+  observing_root_window_ = true;
+  content_view_core_->GetWindowAndroid()->AddObserver(this);
+
+  // Clear existing vsync requests to allow a request to the new window.
+  uint32 outstanding_vsync_requests = outstanding_vsync_requests_;
+  outstanding_vsync_requests_ = 0;
+  RequestVSyncUpdate(outstanding_vsync_requests);
+}
+
+void RenderWidgetHostViewAndroid::StopObservingRootWindow() {
+  if (!content_view_core_) {
+    DCHECK(!observing_root_window_);
+    return;
+  }
+
+  if (!observing_root_window_)
+    return;
+
+  observing_root_window_ = false;
+  content_view_core_->GetWindowAndroid()->RemoveObserver(this);
+}
+
+void RenderWidgetHostViewAndroid::SendBeginFrame(base::TimeTicks frame_time,
+                                                 base::TimeDelta vsync_period) {
+  TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
+  base::TimeTicks display_time = frame_time + vsync_period;
+
+  // TODO(brianderson): Use adaptive draw-time estimation.
+  base::TimeDelta estimated_browser_composite_time =
+      base::TimeDelta::FromMicroseconds(
+          (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60));
+
+  base::TimeTicks deadline = display_time - estimated_browser_composite_time;
+
+  host_->Send(new ViewMsg_BeginFrame(
+      host_->GetRoutingID(),
+      cc::BeginFrameArgs::Create(frame_time, deadline, vsync_period)));
+}
+
 bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) {
   bool needs_animate =
       overscroll_effect_ ? overscroll_effect_->Animate(frame_time) : false;
@@ -1353,11 +1411,8 @@ InputEventAckState RenderWidgetHostViewAndroid::FilterInputEvent(
 }
 
 void RenderWidgetHostViewAndroid::OnSetNeedsFlushInput() {
-  if (flush_input_requested_ || !content_view_core_)
-    return;
   TRACE_EVENT0("input", "RenderWidgetHostViewAndroid::OnSetNeedsFlushInput");
-  flush_input_requested_ = true;
-  content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+  RequestVSyncUpdate(FLUSH_INPUT);
 }
 
 BrowserAccessibilityManager*
@@ -1398,9 +1453,8 @@ void RenderWidgetHostViewAndroid::SendTouchEvent(
   // This is good enough as long as the first touch event has Begin semantics
   // and the actual scroll happens on the next vsync.
   // TODO: Is this actually still needed?
-  if (content_view_core_ && observing_root_window_) {
-    content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
-  }
+  if (observing_root_window_)
+    RequestVSyncUpdate(BEGIN_FRAME);
 }
 
 void RenderWidgetHostViewAndroid::SendMouseEvent(
@@ -1496,13 +1550,11 @@ void RenderWidgetHostViewAndroid::DidStopFlinging() {
 void RenderWidgetHostViewAndroid::SetContentViewCore(
     ContentViewCoreImpl* content_view_core) {
   RemoveLayers();
-  if (observing_root_window_ && content_view_core_) {
-    content_view_core_->GetWindowAndroid()->RemoveObserver(this);
-    observing_root_window_ = false;
-  }
+  StopObservingRootWindow();
 
   bool resize = false;
   if (content_view_core != content_view_core_) {
+    overscroll_effect_.reset();
     selection_controller_.reset();
     ReleaseLocksOnSurface();
     resize = true;
@@ -1525,12 +1577,7 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
   if (!content_view_core_)
     return;
 
-  if (!using_synchronous_compositor_) {
-    content_view_core_->GetWindowAndroid()->AddObserver(this);
-    observing_root_window_ = true;
-    if (needs_begin_frame_)
-      content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
-  }
+  StartObservingRootWindow();
 
   if (resize)
     WasResized();
@@ -1538,9 +1585,8 @@ void RenderWidgetHostViewAndroid::SetContentViewCore(
   if (!selection_controller_)
     selection_controller_.reset(new TouchSelectionController(this));
 
-  if (!content_view_core_)
-    overscroll_effect_.reset();
-  else if (overscroll_effect_enabled_ && !overscroll_effect_)
+  if (overscroll_effect_enabled_ && !overscroll_effect_ &&
+      content_view_core_->GetWindowAndroid()->GetCompositor())
     overscroll_effect_ = CreateOverscrollEffect(content_view_core_);
 }
 
@@ -1563,10 +1609,18 @@ void RenderWidgetHostViewAndroid::OnCompositingDidCommit() {
   RunAckCallbacks();
 }
 
+
+void RenderWidgetHostViewAndroid::OnAttachCompositor() {
+  DCHECK(content_view_core_);
+  if (overscroll_effect_enabled_ && !overscroll_effect_)
+    overscroll_effect_ = CreateOverscrollEffect(content_view_core_);
+}
+
 void RenderWidgetHostViewAndroid::OnDetachCompositor() {
   DCHECK(content_view_core_);
   DCHECK(!using_synchronous_compositor_);
   RunAckCallbacks();
+  overscroll_effect_.reset();
 }
 
 void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time,
@@ -1575,27 +1629,19 @@ void RenderWidgetHostViewAndroid::OnVSync(base::TimeTicks frame_time,
   if (!host_)
     return;
 
-  if (flush_input_requested_) {
-    flush_input_requested_ = false;
-    host_->FlushInput();
-  }
-
-  TRACE_EVENT0("cc", "RenderWidgetHostViewAndroid::SendBeginFrame");
-  base::TimeTicks display_time = frame_time + vsync_period;
+  const uint32 current_vsync_requests = outstanding_vsync_requests_;
+  outstanding_vsync_requests_ = 0;
 
-  // TODO(brianderson): Use adaptive draw-time estimation.
-  base::TimeDelta estimated_browser_composite_time =
-      base::TimeDelta::FromMicroseconds(
-          (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60));
-
-  base::TimeTicks deadline = display_time - estimated_browser_composite_time;
+  if (current_vsync_requests & FLUSH_INPUT)
+    host_->FlushInput();
 
-  host_->Send(new ViewMsg_BeginFrame(
-      host_->GetRoutingID(),
-      cc::BeginFrameArgs::Create(frame_time, deadline, vsync_period)));
+  if (current_vsync_requests & BEGIN_FRAME ||
+      current_vsync_requests & PERSISTENT_BEGIN_FRAME) {
+    SendBeginFrame(frame_time, vsync_period);
+  }
 
-  if (needs_begin_frame_)
-    content_view_core_->GetWindowAndroid()->RequestVSyncUpdate();
+  if (current_vsync_requests & PERSISTENT_BEGIN_FRAME)
+    RequestVSyncUpdate(PERSISTENT_BEGIN_FRAME);
 }
 
 void RenderWidgetHostViewAndroid::OnAnimate(base::TimeTicks begin_frame_time) {
index 7601adc..6f5963b 100644 (file)
@@ -177,7 +177,7 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
 
   // ui::WindowAndroidObserver implementation.
   virtual void OnCompositingDidCommit() OVERRIDE;
-  virtual void OnAttachCompositor() OVERRIDE {}
+  virtual void OnAttachCompositor() OVERRIDE;
   virtual void OnDetachCompositor() OVERRIDE;
   virtual void OnVSync(base::TimeTicks frame_time,
                        base::TimeDelta vsync_period) OVERRIDE;
@@ -310,6 +310,15 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
   void InternalSwapCompositorFrame(uint32 output_surface_id,
                                    scoped_ptr<cc::CompositorFrame> frame);
 
+  enum VSyncRequestType {
+    FLUSH_INPUT = 1 << 0,
+    BEGIN_FRAME = 1 << 1,
+    PERSISTENT_BEGIN_FRAME = 1 << 2
+  };
+  void RequestVSyncUpdate(uint32 requests);
+  void StartObservingRootWindow();
+  void StopObservingRootWindow();
+  void SendBeginFrame(base::TimeTicks frame_time, base::TimeDelta vsync_period);
   bool Animate(base::TimeTicks frame_time);
 
   void OnContentScrollingChange();
@@ -320,8 +329,8 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
   // The model object.
   RenderWidgetHostImpl* host_;
 
-  // Used to track whether this render widget needs a BeginFrame.
-  bool needs_begin_frame_;
+  // Used to control action dispatch at the next |OnVSync()| call.
+  uint32 outstanding_vsync_requests_;
 
   bool is_showing_;
 
@@ -367,8 +376,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid
   bool touch_scrolling_;
   size_t potentially_active_fling_count_;
 
-  bool flush_input_requested_;
-
   int accelerated_surface_route_id_;
 
   // Size to use if we have no backing ContentViewCore
index 9e38f0e..f12faf3 100644 (file)
@@ -374,7 +374,8 @@ RenderWidgetHostViewBase::RenderWidgetHostViewBase()
       current_device_scale_factor_(0),
       current_display_rotation_(gfx::Display::ROTATE_0),
       pinch_zoom_enabled_(content::IsPinchToZoomEnabled()),
-      renderer_frame_number_(0) {
+      renderer_frame_number_(0),
+      weak_factory_(this) {
 }
 
 RenderWidgetHostViewBase::~RenderWidgetHostViewBase() {
@@ -535,6 +536,10 @@ bool RenderWidgetHostViewBase::HasDisplayPropertyChanged(gfx::NativeView view) {
   return true;
 }
 
+base::WeakPtr<RenderWidgetHostViewBase> RenderWidgetHostViewBase::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
 scoped_ptr<SyntheticGestureTarget>
 RenderWidgetHostViewBase::CreateSyntheticGestureTarget() {
   RenderWidgetHostImpl* host =
index 7dd8676..0fdfe5c 100644 (file)
@@ -104,6 +104,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
   // changed since the last time.
   bool HasDisplayPropertyChanged(gfx::NativeView view);
 
+  base::WeakPtr<RenderWidgetHostViewBase> GetWeakPtr();
+
   //----------------------------------------------------------------------------
   // The following methods can be overridden by derived classes.
 
@@ -226,6 +228,13 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView,
   virtual void RenderProcessGone(base::TerminationStatus status,
                                  int error_code) = 0;
 
+  // Notifies the View that the renderer's host has ceased to exist.
+  // The default implementation of this is a no-op. This hack exists to fix
+  // a crash on the branch.
+  // TODO(ccameron): Clean this up.
+  // http://crbug.com/404828
+  virtual void RenderWidgetHostGone() {}
+
   // Tells the View to destroy itself.
   virtual void Destroy() = 0;
 
@@ -428,6 +437,8 @@ protected:
 
   base::OneShotTimer<RenderWidgetHostViewBase> flush_input_timer_;
 
+  base::WeakPtrFactory<RenderWidgetHostViewBase> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewBase);
 };
 
index 533019f..2548294 100644 (file)
@@ -491,14 +491,9 @@ class CompositingRenderWidgetHostViewBrowserTestTabCapture
     SkBitmap bitmap;
     bitmap.allocN32Pixels(video_frame->visible_rect().width(),
                           video_frame->visible_rect().height());
-    bitmap.eraseColor(SK_ColorTRANSPARENT);
+    // Don't clear the canvas because drawing a video frame by Src mode.
     SkCanvas canvas(bitmap);
-
-    video_renderer.Paint(video_frame.get(),
-                         &canvas,
-                         video_frame->visible_rect(),
-                         0xff,
-                         media::VIDEO_ROTATION_0);
+    video_renderer.Copy(video_frame.get(), &canvas);
 
     CopyFromCompositingSurfaceCallback(quit_callback,
                                        result,
index 40dd52f..630f76e 100644 (file)
@@ -287,6 +287,7 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
       const std::vector<gfx::Rect>& character_bounds) OVERRIDE;
   virtual void RenderProcessGone(base::TerminationStatus status,
                                  int error_code) OVERRIDE;
+  virtual void RenderWidgetHostGone() OVERRIDE;
   virtual void Destroy() OVERRIDE;
   virtual void SetTooltipText(const base::string16& tooltip_text) OVERRIDE;
   virtual void SelectionChanged(const base::string16& text,
index c80aafb..8143dfa 100644 (file)
@@ -1129,6 +1129,13 @@ void RenderWidgetHostViewMac::RenderProcessGone(base::TerminationStatus status,
   Destroy();
 }
 
+void RenderWidgetHostViewMac::RenderWidgetHostGone() {
+  // Destroy the DelegatedFrameHost, to prevent crashes when Destroy is never
+  // called on the view.
+  // http://crbug.com/404828
+  ShutdownBrowserCompositor();
+}
+
 void RenderWidgetHostViewMac::Destroy() {
   [[NSNotificationCenter defaultCenter]
       removeObserver:cocoa_view_
index b478c60..530028b 100644 (file)
@@ -197,8 +197,7 @@ ui::Layer* OverscrollNavigationOverlay::CreateSlideLayer(int offset) {
   gfx::Image image;
   if (entry && entry->screenshot().get()) {
     std::vector<gfx::ImagePNGRep> image_reps;
-    image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(),
-        ui::GetScaleFactorForNativeView(window_.get())));
+    image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 1.0f));
     image = gfx::Image(image_reps);
   }
   if (!layer_delegate_)
index 26a7011..a007f21 100644 (file)
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "content/browser/android/interstitial_page_delegate_android.h"
 #include "content/browser/frame_host/interstitial_page_impl.h"
+#include "content/browser/media/android/browser_media_player_manager.h"
 #include "content/browser/media/media_web_contents_observer.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -184,6 +185,21 @@ void WebContentsAndroid::OnShow(JNIEnv* env, jobject obj) {
   web_contents_->WasShown();
 }
 
+void WebContentsAndroid::ReleaseMediaPlayers(JNIEnv* env, jobject jobj) {
+#if defined(ENABLE_BROWSER_CDMS)
+  RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
+      web_contents_->GetRenderViewHost());
+  if (!rvhi || !rvhi->GetMainFrame())
+    return;
+
+  BrowserMediaPlayerManager* manager =
+      rvhi->media_web_contents_observer()->GetMediaPlayerManager(
+          rvhi->GetMainFrame());
+  if (manager)
+    manager->ReleaseAllMediaPlayers();
+#endif // defined(ENABLE_BROWSER_CDMS)
+}
+
 void WebContentsAndroid::PauseVideo() {
   RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(
       web_contents_->GetRenderViewHost());
index efd522e..5144817 100644 (file)
@@ -64,7 +64,9 @@ class CONTENT_EXPORT WebContentsAndroid
 
   void OnHide(JNIEnv* env, jobject obj);
   void OnShow(JNIEnv* env, jobject obj);
+  void ReleaseMediaPlayers(JNIEnv* env, jobject jobj);
   void PauseVideo();
+
   void AddStyleSheetByURL(
       JNIEnv* env, jobject obj, jstring url);
   void ShowInterstitialPage(
index 1a61244..b58b770 100644 (file)
@@ -134,8 +134,7 @@ class OverscrollWindowDelegate : public ImageWindowDelegate {
     gfx::Image image;
     if (entry && entry->screenshot().get()) {
       std::vector<gfx::ImagePNGRep> image_reps;
-      image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(),
-          ui::GetScaleFactorForNativeView(web_contents_window())));
+      image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(), 1.0f));
       image = gfx::Image(image_reps);
     }
     SetImage(image);
index 57326b3..b2458cd 100644 (file)
@@ -25,6 +25,8 @@ const char* GinJavaBridgeErrorToString(GinJavaBridgeError error) {
     case kGinJavaBridgeNonAssignableTypes:
       return "The type of the object passed to the method is incompatible "
           "with the type of method's argument";
+    case kGinJavaBridgeRenderFrameDeleted:
+      return "RenderFrame has been deleted";
   }
   NOTREACHED();
   return "Unknown error";
index 37d14cb..140201e 100644 (file)
@@ -17,6 +17,7 @@ enum GinJavaBridgeError {
   kGinJavaBridgeAccessToObjectGetClassIsBlocked,
   kGinJavaBridgeJavaExceptionRaised,
   kGinJavaBridgeNonAssignableTypes,
+  kGinJavaBridgeRenderFrameDeleted,
 };
 
 CONTENT_EXPORT const char* GinJavaBridgeErrorToString(GinJavaBridgeError error);
index 8b714b9..a784467 100644 (file)
@@ -231,11 +231,13 @@ void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
 }
 
 void GpuVideoDecodeAcceleratorHost::OnPictureReady(
-    int32 picture_buffer_id, int32 bitstream_buffer_id) {
+    int32 picture_buffer_id,
+    int32 bitstream_buffer_id,
+    const gfx::Rect& visible_rect) {
   DCHECK(CalledOnValidThread());
   if (!client_)
     return;
-  media::Picture picture(picture_buffer_id, bitstream_buffer_id);
+  media::Picture picture(picture_buffer_id, bitstream_buffer_id, visible_rect);
   client_->PictureReady(picture);
 }
 
index 571bd0c..e333f6b 100644 (file)
@@ -64,7 +64,9 @@ class GpuVideoDecodeAcceleratorHost
                               const gfx::Size& dimensions,
                               uint32 texture_target);
   void OnDismissPictureBuffer(int32 picture_buffer_id);
-  void OnPictureReady(int32 picture_buffer_id, int32 bitstream_buffer_id);
+  void OnPictureReady(int32 picture_buffer_id,
+                      int32 bitstream_buffer_id,
+                      const gfx::Rect& visible_rect);
   void OnFlushDone();
   void OnResetDone();
   void OnNotifyError(uint32 error);
index 164052e..a91bd1f 100644 (file)
@@ -696,9 +696,10 @@ IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer,
                     int32) /* Picture buffer ID */
 
 // Decoder reports that a picture is ready.
-IPC_MESSAGE_ROUTED2(AcceleratedVideoDecoderHostMsg_PictureReady,
-                    int32,  /* Picture buffer ID */
-                    int32)  /* Bitstream buffer ID */
+IPC_MESSAGE_ROUTED3(AcceleratedVideoDecoderHostMsg_PictureReady,
+                    int32,     /* Picture buffer ID */
+                    int32,     /* Bitstream buffer ID */
+                    gfx::Rect) /* Visible rectangle */
 
 // Confirm decoder has been flushed.
 IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_FlushDone)
index b1de5b1..0eee641 100644 (file)
@@ -377,9 +377,10 @@ void AndroidVideoDecodeAccelerator::SendCurrentSurfaceToClient(
 
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
-      base::Bind(&AndroidVideoDecodeAccelerator::NotifyPictureReady,
-                 weak_this_factory_.GetWeakPtr(),
-                 media::Picture(picture_buffer_id, bitstream_id)));
+      base::Bind(
+          &AndroidVideoDecodeAccelerator::NotifyPictureReady,
+          weak_this_factory_.GetWeakPtr(),
+          media::Picture(picture_buffer_id, bitstream_id, gfx::Rect(size_))));
 }
 
 void AndroidVideoDecodeAccelerator::Decode(
index 2e667d0..3518f20 100644 (file)
@@ -557,12 +557,25 @@ void DXVAVideoDecodeAccelerator::ReusePictureBuffer(
   RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized),
       "Invalid state: " << state_, ILLEGAL_STATE,);
 
-  if (output_picture_buffers_.empty())
+  if (output_picture_buffers_.empty() && stale_output_picture_buffers_.empty())
     return;
 
   OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id);
-  RETURN_AND_NOTIFY_ON_FAILURE(it != output_picture_buffers_.end(),
-      "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,);
+  // If we didn't find the picture id in the |output_picture_buffers_| map we
+  // try the |stale_output_picture_buffers_| map, as this may have been an
+  // output picture buffer from before a resolution change, that at resolution
+  // change time had yet to be displayed. The client is calling us back to tell
+  // us that we can now recycle this picture buffer, so if we were waiting to
+  // dispose of it we now can.
+  if (it == output_picture_buffers_.end()) {
+    it = stale_output_picture_buffers_.find(picture_buffer_id);
+    RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(),
+        "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,);
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+        base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer,
+            weak_this_factory_.GetWeakPtr(), picture_buffer_id));
+    return;
+  }
 
   it->second->ReusePictureBuffer();
   ProcessPendingSamples();
@@ -943,7 +956,8 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() {
           PLATFORM_FAILURE, );
 
       media::Picture output_picture(index->second->id(),
-                                    sample_info.input_buffer_id);
+                                    sample_info.input_buffer_id,
+                                    gfx::Rect(index->second->size()));
       base::MessageLoop::current()->PostTask(
           FROM_HERE,
           base::Bind(&DXVAVideoDecodeAccelerator::NotifyPictureReady,
@@ -981,6 +995,7 @@ void DXVAVideoDecodeAccelerator::Invalidate() {
     return;
   weak_this_factory_.InvalidateWeakPtrs();
   output_picture_buffers_.clear();
+  stale_output_picture_buffers_.clear();
   pending_output_samples_.clear();
   pending_input_buffers_.clear();
   decoder_.Release();
@@ -1157,8 +1172,7 @@ void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width,
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
       base::Bind(&DXVAVideoDecodeAccelerator::DismissStaleBuffers,
-                 weak_this_factory_.GetWeakPtr(),
-                 output_picture_buffers_));
+                 weak_this_factory_.GetWeakPtr()));
 
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
@@ -1166,20 +1180,35 @@ void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width,
                  weak_this_factory_.GetWeakPtr(),
                  width,
                  height));
-
-  output_picture_buffers_.clear();
 }
 
-void DXVAVideoDecodeAccelerator::DismissStaleBuffers(
-    const OutputBuffers& picture_buffers) {
-  OutputBuffers::const_iterator index;
+void DXVAVideoDecodeAccelerator::DismissStaleBuffers() {
+  OutputBuffers::iterator index;
 
-  for (index = picture_buffers.begin();
-       index != picture_buffers.end();
+  for (index = output_picture_buffers_.begin();
+       index != output_picture_buffers_.end();
        ++index) {
-    DVLOG(1) << "Dismissing picture id: " << index->second->id();
-    client_->DismissPictureBuffer(index->second->id());
+    if (index->second->available()) {
+      DVLOG(1) << "Dismissing picture id: " << index->second->id();
+      client_->DismissPictureBuffer(index->second->id());
+    } else {
+      // Move to |stale_output_picture_buffers_| for deferred deletion.
+      stale_output_picture_buffers_.insert(
+          std::make_pair(index->first, index->second));
+    }
   }
+
+  output_picture_buffers_.clear();
+}
+
+void DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer(
+    int32 picture_buffer_id) {
+  OutputBuffers::iterator it = stale_output_picture_buffers_.find(
+      picture_buffer_id);
+  DCHECK(it != stale_output_picture_buffers_.end());
+  DVLOG(1) << "Dismissing picture id: " << it->second->id();
+  client_->DismissPictureBuffer(it->second->id());
+  stale_output_picture_buffers_.erase(it);
 }
 
 }  // namespace content
index 0b92551..65b148b 100644 (file)
@@ -151,7 +151,10 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator
   typedef std::map<int32, linked_ptr<DXVAPictureBuffer> > OutputBuffers;
 
   // Tells the client to dismiss the stale picture buffers passed in.
-  void DismissStaleBuffers(const OutputBuffers& picture_buffers);
+  void DismissStaleBuffers();
+
+  // Called after the client indicates we can recycle a stale picture buffer.
+  void DeferredDismissStaleBuffer(int32 picture_buffer_id);
 
   // To expose client callbacks from VideoDecodeAccelerator.
   media::VideoDecodeAccelerator::Client* client_;
@@ -196,6 +199,12 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator
   // The key is the picture buffer id.
   OutputBuffers output_picture_buffers_;
 
+  // After a resolution change there may be a few output buffers which have yet
+  // to be displayed so they cannot be dismissed immediately. We move them from
+  // |output_picture_buffers_| to this map so they may be dismissed once they
+  // become available.
+  OutputBuffers stale_output_picture_buffers_;
+
   // Set to true if we requested picture slots from the client.
   bool pictures_requested_;
 
index 6ce9330..c1cd553 100644 (file)
@@ -212,7 +212,8 @@ void GpuVideoDecodeAccelerator::PictureReady(
   if (!Send(new AcceleratedVideoDecoderHostMsg_PictureReady(
           host_route_id_,
           picture.picture_buffer_id(),
-          picture.bitstream_buffer_id()))) {
+          picture.bitstream_buffer_id(),
+          picture.visible_rect()))) {
     DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_PictureReady) failed";
   }
 }
index 7ee9401..ce2f94b 100644 (file)
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "base/message_loop/message_loop.h"
@@ -60,6 +61,25 @@ RenderingHelperParams::RenderingHelperParams() {}
 
 RenderingHelperParams::~RenderingHelperParams() {}
 
+VideoFrameTexture::VideoFrameTexture(uint32 texture_target,
+                                     uint32 texture_id,
+                                     const base::Closure& no_longer_needed_cb)
+    : texture_target_(texture_target),
+      texture_id_(texture_id),
+      no_longer_needed_cb_(no_longer_needed_cb) {
+  DCHECK(!no_longer_needed_cb_.is_null());
+}
+
+VideoFrameTexture::~VideoFrameTexture() {
+  base::ResetAndReturn(&no_longer_needed_cb_).Run();
+}
+
+RenderingHelper::RenderedVideo::RenderedVideo() : last_frame_rendered(false) {
+}
+
+RenderingHelper::RenderedVideo::~RenderedVideo() {
+}
+
 // static
 bool RenderingHelper::InitializeOneOff() {
   base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
@@ -78,15 +98,15 @@ RenderingHelper::RenderingHelper() {
 }
 
 RenderingHelper::~RenderingHelper() {
-  CHECK_EQ(clients_.size(), 0U) << "Must call UnInitialize before dtor.";
+  CHECK_EQ(videos_.size(), 0U) << "Must call UnInitialize before dtor.";
   Clear();
 }
 
 void RenderingHelper::Initialize(const RenderingHelperParams& params,
                                  base::WaitableEvent* done) {
-  // Use cients_.size() != 0 as a proxy for the class having already been
+  // Use videos_.size() != 0 as a proxy for the class having already been
   // Initialize()'d, and UnInitialize() before continuing.
-  if (clients_.size()) {
+  if (videos_.size()) {
     base::WaitableEvent done(false, false);
     UnInitialize(&done);
     done.Wait();
@@ -153,12 +173,12 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params,
       NULL, gl_surface_, gfx::PreferIntegratedGpu);
   gl_context_->MakeCurrent(gl_surface_);
 
-  clients_ = params.clients;
-  CHECK_GT(clients_.size(), 0U);
-  LayoutRenderingAreas();
+  CHECK_GT(params.window_sizes.size(), 0U);
+  videos_.resize(params.window_sizes.size());
+  LayoutRenderingAreas(params.window_sizes);
 
   if (render_as_thumbnails_) {
-    CHECK_EQ(clients_.size(), 1U);
+    CHECK_EQ(videos_.size(), 1U);
 
     GLint max_texture_size;
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
@@ -370,6 +390,31 @@ void RenderingHelper::RenderThumbnail(uint32 texture_target,
   ++frame_count_;
 }
 
+void RenderingHelper::QueueVideoFrame(
+    size_t window_id,
+    scoped_refptr<VideoFrameTexture> video_frame) {
+  CHECK_EQ(base::MessageLoop::current(), message_loop_);
+  RenderedVideo* video = &videos_[window_id];
+
+  // Pop the last frame if it has been rendered.
+  if (video->last_frame_rendered) {
+    // When last_frame_rendered is true, we should have only one pending frame.
+    // Since we are going to have a new frame, we can release the pending one.
+    DCHECK(video->pending_frames.size() == 1);
+    video->pending_frames.pop();
+    video->last_frame_rendered = false;
+  }
+
+  video->pending_frames.push(video_frame);
+}
+
+void RenderingHelper::DropPendingFrames(size_t window_id) {
+  CHECK_EQ(base::MessageLoop::current(), message_loop_);
+  RenderedVideo* video = &videos_[window_id];
+  video->pending_frames = std::queue<scoped_refptr<VideoFrameTexture> >();
+  video->last_frame_rendered = false;
+}
+
 void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) {
   // The ExternalOES sampler is bound to GL_TEXTURE1 and the Texture2D sampler
   // is bound to GL_TEXTURE0.
@@ -385,6 +430,7 @@ void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) {
 }
 
 void RenderingHelper::DeleteTexture(uint32 texture_id) {
+  CHECK_EQ(base::MessageLoop::current(), message_loop_);
   glDeleteTextures(1, &texture_id);
   CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
 }
@@ -398,7 +444,7 @@ void* RenderingHelper::GetGLDisplay() {
 }
 
 void RenderingHelper::Clear() {
-  clients_.clear();
+  videos_.clear();
   message_loop_ = NULL;
   gl_context_ = NULL;
   gl_surface_ = NULL;
@@ -461,16 +507,30 @@ void RenderingHelper::RenderContent() {
   CHECK_EQ(base::MessageLoop::current(), message_loop_);
   glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1);
 
+  // Frames that will be returned to the client (via the no_longer_needed_cb)
+  // after this vector falls out of scope at the end of this method. We need
+  // to keep references to them until after SwapBuffers() call below.
+  std::vector<scoped_refptr<VideoFrameTexture> > frames_to_be_returned;
+
   if (render_as_thumbnails_) {
     // In render_as_thumbnails_ mode, we render the FBO content on the
     // screen instead of the decoded textures.
-    GLSetViewPort(render_areas_[0]);
+    GLSetViewPort(videos_[0].render_area);
     RenderTexture(GL_TEXTURE_2D, thumbnails_texture_id_);
   } else {
-    for (size_t i = 0; i < clients_.size(); ++i) {
-      if (clients_[i]) {
-        GLSetViewPort(render_areas_[i]);
-        clients_[i]->RenderContent(this);
+    for (size_t i = 0; i < videos_.size(); ++i) {
+      RenderedVideo* video = &videos_[i];
+      if (video->pending_frames.empty())
+        continue;
+      scoped_refptr<VideoFrameTexture> frame = video->pending_frames.front();
+      GLSetViewPort(video->render_area);
+      RenderTexture(frame->texture_target(), frame->texture_id());
+
+      if (video->pending_frames.size() > 1) {
+        frames_to_be_returned.push_back(video->pending_frames.front());
+        video->pending_frames.pop();
+      } else {
+        video->last_frame_rendered = true;
       }
     }
   }
@@ -492,11 +552,12 @@ static void ScaleAndCalculateOffsets(std::vector<int>* lengths,
   }
 }
 
-void RenderingHelper::LayoutRenderingAreas() {
+void RenderingHelper::LayoutRenderingAreas(
+    const std::vector<gfx::Size>& window_sizes) {
   // Find the number of colums and rows.
-  // The smallest n * n or n * (n + 1) > number of clients.
-  size_t cols = sqrt(clients_.size() - 1) + 1;
-  size_t rows = (clients_.size() + cols - 1) / cols;
+  // The smallest n * n or n * (n + 1) > number of windows.
+  size_t cols = sqrt(videos_.size() - 1) + 1;
+  size_t rows = (videos_.size() + cols - 1) / cols;
 
   // Find the widths and heights of the grid.
   std::vector<int> widths(cols);
@@ -504,31 +565,30 @@ void RenderingHelper::LayoutRenderingAreas() {
   std::vector<int> offset_x(cols);
   std::vector<int> offset_y(rows);
 
-  for (size_t i = 0; i < clients_.size(); ++i) {
-    const gfx::Size& window_size = clients_[i]->GetWindowSize();
-    widths[i % cols] = std::max(widths[i % cols], window_size.width());
-    heights[i / cols] = std::max(heights[i / cols], window_size.height());
+  for (size_t i = 0; i < window_sizes.size(); ++i) {
+    const gfx::Size& size = window_sizes[i];
+    widths[i % cols] = std::max(widths[i % cols], size.width());
+    heights[i / cols] = std::max(heights[i / cols], size.height());
   }
 
   ScaleAndCalculateOffsets(&widths, &offset_x, screen_size_.width());
   ScaleAndCalculateOffsets(&heights, &offset_y, screen_size_.height());
 
   // Put each render_area_ in the center of each cell.
-  render_areas_.clear();
-  for (size_t i = 0; i < clients_.size(); ++i) {
-    const gfx::Size& window_size = clients_[i]->GetWindowSize();
+  for (size_t i = 0; i < window_sizes.size(); ++i) {
+    const gfx::Size& size = window_sizes[i];
     float scale =
-        std::min(static_cast<float>(widths[i % cols]) / window_size.width(),
-                 static_cast<float>(heights[i / cols]) / window_size.height());
+        std::min(static_cast<float>(widths[i % cols]) / size.width(),
+                 static_cast<float>(heights[i / cols]) / size.height());
 
     // Don't scale up the texture.
     scale = std::min(1.0f, scale);
 
-    size_t w = scale * window_size.width();
-    size_t h = scale * window_size.height();
+    size_t w = scale * size.width();
+    size_t h = scale * size.height();
     size_t x = offset_x[i % cols] + (widths[i % cols] - w) / 2;
     size_t y = offset_y[i / cols] + (heights[i / cols] - h) / 2;
-    render_areas_.push_back(gfx::Rect(x, y, w, h));
+    videos_[i].render_area = gfx::Rect(x, y, w, h);
   }
 }
 }  // namespace content
index a2dfb1b..6b0013f 100644 (file)
@@ -6,6 +6,7 @@
 #define CONTENT_COMMON_GPU_MEDIA_RENDERING_HELPER_H_
 
 #include <map>
+#include <queue>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -24,25 +25,53 @@ class WaitableEvent;
 
 namespace content {
 
-struct RenderingHelperParams;
+class VideoFrameTexture : public base::RefCounted<VideoFrameTexture> {
+ public:
+  uint32 texture_id() const { return texture_id_; }
+  uint32 texture_target() const { return texture_target_; }
+
+  VideoFrameTexture(uint32 texture_target,
+                    uint32 texture_id,
+                    const base::Closure& no_longer_needed_cb);
+
+ private:
+  friend class base::RefCounted<VideoFrameTexture>;
+
+  uint32 texture_target_;
+  uint32 texture_id_;
+  base::Closure no_longer_needed_cb_;
+
+  ~VideoFrameTexture();
+};
+
+struct RenderingHelperParams {
+  RenderingHelperParams();
+  ~RenderingHelperParams();
+
+  // The rendering FPS.
+  int rendering_fps;
+
+  // The desired size of each window. We play each stream in its own window
+  // on the screen.
+  std::vector<gfx::Size> window_sizes;
+
+  // The members below are only used for the thumbnail mode where all frames
+  // are rendered in sequence onto one FBO for comparison/verification purposes.
+
+  // Whether the frames are rendered as scaled thumbnails within a
+  // larger FBO that is in turn rendered to the window.
+  bool render_as_thumbnails;
+  // The size of the FBO containing all visible thumbnails.
+  gfx::Size thumbnails_page_size;
+  // The size of each thumbnail within the FBO.
+  gfx::Size thumbnail_size;
+};
 
 // Creates and draws textures used by the video decoder.
 // This class is not thread safe and thus all the methods of this class
 // (except for ctor/dtor) ensure they're being run on a single thread.
 class RenderingHelper {
  public:
-  // Interface for the content provider of the RenderingHelper.
-  class Client {
-   public:
-    // Callback to tell client to render the content.
-    virtual void RenderContent(RenderingHelper* helper) = 0;
-
-    // Callback to get the desired window size of the client.
-    virtual const gfx::Size& GetWindowSize() = 0;
-
-   protected:
-    virtual ~Client() {}
-  };
 
   RenderingHelper();
   ~RenderingHelper();
@@ -67,9 +96,12 @@ class RenderingHelper {
   // |texture_target|.
   void RenderThumbnail(uint32 texture_target, uint32 texture_id);
 
-  // Render |texture_id| to the current view port of the screen using target
-  // |texture_target|.
-  void RenderTexture(uint32 texture_target, uint32 texture_id);
+  // Queues the |video_frame| for rendering.
+  void QueueVideoFrame(size_t window_id,
+                       scoped_refptr<VideoFrameTexture> video_frame);
+
+  // Drops all the pending video frames of the specified window.
+  void DropPendingFrames(size_t window_id);
 
   // Delete |texture_id|.
   void DeleteTexture(uint32 texture_id);
@@ -87,11 +119,33 @@ class RenderingHelper {
                           base::WaitableEvent* done);
 
  private:
+  struct RenderedVideo {
+    // The rect on the screen where the video will be rendered.
+    gfx::Rect render_area;
+
+    // True if the last (and the only one) frame in pending_frames has
+    // been rendered. We keep the last remaining frame in pending_frames even
+    // after it has been rendered, so that we have something to display if the
+    // client is falling behind on providing us with new frames during
+    // timer-driven playback.
+    bool last_frame_rendered;
+
+    // The video frames pending for rendering.
+    std::queue<scoped_refptr<VideoFrameTexture> > pending_frames;
+
+    RenderedVideo();
+    ~RenderedVideo();
+  };
+
   void Clear();
 
   void RenderContent();
 
-  void LayoutRenderingAreas();
+  void LayoutRenderingAreas(const std::vector<gfx::Size>& window_sizes);
+
+  // Render |texture_id| to the current view port of the screen using target
+  // |texture_target|.
+  void RenderTexture(uint32 texture_target, uint32 texture_id);
 
   // Timer to trigger the RenderContent() repeatly.
   scoped_ptr<base::RepeatingTimer<RenderingHelper> > render_timer_;
@@ -104,10 +158,7 @@ class RenderingHelper {
 
   gfx::Size screen_size_;
 
-  // The rendering area of each window on the screen.
-  std::vector<gfx::Rect> render_areas_;
-
-  std::vector<base::WeakPtr<Client> > clients_;
+  std::vector<RenderedVideo> videos_;
 
   bool render_as_thumbnails_;
   int frame_count_;
@@ -121,24 +172,6 @@ class RenderingHelper {
   DISALLOW_COPY_AND_ASSIGN(RenderingHelper);
 };
 
-struct RenderingHelperParams {
-  RenderingHelperParams();
-  ~RenderingHelperParams();
-
-  // The rendering FPS.
-  int rendering_fps;
-
-  // The clients who provide the content for rendering.
-  std::vector<base::WeakPtr<RenderingHelper::Client> > clients;
-
-  // Whether the frames are rendered as scaled thumbnails within a
-  // larger FBO that is in turn rendered to the window.
-  bool render_as_thumbnails;
-  // The size of the FBO containing all visible thumbnails.
-  gfx::Size thumbnails_page_size;
-  // The size of each thumbnail within the FBO.
-  gfx::Size thumbnail_size;
-};
 }  // namespace content
 
 #endif  // CONTENT_COMMON_GPU_MEDIA_RENDERING_HELPER_H_
index 315b2f5..cea1c7b 100644 (file)
@@ -1092,7 +1092,9 @@ void V4L2VideoDecodeAccelerator::Dequeue() {
       DVLOG(3) << "Dequeue(): returning input_id=" << dqbuf.timestamp.tv_sec
                << " as picture_id=" << output_record.picture_id;
       const media::Picture& picture =
-          media::Picture(output_record.picture_id, dqbuf.timestamp.tv_sec);
+          media::Picture(output_record.picture_id,
+                         dqbuf.timestamp.tv_sec,
+                         gfx::Rect(frame_buffer_size_));
       pending_picture_ready_.push(
           PictureRecord(output_record.cleared, picture));
       SendPictureReady();
index afcfc8a..0b30012 100644 (file)
@@ -371,8 +371,11 @@ void VaapiVideoDecodeAccelerator::OutputPicture(
   TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
   DVLOG(4) << "Notifying output picture id " << output_id
            << " for input "<< input_id << " is ready";
+  // TODO(posciak): Use visible size from decoder here instead
+  // (crbug.com/402760).
   if (client_)
-    client_->PictureReady(media::Picture(output_id, input_id));
+    client_->PictureReady(
+        media::Picture(output_id, input_id, gfx::Rect(tfp_picture->size())));
 }
 
 void VaapiVideoDecodeAccelerator::TryOutputSurface() {
index 071dced..65cc939 100644 (file)
@@ -193,9 +193,10 @@ enum ClientState {
 // the TESTs below.
 class GLRenderingVDAClient
     : public VideoDecodeAccelerator::Client,
-      public RenderingHelper::Client,
       public base::SupportsWeakPtr<GLRenderingVDAClient> {
  public:
+  // |window_id| the window_id of the client, which is used to identify the
+  // rendering area in the |rendering_helper|.
   // Doesn't take ownership of |rendering_helper| or |note|, which must outlive
   // |*this|.
   // |num_play_throughs| indicates how many times to play through the video.
@@ -212,7 +213,8 @@ class GLRenderingVDAClient
   // will start delaying the call to ReusePictureBuffer() for kReuseDelay.
   // |decode_calls_per_second| is the number of VDA::Decode calls per second.
   // If |decode_calls_per_second| > 0, |num_in_flight_decodes| must be 1.
-  GLRenderingVDAClient(RenderingHelper* rendering_helper,
+  GLRenderingVDAClient(size_t window_id,
+                       RenderingHelper* rendering_helper,
                        ClientStateNotification<ClientState>* note,
                        const std::string& encoded_data,
                        int num_in_flight_decodes,
@@ -242,14 +244,8 @@ class GLRenderingVDAClient
   virtual void NotifyResetDone() OVERRIDE;
   virtual void NotifyError(VideoDecodeAccelerator::Error error) OVERRIDE;
 
-  // RenderingHelper::Client implementation.
-  virtual void RenderContent(RenderingHelper*) OVERRIDE;
-  virtual const gfx::Size& GetWindowSize() OVERRIDE;
-
   void OutputFrameDeliveryTimes(base::File* output);
 
-  void NotifyFrameDropped(int32 picture_buffer_id);
-
   // Simple getters for inspecting the state of the Client.
   int num_done_bitstream_buffers() { return num_done_bitstream_buffers_; }
   int num_skipped_fragments() { return num_skipped_fragments_; }
@@ -285,6 +281,7 @@ class GLRenderingVDAClient
   // Request decode of the next fragment in the encoded data.
   void DecodeNextFragment();
 
+  size_t window_id_;
   RenderingHelper* rendering_helper_;
   gfx::Size frame_size_;
   std::string encoded_data_;
@@ -319,13 +316,12 @@ class GLRenderingVDAClient
   // The number of VDA::Decode calls per second. This is to simulate webrtc.
   int decode_calls_per_second_;
   bool render_as_thumbnails_;
-  bool pending_picture_updated_;
-  std::deque<int32> pending_picture_buffer_ids_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(GLRenderingVDAClient);
 };
 
 GLRenderingVDAClient::GLRenderingVDAClient(
+    size_t window_id,
     RenderingHelper* rendering_helper,
     ClientStateNotification<ClientState>* note,
     const std::string& encoded_data,
@@ -340,7 +336,8 @@ GLRenderingVDAClient::GLRenderingVDAClient(
     int delay_reuse_after_frame_num,
     int decode_calls_per_second,
     bool render_as_thumbnails)
-    : rendering_helper_(rendering_helper),
+    : window_id_(window_id),
+      rendering_helper_(rendering_helper),
       frame_size_(frame_width, frame_height),
       encoded_data_(encoded_data),
       num_in_flight_decodes_(num_in_flight_decodes),
@@ -360,8 +357,7 @@ GLRenderingVDAClient::GLRenderingVDAClient(
       suppress_rendering_(suppress_rendering),
       delay_reuse_after_frame_num_(delay_reuse_after_frame_num),
       decode_calls_per_second_(decode_calls_per_second),
-      render_as_thumbnails_(render_as_thumbnails),
-      pending_picture_updated_(true) {
+      render_as_thumbnails_(render_as_thumbnails) {
   CHECK_GT(num_in_flight_decodes, 0);
   CHECK_GT(num_play_throughs, 0);
   // |num_in_flight_decodes_| is unsupported if |decode_calls_per_second_| > 0.
@@ -459,42 +455,6 @@ void GLRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) {
   picture_buffers_by_id_.erase(it);
 }
 
-void GLRenderingVDAClient::RenderContent(RenderingHelper*) {
-  CHECK(!render_as_thumbnails_);
-
-  // No decoded texture for rendering yet, just skip.
-  if (pending_picture_buffer_ids_.size() == 0)
-    return;
-
-  int32 buffer_id = pending_picture_buffer_ids_.front();
-  media::PictureBuffer* picture_buffer = picture_buffers_by_id_[buffer_id];
-
-  CHECK(picture_buffer);
-  if (!pending_picture_updated_) {
-    // Frame dropped, just redraw the last texture.
-    rendering_helper_->RenderTexture(texture_target_,
-                                     picture_buffer->texture_id());
-    return;
-  }
-
-  base::TimeTicks now = base::TimeTicks::Now();
-  frame_delivery_times_.push_back(now);
-
-  rendering_helper_->RenderTexture(texture_target_,
-                                   picture_buffer->texture_id());
-
-  if (pending_picture_buffer_ids_.size() == 1) {
-    pending_picture_updated_ = false;
-  } else {
-    pending_picture_buffer_ids_.pop_front();
-    ReturnPicture(buffer_id);
-  }
-}
-
-const gfx::Size& GLRenderingVDAClient::GetWindowSize() {
-  return render_as_thumbnails_ ? kThumbnailsPageSize : frame_size_;
-}
-
 void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
   // We shouldn't be getting pictures delivered after Reset has completed.
   CHECK_LT(state_, CS_RESET);
@@ -503,6 +463,9 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
     return;
 
   base::TimeTicks now = base::TimeTicks::Now();
+
+  frame_delivery_times_.push_back(now);
+
   // Save the decode time of this picture.
   std::map<int, base::TimeTicks>::iterator it =
       decode_start_time_.find(picture.bitstream_buffer_id());
@@ -524,25 +487,22 @@ void GLRenderingVDAClient::PictureReady(const media::Picture& picture) {
     encoded_data_next_pos_to_decode_ = 0;
   }
 
+  media::PictureBuffer* picture_buffer =
+      picture_buffers_by_id_[picture.picture_buffer_id()];
+  CHECK(picture_buffer);
+
+  scoped_refptr<VideoFrameTexture> video_frame =
+      new VideoFrameTexture(texture_target_,
+                            picture_buffer->texture_id(),
+                            base::Bind(&GLRenderingVDAClient::ReturnPicture,
+                                       AsWeakPtr(),
+                                       picture.picture_buffer_id()));
+
   if (render_as_thumbnails_) {
-    frame_delivery_times_.push_back(now);
-    media::PictureBuffer* picture_buffer =
-        picture_buffers_by_id_[picture.picture_buffer_id()];
-    CHECK(picture_buffer);
-    rendering_helper_->RenderThumbnail(texture_target_,
-                                       picture_buffer->texture_id());
-    ReturnPicture(picture.picture_buffer_id());
+    rendering_helper_->RenderThumbnail(video_frame->texture_target(),
+                                       video_frame->texture_id());
   } else if (!suppress_rendering_) {
-    // Keep the picture for rendering.
-    pending_picture_buffer_ids_.push_back(picture.picture_buffer_id());
-    if (pending_picture_buffer_ids_.size() > 1 && !pending_picture_updated_) {
-      ReturnPicture(pending_picture_buffer_ids_.front());
-      pending_picture_buffer_ids_.pop_front();
-      pending_picture_updated_ = true;
-    }
-  } else {
-    frame_delivery_times_.push_back(now);
-    ReturnPicture(picture.picture_buffer_id());
+    rendering_helper_->QueueVideoFrame(window_id_, video_frame);
   }
 }
 
@@ -590,12 +550,7 @@ void GLRenderingVDAClient::NotifyResetDone() {
   if (decoder_deleted())
     return;
 
-  // Clear pending_pictures and reuse them.
-  while (!pending_picture_buffer_ids_.empty()) {
-    decoder_->ReusePictureBuffer(pending_picture_buffer_ids_.front());
-    pending_picture_buffer_ids_.pop_front();
-  }
-  pending_picture_updated_ = true;
+  rendering_helper_->DropPendingFrames(window_id_);
 
   if (reset_after_frame_num_ == MID_STREAM_RESET) {
     reset_after_frame_num_ = END_OF_STREAM_RESET;
@@ -637,10 +592,6 @@ void GLRenderingVDAClient::OutputFrameDeliveryTimes(base::File* output) {
   }
 }
 
-void GLRenderingVDAClient::NotifyFrameDropped(int32 picture_buffer_id) {
-  decoder_->ReusePictureBuffer(picture_buffer_id);
-}
-
 static bool LookingAtNAL(const std::string& encoded, size_t pos) {
   return encoded[pos] == 0 && encoded[pos + 1] == 0 &&
       encoded[pos + 2] == 0 && encoded[pos + 3] == 1;
@@ -1127,7 +1078,8 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
     }
 
     GLRenderingVDAClient* client =
-        new GLRenderingVDAClient(&rendering_helper_,
+        new GLRenderingVDAClient(index,
+                                 &rendering_helper_,
                                  note,
                                  video_file->data_str,
                                  num_in_flight_decodes,
@@ -1143,7 +1095,10 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
                                  render_as_thumbnails);
 
     clients[index] = client;
-    helper_params.clients.push_back(client->AsWeakPtr());
+    helper_params.window_sizes.push_back(
+        render_as_thumbnails
+            ? kThumbnailsPageSize
+            : gfx::Size(video_file->width, video_file->height));
   }
 
   InitializeRenderingHelper(helper_params);
@@ -1376,7 +1331,8 @@ TEST_F(VideoDecodeAcceleratorTest, TestDecodeTimeMedian) {
   ClientStateNotification<ClientState>* note =
       new ClientStateNotification<ClientState>();
   GLRenderingVDAClient* client =
-      new GLRenderingVDAClient(&rendering_helper_,
+      new GLRenderingVDAClient(0,
+                               &rendering_helper_,
                                note,
                                test_video_files_[0]->data_str,
                                1,
@@ -1390,7 +1346,8 @@ TEST_F(VideoDecodeAcceleratorTest, TestDecodeTimeMedian) {
                                std::numeric_limits<int>::max(),
                                kWebRtcDecodeCallsPerSecond,
                                false /* render_as_thumbnail */);
-  helper_params.clients.push_back(client->AsWeakPtr());
+  helper_params.window_sizes.push_back(
+      gfx::Size(test_video_files_[0]->width, test_video_files_[0]->height));
   InitializeRenderingHelper(helper_params);
   CreateAndStartDecoder(client, note);
   WaitUntilDecodeFinish(note);
index 5b91650..8e4c408 100644 (file)
@@ -376,7 +376,8 @@ void VTVideoDecodeAccelerator::SendPictures() {
         0));                          // plane
 
     picture_bindings_[picture_id] = frame.image_buffer;
-    client_->PictureReady(media::Picture(picture_id, frame.bitstream_id));
+    client_->PictureReady(media::Picture(
+        picture_id, frame.bitstream_id, gfx::Rect(texture_size_)));
     client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
   }
 
index aed113e..8488038 100644 (file)
@@ -297,6 +297,12 @@ public class ContentViewCore
     // Accessibility touch exploration state.
     private boolean mTouchExplorationEnabled;
 
+    // Whether accessibility focus should be set to the page when it finishes loading.
+    // This only applies if an accessibility service like TalkBack is running.
+    // This is desirable behavior for a browser window, but not for an embedded
+    // WebView.
+    private boolean mShouldSetAccessibilityFocusOnPageLoad;
+
     // Allows us to dynamically respond when the accessibility script injection flag changes.
     private ContentObserver mAccessibilityScriptInjectionObserver;
 
@@ -441,6 +447,11 @@ public class ContentViewCore
             @SuppressWarnings("deprecation")  // AbsoluteLayout
             public void setAnchorViewPosition(
                     View view, float x, float y, float width, float height) {
+                if (view.getParent() == null) {
+                    // Ignore. setAnchorViewPosition has been called after the anchor view has
+                    // already been released.
+                    return;
+                }
                 assert view.getParent() == mContainerViewAtCreation;
 
                 float scale = (float) DeviceDisplayInfo.create(mContext).getDIPScale();
@@ -2406,12 +2417,21 @@ public class ContentViewCore
 
     @SuppressWarnings("unused")
     @CalledByNative
-    private void showPastePopup(int xDip, int yDip) {
-        if (!mHasInsertion || !canPaste()) return;
+    private void showPastePopupWithFeedback(int xDip, int yDip) {
+        // TODO(jdduke): Remove this when there is a better signal that long press caused
+        // showing of the paste popup. See http://crbug.com/150151.
+        if (showPastePopup(xDip, yDip)) {
+            mContainerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+        }
+    }
+
+    private boolean showPastePopup(int xDip, int yDip) {
+        if (!mHasInsertion || !canPaste()) return false;
         final float contentOffsetYPix = mRenderCoordinates.getContentOffsetYPix();
         getPastePopup().showAt(
             (int) mRenderCoordinates.fromDipToPix(xDip),
             (int) (mRenderCoordinates.fromDipToPix(yDip) + contentOffsetYPix));
+        return true;
     }
 
     private PastePopupMenu getPastePopup() {
@@ -2884,6 +2904,23 @@ public class ContentViewCore
     }
 
     /**
+     * Return whether or not we should set accessibility focus on page load.
+     */
+    public boolean shouldSetAccessibilityFocusOnPageLoad() {
+        return mShouldSetAccessibilityFocusOnPageLoad;
+    }
+
+    /**
+     * Return whether or not we should set accessibility focus on page load.
+     * This only applies if an accessibility service like TalkBack is running.
+     * This is desirable behavior for a browser window, but not for an embedded
+     * WebView.
+     */
+    public void setShouldSetAccessibilityFocusOnPageLoad(boolean on) {
+        mShouldSetAccessibilityFocusOnPageLoad = on;
+    }
+
+    /**
      * Inform WebKit that Fullscreen mode has been exited by the user.
      */
     public void exitFullscreen() {
index be8e525..66950c2 100644 (file)
@@ -273,6 +273,15 @@ public class ContentViewRenderView extends FrameLayout {
     }
 
     /**
+     * Trigger a redraw of the compositor.  This is only needed if the UI changes something that
+     * does not trigger a redraw itself by updating the layer tree.
+     */
+    public void setNeedsComposite() {
+        if (mNativeContentViewRenderView == 0) return;
+        nativeSetNeedsComposite(mNativeContentViewRenderView);
+    }
+
+    /**
      * This method should be subclassed to provide actions to be performed once the view is ready to
      * render.
      */
@@ -351,7 +360,15 @@ public class ContentViewRenderView extends FrameLayout {
         }
     }
 
+    /**
+     * @return Native pointer for the UI resource provider taken from the compositor.
+     */
+    public long getUIResourceProvider() {
+        return nativeGetUIResourceProvider(mNativeContentViewRenderView);
+    }
+
     private native long nativeInit(long rootWindowNativePointer);
+    private native long nativeGetUIResourceProvider(long nativeContentViewRenderView);
     private native void nativeDestroy(long nativeContentViewRenderView);
     private native void nativeSetCurrentContentViewCore(long nativeContentViewRenderView,
             long nativeContentViewCore);
@@ -363,4 +380,5 @@ public class ContentViewRenderView extends FrameLayout {
             int format, int width, int height, Surface surface);
     private native void nativeSetOverlayVideoMode(long nativeContentViewRenderView,
             boolean enabled);
+    private native void nativeSetNeedsComposite(long nativeContentViewRenderView);
 }
index 3b75d1f..c8f0e1a 100644 (file)
@@ -60,14 +60,15 @@ public class ResourceExtractor {
 
         @Override
         protected Void doInBackground(Void... unused) {
-            if (!mOutputDir.exists() && !mOutputDir.mkdirs()) {
+            final File outputDir = getOutputDir();
+            if (!outputDir.exists() && !outputDir.mkdirs()) {
                 Log.e(LOGTAG, "Unable to create pak resources directory!");
                 return null;
             }
 
-            String timestampFile = checkPakTimestamp();
+            String timestampFile = checkPakTimestamp(outputDir);
             if (timestampFile != null) {
-                deleteFiles(mContext);
+                deleteFiles();
             }
 
             SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
@@ -81,7 +82,7 @@ public class ResourceExtractor {
                     &&  filenames.size() >= sMandatoryPaks.length) {
                 boolean filesPresent = true;
                 for (String file : filenames) {
-                    if (!new File(mOutputDir, file).exists()) {
+                    if (!new File(outputDir, file).exists()) {
                         filesPresent = false;
                         break;
                     }
@@ -132,7 +133,7 @@ public class ResourceExtractor {
                         continue;
                     }
                     boolean isICUData = file.equals(ICU_DATA_FILENAME);
-                    File output = new File(isICUData ? mAppDataDir : mOutputDir, file);
+                    File output = new File(isICUData ? getAppDataDir() : outputDir, file);
                     if (output.exists()) {
                         continue;
                     }
@@ -185,7 +186,7 @@ public class ResourceExtractor {
                 // returning null? It might be useful to gather UMA here too to track if
                 // this happens with regularity.
                 Log.w(LOGTAG, "Exception unpacking required pak resources: " + e.getMessage());
-                deleteFiles(mContext);
+                deleteFiles();
                 return null;
             }
 
@@ -193,7 +194,7 @@ public class ResourceExtractor {
 
             if (timestampFile != null) {
                 try {
-                    new File(mOutputDir, timestampFile).createNewFile();
+                    new File(outputDir, timestampFile).createNewFile();
                 } catch (IOException e) {
                     // Worst case we don't write a timestamp, so we'll re-extract the resource
                     // paks next start up.
@@ -213,7 +214,7 @@ public class ResourceExtractor {
         // Note that we do this to avoid adding a BroadcastReceiver on
         // android.content.Intent#ACTION_PACKAGE_CHANGED as that causes process churn
         // on (re)installation of *all* APK files.
-        private String checkPakTimestamp() {
+        private String checkPakTimestamp(File outputDir) {
             final String TIMESTAMP_PREFIX = "pak_timestamp-";
             PackageManager pm = mContext.getPackageManager();
             PackageInfo pi = null;
@@ -230,7 +231,7 @@ public class ResourceExtractor {
 
             String expectedTimestamp = TIMESTAMP_PREFIX + pi.versionCode + "-" + pi.lastUpdateTime;
 
-            String[] timestamps = mOutputDir.list(new FilenameFilter() {
+            String[] timestamps = outputDir.list(new FilenameFilter() {
                 @Override
                 public boolean accept(File dir, String name) {
                     return name.startsWith(TIMESTAMP_PREFIX);
@@ -254,8 +255,6 @@ public class ResourceExtractor {
 
     private final Context mContext;
     private ExtractTask mExtractTask;
-    private final File mAppDataDir;
-    private final File mOutputDir;
 
     private static ResourceExtractor sInstance;
 
@@ -307,9 +306,7 @@ public class ResourceExtractor {
     }
 
     private ResourceExtractor(Context context) {
-        mContext = context;
-        mAppDataDir = getAppDataDirFromContext(mContext);
-        mOutputDir = getOutputDirFromContext(mContext);
+        mContext = context.getApplicationContext();
     }
 
     public void waitForCompletion() {
@@ -327,11 +324,11 @@ public class ResourceExtractor {
             sInstance = null;
         } catch (CancellationException e) {
             // Don't leave the files in an inconsistent state.
-            deleteFiles(mContext);
+            deleteFiles();
         } catch (ExecutionException e2) {
-            deleteFiles(mContext);
+            deleteFiles();
         } catch (InterruptedException e3) {
-            deleteFiles(mContext);
+            deleteFiles();
         }
     }
 
@@ -353,12 +350,12 @@ public class ResourceExtractor {
         mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
-    public static File getAppDataDirFromContext(Context context) {
-        return new File(PathUtils.getDataDirectory(context.getApplicationContext()));
+    private File getAppDataDir() {
+        return new File(PathUtils.getDataDirectory(mContext));
     }
 
-    public static File getOutputDirFromContext(Context context) {
-        return new File(getAppDataDirFromContext(context), "paks");
+    private File getOutputDir() {
+        return new File(getAppDataDir(), "paks");
     }
 
     /**
@@ -368,12 +365,12 @@ public class ResourceExtractor {
      * lead to malfunction/UX misbehavior. So, we regard failing to update them
      * as an error.
      */
-    public static void deleteFiles(Context context) {
-        File icudata = new File(getAppDataDirFromContext(context), ICU_DATA_FILENAME);
+    private void deleteFiles() {
+        File icudata = new File(getAppDataDir(), ICU_DATA_FILENAME);
         if (icudata.exists() && !icudata.delete()) {
             Log.e(LOGTAG, "Unable to remove the icudata " + icudata.getName());
         }
-        File dir = getOutputDirFromContext(context);
+        File dir = getOutputDir();
         if (dir.exists()) {
             File[] files = dir.listFiles();
             for (File file : files) {
index 6f47233..8ba9800 100644 (file)
@@ -370,8 +370,10 @@ public class BrowserAccessibilityManager {
     private void handlePageLoaded(int id) {
         if (mUserHasTouchExplored) return;
 
-        mAccessibilityFocusId = id;
-        sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+        if (mContentViewCore.shouldSetAccessibilityFocusOnPageLoad()) {
+            mAccessibilityFocusId = id;
+            sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+        }
     }
 
     @CalledByNative
index c2cffa9..bfafff0 100644 (file)
@@ -85,6 +85,11 @@ import org.chromium.content_public.browser.WebContents;
     }
 
     @Override
+    public void releaseMediaPlayers() {
+        nativeReleaseMediaPlayers(mNativeWebContentsAndroid);
+    }
+
+    @Override
     public int getBackgroundColor() {
         return nativeGetBackgroundColor(mNativeWebContentsAndroid);
     }
@@ -229,6 +234,7 @@ import org.chromium.content_public.browser.WebContents;
     private native void nativeInsertCSS(long nativeWebContentsAndroid, String css);
     private native void nativeOnHide(long nativeWebContentsAndroid);
     private native void nativeOnShow(long nativeWebContentsAndroid);
+    private native void nativeReleaseMediaPlayers(long nativeWebContentsAndroid);
     private native int nativeGetBackgroundColor(long nativeWebContentsAndroid);
     private native void nativeAddStyleSheetByURL(long nativeWebContentsAndroid,
             String url);
index 5db2c7c..9a7174d 100644 (file)
@@ -43,6 +43,11 @@ public interface WebContents {
     public void onShow();
 
     /**
+     * Stops all media players for this WebContents.
+     */
+    public void releaseMediaPlayers();
+
+    /**
      * Get the Background color from underlying RenderWidgetHost for this WebContent.
      */
     public int getBackgroundColor();
index 94e1794..8ec79e1 100644 (file)
@@ -381,11 +381,50 @@ public class ImeTest extends ContentShellTestBase {
 
     @SmallTest
     @Feature({"TextInput", "Main"})
+    public void testKeyCodesWhileSwipingText() throws Throwable {
+        DOMUtils.focusNode(mContentViewCore, "textarea");
+        assertWaitForKeyboardStatus(true);
+
+        // The calls below are a reflection of what the stock Google Keyboard (Android 4.4) sends
+        // when the word is swiped on the soft keyboard.  Exercise care when altering to make sure
+        // that the test reflects reality.  If this test breaks, it's possible that code has
+        // changed and different calls need to be made instead.
+        mConnection = (TestAdapterInputConnection) getAdapterInputConnection();
+        waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 0, "", 0, 0, -1, -1);
+
+        // "three"
+        expectUpdateStateCall(mConnection);
+        setComposingText(mConnection, "three", 1);
+        assertEquals(KeyEvent.KEYCODE_UNKNOWN, mImeAdapter.mLastSyntheticKeyCode);
+        assertUpdateStateCall(mConnection, 1000);
+        assertEquals("three", mConnection.getTextBeforeCursor(99, 0));
+
+        // "word"
+        commitText(mConnection, "three", 1);
+        commitText(mConnection, " ", 1);
+        expectUpdateStateCall(mConnection);
+        setComposingText(mConnection, "word", 1);
+        assertEquals(KeyEvent.KEYCODE_UNKNOWN, mImeAdapter.mLastSyntheticKeyCode);
+        assertUpdateStateCall(mConnection, 1000);
+        assertEquals("three word", mConnection.getTextBeforeCursor(99, 0));
+
+        // "test"
+        commitText(mConnection, "word", 1);
+        commitText(mConnection, " ", 1);
+        expectUpdateStateCall(mConnection);
+        setComposingText(mConnection, "test", 1);
+        assertEquals(KeyEvent.KEYCODE_UNKNOWN, mImeAdapter.mLastSyntheticKeyCode);
+        assertUpdateStateCall(mConnection, 1000);
+        assertEquals("three word test", mConnection.getTextBeforeCursor(99, 0));
+    }
+
+    @SmallTest
+    @Feature({"TextInput", "Main"})
     public void testKeyCodesWhileTypingText() throws Throwable {
         DOMUtils.focusNode(mContentViewCore, "textarea");
         assertWaitForKeyboardStatus(true);
 
-        // The calls below are a reflection of what the Hacker's Keyboard sends  when the noted
+        // The calls below are a reflection of what the Hacker's Keyboard sends when the noted
         // key is touched on screen.  Exercise care when altering to make sure that the test
         // reflects reality.
         mConnection = (TestAdapterInputConnection) getAdapterInputConnection();
index 43bbe32..d4bfd4e 100644 (file)
@@ -871,6 +871,9 @@ const char kDisableWebRtcHWEncoding[]       = "disable-webrtc-hw-encoding";
 
 // Enables VP8 HW encode acceleration for WebRTC.
 const char kEnableWebRtcHWVp8Encoding[]     = "enable-webrtc-hw-vp8-encoding";
+
+// Enables H264 HW encode acceleration for WebRTC.
+const char kEnableWebRtcHWH264Encoding[]    = "enable-webrtc-hw-h264-encoding";
 #endif
 
 #if defined(OS_ANDROID)
index 69add0a..c90fa96 100644 (file)
@@ -243,6 +243,7 @@ CONTENT_EXPORT extern const char kDisableWebRtcHWDecoding[];
 CONTENT_EXPORT extern const char kDisableWebRtcEncryption[];
 CONTENT_EXPORT extern const char kDisableWebRtcHWEncoding[];
 CONTENT_EXPORT extern const char kEnableWebRtcHWVp8Encoding[];
+CONTENT_EXPORT extern const char kEnableWebRtcHWH264Encoding[];
 #endif
 
 #if defined(OS_ANDROID)
index 0d53dac..63dcd4d 100644 (file)
@@ -58,7 +58,7 @@ ContextMenuParams ContextMenuParamsBuilder::Build(
   if (!params.link_url.is_empty()) {
     blink::WebNode selectedNode = DomUtils::ExtractParentAnchorNode(data.node);
     blink::WebElement selectedElement = selectedNode.to<blink::WebElement>();
-    if (selectedNode.isLink() && !selectedElement.isNull()) {
+    if (!selectedElement.isNull() && selectedNode.isLink()) {
       params.link_text = selectedElement.innerText();
     } else {
       LOG(ERROR) << "Creating a ContextMenuParams for a node that has a link"
index 9db2246..6181642 100644 (file)
@@ -515,6 +515,13 @@ bool WebMediaPlayerAndroid::EnsureTextureBackedSkBitmap(GrContext* gr,
 void WebMediaPlayerAndroid::paint(blink::WebCanvas* canvas,
                                   const blink::WebRect& rect,
                                   unsigned char alpha) {
+  paint(canvas, rect, alpha, SkXfermode::kSrcOver_Mode);
+}
+
+void WebMediaPlayerAndroid::paint(blink::WebCanvas* canvas,
+                                  const blink::WebRect& rect,
+                                  unsigned char alpha,
+                                  SkXfermode::Mode mode) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   scoped_ptr<blink::WebGraphicsContext3DProvider> provider =
     scoped_ptr<blink::WebGraphicsContext3DProvider>(blink::Platform::current(
@@ -551,6 +558,7 @@ void WebMediaPlayerAndroid::paint(blink::WebCanvas* canvas,
   dest.set(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
   SkPaint paint;
   paint.setAlpha(alpha);
+  paint.setXfermodeMode(mode);
   // It is not necessary to pass the dest into the drawBitmap call since all
   // the context have been set up before calling paintCurrentFrameInContext.
   canvas->drawBitmapRect(bitmap_, 0, dest, &paint);
index c994b52..dcb63c7 100644 (file)
@@ -113,6 +113,11 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer,
   // https://code.google.com/p/skia/issues/detail?id=1189
   virtual void paint(blink::WebCanvas* canvas,
                      const blink::WebRect& rect,
+                     unsigned char alpha,
+                     SkXfermode::Mode mode);
+  // TODO(dshwang): remove it because above method replaces. crbug.com/401027
+  virtual void paint(blink::WebCanvas* canvas,
+                     const blink::WebRect& rect,
                      unsigned char alpha);
 
   virtual bool copyVideoTextureToPlatformTexture(
index 412196c..02b0b57 100644 (file)
 #include "ipc/ipc_logging.h"
 #include "ipc/ipc_sender.h"
 
-namespace content {
-
 namespace {
+
 const int kStreamIDNotSet = -1;
+
+void LogMessage(int stream_id, const std::string& msg) {
+  std::ostringstream oss;
+  oss << "[stream_id=" << stream_id << "] AIMF::" << msg;
+  content::WebRtcLogMessage(oss.str());
+  DVLOG(1) << oss.str();
 }
 
+}
+
+namespace content {
+
 class AudioInputMessageFilter::AudioInputIPCImpl
     : public NON_EXPORTED_BASE(media::AudioInputIPC) {
  public:
@@ -125,10 +134,7 @@ void AudioInputMessageFilter::OnStreamCreated(
     uint32 length,
     uint32 total_segments) {
   DCHECK(io_message_loop_->BelongsToCurrentThread());
-
-  WebRtcLogMessage(base::StringPrintf(
-      "AIMF::OnStreamCreated. stream_id=%d",
-      stream_id));
+  LogMessage(stream_id, "OnStreamCreated");
 
 #if !defined(OS_WIN)
   base::SyncSocket::Handle socket_handle = socket_descriptor.fd;
@@ -193,6 +199,9 @@ void AudioInputMessageFilter::AudioInputIPCImpl::CreateStream(
   DCHECK(delegate);
 
   stream_id_ = filter_->delegates_.Add(delegate);
+  // TODO(henrika): remove all LogMessage calls when we have sorted out the
+  // existing "no input audio" issues.
+  LogMessage(stream_id_, "CreateStream");
 
   AudioInputHostMsg_CreateStream_Config config;
   config.params = params;
@@ -204,6 +213,7 @@ void AudioInputMessageFilter::AudioInputIPCImpl::CreateStream(
 
 void AudioInputMessageFilter::AudioInputIPCImpl::RecordStream() {
   DCHECK_NE(stream_id_, kStreamIDNotSet);
+  LogMessage(stream_id_, "RecordStream");
   filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
 }
 
@@ -215,6 +225,7 @@ void AudioInputMessageFilter::AudioInputIPCImpl::SetVolume(double volume) {
 void AudioInputMessageFilter::AudioInputIPCImpl::CloseStream() {
   DCHECK(filter_->io_message_loop_->BelongsToCurrentThread());
   DCHECK_NE(stream_id_, kStreamIDNotSet);
+  LogMessage(stream_id_, "CloseStream");
   filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
   filter_->delegates_.Remove(stream_id_);
   stream_id_ = kStreamIDNotSet;
index 23e6e54..55b855c 100644 (file)
@@ -43,6 +43,7 @@ const char* kSupportedConstraints[] = {
 const int MediaStreamVideoSource::kDefaultWidth = 640;
 const int MediaStreamVideoSource::kDefaultHeight = 480;
 const int MediaStreamVideoSource::kDefaultFrameRate = 30;
+const int MediaStreamVideoSource::kUnknownFrameRate = 0;
 
 namespace {
 
index cbf8c82..3aed40a 100644 (file)
@@ -81,6 +81,7 @@ class CONTENT_EXPORT MediaStreamVideoSource
   static const int kDefaultWidth;
   static const int kDefaultHeight;
   static const int kDefaultFrameRate;
+  static const int kUnknownFrameRate;
 
  protected:
   virtual void DoStopSource() OVERRIDE;
index 1658970..60ae893 100644 (file)
@@ -61,13 +61,9 @@ RTCVideoDecoder::SHMBuffer::~SHMBuffer() { shm->Close(); }
 
 RTCVideoDecoder::BufferData::BufferData(int32 bitstream_buffer_id,
                                         uint32_t timestamp,
-                                        int width,
-                                        int height,
                                         size_t size)
     : bitstream_buffer_id(bitstream_buffer_id),
       timestamp(timestamp),
-      width(width),
-      height(height),
       size(size) {}
 
 RTCVideoDecoder::BufferData::BufferData() {}
@@ -75,8 +71,10 @@ RTCVideoDecoder::BufferData::BufferData() {}
 RTCVideoDecoder::BufferData::~BufferData() {}
 
 RTCVideoDecoder::RTCVideoDecoder(
+    webrtc::VideoCodecType type,
     const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories)
-    : factories_(factories),
+    : video_codec_type_(type),
+      factories_(factories),
       decoder_texture_target_(0),
       next_picture_buffer_id_(0),
       state_(UNINITIALIZED),
@@ -120,13 +118,16 @@ scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create(
     case webrtc::kVideoCodecVP8:
       profile = media::VP8PROFILE_ANY;
       break;
+    case webrtc::kVideoCodecH264:
+      profile = media::H264PROFILE_MAIN;
+      break;
     default:
       DVLOG(2) << "Video codec not supported:" << type;
       return decoder.Pass();
   }
 
   base::WaitableEvent waiter(true, false);
-  decoder.reset(new RTCVideoDecoder(factories));
+  decoder.reset(new RTCVideoDecoder(type, factories));
   decoder->factories_->GetTaskRunner()->PostTask(
       FROM_HERE,
       base::Bind(&RTCVideoDecoder::CreateVDA,
@@ -134,7 +135,7 @@ scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create(
                  profile,
                  &waiter));
   waiter.Wait();
-  // vda can be NULL if VP8 is not supported.
+  // vda can be NULL if the codec is not supported.
   if (decoder->vda_ != NULL) {
     decoder->state_ = INITIALIZED;
   } else {
@@ -146,8 +147,9 @@ scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create(
 int32_t RTCVideoDecoder::InitDecode(const webrtc::VideoCodec* codecSettings,
                                     int32_t /*numberOfCores*/) {
   DVLOG(2) << "InitDecode";
-  DCHECK_EQ(codecSettings->codecType, webrtc::kVideoCodecVP8);
-  if (codecSettings->codecSpecific.VP8.feedbackModeOn) {
+  DCHECK_EQ(video_codec_type_, codecSettings->codecType);
+  if (codecSettings->codecType == webrtc::kVideoCodecVP8 &&
+      codecSettings->codecSpecific.VP8.feedbackModeOn) {
     LOG(ERROR) << "Feedback mode not supported";
     return RecordInitDecodeUMA(WEBRTC_VIDEO_CODEC_ERROR);
   }
@@ -227,8 +229,6 @@ int32_t RTCVideoDecoder::Decode(
   // Create buffer metadata.
   BufferData buffer_data(next_bitstream_buffer_id_,
                          inputImage._timeStamp,
-                         frame_size_.width(),
-                         frame_size_.height(),
                          inputImage._length);
   // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
   next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & ID_LAST;
@@ -364,13 +364,21 @@ void RTCVideoDecoder::PictureReady(const media::Picture& picture) {
   }
   const media::PictureBuffer& pb = it->second;
 
+  // Validate picture rectangle from GPU.
+  if (picture.visible_rect().IsEmpty() ||
+      !gfx::Rect(pb.size()).Contains(picture.visible_rect())) {
+    NOTREACHED() << "Invalid picture size from VDA: "
+                 << picture.visible_rect().ToString() << " should fit in "
+                 << pb.size().ToString();
+    NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
+    return;
+  }
+
   // Create a media::VideoFrame.
-  uint32_t timestamp = 0, width = 0, height = 0;
-  size_t size = 0;
-  GetBufferData(
-      picture.bitstream_buffer_id(), &timestamp, &width, &height, &size);
+  uint32_t timestamp = 0;
+  GetBufferData(picture.bitstream_buffer_id(), &timestamp);
   scoped_refptr<media::VideoFrame> frame =
-      CreateVideoFrame(picture, pb, timestamp, width, height, size);
+      CreateVideoFrame(picture, pb, timestamp);
   bool inserted =
       picture_buffers_at_display_.insert(std::make_pair(
                                              picture.picture_buffer_id(),
@@ -380,7 +388,11 @@ void RTCVideoDecoder::PictureReady(const media::Picture& picture) {
   // Create a WebRTC video frame.
   webrtc::RefCountImpl<NativeHandleImpl>* handle =
       new webrtc::RefCountImpl<NativeHandleImpl>(frame);
-  webrtc::TextureVideoFrame decoded_image(handle, width, height, timestamp, 0);
+  webrtc::TextureVideoFrame decoded_image(handle,
+                                          picture.visible_rect().width(),
+                                          picture.visible_rect().height(),
+                                          timestamp,
+                                          0);
 
   // Invoke decode callback. WebRTC expects no callback after Reset or Release.
   {
@@ -423,11 +435,8 @@ static void ReadPixelsSync(
 scoped_refptr<media::VideoFrame> RTCVideoDecoder::CreateVideoFrame(
     const media::Picture& picture,
     const media::PictureBuffer& pb,
-    uint32_t timestamp,
-    uint32_t width,
-    uint32_t height,
-    size_t size) {
-  gfx::Rect visible_rect(width, height);
+    uint32_t timestamp) {
+  gfx::Rect visible_rect(picture.visible_rect());
   DCHECK(decoder_texture_target_);
   // Convert timestamp from 90KHz to ms.
   base::TimeDelta timestamp_ms = base::TimeDelta::FromInternalValue(
@@ -777,18 +786,13 @@ void RTCVideoDecoder::RecordBufferData(const BufferData& buffer_data) {
 }
 
 void RTCVideoDecoder::GetBufferData(int32 bitstream_buffer_id,
-                                    uint32_t* timestamp,
-                                    uint32_t* width,
-                                    uint32_t* height,
-                                    size_t* size) {
+                                    uint32_t* timestamp) {
   for (std::list<BufferData>::iterator it = input_buffer_data_.begin();
        it != input_buffer_data_.end();
        ++it) {
     if (it->bitstream_buffer_id != bitstream_buffer_id)
       continue;
     *timestamp = it->timestamp;
-    *width = it->width;
-    *height = it->height;
     return;
   }
   NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id;
index 0c8e45b..8c8a6e3 100644 (file)
@@ -91,15 +91,11 @@ class CONTENT_EXPORT RTCVideoDecoder
   struct BufferData {
     BufferData(int32 bitstream_buffer_id,
                uint32_t timestamp,
-               int width,
-               int height,
                size_t size);
     BufferData();
     ~BufferData();
     int32 bitstream_buffer_id;
     uint32_t timestamp;  // in 90KHz
-    uint32_t width;
-    uint32_t height;
     size_t size;  // buffer size
   };
 
@@ -107,6 +103,7 @@ class CONTENT_EXPORT RTCVideoDecoder
   FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, IsFirstBufferAfterReset);
 
   RTCVideoDecoder(
+      webrtc::VideoCodecType type,
       const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories);
 
   // Requests a buffer to be decoded by VDA.
@@ -138,10 +135,7 @@ class CONTENT_EXPORT RTCVideoDecoder
   scoped_refptr<media::VideoFrame> CreateVideoFrame(
       const media::Picture& picture,
       const media::PictureBuffer& pb,
-      uint32_t timestamp,
-      uint32_t width,
-      uint32_t height,
-      size_t size);
+      uint32_t timestamp);
 
   // Resets VDA.
   void ResetInternal();
@@ -176,11 +170,7 @@ class CONTENT_EXPORT RTCVideoDecoder
   // Stores the buffer metadata to |input_buffer_data_|.
   void RecordBufferData(const BufferData& buffer_data);
   // Gets the buffer metadata from |input_buffer_data_|.
-  void GetBufferData(int32 bitstream_buffer_id,
-                     uint32_t* timestamp,
-                     uint32_t* width,
-                     uint32_t* height,
-                     size_t* size);
+  void GetBufferData(int32 bitstream_buffer_id, uint32_t* timestamp);
 
   // Records the result of InitDecode to UMA and returns |status|.
   int32_t RecordInitDecodeUMA(int32_t status);
@@ -202,6 +192,9 @@ class CONTENT_EXPORT RTCVideoDecoder
   // The hardware video decoder.
   scoped_ptr<media::VideoDecodeAccelerator> vda_;
 
+  // The video codec type, as reported by WebRTC.
+  const webrtc::VideoCodecType video_codec_type_;
+
   // The size of the incoming video frames.
   gfx::Size frame_size_;
 
index e6dfe3e..a1e6341 100644 (file)
@@ -45,8 +45,6 @@ class RTCVideoDecoderTest : public ::testing::Test,
         .Times(1)
         .WillRepeatedly(Return(true));
     EXPECT_CALL(*mock_vda_, Destroy()).Times(1);
-    rtc_decoder_ =
-        RTCVideoDecoder::Create(webrtc::kVideoCodecVP8, mock_gpu_factories_);
   }
 
   virtual void TearDown() OVERRIDE {
@@ -65,9 +63,15 @@ class RTCVideoDecoderTest : public ::testing::Test,
     return WEBRTC_VIDEO_CODEC_OK;
   }
 
+  void CreateDecoder(webrtc::VideoCodecType codec_type) {
+    VLOG(2) << "CreateDecoder";
+    codec_.codecType = codec_type;
+    rtc_decoder_ =
+        RTCVideoDecoder::Create(codec_type, mock_gpu_factories_);
+  }
+
   void Initialize() {
     VLOG(2) << "Initialize";
-    codec_.codecType = webrtc::kVideoCodecVP8;
     EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->InitDecode(&codec_, 1));
     EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
               rtc_decoder_->RegisterDecodeCompleteCallback(this));
@@ -104,24 +108,32 @@ class RTCVideoDecoderTest : public ::testing::Test,
 };
 
 TEST_F(RTCVideoDecoderTest, CreateReturnsNullOnUnsupportedCodec) {
+  CreateDecoder(webrtc::kVideoCodecVP8);
   scoped_ptr<RTCVideoDecoder> null_rtc_decoder(
       RTCVideoDecoder::Create(webrtc::kVideoCodecI420, mock_gpu_factories_));
   EXPECT_EQ(NULL, null_rtc_decoder.get());
 }
 
+TEST_F(RTCVideoDecoderTest, CreateAndInitSucceedsForH264Codec) {
+  CreateDecoder(webrtc::kVideoCodecH264);
+  EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->InitDecode(&codec_, 1));
+}
+
 TEST_F(RTCVideoDecoderTest, InitDecodeReturnsErrorOnFeedbackMode) {
-  codec_.codecType = webrtc::kVideoCodecVP8;
+  CreateDecoder(webrtc::kVideoCodecVP8);
   codec_.codecSpecific.VP8.feedbackModeOn = true;
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, rtc_decoder_->InitDecode(&codec_, 1));
 }
 
 TEST_F(RTCVideoDecoderTest, DecodeReturnsErrorWithoutInitDecode) {
+  CreateDecoder(webrtc::kVideoCodecVP8);
   webrtc::EncodedImage input_image;
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_UNINITIALIZED,
             rtc_decoder_->Decode(input_image, false, NULL, NULL, 0));
 }
 
 TEST_F(RTCVideoDecoderTest, DecodeReturnsErrorOnIncompleteFrame) {
+  CreateDecoder(webrtc::kVideoCodecVP8);
   Initialize();
   webrtc::EncodedImage input_image;
   input_image._completeFrame = false;
@@ -130,6 +142,7 @@ TEST_F(RTCVideoDecoderTest, DecodeReturnsErrorOnIncompleteFrame) {
 }
 
 TEST_F(RTCVideoDecoderTest, DecodeReturnsErrorOnMissingFrames) {
+  CreateDecoder(webrtc::kVideoCodecVP8);
   Initialize();
   webrtc::EncodedImage input_image;
   input_image._completeFrame = true;
@@ -139,6 +152,7 @@ TEST_F(RTCVideoDecoderTest, DecodeReturnsErrorOnMissingFrames) {
 }
 
 TEST_F(RTCVideoDecoderTest, ResetReturnsOk) {
+  CreateDecoder(webrtc::kVideoCodecVP8);
   Initialize();
   EXPECT_CALL(*mock_vda_, Reset())
       .WillOnce(Invoke(this, &RTCVideoDecoderTest::NotifyResetDone));
@@ -146,6 +160,7 @@ TEST_F(RTCVideoDecoderTest, ResetReturnsOk) {
 }
 
 TEST_F(RTCVideoDecoderTest, ReleaseReturnsOk) {
+  CreateDecoder(webrtc::kVideoCodecVP8);
   Initialize();
   EXPECT_CALL(*mock_vda_, Reset())
       .WillOnce(Invoke(this, &RTCVideoDecoderTest::NotifyResetDone));
@@ -153,6 +168,7 @@ TEST_F(RTCVideoDecoderTest, ReleaseReturnsOk) {
 }
 
 TEST_F(RTCVideoDecoderTest, InitDecodeAfterRelease) {
+  CreateDecoder(webrtc::kVideoCodecVP8);
   EXPECT_CALL(*mock_vda_, Reset())
       .WillRepeatedly(Invoke(this, &RTCVideoDecoderTest::NotifyResetDone));
   Initialize();
@@ -162,6 +178,7 @@ TEST_F(RTCVideoDecoderTest, InitDecodeAfterRelease) {
 }
 
 TEST_F(RTCVideoDecoderTest, IsBufferAfterReset) {
+  CreateDecoder(webrtc::kVideoCodecVP8);
   EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_INVALID));
   EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST,
                                                RTCVideoDecoder::ID_INVALID));
@@ -187,6 +204,7 @@ TEST_F(RTCVideoDecoderTest, IsBufferAfterReset) {
 }
 
 TEST_F(RTCVideoDecoderTest, IsFirstBufferAfterReset) {
+  CreateDecoder(webrtc::kVideoCodecVP8);
   EXPECT_TRUE(
       rtc_decoder_->IsFirstBufferAfterReset(0, RTCVideoDecoder::ID_INVALID));
   EXPECT_FALSE(
index 1b33fc5..4b3f99f 100644 (file)
@@ -16,6 +16,7 @@
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
 #include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/filters/h264_parser.h"
 #include "media/video/video_encode_accelerator.h"
 #include "third_party/webrtc/system_wrappers/interface/tick_util.h"
 
 
 namespace content {
 
+namespace {
+
+// Populates struct webrtc::RTPFragmentationHeader for H264 codec.
+// Each entry specifies the offset and length (excluding start code) of a NALU.
+// Returns true if successful.
+bool GetRTPFragmentationHeaderH264(webrtc::RTPFragmentationHeader* header,
+                                   const uint8_t* data, uint32_t length) {
+  media::H264Parser parser;
+  parser.SetStream(data, length);
+
+  std::vector<media::H264NALU> nalu_vector;
+  while (true) {
+    media::H264NALU nalu;
+    const media::H264Parser::Result result = parser.AdvanceToNextNALU(&nalu);
+    if (result == media::H264Parser::kOk) {
+      nalu_vector.push_back(nalu);
+    } else if (result == media::H264Parser::kEOStream) {
+      break;
+    } else {
+      DLOG(ERROR) << "Unexpected H264 parser result";
+      return false;
+    }
+  }
+
+  header->VerifyAndAllocateFragmentationHeader(nalu_vector.size());
+  for (size_t i = 0; i < nalu_vector.size(); ++i) {
+    header->fragmentationOffset[i] = nalu_vector[i].data - data;
+    header->fragmentationLength[i] = nalu_vector[i].size;
+    header->fragmentationPlType[i] = 0;
+    header->fragmentationTimeDiff[i] = 0;
+  }
+  return true;
+}
+
+}  // namespace
+
 // This private class of RTCVideoEncoder does the actual work of communicating
 // with a media::VideoEncodeAccelerator for handling video encoding.  It can
 // be created on any thread, but should subsequently be posted to (and Destroy()
@@ -648,6 +685,32 @@ void RTCVideoEncoder::ReturnEncodedImage(scoped_ptr<webrtc::EncodedImage> image,
   if (!encoded_image_callback_)
     return;
 
+  webrtc::RTPFragmentationHeader header;
+  memset(&header, 0, sizeof(header));
+  switch (video_codec_type_) {
+    case webrtc::kVideoCodecVP8:
+    case webrtc::kVideoCodecGeneric:
+      // Generate a header describing a single fragment.
+      // Note that webrtc treats the generic-type payload as an opaque buffer.
+      header.VerifyAndAllocateFragmentationHeader(1);
+      header.fragmentationOffset[0] = 0;
+      header.fragmentationLength[0] = image->_length;
+      header.fragmentationPlType[0] = 0;
+      header.fragmentationTimeDiff[0] = 0;
+      break;
+    case webrtc::kVideoCodecH264:
+      if (!GetRTPFragmentationHeaderH264(
+          &header, image->_buffer, image->_length)) {
+        DLOG(ERROR) << "Failed to get RTP fragmentation header for H264";
+        NotifyError(WEBRTC_VIDEO_CODEC_ERROR);
+        return;
+      }
+      break;
+    default:
+      NOTREACHED() << "Invalid video codec type";
+      return;
+  }
+
   webrtc::CodecSpecificInfo info;
   memset(&info, 0, sizeof(info));
   info.codecType = video_codec_type_;
@@ -657,15 +720,6 @@ void RTCVideoEncoder::ReturnEncodedImage(scoped_ptr<webrtc::EncodedImage> image,
     info.codecSpecific.VP8.keyIdx = -1;
   }
 
-  // Generate a header describing a single fragment.
-  webrtc::RTPFragmentationHeader header;
-  memset(&header, 0, sizeof(header));
-  header.VerifyAndAllocateFragmentationHeader(1);
-  header.fragmentationOffset[0] = 0;
-  header.fragmentationLength[0] = image->_length;
-  header.fragmentationPlType[0] = 0;
-  header.fragmentationTimeDiff[0] = 0;
-
   int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header);
   if (retval < 0) {
     DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
index e9c1578..ec92f55 100644 (file)
@@ -4,7 +4,9 @@
 
 #include "content/renderer/media/rtc_video_encoder_factory.h"
 
+#include "base/command_line.h"
 #include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
+#include "content/public/common/content_switches.h"
 #include "content/renderer/media/rtc_video_encoder.h"
 #include "media/filters/gpu_video_accelerator_factories.h"
 #include "media/video/video_encode_accelerator.h"
@@ -14,32 +16,32 @@ namespace content {
 namespace {
 
 // Translate from media::VideoEncodeAccelerator::SupportedProfile to
-// cricket::WebRtcVideoEncoderFactory::VideoCodec
-cricket::WebRtcVideoEncoderFactory::VideoCodec VEAToWebRTCCodec(
+// one or more instances of cricket::WebRtcVideoEncoderFactory::VideoCodec
+void VEAToWebRTCCodecs(
+    std::vector<cricket::WebRtcVideoEncoderFactory::VideoCodec>* codecs,
     const media::VideoEncodeAccelerator::SupportedProfile& profile) {
-  webrtc::VideoCodecType type = webrtc::kVideoCodecUnknown;
-  std::string name;
-  int width = 0, height = 0, fps = 0;
+  int width = profile.max_resolution.width();
+  int height = profile.max_resolution.height();
+  int fps = profile.max_framerate.numerator;
+  DCHECK_EQ(profile.max_framerate.denominator, 1U);
 
+  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
   if (profile.profile >= media::VP8PROFILE_MIN &&
       profile.profile <= media::VP8PROFILE_MAX) {
-    type = webrtc::kVideoCodecVP8;
-    name = "VP8";
+    if (cmd_line->HasSwitch(switches::kEnableWebRtcHWVp8Encoding)) {
+      codecs->push_back(cricket::WebRtcVideoEncoderFactory::VideoCodec(
+          webrtc::kVideoCodecVP8, "VP8", width, height, fps));
+    }
   } else if (profile.profile >= media::H264PROFILE_MIN &&
              profile.profile <= media::H264PROFILE_MAX) {
-    type = webrtc::kVideoCodecGeneric;
-    name = "CAST1";
-  }
-
-  if (type != webrtc::kVideoCodecUnknown) {
-    width = profile.max_resolution.width();
-    height = profile.max_resolution.height();
-    fps = profile.max_framerate.numerator;
-    DCHECK_EQ(profile.max_framerate.denominator, 1U);
+    if (cmd_line->HasSwitch(switches::kEnableWebRtcHWH264Encoding)) {
+      codecs->push_back(cricket::WebRtcVideoEncoderFactory::VideoCodec(
+          webrtc::kVideoCodecH264, "H264", width, height, fps));
+    }
+    // TODO(hshi): remove the generic codec type after CASTv1 deprecation.
+    codecs->push_back(cricket::WebRtcVideoEncoderFactory::VideoCodec(
+        webrtc::kVideoCodecGeneric, "CAST1", width, height, fps));
   }
-
-  return cricket::WebRtcVideoEncoderFactory::VideoCodec(
-      type, name, width, height, fps);
 }
 
 // Translate from cricket::WebRtcVideoEncoderFactory::VideoCodec to
@@ -49,6 +51,7 @@ media::VideoCodecProfile WebRTCCodecToVideoCodecProfile(
   switch (type) {
     case webrtc::kVideoCodecVP8:
       return media::VP8PROFILE_ANY;
+    case webrtc::kVideoCodecH264:
     case webrtc::kVideoCodecGeneric:
       return media::H264PROFILE_MAIN;
     default:
@@ -64,11 +67,8 @@ RTCVideoEncoderFactory::RTCVideoEncoderFactory(
   // Query media::VideoEncodeAccelerator (statically) for our supported codecs.
   std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles =
       GpuVideoEncodeAcceleratorHost::GetSupportedProfiles();
-  for (size_t i = 0; i < profiles.size(); ++i) {
-    VideoCodec codec = VEAToWebRTCCodec(profiles[i]);
-    if (codec.type != webrtc::kVideoCodecUnknown)
-      codecs_.push_back(codec);
-  }
+  for (size_t i = 0; i < profiles.size(); ++i)
+    VEAToWebRTCCodecs(&codecs_, profiles[i]);
 }
 
 RTCVideoEncoderFactory::~RTCVideoEncoderFactory() {}
index 9a9ab08..12a130e 100644 (file)
@@ -24,6 +24,10 @@ namespace {
 const float kFirstFrameTimeoutInFrameIntervals = 100.0f;
 const float kNormalFrameTimeoutInFrameIntervals = 25.0f;
 
+// Min delta time between two frames allowed without being dropped if a max
+// frame rate is specified.
+const int kMinTimeInMsBetweenFrames = 5;
+
 // Empty method used for keeping a reference to the original media::VideoFrame
 // in VideoFrameResolutionAdapter::DeliverFrame if cropping is needed.
 // The reference to |frame| is kept in the closure that calls this method.
@@ -85,7 +89,8 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
 
   // Returns |true| if the input frame rate is higher that the requested max
   // frame rate and |frame| should be dropped.
-  bool MaybeDropFrame(const scoped_refptr<media::VideoFrame>& frame);
+  bool MaybeDropFrame(const scoped_refptr<media::VideoFrame>& frame,
+                      float source_frame_rate);
 
   // Bound to the IO-thread.
   base::ThreadChecker io_thread_checker_;
@@ -148,7 +153,7 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
     const base::TimeTicks& estimated_capture_time) {
   DCHECK(io_thread_checker_.CalledOnValidThread());
 
-  if (MaybeDropFrame(frame))
+  if (MaybeDropFrame(frame, format.frame_rate))
     return;
 
   // TODO(perkj): Allow cropping / scaling of textures once
@@ -220,16 +225,36 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
 }
 
 bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeDropFrame(
-    const scoped_refptr<media::VideoFrame>& frame) {
-  if (max_frame_rate_ == 0.0f)
+    const scoped_refptr<media::VideoFrame>& frame,
+    float source_frame_rate) {
+  DCHECK(io_thread_checker_.CalledOnValidThread());
+
+  // Do not drop frames if max frame rate hasn't been specified or the source
+  // frame rate is known and is lower than max.
+  if (max_frame_rate_ == 0.0f ||
+      (source_frame_rate > 0 &&
+          source_frame_rate <= max_frame_rate_))
     return false;
 
   base::TimeDelta delta = frame->timestamp() - last_time_stamp_;
+  if (delta.InMilliseconds() < kMinTimeInMsBetweenFrames) {
+    // We have seen video frames being delivered from camera devices back to
+    // back. The simple AR filter for frame rate calculation is too short to
+    // handle that. http://crbug/394315
+    // TODO(perkj): Can we come up with a way to fix the times stamps and the
+    // timing when frames are delivered so all frames can be used?
+    // The time stamps are generated by Chrome and not the actual device.
+    // Most likely the back to back problem is caused by software and not the
+    // actual camera.
+    DVLOG(3) << "Drop frame since delta time since previous frame is "
+             << delta.InMilliseconds() << "ms.";
+    return true;
+  }
   last_time_stamp_ = frame->timestamp();
-  if (delta.ToInternalValue() == 0 || delta == last_time_stamp_)
+  if (delta == last_time_stamp_)  // First received frame.
     return false;
-  // Calculate the moving average frame rate. Use a simple filter with 0.1
-  // weight of the current sample.
+  // Calculate the frame rate using a simple AR filter.
+  // Use a simple filter with 0.1 weight of the current sample.
   frame_rate_ = 100 / delta.InMillisecondsF() + 0.9 * frame_rate_;
 
   // Prefer to not drop frames.
index cd5f9ef..fc723c7 100644 (file)
@@ -536,9 +536,16 @@ bool WebMediaPlayerImpl::didLoadingProgress() {
   return pipeline_progress || data_progress;
 }
 
-void WebMediaPlayerImpl::paint(WebCanvas* canvas,
-                               const WebRect& rect,
+void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
+                               const blink::WebRect& rect,
                                unsigned char alpha) {
+  paint(canvas, rect, alpha, SkXfermode::kSrcOver_Mode);
+}
+
+void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
+                               const blink::WebRect& rect,
+                               unsigned char alpha,
+                               SkXfermode::Mode mode) {
   DCHECK(main_loop_->BelongsToCurrentThread());
   TRACE_EVENT0("media", "WebMediaPlayerImpl:paint");
 
@@ -556,6 +563,7 @@ void WebMediaPlayerImpl::paint(WebCanvas* canvas,
                                  canvas,
                                  gfx_rect,
                                  alpha,
+                                 mode,
                                  pipeline_metadata_.video_rotation);
 }
 
index 89f84df..7962961 100644 (file)
@@ -92,6 +92,11 @@ class WebMediaPlayerImpl
   // Methods for painting.
   virtual void paint(blink::WebCanvas* canvas,
                      const blink::WebRect& rect,
+                     unsigned char alpha,
+                     SkXfermode::Mode mode);
+  // TODO(dshwang): remove it because above method replaces. crbug.com/401027
+  virtual void paint(blink::WebCanvas* canvas,
+                     const blink::WebRect& rect,
                      unsigned char alpha);
 
   // True if the loaded media has a playable video/audio track.
index be498bb..8500e43 100644 (file)
@@ -319,15 +319,26 @@ bool WebMediaPlayerMS::didLoadingProgress() {
   return true;
 }
 
-void WebMediaPlayerMS::paint(WebCanvas* canvas,
-                             const WebRect& rect,
+void WebMediaPlayerMS::paint(blink::WebCanvas* canvas,
+                             const blink::WebRect& rect,
                              unsigned char alpha) {
+  paint(canvas, rect, alpha, SkXfermode::kSrcOver_Mode);
+}
+
+void WebMediaPlayerMS::paint(blink::WebCanvas* canvas,
+                             const blink::WebRect& rect,
+                             unsigned char alpha,
+                             SkXfermode::Mode mode) {
   DVLOG(3) << "WebMediaPlayerMS::paint";
   DCHECK(thread_checker_.CalledOnValidThread());
 
   gfx::RectF dest_rect(rect.x, rect.y, rect.width, rect.height);
-  video_renderer_.Paint(
-      current_frame_.get(), canvas, dest_rect, alpha, media::VIDEO_ROTATION_0);
+  video_renderer_.Paint(current_frame_.get(),
+                        canvas,
+                        dest_rect,
+                        alpha,
+                        mode,
+                        media::VIDEO_ROTATION_0);
 
   {
     base::AutoLock auto_lock(current_frame_lock_);
index 0bbfec5..bf563e8 100644 (file)
@@ -79,6 +79,11 @@ class WebMediaPlayerMS
   // Methods for painting.
   virtual void paint(blink::WebCanvas* canvas,
                      const blink::WebRect& rect,
+                     unsigned char alpha,
+                     SkXfermode::Mode mode);
+  // TODO(dshwang): remove it because above method replaces. crbug.com/401027
+  virtual void paint(blink::WebCanvas* canvas,
+                     const blink::WebRect& rect,
                      unsigned char alpha);
 
   // True if the loaded media has a playable video/audio track.
index 24e4d53..4cfefb3 100644 (file)
@@ -106,7 +106,7 @@ RemoteVideoSourceDelegate::RenderFrame(
   media::VideoCaptureFormat format(
       gfx::Size(video_frame->natural_size().width(),
                 video_frame->natural_size().height()),
-                MediaStreamVideoSource::kDefaultFrameRate,
+                MediaStreamVideoSource::kUnknownFrameRate,
                 pixel_format);
 
   io_message_loop_->PostTask(
index 240f5cd..887dbc3 100644 (file)
@@ -146,7 +146,7 @@ void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
                               gfx::Rect(frame_size), frame_size, timestamp);
   media::VideoCaptureFormat format(
       frame_size,
-      MediaStreamVideoSource::kDefaultFrameRate,
+      MediaStreamVideoSource::kUnknownFrameRate,
       media::PIXEL_FORMAT_YV12);
 
   libyuv::BGRAToI420(reinterpret_cast<uint8*>(bitmap->getPixels()),
index 994f77b..a9eb073 100644 (file)
@@ -23,22 +23,6 @@ namespace content {
 
 namespace {
 
-// Supported hardware sample rates for input and output sides.
-#if defined(OS_WIN) || defined(OS_MACOSX)
-// media::GetAudioInputHardwareSampleRate() asks the audio layer
-// for its current sample rate (set by the user) on Windows and Mac OS X.
-// The listed rates below adds restrictions and WebRtcAudioDeviceImpl::Init()
-// will fail if the user selects any rate outside these ranges.
-const int kValidInputRates[] =
-    {192000, 96000, 48000, 44100, 32000, 16000, 8000};
-#elif defined(OS_LINUX) || defined(OS_OPENBSD)
-const int kValidInputRates[] = {48000, 44100};
-#elif defined(OS_ANDROID)
-const int kValidInputRates[] = {48000, 44100};
-#else
-const int kValidInputRates[] = {44100};
-#endif
-
 // Time constant for AudioPowerMonitor.  See AudioPowerMonitor ctor comments
 // for semantics.  This value was arbitrarily chosen, but seems to work well.
 const int kPowerMonitorTimeConstantMs = 10;
@@ -196,17 +180,6 @@ bool WebRtcAudioCapturer::Initialize() {
                          device_info_.device.input.sample_rate);
   }
 
-  // Verify that the reported input hardware sample rate is supported
-  // on the current platform.
-  if (std::find(&kValidInputRates[0],
-                &kValidInputRates[0] + arraysize(kValidInputRates),
-                device_info_.device.input.sample_rate) ==
-          &kValidInputRates[arraysize(kValidInputRates)]) {
-    DLOG(ERROR) << device_info_.device.input.sample_rate
-                << " is not a supported input rate.";
-    return false;
-  }
-
   // Create and configure the default audio capturing source.
   SetCapturerSource(AudioDeviceFactory::NewInputDevice(render_view_id_),
                     channel_layout,
index 006f12f..b575db8 100644 (file)
@@ -29,69 +29,6 @@ namespace content {
 
 namespace {
 
-// Supported hardware sample rates for output sides.
-#if defined(OS_WIN) || defined(OS_MACOSX)
-// AudioHardwareConfig::GetOutputSampleRate() asks the audio layer for its
-// current sample rate (set by the user) on Windows and Mac OS X.  The listed
-// rates below adds restrictions and Initialize() will fail if the user selects
-// any rate outside these ranges.
-const int kValidOutputRates[] = {96000, 48000, 44100, 32000, 16000};
-#elif defined(OS_LINUX) || defined(OS_OPENBSD)
-const int kValidOutputRates[] = {48000, 44100};
-#elif defined(OS_ANDROID)
-// TODO(leozwang): We want to use native sampling rate on Android to achieve
-// low latency, currently 16000 is used to work around audio problem on some
-// Android devices.
-const int kValidOutputRates[] = {48000, 44100, 16000};
-#else
-const int kValidOutputRates[] = {44100};
-#endif
-
-// TODO(xians): Merge the following code to WebRtcAudioCapturer, or remove.
-enum AudioFramesPerBuffer {
-  k160,
-  k320,
-  k440,
-  k480,
-  k640,
-  k880,
-  k960,
-  k1440,
-  k1920,
-  kUnexpectedAudioBufferSize  // Must always be last!
-};
-
-// Helper method to convert integral values to their respective enum values
-// above, or kUnexpectedAudioBufferSize if no match exists.
-// We map 441 to k440 to avoid changes in the XML part for histograms.
-// It is still possible to map the histogram result to the actual buffer size.
-// See http://crbug.com/243450 for details.
-AudioFramesPerBuffer AsAudioFramesPerBuffer(int frames_per_buffer) {
-  switch (frames_per_buffer) {
-    case 160: return k160;
-    case 320: return k320;
-    case 441: return k440;
-    case 480: return k480;
-    case 640: return k640;
-    case 880: return k880;
-    case 960: return k960;
-    case 1440: return k1440;
-    case 1920: return k1920;
-  }
-  return kUnexpectedAudioBufferSize;
-}
-
-void AddHistogramFramesPerBuffer(int param) {
-  AudioFramesPerBuffer afpb = AsAudioFramesPerBuffer(param);
-  if (afpb != kUnexpectedAudioBufferSize) {
-    UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer",
-                              afpb, kUnexpectedAudioBufferSize);
-  } else {
-    // Report unexpected sample rates using a unique histogram name.
-    UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputFramesPerBufferUnexpected", param);
-  }
-}
-
 // This is a simple wrapper class that's handed out to users of a shared
 // WebRtcAudioRenderer instance.  This class maintains the per-user 'playing'
 // and 'started' states to avoid problems related to incorrect usage which
@@ -198,6 +135,39 @@ int GetCurrentDuckingFlag(int render_frame_id) {
   return media::AudioParameters::NO_EFFECTS;
 }
 
+// Helper method to get platform specific optimal buffer size.
+int GetOptimalBufferSize(int sample_rate, int hardware_buffer_size) {
+  // Use native hardware buffer size as default. On Windows, we strive to open
+  // up using this native hardware buffer size to achieve best
+  // possible performance and to ensure that no FIFO is needed on the browser
+  // side to match the client request. That is why there is no #if case for
+  // Windows below.
+  int frames_per_buffer = hardware_buffer_size;
+
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+  // On Linux and MacOS, the low level IO implementations on the browser side
+  // supports all buffer size the clients want. We use the native peer
+  // connection buffer size (10ms) to achieve best possible performance.
+  frames_per_buffer = sample_rate / 100;
+#elif defined(OS_ANDROID)
+  // TODO(henrika): Keep tuning this scheme and espcicially for low-latency
+  // cases. Might not be possible to come up with the perfect solution using
+  // the render side only.
+  int frames_per_10ms = sample_rate / 100;
+  if (frames_per_buffer < 2 * frames_per_10ms) {
+    // Examples of low-latency frame sizes and the resulting |buffer_size|:
+    //  Nexus 7     : 240 audio frames => 2*480 = 960
+    //  Nexus 10    : 256              => 2*441 = 882
+    //  Galaxy Nexus: 144              => 2*441 = 882
+    frames_per_buffer = 2 * frames_per_10ms;
+    DVLOG(1) << "Low-latency output detected on Android";
+  }
+#endif
+
+  DVLOG(1) << "Using sink output buffer size: " << frames_per_buffer;
+  return frames_per_buffer;
+}
+
 }  // namespace
 
 WebRtcAudioRenderer::WebRtcAudioRenderer(
@@ -266,16 +236,6 @@ bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
                          sample_rate);
   }
 
-  // Verify that the reported output hardware sample rate is supported
-  // on the current platform.
-  if (std::find(&kValidOutputRates[0],
-                &kValidOutputRates[0] + arraysize(kValidOutputRates),
-                sample_rate) ==
-                    &kValidOutputRates[arraysize(kValidOutputRates)]) {
-    DLOG(ERROR) << sample_rate << " is not a supported output rate.";
-    return false;
-  }
-
   // Set up audio parameters for the source, i.e., the WebRTC client.
 
   // The WebRTC client only supports multiples of 10ms as buffer size where
@@ -288,28 +248,8 @@ bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
                       sink_params_.channel_layout(), sink_params_.channels(), 0,
                       sample_rate, 16, frames_per_10ms);
 
-  // Update audio parameters for the sink, i.e., the native audio output stream.
-  // We strive to open up using native parameters to achieve best possible
-  // performance and to ensure that no FIFO is needed on the browser side to
-  // match the client request. Any mismatch between the source and the sink is
-  // taken care of in this class instead using a pull FIFO.
-
-  // Use native output size as default.
-  int frames_per_buffer = sink_params_.frames_per_buffer();
-#if defined(OS_ANDROID)
-  // TODO(henrika): Keep tuning this scheme and espcicially for low-latency
-  // cases. Might not be possible to come up with the perfect solution using
-  // the render side only.
-  if (frames_per_buffer < 2 * frames_per_10ms) {
-    // Examples of low-latency frame sizes and the resulting |buffer_size|:
-    //  Nexus 7     : 240 audio frames => 2*480 = 960
-    //  Nexus 10    : 256              => 2*441 = 882
-    //  Galaxy Nexus: 144              => 2*441 = 882
-    frames_per_buffer = 2 * frames_per_10ms;
-    DVLOG(1) << "Low-latency output detected on Android";
-  }
-#endif
-  DVLOG(1) << "Using sink output buffer size: " << frames_per_buffer;
+  const int frames_per_buffer =
+      GetOptimalBufferSize(sample_rate, sink_params_.frames_per_buffer());
 
   sink_params_.Reset(sink_params_.format(), sink_params_.channel_layout(),
                      sink_params_.channels(), 0, sample_rate, 16,
@@ -351,11 +291,6 @@ bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) {
   // User must call Play() before any audio can be heard.
   state_ = PAUSED;
 
-  UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputFramesPerBuffer",
-                            source_params.frames_per_buffer(),
-                            kUnexpectedAudioBufferSize);
-  AddHistogramFramesPerBuffer(source_params.frames_per_buffer());
-
   return true;
 }
 
index 61b0b24..5806599 100644 (file)
@@ -99,6 +99,7 @@ class CONTENT_EXPORT WebRtcAudioRenderer
   // Accessors to the sink audio parameters.
   int channels() const { return sink_params_.channels(); }
   int sample_rate() const { return sink_params_.sample_rate(); }
+  int frames_per_buffer() const { return sink_params_.frames_per_buffer(); }
 
  private:
   // MediaStreamAudioRenderer implementation.  This is private since we want
index 914dd52..a481f9e 100644 (file)
@@ -24,6 +24,9 @@ namespace content {
 
 namespace {
 
+const int kHardwareSampleRate = 44100;
+const int kHardwareBufferSize = 512;
+
 class MockAudioOutputIPC : public media::AudioOutputIPC {
  public:
   MockAudioOutputIPC() {}
@@ -88,7 +91,8 @@ class WebRtcAudioRendererTest : public testing::Test {
         factory_(new MockAudioDeviceFactory()),
         source_(new MockAudioRendererSource()),
         stream_(new rtc::RefCountedObject<MockMediaStream>("label")),
-        renderer_(new WebRtcAudioRenderer(stream_, 1, 1, 1, 44100, 441)) {
+        renderer_(new WebRtcAudioRenderer(stream_, 1, 1, 1, 44100,
+                                          kHardwareBufferSize)) {
     EXPECT_CALL(*factory_.get(), CreateOutputDevice(1))
         .WillOnce(Return(mock_output_device_));
     EXPECT_CALL(*mock_output_device_, Start());
@@ -151,4 +155,25 @@ TEST_F(WebRtcAudioRendererTest, MultipleRenderers) {
   }
 }
 
+// Verify that the sink of the renderer is using the expected sample rate and
+// buffer size.
+TEST_F(WebRtcAudioRendererTest, VerifySinkParameters) {
+  renderer_proxy_->Start();
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+  static const int kExpectedBufferSize = kHardwareSampleRate / 100;
+#elif defined(OS_ANDROID)
+  static const int kExpectedBufferSize = 2 * kHardwareSampleRate / 100;
+#else
+  // Windows.
+  static const int kExpectedBufferSize = kHardwareBufferSize;
+#endif
+  EXPECT_EQ(kExpectedBufferSize, renderer_->frames_per_buffer());
+  EXPECT_EQ(kHardwareSampleRate, renderer_->sample_rate());
+  EXPECT_EQ(2, renderer_->channels());
+
+  EXPECT_CALL(*mock_output_device_.get(), Stop());
+  EXPECT_CALL(*source_.get(), RemoveAudioRenderer(renderer_.get()));
+  renderer_proxy_->Stop();
+}
+
 }  // namespace content
index e1b0b1b..5a9e527 100644 (file)
@@ -625,26 +625,46 @@ bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
 
 void ContentDecryptorDelegate::OnPromiseResolved(uint32 promise_id) {
   scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
-  if (promise) {
-    SimpleCdmPromise* simple_promise(
-        static_cast<SimpleCdmPromise*>(promise.get()));
-    simple_promise->resolve();
+
+  // Special case due to http://crbug.com/408330. CDM is resolving LoadSession()
+  // with this method when the session is not found. Instead it should call
+  // PromiseResolvedWithSession(""), so emulate that here until 408330 is fixed.
+  // TODO(jrummell): Remove this code when the CDM is updated.
+  if (promise &&
+      promise->GetResolveParameterType() == media::CdmPromise::STRING_TYPE) {
+    NewSessionCdmPromise* session_promise =
+        static_cast<NewSessionCdmPromise*>(promise.get());
+    session_promise->resolve(std::string());
+    return;
+  }
+
+  if (!promise ||
+      promise->GetResolveParameterType() != media::CdmPromise::VOID_TYPE) {
+    NOTREACHED();
+    return;
   }
+
+  SimpleCdmPromise* simple_promise =
+      static_cast<SimpleCdmPromise*>(promise.get());
+  simple_promise->resolve();
 }
 
 void ContentDecryptorDelegate::OnPromiseResolvedWithSession(
     uint32 promise_id,
     PP_Var web_session_id) {
   scoped_ptr<CdmPromise> promise = TakePromise(promise_id);
+  if (!promise ||
+      promise->GetResolveParameterType() != media::CdmPromise::STRING_TYPE) {
+    NOTREACHED();
+    return;
+  }
 
   StringVar* web_session_id_string = StringVar::FromPPVar(web_session_id);
   DCHECK(web_session_id_string);
 
-  if (promise) {
-    NewSessionCdmPromise* session_promise(
-        static_cast<NewSessionCdmPromise*>(promise.get()));
-    session_promise->resolve(web_session_id_string->value());
-  }
+  NewSessionCdmPromise* session_promise =
+      static_cast<NewSessionCdmPromise*>(promise.get());
+  session_promise->resolve(web_session_id_string->value());
 }
 
 void ContentDecryptorDelegate::OnPromiseRejected(
index fdb5cc3..3f39c94 100644 (file)
@@ -313,6 +313,8 @@ void PepperVideoDecoderHost::ProvidePictureBuffers(
 }
 
 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
+  // So far picture.visible_rect is not used. If used, visible_rect should
+  // be validated since it comes from GPU process and may not be trustworthy.
   host()->SendUnsolicitedReply(
       pp_resource(),
       PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(),
index f52d423..53b2ef9 100644 (file)
@@ -246,6 +246,8 @@ void PPB_VideoDecoder_Impl::ProvidePictureBuffers(
 }
 
 void PPB_VideoDecoder_Impl::PictureReady(const media::Picture& picture) {
+  // So far picture.visible_rect is not used. If used, visible_rect should
+  // be validated since it comes from GPU process and may not be trustworthy.
   DCHECK(RenderThreadImpl::current());
   if (!ppp_videodecoder_)
     return;
index c52c285..d213ac9 100644 (file)
@@ -47,11 +47,14 @@ VideoDecoderShim::PendingDecode::~PendingDecode() {
 
 struct VideoDecoderShim::PendingFrame {
   explicit PendingFrame(uint32_t decode_id);
-  PendingFrame(uint32_t decode_id, const gfx::Size& size);
+  PendingFrame(uint32_t decode_id,
+               const gfx::Size& coded_size,
+               const gfx::Rect& visible_rect);
   ~PendingFrame();
 
   const uint32_t decode_id;
-  const gfx::Size size;
+  const gfx::Size coded_size;
+  const gfx::Rect visible_rect;
   std::vector<uint8_t> argb_pixels;
 
  private:
@@ -64,10 +67,12 @@ VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id)
 }
 
 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id,
-                                             const gfx::Size& size)
+                                             const gfx::Size& coded_size,
+                                             const gfx::Rect& visible_rect)
     : decode_id(decode_id),
-      size(size),
-      argb_pixels(size.width() * size.height() * 4) {
+      coded_size(coded_size),
+      visible_rect(visible_rect),
+      argb_pixels(coded_size.width() * coded_size.height() * 4) {
 }
 
 VideoDecoderShim::PendingFrame::~PendingFrame() {
@@ -258,7 +263,8 @@ void VideoDecoderShim::DecoderImpl::OnOutputComplete(
     const scoped_refptr<media::VideoFrame>& frame) {
   scoped_ptr<PendingFrame> pending_frame;
   if (!frame->end_of_stream()) {
-    pending_frame.reset(new PendingFrame(decode_id_, frame->coded_size()));
+    pending_frame.reset(new PendingFrame(
+        decode_id_, frame->coded_size(), frame->visible_rect()));
     // Convert the VideoFrame pixels to ABGR to match VideoDecodeAccelerator.
     libyuv::I420ToABGR(frame->data(media::VideoFrame::kYPlane),
                        frame->stride(media::VideoFrame::kYPlane),
@@ -470,7 +476,7 @@ void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) {
   DCHECK(host_);
 
   if (!frame->argb_pixels.empty()) {
-    if (texture_size_ != frame->size) {
+    if (texture_size_ != frame->coded_size) {
       // If the size has changed, all current textures must be dismissed. Add
       // all textures to |textures_to_dismiss_| and dismiss any that aren't in
       // use by the plugin. We will dismiss the rest as they are recycled.
@@ -492,10 +498,10 @@ void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) {
         pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate());
 
       host_->RequestTextures(texture_pool_size_,
-                             frame->size,
+                             frame->coded_size,
                              GL_TEXTURE_2D,
                              pending_texture_mailboxes_);
-      texture_size_ = frame->size;
+      texture_size_ = frame->coded_size;
     }
 
     pending_frames_.push(linked_ptr<PendingFrame>(frame.release()));
@@ -527,7 +533,8 @@ void VideoDecoderShim::SendPictures() {
                       GL_UNSIGNED_BYTE,
                       &frame->argb_pixels.front());
 
-    host_->PictureReady(media::Picture(texture_id, frame->decode_id));
+    host_->PictureReady(
+        media::Picture(texture_id, frame->decode_id, frame->visible_rect));
     pending_frames_.pop();
   }
 
index 10d87e1..07fcb27 100644 (file)
@@ -925,7 +925,7 @@ void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
   base::AutoReset<WebInputEvent::Type> handling_event_type_resetter(
       &handling_event_type_, input_event->type);
 #if defined(OS_ANDROID)
-  // On Android, when the delete key or forward delete key is pressed using IME,
+  // On Android, when a key is pressed or sent from the Keyboard using IME,
   // |AdapterInputConnection| generates input key events to make sure all JS
   // listeners that monitor KeyUp and KeyDown events receive the proper key
   // code. Since this input key event comes from IME, we need to set the
@@ -935,10 +935,9 @@ void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event,
   if (WebInputEvent::isKeyboardEventType(input_event->type)) {
     const WebKeyboardEvent& key_event =
         *static_cast<const WebKeyboardEvent*>(input_event);
-    if (key_event.nativeKeyCode == AKEYCODE_FORWARD_DEL ||
-        key_event.nativeKeyCode == AKEYCODE_DEL) {
+    // Some keys are special and it's essential that no events get blocked.
+    if (key_event.nativeKeyCode != AKEYCODE_TAB)
       ime_event_guard_maybe.reset(new ImeEventGuard(this));
-    }
   }
 #endif
 
index 2087046..4812a4e 100644 (file)
 #include <wrl/wrappers/corewrappers.h>
 
 #include "base/debug/alias.h"
+#include "base/debug/crash_logging.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/memory_mapped_file.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
+#include "base/metrics/histogram.h"
 #include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/win/iat_patch_function.h"
 #include "base/win/registry.h"
@@ -27,6 +30,8 @@ namespace {
 namespace mswr = Microsoft::WRL;
 namespace mswrw = Microsoft::WRL::Wrappers;
 
+static const char kFontKeyName[] = "font_key_name";
+
 class FontCollectionLoader
     : public mswr::RuntimeClass<mswr::RuntimeClassFlags<mswr::ClassicCom>,
                                 IDWriteFontCollectionLoader> {
@@ -45,6 +50,7 @@ class FontCollectionLoader
   std::wstring GetFontNameFromKey(UINT32 idx);
 
   bool LoadFontListFromRegistry();
+  bool LoadRestrictedFontList();
 
   FontCollectionLoader() {};
   virtual ~FontCollectionLoader() {};
@@ -67,7 +73,9 @@ class FontFileStream
                    UINT64 file_offset,
                    UINT64 fragment_size,
                    void** context) {
-    if (!memory_.get() || !memory_->IsValid())
+    if (!memory_.get() || !memory_->IsValid() ||
+        file_offset >= memory_->length() ||
+        (file_offset + fragment_size) > memory_->length())
       return E_FAIL;
 
     *fragment_start = static_cast<BYTE const*>(memory_->data()) +
@@ -106,7 +114,8 @@ class FontFileStream
   HRESULT RuntimeClassInitialize(UINT32 font_key) {
     base::FilePath path;
     PathService::Get(base::DIR_WINDOWS_FONTS, &path);
-    path = path.Append(g_font_loader->GetFontNameFromKey(font_key).c_str());
+    std::wstring font_key_name(g_font_loader->GetFontNameFromKey(font_key));
+    path = path.Append(font_key_name.c_str());
     memory_.reset(new base::MemoryMappedFile());
 
     // Put some debug information on stack.
@@ -120,6 +129,9 @@ class FontFileStream
     }
 
     font_key_ = font_key;
+
+    base::debug::SetCrashKeyValue(kFontKeyName,
+                                  base::WideToUTF8(font_key_name));
     return S_OK;
   }
 
@@ -255,6 +267,9 @@ bool FontCollectionLoader::LoadFontListFromRegistry() {
     return false;
   }
 
+  base::FilePath system_font_path;
+  PathService::Get(base::DIR_WINDOWS_FONTS, &system_font_path);
+
   std::wstring name;
   std::wstring value;
   for (DWORD idx = 0; idx < regkey.GetValueCount(); idx++) {
@@ -265,11 +280,57 @@ bool FontCollectionLoader::LoadFontListFromRegistry() {
       // we will ignore all other registry entries.
       std::vector<base::FilePath::StringType> components;
       path.GetComponents(&components);
-      if (components.size() == 1) {
-        reg_fonts_.push_back(value.c_str());
+      if (components.size() == 1 ||
+          base::FilePath::CompareEqualIgnoreCase(system_font_path.value(),
+                                                 path.DirName().value())) {
+        reg_fonts_.push_back(path.BaseName().value());
       }
     }
   }
+  UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Loaded", reg_fonts_.size());
+  UMA_HISTOGRAM_COUNTS("DirectWrite.Fonts.Ignored",
+                       regkey.GetValueCount() - reg_fonts_.size());
+  return true;
+}
+
+// This list is mainly based on prefs/prefs_tab_helper.cc kFontDefaults.
+const wchar_t* kRestrictedFontSet[] = {
+  L"times.ttf",     // IDS_STANDARD_FONT_FAMILY
+  L"timesbd.ttf",   // IDS_STANDARD_FONT_FAMILY
+  L"timesbi.ttf",   // IDS_STANDARD_FONT_FAMILY
+  L"timesi.ttf",    // IDS_STANDARD_FONT_FAMILY
+  L"cour.ttf",      // IDS_FIXED_FONT_FAMILY
+  L"courbd.ttf",    // IDS_FIXED_FONT_FAMILY
+  L"courbi.ttf",    // IDS_FIXED_FONT_FAMILY
+  L"couri.ttf",     // IDS_FIXED_FONT_FAMILY
+  L"consola.ttf",   // IDS_FIXED_FONT_FAMILY_ALT_WIN
+  L"consolab.ttf",  // IDS_FIXED_FONT_FAMILY_ALT_WIN
+  L"consolai.ttf",  // IDS_FIXED_FONT_FAMILY_ALT_WIN
+  L"consolaz.ttf",  // IDS_FIXED_FONT_FAMILY_ALT_WIN
+  L"arial.ttf",     // IDS_SANS_SERIF_FONT_FAMILY
+  L"arialbd.ttf",   // IDS_SANS_SERIF_FONT_FAMILY
+  L"arialbi.ttf",   // IDS_SANS_SERIF_FONT_FAMILY
+  L"ariali.ttf",    // IDS_SANS_SERIF_FONT_FAMILY
+  L"comic.ttf",     // IDS_CURSIVE_FONT_FAMILY
+  L"comicbd.ttf",   // IDS_CURSIVE_FONT_FAMILY
+  L"comici.ttf",    // IDS_CURSIVE_FONT_FAMILY
+  L"comicz.ttf",    // IDS_CURSIVE_FONT_FAMILY
+  L"impact.ttf",    // IDS_FANTASY_FONT_FAMILY
+  L"segoeui.ttf",   // IDS_PICTOGRAPH_FONT_FAMILY
+  L"segoeuib.ttf",  // IDS_PICTOGRAPH_FONT_FAMILY
+  L"segoeuii.ttf",  // IDS_PICTOGRAPH_FONT_FAMILY
+  L"msgothic.ttc",  // IDS_STANDARD_FONT_FAMILY_JAPANESE
+  L"msmincho.ttc",  // IDS_SERIF_FONT_FAMILY_JAPANESE
+  L"gulim.ttc",     // IDS_FIXED_FONT_FAMILY_KOREAN
+  L"batang.ttc",    // IDS_SERIF_FONT_FAMILY_KOREAN
+  L"simsun.ttc",    // IDS_STANDARD_FONT_FAMILY_SIMPLIFIED_HAN
+  L"mingliu.ttc",   // IDS_SERIF_FONT_FAMILY_TRADITIONAL_HAN
+};
+
+bool FontCollectionLoader::LoadRestrictedFontList() {
+  reg_fonts_.clear();
+  reg_fonts_.assign(kRestrictedFontSet,
+                    kRestrictedFontSet + _countof(kRestrictedFontSet));
   return true;
 }
 
@@ -287,18 +348,37 @@ IDWriteFontCollection* GetCustomFontCollection(IDWriteFactory* factory) {
 
   FontCollectionLoader::Initialize(factory);
 
-  HRESULT hr = factory->CreateCustomFontCollection(
-      g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
+  // We try here to put arbitrary limit on max number of fonts that could
+  // be loaded, otherwise we fallback to restricted set of fonts.
+  const UINT32 kMaxFontThreshold = 1000;
+  HRESULT hr = E_FAIL;
+  if (g_font_loader->GetFontMapSize() < kMaxFontThreshold) {
+    hr = factory->CreateCustomFontCollection(
+        g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
+  }
+
+  bool loadingRestricted = false;
+  if (FAILED(hr) || !g_font_collection.Get()) {
+    // We will try here just one more time with restricted font set.
+    g_font_loader->LoadRestrictedFontList();
+    hr = factory->CreateCustomFontCollection(
+        g_font_loader.Get(), NULL, 0, g_font_collection.GetAddressOf());
+  }
 
   base::TimeDelta time_delta = base::TimeTicks::Now() - start_tick;
   int64 delta = time_delta.ToInternalValue();
   base::debug::Alias(&delta);
   UINT32 size = g_font_loader->GetFontMapSize();
   base::debug::Alias(&size);
+  base::debug::Alias(&loadingRestricted);
 
   CHECK(SUCCEEDED(hr));
   CHECK(g_font_collection.Get() != NULL);
 
+  UMA_HISTOGRAM_TIMES("DirectWrite.Fonts.LoadTime", time_delta);
+
+  base::debug::ClearCrashKey(kFontKeyName);
+
   return g_font_collection.Get();
 }
 
index 9475a07..89cb957 100644 (file)
@@ -89,6 +89,11 @@ void PropertySet::ChangedConnected(const std::string& interface_name,
                                    bool success) {
   LOG_IF(WARNING, !success) << "Failed to connect to " << signal_name
                             << "signal.";
+
+  // This is a simple workaround for crbug.com/407109, which causes signals to
+  // be missed if they are received before a match rule is added for them. This
+  // is a branch-only workaround that is only present in 2125 (38).
+  GetAll();
 }
 
 
index e078c00..3e85126 100644 (file)
@@ -82,8 +82,9 @@ class PropertyTest : public testing::Test {
         object_proxy_,
         base::Bind(&PropertyTest::OnPropertyChanged,
                    base::Unretained(this))));
+
+    // GetAll is called once the signals are connected.
     properties_->ConnectSignals();
-    properties_->GetAll();
   }
 
   virtual void TearDown() {
index 0f1f273..0fe723e 100644 (file)
@@ -432,7 +432,21 @@ void BluetoothDeviceChromeOS::ConnectToService(
   scoped_refptr<BluetoothSocketChromeOS> socket =
       BluetoothSocketChromeOS::CreateBluetoothSocket(
           ui_task_runner_, socket_thread_);
-  socket->Connect(this, uuid, base::Bind(callback, socket), error_callback);
+  socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_MEDIUM,
+                  base::Bind(callback, socket), error_callback);
+}
+
+void BluetoothDeviceChromeOS::ConnectToServiceInsecurely(
+    const BluetoothUUID& uuid,
+    const ConnectToServiceCallback& callback,
+    const ConnectToServiceErrorCallback& error_callback) {
+  VLOG(1) << object_path_.value() << ": Connecting insecurely to service: "
+          << uuid.canonical_value();
+  scoped_refptr<BluetoothSocketChromeOS> socket =
+      BluetoothSocketChromeOS::CreateBluetoothSocket(
+          ui_task_runner_, socket_thread_);
+  socket->Connect(this, uuid, BluetoothSocketChromeOS::SECURITY_LEVEL_LOW,
+                  base::Bind(callback, socket), error_callback);
 }
 
 void BluetoothDeviceChromeOS::CreateGattConnection(
index 6f33560..85ed070 100644 (file)
@@ -73,6 +73,19 @@ class BluetoothDeviceChromeOS
       const base::Closure& callback,
       const ErrorCallback& error_callback) OVERRIDE;
 
+  // Attempts to initiate an insecure outgoing L2CAP or RFCOMM connection to the
+  // advertised service on this device matching |uuid|, performing an SDP lookup
+  // if necessary to determine the correct protocol and channel for the
+  // connection. Unlike ConnectToService, the outgoing connection will request
+  // no bonding rather than general bonding. |callback| will be called on a
+  // successful connection with a BluetoothSocket instance that is to be owned
+  // by the receiver. |error_callback| will be called on failure with a message
+  // indicating the cause.
+  void ConnectToServiceInsecurely(
+    const device::BluetoothUUID& uuid,
+    const ConnectToServiceCallback& callback,
+    const ConnectToServiceErrorCallback& error_callback);
+
   // Creates a pairing object with the given delegate |pairing_delegate| and
   // establishes it as the pairing context for this device. All pairing-related
   // method calls will be forwarded to this object until it is released.
index eb53bd2..5eedf5b 100644 (file)
@@ -92,6 +92,7 @@ BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
 void BluetoothSocketChromeOS::Connect(
     const BluetoothDeviceChromeOS* device,
     const BluetoothUUID& uuid,
+    SecurityLevel security_level,
     const base::Closure& success_callback,
     const ErrorCompletionCallback& error_callback) {
   DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
@@ -107,6 +108,8 @@ void BluetoothSocketChromeOS::Connect(
   device_path_ = device->object_path();
   uuid_ = uuid;
   options_.reset(new BluetoothProfileManagerClient::Options());
+  if (security_level == SECURITY_LEVEL_LOW)
+    options_->require_authentication.reset(new bool(false));
 
   RegisterProfile(success_callback, error_callback);
 }
index 949abf6..ff8ee77 100644 (file)
@@ -34,6 +34,11 @@ class CHROMEOS_EXPORT BluetoothSocketChromeOS
       public device::BluetoothAdapter::Observer,
       public BluetoothProfileServiceProvider::Delegate {
  public:
+  enum SecurityLevel {
+    SECURITY_LEVEL_LOW,
+    SECURITY_LEVEL_MEDIUM
+  };
+
   static scoped_refptr<BluetoothSocketChromeOS> CreateBluetoothSocket(
       scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
       scoped_refptr<device::BluetoothSocketThread> socket_thread);
@@ -45,6 +50,7 @@ class CHROMEOS_EXPORT BluetoothSocketChromeOS
   // with a message explaining the cause of the failure.
   virtual void Connect(const BluetoothDeviceChromeOS* device,
                        const device::BluetoothUUID& uuid,
+                       SecurityLevel security_level,
                        const base::Closure& success_callback,
                        const ErrorCompletionCallback& error_callback);
 
index b357216..3df6e60 100644 (file)
@@ -17,21 +17,28 @@ HidConnectionMac::HidConnectionMac(HidDeviceInfo device_info)
   message_loop_ = base::MessageLoopProxy::current();
 
   DCHECK(device_.get());
+
   size_t expected_report_size = device_info.max_input_report_size;
   if (device_info.has_report_id) {
     expected_report_size++;
   }
-  inbound_buffer_.reset((uint8_t*)malloc(expected_report_size));
-  IOHIDDeviceRegisterInputReportCallback(device_.get(),
-                                         inbound_buffer_.get(),
-                                         expected_report_size,
-                                         &HidConnectionMac::InputReportCallback,
-                                         this);
-  IOHIDDeviceOpen(device_, kIOHIDOptionsTypeNone);
+  inbound_buffer_.resize(expected_report_size);
+  if (inbound_buffer_.size() > 0) {
+    IOHIDDeviceRegisterInputReportCallback(
+        device_.get(),
+        &inbound_buffer_[0],
+        inbound_buffer_.size(),
+        &HidConnectionMac::InputReportCallback,
+        this);
+  }
 }
 
 HidConnectionMac::~HidConnectionMac() {
-  IOHIDDeviceClose(device_, kIOHIDOptionsTypeNone);
+  if (inbound_buffer_.size() > 0) {
+    // Unregister the input report callback before this object is freed.
+    IOHIDDeviceRegisterInputReportCallback(
+        device_.get(), &inbound_buffer_[0], inbound_buffer_.size(), NULL, this);
+  }
   Flush();
 }
 
@@ -74,8 +81,10 @@ void HidConnectionMac::PlatformGetFeatureReport(
                                          &report_size);
   if (result == kIOReturnSuccess)
     callback.Run(true, report_size);
-  else
+  else {
+    VLOG(1) << "Failed to get feature report: " << result;
     callback.Run(false, 0);
+  }
 }
 
 void HidConnectionMac::PlatformSendFeatureReport(
@@ -92,6 +101,11 @@ void HidConnectionMac::InputReportCallback(void* context,
                                            uint32_t report_id,
                                            uint8_t* report_bytes,
                                            CFIndex report_length) {
+  if (result != kIOReturnSuccess) {
+    VLOG(1) << "Failed to read input report: " << result;
+    return;
+  }
+
   HidConnectionMac* connection = static_cast<HidConnectionMac*>(context);
   // report_id is already contained in report_bytes
   scoped_refptr<net::IOBufferWithSize> buffer;
@@ -130,6 +144,7 @@ void HidConnectionMac::WriteReport(IOHIDReportType type,
   if (res != kIOReturnSuccess) {
     callback.Run(false, 0);
   } else {
+    VLOG(1) << "Failed to set report: " << res;
     callback.Run(true, output_buffer->size());
   }
 }
index 02dde04..33deadf 100644 (file)
@@ -65,7 +65,7 @@ class HidConnectionMac : public HidConnection {
 
   base::ScopedCFTypeRef<IOHIDDeviceRef> device_;
   scoped_refptr<base::MessageLoopProxy> message_loop_;
-  scoped_ptr<uint8_t, base::FreeDeleter> inbound_buffer_;
+  std::vector<uint8_t> inbound_buffer_;
 
   std::queue<PendingHidReport> pending_reports_;
   std::queue<PendingHidRead> pending_reads_;
index eb55e41..ee6fab3 100644 (file)
@@ -114,12 +114,12 @@ void SerialIoHandler::ReadCompleted(int bytes_read,
                                     serial::ReceiveError error) {
   DCHECK(CalledOnValidThread());
   DCHECK(IsReadPending());
+  scoped_ptr<WritableBuffer> pending_read_buffer = pending_read_buffer_.Pass();
   if (error == serial::RECEIVE_ERROR_NONE) {
-    pending_read_buffer_->Done(bytes_read);
+    pending_read_buffer->Done(bytes_read);
   } else {
-    pending_read_buffer_->DoneWithError(bytes_read, error);
+    pending_read_buffer->DoneWithError(bytes_read, error);
   }
-  pending_read_buffer_.reset();
   Release();
 }
 
@@ -127,12 +127,13 @@ void SerialIoHandler::WriteCompleted(int bytes_written,
                                      serial::SendError error) {
   DCHECK(CalledOnValidThread());
   DCHECK(IsWritePending());
+  scoped_ptr<ReadOnlyBuffer> pending_write_buffer =
+      pending_write_buffer_.Pass();
   if (error == serial::SEND_ERROR_NONE) {
-    pending_write_buffer_->Done(bytes_written);
+    pending_write_buffer->Done(bytes_written);
   } else {
-    pending_write_buffer_->DoneWithError(bytes_written, error);
+    pending_write_buffer->DoneWithError(bytes_written, error);
   }
-  pending_write_buffer_.reset();
   Release();
 }
 
index f409865..3f0e258 100644 (file)
@@ -310,6 +310,7 @@ void HidSendFeatureReportFunction::AsyncWorkStart() {
   }
   scoped_refptr<net::IOBufferWithSize> buffer(
       new net::IOBufferWithSize(parameters_->data.size()));
+  memcpy(buffer->data(), parameters_->data.c_str(), parameters_->data.size());
   resource->connection()->SendFeatureReport(
       static_cast<uint8_t>(parameters_->report_id),
       buffer,
index c1e6e95..1c9ae97 100644 (file)
@@ -35,6 +35,7 @@ ContentHashReader::ContentHashReader(const std::string& extension_id,
       relative_path_(relative_path),
       key_(key),
       status_(NOT_INITIALIZED),
+      content_exists_(false),
       have_verified_contents_(false),
       have_computed_hashes_(false),
       block_size_(0) {
@@ -50,6 +51,13 @@ bool ContentHashReader::Init() {
   base::FilePath verified_contents_path =
       file_util::GetVerifiedContentsPath(extension_root_);
 
+  // Check that this is a valid resource to verify (i.e., it exists).
+  base::FilePath content_path = extension_root_.Append(relative_path_);
+  if (!base::PathExists(content_path))
+    return false;
+
+  content_exists_ = true;
+
   if (!base::PathExists(verified_contents_path))
     return false;
 
index cc2ea38..516897b 100644 (file)
@@ -40,11 +40,15 @@ class ContentHashReader : public base::RefCountedThreadSafe<ContentHashReader> {
   // should likely be discarded.
   bool Init();
 
+  // Indicates whether the content in question exists in the local extension
+  // installation. This may be |false| if Init fails.
+  bool content_exists() const { return content_exists_; }
+
   // These return whether we found valid verified_contents.json /
   // computed_hashes.json files respectively. Note that both of these can be
   // true but we still didn't find an entry for |relative_path_| in them.
-  bool have_verified_contents() { return have_verified_contents_; }
-  bool have_computed_hashes() { return have_computed_hashes_; }
+  bool have_verified_contents() const { return have_verified_contents_; }
+  bool have_computed_hashes() const { return have_computed_hashes_; }
 
   // Return the number of blocks and block size, respectively. Only valid after
   // calling Init().
@@ -69,6 +73,8 @@ class ContentHashReader : public base::RefCountedThreadSafe<ContentHashReader> {
 
   InitStatus status_;
 
+  bool content_exists_;
+
   bool have_verified_contents_;
   bool have_computed_hashes_;
 
index f8618bc..e7e8cab 100644 (file)
@@ -152,11 +152,15 @@ bool ContentVerifyJob::FinishBlock() {
 
 void ContentVerifyJob::OnHashesReady(bool success) {
   if (!success && !g_test_delegate) {
-    if (hash_reader_->have_verified_contents() &&
-        hash_reader_->have_computed_hashes())
+    if (!hash_reader_->content_exists()) {
+      // Ignore verification of non-existent resources.
+      return;
+    } else if (hash_reader_->have_verified_contents() &&
+               hash_reader_->have_computed_hashes()) {
       DispatchFailureCallback(NO_HASHES_FOR_FILE);
-    else
+    } else {
       DispatchFailureCallback(MISSING_ALL_HASHES);
+    }
     return;
   }
 
index d7687ea..ce88dd9 100644 (file)
@@ -941,6 +941,8 @@ enum HistogramValue {
   EASYUNLOCKPRIVATE_CLEARPERMITACCESS,
   EASYUNLOCKPRIVATE_SETREMOTEDEVICES,
   EASYUNLOCKPRIVATE_GETREMOTEDEVICES,
+  FILESYSTEMPROVIDER_GETALL,
+  EASYUNLOCKPRIVATE_CONNECTTOBLUETOOTHSERVICEINSECURELY,
   // Last entry: Add new entries above and ensure to update
   // tools/metrics/histograms/histograms.xml.
   ENUM_BOUNDARY
index f4cd4f0..08e45d2 100644 (file)
@@ -183,9 +183,8 @@ void OAuth2AccessTokenFetcherImpl::EndGetAccessToken(
     case net::HTTP_OK:
       break;
     case net::HTTP_FORBIDDEN:
-    case net::HTTP_INTERNAL_SERVER_ERROR:
       // HTTP_FORBIDDEN (403) is treated as temporary error, because it may be
-      // '403 Rate Limit Exeeded.' 500 is always treated as transient.
+      // '403 Rate Limit Exeeded.'
       OnGetTokenFailure(
           GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
       return;
@@ -212,11 +211,20 @@ void OAuth2AccessTokenFetcherImpl::EndGetAccessToken(
               : GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR));
       return;
     }
-    default:
-      // The other errors are treated as permanent error.
-      OnGetTokenFailure(GoogleServiceAuthError(
-          GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+    default: {
+      if (source->GetResponseCode() >= net::HTTP_INTERNAL_SERVER_ERROR) {
+        // 5xx is always treated as transient.
+        OnGetTokenFailure(GoogleServiceAuthError(
+            GoogleServiceAuthError::SERVICE_UNAVAILABLE));
+      } else {
+        // The other errors are treated as permanent error.
+        DLOG(ERROR) << "Unexpected persistent error: http_status="
+                    << source->GetResponseCode();
+        OnGetTokenFailure(GoogleServiceAuthError(
+            GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+      }
       return;
+    }
   }
 
   // The request was successfully fetched and it returned OK.
index cf90aed..4963f13 100644 (file)
@@ -536,7 +536,7 @@ int ConnectionFactoryImpl::ReconsiderProxyAfterError(int error) {
 
 void ConnectionFactoryImpl::ReportSuccessfulProxyConnection() {
   if (gcm_network_session_ && gcm_network_session_->proxy_service())
-    gcm_network_session_->proxy_service()->ReportSuccess(proxy_info_);
+    gcm_network_session_->proxy_service()->ReportSuccess(proxy_info_, NULL);
 }
 
 void ConnectionFactoryImpl::CloseSocket() {
index 0a8294a..a5648df 100644 (file)
@@ -37,18 +37,17 @@ namespace gpu {
 
 namespace {
 
-const int32 kCommandBufferSize = 1024 * 1024;
-// TODO(kbr): make the transfer buffer size configurable via context
-// creation attributes.
-const size_t kStartTransferBufferSize = 4 * 1024 * 1024;
-const size_t kMinTransferBufferSize = 1 * 256 * 1024;
-const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
+const int32 kDefaultCommandBufferSize = 1024 * 1024;
+const unsigned int kDefaultStartTransferBufferSize = 4 * 1024 * 1024;
+const unsigned int kDefaultMinTransferBufferSize = 1 * 256 * 1024;
+const unsigned int kDefaultMaxTransferBufferSize = 16 * 1024 * 1024;
 
 class GLInProcessContextImpl
     : public GLInProcessContext,
       public base::SupportsWeakPtr<GLInProcessContextImpl> {
  public:
-  explicit GLInProcessContextImpl();
+  explicit GLInProcessContextImpl(
+      const GLInProcessContextSharedMemoryLimits& mem_limits);
   virtual ~GLInProcessContextImpl();
 
   bool Initialize(
@@ -65,6 +64,7 @@ class GLInProcessContextImpl
   // GLInProcessContext implementation:
   virtual void SetContextLostCallback(const base::Closure& callback) OVERRIDE;
   virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE;
+  virtual size_t GetMappedMemoryLimit() OVERRIDE;
 
 #if defined(OS_ANDROID)
   virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
@@ -81,6 +81,7 @@ class GLInProcessContextImpl
   scoped_ptr<gles2::GLES2Implementation> gles2_implementation_;
   scoped_ptr<InProcessCommandBuffer> command_buffer_;
 
+  const GLInProcessContextSharedMemoryLimits mem_limits_;
   bool context_lost_;
   base::Closure context_lost_callback_;
 
@@ -92,8 +93,10 @@ base::LazyInstance<base::Lock> g_all_shared_contexts_lock =
 base::LazyInstance<std::set<GLInProcessContextImpl*> > g_all_shared_contexts =
     LAZY_INSTANCE_INITIALIZER;
 
-GLInProcessContextImpl::GLInProcessContextImpl()
-    : context_lost_(false) {}
+GLInProcessContextImpl::GLInProcessContextImpl(
+    const GLInProcessContextSharedMemoryLimits& mem_limits)
+    : mem_limits_(mem_limits), context_lost_(false) {
+}
 
 GLInProcessContextImpl::~GLInProcessContextImpl() {
   {
@@ -107,6 +110,10 @@ gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() {
   return gles2_implementation_.get();
 }
 
+size_t GLInProcessContextImpl::GetMappedMemoryLimit() {
+  return mem_limits_.mapped_memory_reclaim_limit;
+}
+
 void GLInProcessContextImpl::SetContextLostCallback(
     const base::Closure& callback) {
   context_lost_callback_ = callback;
@@ -181,7 +188,7 @@ bool GLInProcessContextImpl::Initialize(
 
   // Create the GLES2 helper, which writes the command buffer protocol.
   gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
-  if (!gles2_helper_->Initialize(kCommandBufferSize)) {
+  if (!gles2_helper_->Initialize(mem_limits_.command_buffer_size)) {
     LOG(ERROR) << "Failed to initialize GLES2CmdHelper";
     Destroy();
     return false;
@@ -209,10 +216,10 @@ bool GLInProcessContextImpl::Initialize(
   }
 
   if (!gles2_implementation_->Initialize(
-      kStartTransferBufferSize,
-      kMinTransferBufferSize,
-      kMaxTransferBufferSize,
-      gles2::GLES2Implementation::kNoLimit)) {
+          mem_limits_.start_transfer_buffer_size,
+          mem_limits_.min_transfer_buffer_size,
+          mem_limits_.max_transfer_buffer_size,
+          mem_limits_.mapped_memory_reclaim_limit)) {
     return false;
   }
 
@@ -245,6 +252,15 @@ GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id) {
 
 }  // anonymous namespace
 
+GLInProcessContextSharedMemoryLimits::GLInProcessContextSharedMemoryLimits()
+    : command_buffer_size(kDefaultCommandBufferSize),
+      start_transfer_buffer_size(kDefaultStartTransferBufferSize),
+      min_transfer_buffer_size(kDefaultMinTransferBufferSize),
+      max_transfer_buffer_size(kDefaultMaxTransferBufferSize),
+      mapped_memory_reclaim_limit(gles2::GLES2Implementation::kNoLimit) {
+}
+
+// static
 GLInProcessContext* GLInProcessContext::Create(
     scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
     scoped_refptr<gfx::GLSurface> surface,
@@ -254,7 +270,8 @@ GLInProcessContext* GLInProcessContext::Create(
     GLInProcessContext* share_context,
     bool use_global_share_group,
     const ::gpu::gles2::ContextCreationAttribHelper& attribs,
-    gfx::GpuPreference gpu_preference) {
+    gfx::GpuPreference gpu_preference,
+    const GLInProcessContextSharedMemoryLimits& memory_limits) {
   DCHECK(!use_global_share_group || !share_context);
   if (surface.get()) {
     DCHECK_EQ(surface->IsOffscreen(), is_offscreen);
@@ -262,7 +279,8 @@ GLInProcessContext* GLInProcessContext::Create(
     DCHECK_EQ(gfx::kNullAcceleratedWidget, window);
   }
 
-  scoped_ptr<GLInProcessContextImpl> context(new GLInProcessContextImpl());
+  scoped_ptr<GLInProcessContextImpl> context(
+      new GLInProcessContextImpl(memory_limits));
   if (!context->Initialize(surface,
                            is_offscreen,
                            use_global_share_group,
index 6175cc5..33b1348 100644 (file)
@@ -30,6 +30,16 @@ namespace gles2 {
 class GLES2Implementation;
 }
 
+struct GL_IN_PROCESS_CONTEXT_EXPORT GLInProcessContextSharedMemoryLimits {
+  GLInProcessContextSharedMemoryLimits();
+
+  int32 command_buffer_size;
+  unsigned int start_transfer_buffer_size;
+  unsigned int min_transfer_buffer_size;
+  unsigned int max_transfer_buffer_size;
+  unsigned int mapped_memory_reclaim_limit;
+};
+
 class GL_IN_PROCESS_CONTEXT_EXPORT GLInProcessContext {
  public:
   virtual ~GLInProcessContext() {}
@@ -53,7 +63,8 @@ class GL_IN_PROCESS_CONTEXT_EXPORT GLInProcessContext {
       GLInProcessContext* share_context,
       bool use_global_share_group,
       const gpu::gles2::ContextCreationAttribHelper& attribs,
-      gfx::GpuPreference gpu_preference);
+      gfx::GpuPreference gpu_preference,
+      const GLInProcessContextSharedMemoryLimits& memory_limits);
 
   virtual void SetContextLostCallback(const base::Closure& callback) = 0;
 
@@ -61,6 +72,8 @@ class GL_IN_PROCESS_CONTEXT_EXPORT GLInProcessContext {
   // can be used without making it current.
   virtual gles2::GLES2Implementation* GetImplementation() = 0;
 
+  virtual size_t GetMappedMemoryLimit() = 0;
+
 #if defined(OS_ANDROID)
   virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
       uint32 stream_id) = 0;
index ba1ad2e..eadc34f 100644 (file)
 namespace gpu {
 namespace {
 
-bool IsBroadcom() {
-  const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
-  if (vendor)
-    return std::string(vendor).find("Broadcom") != std::string::npos;
-  return false;
+enum GpuType {
+  GPU_BROADCOM,
+  GPU_IMAGINATION,
+  GPU_NVIDIA_ES31,
+  GPU_ADRENO_420,
+  GPU_OTHER,
+};
+
+std::string MakeString(const char* s) {
+  return std::string(s ? s : "");
 }
 
-bool IsImagination() {
-  const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
-  if (vendor)
-    return std::string(vendor).find("Imagination") != std::string::npos;
-  return false;
+GpuType GetGpuType() {
+  const std::string vendor = MakeString(
+      reinterpret_cast<const char*>(glGetString(GL_VENDOR)));
+  const std::string renderer = MakeString(
+      reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
+  const std::string version = MakeString(
+      reinterpret_cast<const char*>(glGetString(GL_VERSION)));
+
+  if (vendor.find("Broadcom") != std::string::npos)
+    return GPU_BROADCOM;
+
+  if (vendor.find("Imagination") != std::string::npos)
+    return GPU_IMAGINATION;
+
+  if (vendor.find("NVIDIA") != std::string::npos &&
+      version.find("OpenGL ES 3.1") != std::string::npos) {
+    return GPU_NVIDIA_ES31;
+  }
+
+  if (vendor.find("Qualcomm") != std::string::npos &&
+      renderer.find("Adreno (TM) 420") != std::string::npos) {
+    return GPU_ADRENO_420;
+  }
+
+  return GPU_OTHER;
 }
 
-bool IsNvidia31() {
-  const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
-  const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
-  return vendor && version &&
-         std::string(vendor).find("NVIDIA") != std::string::npos &&
-         std::string(version).find("OpenGL ES 3.1") != std::string::npos;
+bool AllowTransferThreadForGpu() {
+  GpuType gpu = GetGpuType();
+  return gpu != GPU_BROADCOM && gpu != GPU_IMAGINATION &&
+         gpu != GPU_NVIDIA_ES31 && gpu != GPU_ADRENO_420;
 }
 
 }
@@ -51,24 +74,25 @@ bool IsNvidia31() {
 // resolution of crbug.com/271929
 AsyncPixelTransferManager* AsyncPixelTransferManager::Create(
     gfx::GLContext* context) {
-  TRACE_EVENT0("gpu", "AsyncPixelTransferManager::Create");
+  DCHECK(context->IsCurrent(NULL));
   switch (gfx::GetGLImplementation()) {
     case gfx::kGLImplementationEGLGLES2:
       DCHECK(context);
-      if (context->HasExtension("EGL_KHR_fence_sync") &&
+      if (!base::SysInfo::IsLowEndDevice() &&
+          context->HasExtension("EGL_KHR_fence_sync") &&
           context->HasExtension("EGL_KHR_image") &&
           context->HasExtension("EGL_KHR_image_base") &&
           context->HasExtension("EGL_KHR_gl_texture_2D_image") &&
           context->HasExtension("GL_OES_EGL_image") &&
-          !IsBroadcom() &&
-          !IsImagination() &&
-          !IsNvidia31() &&
-          !base::SysInfo::IsLowEndDevice()) {
+          AllowTransferThreadForGpu()) {
+        TRACE_EVENT0("gpu", "AsyncPixelTransferManager_CreateWithThread");
         return new AsyncPixelTransferManagerEGL;
       }
       return new AsyncPixelTransferManagerIdle;
-    case gfx::kGLImplementationOSMesaGL:
+    case gfx::kGLImplementationOSMesaGL: {
+      TRACE_EVENT0("gpu", "AsyncPixelTransferManager_CreateIdle");
       return new AsyncPixelTransferManagerIdle;
+    }
     case gfx::kGLImplementationMockGL:
       return new AsyncPixelTransferManagerStub;
     default:
index 6aa7cfb..4c9ed26 100644 (file)
@@ -514,7 +514,7 @@ void InProcessCommandBuffer::PerformIdleWork() {
   CheckSequencedThread();
   idle_work_pending_ = false;
   base::AutoLock lock(command_buffer_lock_);
-  if (gpu_scheduler_->HasMoreWork()) {
+  if (MakeCurrent() && gpu_scheduler_->HasMoreWork()) {
     gpu_scheduler_->PerformIdleWork();
     ScheduleIdleWorkOnGpuThread();
   }
index 4cbb757..6a12707 100644 (file)
@@ -18,7 +18,7 @@ const char kSoftwareRenderingListJson[] = LONG_STRING_CONST(
 {
   "name": "software rendering list",
   // Please update the version number whenever you change this file.
-  "version": "9.3",
+  "version": "9.7",
   "entries": [
     {
       "id": 1,
@@ -861,28 +861,24 @@ LONG_STRING_CONST(
     },
     {
       "id": 83,
-      "description": "Samsung Gaxlaxy NOTE II is too buggy to use for video decoding",
+      "description": "Samsung Galaxy NOTE is too buggy to use for video decoding",
       "cr_bugs": [308721],
       "os": {
-        "type": "android",
-        "version": {
-          "op": "<=",
-          "value": "4.1.2"
-        }
+        "type": "android"
       },
-      "machine_model_name": ["GT-N7100"],
+      "machine_model_name": ["GT-.*"],
       "features": [
         "accelerated_video_decode"
       ]
     },
     {
       "id": 85,
-      "description": "Samsung Gaxlaxy S4 is too buggy to use for video decoding",
+      "description": "Samsung Galaxy S4 is too buggy to use for video decoding",
       "cr_bugs": [329072],
       "os": {
         "type": "android"
       },
-      "machine_model_name": ["SCH-I545"],
+      "machine_model_name": ["SCH-.*"],
       "features": [
         "accelerated_video_decode"
       ]
@@ -1092,8 +1088,8 @@ LONG_STRING_CONST(
           },
           "machine_model_name": ["HTC One",
                                  "C5303", "C6603", "C6903",
-                                 "GT-I8262", "GT-I8552", "GT-I9195", "GT-I9300",
-                                 "GT-I9500", "GT-I9505", "GT-N7100",
+                                 "GT-I8262", "GT-I8552", "GT-I9195",
+                                 "GT-I9500", "GT-I9505",
                                  "SAMSUNG-SCH-I337", "SCH-I545", "SGH-M919",
                                  "SM-N900", "SM-N9005", "SPH-L720",
                                  "XT907", "XT1032", "XT1033", "XT1080"]
@@ -1136,6 +1132,27 @@ LONG_STRING_CONST(
       "features": [
         "gpu_rasterization"
       ]
+    },
+    {
+      "id": 100,
+      "description": "GPU rasterization is blacklisted on Nexus 10",
+      "cr_bugs": [407144],
+      "gl_renderer": ".*Mali-T604.*",
+      "features": [
+        "gpu_rasterization"
+      ]
+    },
+    {
+      "id": 101,
+      "description": "Samsung Galaxy Tab is too buggy to use for video decoding",
+      "cr_bugs": [408353],
+      "os": {
+        "type": "android"
+      },
+      "machine_model_name": ["SM-.*"],
+      "features": [
+        "accelerated_video_decode"
+      ]
     }
   ]
 }
index 879667e..24fb646 100644 (file)
@@ -33,6 +33,7 @@ const UAVersions& GetUAVersionsForCurrentOS() {
   // Safari version can't be, so a lookup table is used instead (for both, since
   // the reported versions should stay in sync).
   static const OSVersionMap version_map[] = {
+    { 8, 0, { "600.1.4",   "600.1.4" } },
     { 7, 1, { "9537.53",   "537.51.2" } },
     { 7, 0, { "9537.53",   "537.51.1" } },
     // 6.1 has the same values as 6.0.
index eabf85e..cff6cd4 100644 (file)
@@ -66,6 +66,9 @@ ChannelWin::ChannelWin(const IPC::ChannelHandle &channel_handle,
       validate_client_(false),
       writing_(false),
       debug_flags_(0),
+      write_error_(0),
+      last_write_error_(0),
+      write_size_(0),
       client_secret_(0),
       weak_factory_(this) {
   CreatePipe(channel_handle, mode);
@@ -439,14 +442,16 @@ bool ChannelWin::ProcessOutgoingMessages(
   debug_flags_ |= WRITE_MSG;
   CHECK(!writing_);
   writing_ = true;
+  write_size_ = static_cast<uint32>(m->size());
+  write_error_ = 0;
   BOOL ok = WriteFile(pipe_,
                       m->data(),
-                      static_cast<int>(m->size()),
-                      &bytes_written,
+                      write_size_,
+                      NULL,
                       &output_state_.context.overlapped);
   if (!ok) {
-    DWORD err = GetLastError();
-    if (err == ERROR_IO_PENDING) {
+    write_error_ = GetLastError();
+    if (write_error_ == ERROR_IO_PENDING) {
       output_state_.is_pending = true;
 
       DVLOG(2) << "sent pending message @" << m << " on channel @" << this
@@ -455,7 +460,8 @@ bool ChannelWin::ProcessOutgoingMessages(
       return true;
     }
     writing_ = false;
-    LOG(ERROR) << "pipe error: " << err;
+    last_write_error_ = write_error_;
+    LOG(ERROR) << "pipe error: " << write_error_;
     return false;
   }
 
index 2bbb294..a38f976 100644 (file)
@@ -98,7 +98,16 @@ class ChannelWin : public Channel,
   bool writing_;
 
   // Tracks the lifetime of this object, for debugging purposes.
-  int32 debug_flags_;
+  uint32 debug_flags_;
+
+  // OS result for the current write. TODO(rvargas): remove this.
+  uint32 write_error_;
+
+  // OS result for a previous failed write. TODO(rvargas): remove this.
+  uint32 last_write_error_;
+
+  // Size of the current write. TODO(rvargas): remove this.
+  uint32 write_size_;
 
   // This is a unique per-channel value used to authenticate the client end of
   // a connection. If the value is non-zero, the client passes it in the hello
index d7fcb13..91eb5ae 100644 (file)
@@ -12,7 +12,9 @@
 #include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
+#include "net/http/http_auth_controller.h"
 #include "net/http/http_network_session.h"
+#include "net/http/proxy_client_socket.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/client_socket_pool_manager.h"
 #include "net/url_request/url_request_context.h"
@@ -270,6 +272,15 @@ int ProxyResolvingClientSocket::ReconsiderProxyAfterError(int error) {
       // "address unreachable" error, and will report both of these failures as
       // ERR_ADDRESS_UNREACHABLE.
       return net::ERR_ADDRESS_UNREACHABLE;
+    case net::ERR_PROXY_AUTH_REQUESTED: {
+      net::ProxyClientSocket* proxy_socket =
+          static_cast<net::ProxyClientSocket*>(transport_->socket());
+
+      if (proxy_socket->GetAuthController()->HaveAuth())
+        return proxy_socket->RestartWithAuth(connect_callback_);
+
+      return error;
+    }
     default:
       return error;
   }
@@ -309,7 +320,7 @@ int ProxyResolvingClientSocket::ReconsiderProxyAfterError(int error) {
 }
 
 void ProxyResolvingClientSocket::ReportSuccessfulProxyConnection() {
-  network_session_->proxy_service()->ReportSuccess(proxy_info_);
+  network_session_->proxy_service()->ReportSuccess(proxy_info_, NULL);
 }
 
 void ProxyResolvingClientSocket::Disconnect() {
index bcd9c72..72fb83b 100644 (file)
@@ -8,6 +8,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
+#include "media/audio/audio_parameters.h"
 #include "media/base/limits.h"
 #include "media/base/scoped_histogram_timer.h"
 #include "media/base/user_input_monitor.h"
@@ -85,6 +86,7 @@ AudioInputController::AudioInputController(EventHandler* handler,
       max_volume_(0.0),
       user_input_monitor_(user_input_monitor),
 #if defined(AUDIO_POWER_MONITORING)
+      log_silence_state_(false),
       silence_state_(SILENCE_STATE_NO_MEASUREMENT),
 #endif
       prev_key_down_count_(0) {
@@ -118,9 +120,13 @@ scoped_refptr<AudioInputController> AudioInputController::Create(
 
   // Create and open a new audio input stream from the existing
   // audio-device thread.
-  if (!controller->task_runner_->PostTask(FROM_HERE,
-          base::Bind(&AudioInputController::DoCreate, controller,
-                     base::Unretained(audio_manager), params, device_id))) {
+  if (!controller->task_runner_->PostTask(
+          FROM_HERE,
+          base::Bind(&AudioInputController::DoCreate,
+                     controller,
+                     base::Unretained(audio_manager),
+                     params,
+                     device_id))) {
     controller = NULL;
   }
 
@@ -149,9 +155,13 @@ scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
 
   // Create and open a new audio input stream from the existing
   // audio-device thread. Use the provided audio-input device.
-  if (!controller->task_runner_->PostTask(FROM_HERE,
-          base::Bind(&AudioInputController::DoCreate, controller,
-                     base::Unretained(audio_manager), params, device_id))) {
+  if (!controller->task_runner_->PostTask(
+          FROM_HERE,
+          base::Bind(&AudioInputController::DoCreateForLowLatency,
+                     controller,
+                     base::Unretained(audio_manager),
+                     params,
+                     device_id))) {
     controller = NULL;
   }
 
@@ -218,12 +228,15 @@ void AudioInputController::DoCreate(AudioManager* audio_manager,
                                     const std::string& device_id) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
+  if (handler_)
+    handler_->OnLog(this, "AIC::DoCreate");
 
 #if defined(AUDIO_POWER_MONITORING)
   // Create the audio (power) level meter given the provided audio parameters.
   // An AudioBus is also needed to wrap the raw data buffer from the native
   // layer to match AudioPowerMonitor::Scan().
   // TODO(henrika): Remove use of extra AudioBus. See http://crbug.com/375155.
+  last_audio_level_log_time_ = base::TimeTicks::Now();
   audio_level_.reset(new media::AudioPowerMonitor(
       params.sample_rate(),
       TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMilliseconds)));
@@ -238,6 +251,21 @@ void AudioInputController::DoCreate(AudioManager* audio_manager,
   DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id));
 }
 
+void AudioInputController::DoCreateForLowLatency(AudioManager* audio_manager,
+                                                 const AudioParameters& params,
+                                                 const std::string& device_id) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+#if defined(AUDIO_POWER_MONITORING)
+  // We only log silence state UMA stats for low latency mode and if we use a
+  // real device.
+  if (params.format() != AudioParameters::AUDIO_FAKE)
+    log_silence_state_ = true;
+#endif
+
+  DoCreate(audio_manager, params, device_id);
+}
+
 void AudioInputController::DoCreateForStream(
     AudioInputStream* stream_to_control) {
   DCHECK(task_runner_->BelongsToCurrentThread());
@@ -298,6 +326,9 @@ void AudioInputController::DoRecord() {
     state_ = RECORDING;
   }
 
+  if (handler_)
+    handler_->OnLog(this, "AIC::DoRecord");
+
   if (no_data_timer_) {
     // Start the data timer. Once |kTimerResetIntervalSeconds| have passed,
     // a callback to FirstCheckForNoData() is made.
@@ -316,6 +347,9 @@ void AudioInputController::DoClose() {
   if (state_ == CLOSED)
     return;
 
+  if (handler_)
+    handler_->OnLog(this, "AIC::DoClose");
+
   // Delete the timer on the same thread that created it.
   no_data_timer_.reset();
 
@@ -329,10 +363,10 @@ void AudioInputController::DoClose() {
     user_input_monitor_->DisableKeyPressMonitoring();
 
 #if defined(AUDIO_POWER_MONITORING)
-  // Send UMA stats if we have enabled power monitoring.
-  if (audio_level_) {
+  // Send UMA stats if enabled.
+  if (log_silence_state_)
     LogSilenceState(silence_state_);
-  }
+  log_silence_state_ = false;
 #endif
 
   state_ = CLOSED;
@@ -383,6 +417,11 @@ void AudioInputController::FirstCheckForNoData() {
   LogCaptureStartupResult(GetDataIsActive() ?
                           CAPTURE_STARTUP_OK :
                           CAPTURE_STARTUP_NO_DATA_CALLBACK);
+  if (handler_) {
+    handler_->OnLog(this, GetDataIsActive() ?
+                    "AIC::FirstCheckForNoData => data is active" :
+                    "AIC::FirstCheckForNoData => data is NOT active");
+  }
   DoCheckForNoData();
 }
 
@@ -503,26 +542,11 @@ void AudioInputController::DoLogAudioLevel(float level_dbfs) {
   std::string log_string = base::StringPrintf(
       "AIC::OnData: average audio level=%.2f dBFS", level_dbfs);
   static const float kSilenceThresholdDBFS = -72.24719896f;
-  if (level_dbfs < kSilenceThresholdDBFS) {
+  if (level_dbfs < kSilenceThresholdDBFS)
     log_string += " <=> no audio input!";
-    if (silence_state_ == SILENCE_STATE_NO_MEASUREMENT)
-      silence_state_ = SILENCE_STATE_ONLY_SILENCE;
-    else if (silence_state_ == SILENCE_STATE_ONLY_AUDIO)
-      silence_state_ = SILENCE_STATE_AUDIO_AND_SILENCE;
-    else
-      DCHECK(silence_state_ == SILENCE_STATE_ONLY_SILENCE ||
-             silence_state_ == SILENCE_STATE_AUDIO_AND_SILENCE);
-  } else {
-    if (silence_state_ == SILENCE_STATE_NO_MEASUREMENT)
-      silence_state_ = SILENCE_STATE_ONLY_AUDIO;
-    else if (silence_state_ == SILENCE_STATE_ONLY_SILENCE)
-      silence_state_ = SILENCE_STATE_AUDIO_AND_SILENCE;
-    else
-      DCHECK(silence_state_ == SILENCE_STATE_ONLY_AUDIO ||
-             silence_state_ == SILENCE_STATE_AUDIO_AND_SILENCE);
-  }
-
   handler_->OnLog(this, log_string);
+
+  UpdateSilenceState(level_dbfs < kSilenceThresholdDBFS);
 #endif
 }
 
@@ -555,6 +579,28 @@ bool AudioInputController::GetDataIsActive() {
 }
 
 #if defined(AUDIO_POWER_MONITORING)
+void AudioInputController::UpdateSilenceState(bool silence) {
+  if (silence) {
+    if (silence_state_ == SILENCE_STATE_NO_MEASUREMENT) {
+      silence_state_ = SILENCE_STATE_ONLY_SILENCE;
+    } else if (silence_state_ == SILENCE_STATE_ONLY_AUDIO) {
+      silence_state_ = SILENCE_STATE_AUDIO_AND_SILENCE;
+    } else {
+      DCHECK(silence_state_ == SILENCE_STATE_ONLY_SILENCE ||
+             silence_state_ == SILENCE_STATE_AUDIO_AND_SILENCE);
+    }
+  } else {
+    if (silence_state_ == SILENCE_STATE_NO_MEASUREMENT) {
+      silence_state_ = SILENCE_STATE_ONLY_AUDIO;
+    } else if (silence_state_ == SILENCE_STATE_ONLY_SILENCE) {
+      silence_state_ = SILENCE_STATE_AUDIO_AND_SILENCE;
+    } else {
+      DCHECK(silence_state_ == SILENCE_STATE_ONLY_AUDIO ||
+             silence_state_ == SILENCE_STATE_AUDIO_AND_SILENCE);
+    }
+  }
+}
+
 void AudioInputController::LogSilenceState(SilenceState value) {
   UMA_HISTOGRAM_ENUMERATION("Media.AudioInputControllerSessionSilenceReport",
                             value,
index e1e14ee..691f1af 100644 (file)
@@ -191,11 +191,11 @@ class MEDIA_EXPORT AudioInputController
       SyncWriter* sync_writer,
       UserInputMonitor* user_input_monitor);
 
-  // Factory method for creating an AudioInputController for low-latency mode,
-  // taking ownership of |stream|.  The stream will be opened on the audio
-  // thread, and when that is done, the event handler will receive an
-  // OnCreated() call from that same thread. |user_input_monitor| is used for
-  // typing detection and can be NULL.
+  // Factory method for creating an AudioInputController with an existing
+  // |stream| for low-latency mode, taking ownership of |stream|. The stream
+  // will be opened on the audio thread, and when that is done, the event
+  // handler will receive an OnCreated() call from that same thread.
+  // |user_input_monitor| is used for typing detection and can be NULL.
   static scoped_refptr<AudioInputController> CreateForStream(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       EventHandler* event_handler,
@@ -251,6 +251,12 @@ class MEDIA_EXPORT AudioInputController
   // Elements in this enum should not be deleted or rearranged; the only
   // permitted operation is to add new elements before SILENCE_STATE_MAX and
   // update SILENCE_STATE_MAX.
+  // Possible silence state transitions:
+  //           SILENCE_STATE_AUDIO_AND_SILENCE
+  //               ^                  ^
+  // SILENCE_STATE_ONLY_AUDIO   SILENCE_STATE_ONLY_SILENCE
+  //               ^                  ^
+  //            SILENCE_STATE_NO_MEASUREMENT
   enum SilenceState {
     SILENCE_STATE_NO_MEASUREMENT = 0,
     SILENCE_STATE_ONLY_AUDIO = 1,
@@ -266,8 +272,12 @@ class MEDIA_EXPORT AudioInputController
   virtual ~AudioInputController();
 
   // Methods called on the audio thread (owned by the AudioManager).
-  void DoCreate(AudioManager* audio_manager, const AudioParameters& params,
+  void DoCreate(AudioManager* audio_manager,
+                const AudioParameters& params,
                 const std::string& device_id);
+  void DoCreateForLowLatency(AudioManager* audio_manager,
+                             const AudioParameters& params,
+                             const std::string& device_id);
   void DoCreateForStream(AudioInputStream* stream_to_control);
   void DoRecord();
   void DoClose();
@@ -292,6 +302,11 @@ class MEDIA_EXPORT AudioInputController
   bool GetDataIsActive();
 
 #if defined(AUDIO_POWER_MONITORING)
+  // Updates the silence state, see enum SilenceState above for state
+  // transitions.
+  void UpdateSilenceState(bool silence);
+
+  // Logs the silence state as UMA stat.
   void LogSilenceState(SilenceState value);
 #endif
 
@@ -345,6 +360,9 @@ class MEDIA_EXPORT AudioInputController
   media::AudioParameters audio_params_;
   base::TimeTicks last_audio_level_log_time_;
 
+  // Whether the silence state should sent as UMA stat.
+  bool log_silence_state_;
+
   // The silence report sent as UMA stat at the end of a session.
   SilenceState silence_state_;
 #endif
index f1dbdf7..3d95f90 100644 (file)
@@ -165,23 +165,6 @@ bool AUAudioInputStream::Open() {
     return false;
   }
 
-  // Register the input procedure for the AUHAL.
-  // This procedure will be called when the AUHAL has received new data
-  // from the input device.
-  AURenderCallbackStruct callback;
-  callback.inputProc = InputProc;
-  callback.inputProcRefCon = this;
-  result = AudioUnitSetProperty(audio_unit_,
-                                kAudioOutputUnitProperty_SetInputCallback,
-                                kAudioUnitScope_Global,
-                                0,
-                                &callback,
-                                sizeof(callback));
-  if (result) {
-    HandleError(result);
-    return false;
-  }
-
   // Set up the the desired (output) format.
   // For obtaining input from a device, the device format is always expressed
   // on the output scope of the AUHAL's Element 1.
@@ -229,6 +212,23 @@ bool AUAudioInputStream::Open() {
     }
   }
 
+  // Register the input procedure for the AUHAL.
+  // This procedure will be called when the AUHAL has received new data
+  // from the input device.
+  AURenderCallbackStruct callback;
+  callback.inputProc = InputProc;
+  callback.inputProcRefCon = this;
+  result = AudioUnitSetProperty(audio_unit_,
+                                kAudioOutputUnitProperty_SetInputCallback,
+                                kAudioUnitScope_Global,
+                                0,
+                                &callback,
+                                sizeof(callback));
+  if (result) {
+    HandleError(result);
+    return false;
+  }
+
   // Finally, initialize the audio unit and ensure that it is ready to render.
   // Allocates memory according to the maximum number of audio frames
   // it can produce in response to a single render call.
@@ -299,10 +299,14 @@ void AUAudioInputStream::Close() {
   }
   if (audio_unit_) {
     // Deallocate the audio unit’s resources.
-    AudioUnitUninitialize(audio_unit_);
+    OSStatus result = AudioUnitUninitialize(audio_unit_);
+    OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
+        << "AudioUnitUninitialize() failed.";
+
+    result = AudioComponentInstanceDispose(audio_unit_);
+    OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
+        << "AudioComponentInstanceDispose() failed.";
 
-    // Terminates our connection to the AUHAL component.
-    CloseComponent(audio_unit_);
     audio_unit_ = 0;
   }
 
index 7fa62a7..3757f83 100644 (file)
@@ -44,6 +44,9 @@ bool ToAudioSampleRate(int sample_rate, AudioSampleRate* asr) {
     case 192000:
       *asr = k192000Hz;
       return true;
+    case 24000:
+      *asr = k24000Hz;
+      return true;
   }
   return false;
 }
index 482ec0f..d2834e7 100644 (file)
@@ -23,8 +23,9 @@ enum AudioSampleRate {
   k88200Hz = 8,
   k176400Hz = 9,
   k192000Hz = 10,
+  k24000Hz = 11,
   // Must always equal the largest value ever reported:
-  kAudioSampleRateMax = k192000Hz,
+  kAudioSampleRateMax = k24000Hz,
 };
 
 // Helper method to convert integral values to their respective enum values,
index 13ee760..74ff8bc 100644 (file)
@@ -63,34 +63,66 @@ void CdmPromise::reject(MediaKeys::Exception exception_code,
   reject_cb_.Run(exception_code, system_code, error_message);
 }
 
-template <typename T>
-CdmPromiseTemplate<T>::CdmPromiseTemplate(
-    base::Callback<void(const T&)> resolve_cb,
+CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
+                                             PromiseRejectedCB reject_cb)
+    : CdmPromise(reject_cb), resolve_cb_(resolve_cb) {
+  DCHECK(!resolve_cb_.is_null());
+}
+
+CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
+                                             PromiseRejectedCB reject_cb,
+                                             const std::string& uma_name)
+    : CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) {
+  DCHECK(!resolve_cb_.is_null());
+  DCHECK(!uma_name_.empty());
+}
+
+CdmPromiseTemplate<void>::CdmPromiseTemplate() {
+}
+
+CdmPromiseTemplate<void>::~CdmPromiseTemplate() {
+  DCHECK(!is_pending_);
+}
+
+void CdmPromiseTemplate<void>::resolve() {
+  DCHECK(is_pending_);
+  is_pending_ = false;
+  if (!uma_name_.empty()) {
+    base::LinearHistogram::FactoryGet(
+        uma_name_, 1, NUM_RESULT_CODES, NUM_RESULT_CODES + 1,
+        base::HistogramBase::kUmaTargetedHistogramFlag)->Add(SUCCESS);
+  }
+  resolve_cb_.Run();
+}
+
+CdmPromise::ResolveParameterType
+CdmPromiseTemplate<void>::GetResolveParameterType() const {
+  return VOID_TYPE;
+}
+
+CdmPromiseTemplate<std::string>::CdmPromiseTemplate(
+    base::Callback<void(const std::string&)> resolve_cb,
     PromiseRejectedCB reject_cb)
     : CdmPromise(reject_cb), resolve_cb_(resolve_cb) {
   DCHECK(!resolve_cb_.is_null());
 }
 
-template <typename T>
-CdmPromiseTemplate<T>::CdmPromiseTemplate(
-    base::Callback<void(const T&)> resolve_cb,
+CdmPromiseTemplate<std::string>::CdmPromiseTemplate(
+    base::Callback<void(const std::string&)> resolve_cb,
     PromiseRejectedCB reject_cb,
     const std::string& uma_name)
     : CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) {
   DCHECK(!resolve_cb_.is_null());
 }
 
-template <typename T>
-CdmPromiseTemplate<T>::CdmPromiseTemplate() {
+CdmPromiseTemplate<std::string>::CdmPromiseTemplate() {
 }
 
-template <typename T>
-CdmPromiseTemplate<T>::~CdmPromiseTemplate() {
+CdmPromiseTemplate<std::string>::~CdmPromiseTemplate() {
   DCHECK(!is_pending_);
 }
 
-template <typename T>
-void CdmPromiseTemplate<T>::resolve(const T& result) {
+void CdmPromiseTemplate<std::string>::resolve(const std::string& result) {
   DCHECK(is_pending_);
   is_pending_ = false;
   if (!uma_name_.empty()) {
@@ -101,28 +133,31 @@ void CdmPromiseTemplate<T>::resolve(const T& result) {
   resolve_cb_.Run(result);
 }
 
-CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
-                                             PromiseRejectedCB reject_cb)
+CdmPromise::ResolveParameterType
+CdmPromiseTemplate<std::string>::GetResolveParameterType() const {
+  return STRING_TYPE;
+}
+
+CdmPromiseTemplate<KeyIdsVector>::CdmPromiseTemplate(
+    base::Callback<void(const KeyIdsVector&)> resolve_cb,
+    PromiseRejectedCB reject_cb)
     : CdmPromise(reject_cb), resolve_cb_(resolve_cb) {
   DCHECK(!resolve_cb_.is_null());
 }
 
-CdmPromiseTemplate<void>::CdmPromiseTemplate(base::Callback<void()> resolve_cb,
-                                             PromiseRejectedCB reject_cb,
-                                             const std::string& uma_name)
+CdmPromiseTemplate<KeyIdsVector>::CdmPromiseTemplate(
+    base::Callback<void(const KeyIdsVector&)> resolve_cb,
+    PromiseRejectedCB reject_cb,
+    const std::string& uma_name)
     : CdmPromise(reject_cb, uma_name), resolve_cb_(resolve_cb) {
   DCHECK(!resolve_cb_.is_null());
-  DCHECK(!uma_name_.empty());
 }
 
-CdmPromiseTemplate<void>::CdmPromiseTemplate() {
-}
-
-CdmPromiseTemplate<void>::~CdmPromiseTemplate() {
+CdmPromiseTemplate<KeyIdsVector>::~CdmPromiseTemplate() {
   DCHECK(!is_pending_);
 }
 
-void CdmPromiseTemplate<void>::resolve() {
+void CdmPromiseTemplate<KeyIdsVector>::resolve(const KeyIdsVector& result) {
   DCHECK(is_pending_);
   is_pending_ = false;
   if (!uma_name_.empty()) {
@@ -130,11 +165,12 @@ void CdmPromiseTemplate<void>::resolve() {
         uma_name_, 1, NUM_RESULT_CODES, NUM_RESULT_CODES + 1,
         base::HistogramBase::kUmaTargetedHistogramFlag)->Add(SUCCESS);
   }
-  resolve_cb_.Run();
+  resolve_cb_.Run(result);
 }
 
-// Explicit template instantiation for the Promises needed.
-template class MEDIA_EXPORT CdmPromiseTemplate<std::string>;
-template class MEDIA_EXPORT CdmPromiseTemplate<KeyIdsVector>;
+CdmPromise::ResolveParameterType
+CdmPromiseTemplate<KeyIdsVector>::GetResolveParameterType() const {
+  return KEY_IDS_VECTOR_TYPE;
+}
 
 }  // namespace media
index 14f79f8..33ec042 100644 (file)
@@ -35,6 +35,12 @@ class MEDIA_EXPORT CdmPromise {
     NUM_RESULT_CODES
   };
 
+  enum ResolveParameterType {
+    VOID_TYPE,
+    STRING_TYPE,
+    KEY_IDS_VECTOR_TYPE
+  };
+
   typedef base::Callback<void(MediaKeys::Exception exception_code,
                               uint32 system_code,
                               const std::string& error_message)>
@@ -50,6 +56,8 @@ class MEDIA_EXPORT CdmPromise {
                       uint32 system_code,
                       const std::string& error_message);
 
+  virtual ResolveParameterType GetResolveParameterType() const = 0;
+
  protected:
   CdmPromise();
   CdmPromise(PromiseRejectedCB reject_cb);
@@ -70,47 +78,67 @@ class MEDIA_EXPORT CdmPromise {
   DISALLOW_COPY_AND_ASSIGN(CdmPromise);
 };
 
-template <typename T>
-class MEDIA_EXPORT CdmPromiseTemplate : public CdmPromise {
+// Specialization for no parameter to resolve().
+template <>
+class MEDIA_EXPORT CdmPromiseTemplate<void> : public CdmPromise {
  public:
-  CdmPromiseTemplate(base::Callback<void(const T&)> resolve_cb,
+  CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
                      PromiseRejectedCB rejected_cb);
-  CdmPromiseTemplate(base::Callback<void(const T&)> resolve_cb,
+  CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
                      PromiseRejectedCB rejected_cb,
                      const std::string& uma_name);
   virtual ~CdmPromiseTemplate();
-  virtual void resolve(const T& result);
+  virtual void resolve();
+  virtual ResolveParameterType GetResolveParameterType() const OVERRIDE;
 
  protected:
   // Allow subclasses to completely override the implementation.
-  // TODO(jrummell): Remove when derived class SessionLoadedPromise
-  // (in ppapi_decryptor.cc) is no longer needed.
   CdmPromiseTemplate();
 
  private:
-  base::Callback<void(const T&)> resolve_cb_;
+  base::Callback<void(void)> resolve_cb_;
 
   DISALLOW_COPY_AND_ASSIGN(CdmPromiseTemplate);
 };
 
-// Specialization for no parameter to resolve().
 template <>
-class MEDIA_EXPORT CdmPromiseTemplate<void> : public CdmPromise {
+class MEDIA_EXPORT CdmPromiseTemplate<std::string> : public CdmPromise {
  public:
-  CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
+  CdmPromiseTemplate(base::Callback<void(const std::string&)> resolve_cb,
                      PromiseRejectedCB rejected_cb);
-  CdmPromiseTemplate(base::Callback<void(void)> resolve_cb,
+  CdmPromiseTemplate(base::Callback<void(const std::string&)> resolve_cb,
                      PromiseRejectedCB rejected_cb,
                      const std::string& uma_name);
   virtual ~CdmPromiseTemplate();
-  virtual void resolve();
+  virtual void resolve(const std::string& result);
+  virtual ResolveParameterType GetResolveParameterType() const OVERRIDE;
 
  protected:
   // Allow subclasses to completely override the implementation.
+  // TODO(jrummell): Remove when derived class SessionLoadedPromise
+  // (in ppapi_decryptor.cc) is no longer needed.
   CdmPromiseTemplate();
 
  private:
-  base::Callback<void(void)> resolve_cb_;
+  base::Callback<void(const std::string&)> resolve_cb_;
+
+  DISALLOW_COPY_AND_ASSIGN(CdmPromiseTemplate);
+};
+
+template <>
+class MEDIA_EXPORT CdmPromiseTemplate<KeyIdsVector> : public CdmPromise {
+ public:
+  CdmPromiseTemplate(base::Callback<void(const KeyIdsVector&)> resolve_cb,
+                     PromiseRejectedCB rejected_cb);
+  CdmPromiseTemplate(base::Callback<void(const KeyIdsVector&)> resolve_cb,
+                     PromiseRejectedCB rejected_cb,
+                     const std::string& uma_name);
+  virtual ~CdmPromiseTemplate();
+  virtual void resolve(const KeyIdsVector& result);
+  virtual ResolveParameterType GetResolveParameterType() const OVERRIDE;
+
+ private:
+  base::Callback<void(const KeyIdsVector&)> resolve_cb_;
 
   DISALLOW_COPY_AND_ASSIGN(CdmPromiseTemplate);
 };
index 70fcfe9..9efe50a 100644 (file)
@@ -113,9 +113,16 @@ void CongestionControl::AckFrame(uint32 frame_id, base::TimeTicks when) {
   FrameStats* frame_stats = GetFrameStats(last_acked_frame_);
   while (IsNewerFrameId(frame_id, last_acked_frame_)) {
     FrameStats* last_frame_stats = frame_stats;
-    last_acked_frame_++;
-    frame_stats = GetFrameStats(last_acked_frame_);
+    frame_stats = GetFrameStats(last_acked_frame_ + 1);
     DCHECK(frame_stats);
+    if (frame_stats->sent_time.is_null()) {
+      // Can't ack a frame that hasn't been sent yet.
+      return;
+    }
+    last_acked_frame_++;
+    if (when < frame_stats->sent_time)
+      when = frame_stats->sent_time;
+
     frame_stats->ack_time = when;
     acked_bits_in_history_ += frame_stats->frame_size;
     dead_time_in_history_ += DeadTime(*last_frame_stats, *frame_stats);
index a54ab39..2452be8 100644 (file)
@@ -383,21 +383,21 @@ void CdmAdapter::UpdateSession(uint32_t promise_id,
                       response_size);
 }
 
-void CdmAdapter::ReleaseSession(uint32_t promise_id,
-                                const std::string& web_session_id) {
-  cdm_->CloseSession(
-      promise_id, web_session_id.data(), web_session_id.length());
-}
-
-void CdmAdapter::RemoveSession(uint32_t promise_id,
-                               const std::string& web_session_id) {
-  if (!cdm_->RemoveSession(
+void CdmAdapter::CloseSession(uint32_t promise_id,
+                              const std::string& web_session_id) {
+  if (!cdm_->CloseSession(
           promise_id, web_session_id.data(), web_session_id.length())) {
     // CDM_4 and CDM_5 don't support this method, so reject the promise.
     RejectPromise(promise_id, cdm::kNotSupportedError, 0, "Not implemented.");
   }
 }
 
+void CdmAdapter::ReleaseSession(uint32_t promise_id,
+                                const std::string& web_session_id) {
+  cdm_->RemoveSession(
+      promise_id, web_session_id.data(), web_session_id.length());
+}
+
 void CdmAdapter::GetUsableKeyIds(uint32_t promise_id,
                                  const std::string& web_session_id) {
   if (!cdm_->GetUsableKeyIds(
index 07b5ad1..cd4738b 100644 (file)
@@ -67,12 +67,13 @@ class CdmAdapter : public pp::Instance,
   virtual void UpdateSession(uint32_t promise_id,
                              const std::string& web_session_id,
                              pp::VarArrayBuffer response) OVERRIDE;
-  // TODO(jrummell): Rename to CloseSession().
+  // TODO(jrummell): Pass this function through Pepper and add OVERRIDE.
+  virtual void CloseSession(uint32_t promise_id,
+                            const std::string& web_session_id);
+  // TODO(jrummell): Rename to RemoveSession().
   virtual void ReleaseSession(uint32_t promise_id,
                               const std::string& web_session_id) OVERRIDE;
-  // TODO(jrummell): Pass these 2 functions through Pepper and add OVERRIDE.
-  virtual void RemoveSession(uint32_t promise_id,
-                             const std::string& web_session_id);
+  // TODO(jrummell): Pass this function through Pepper and add OVERRIDE.
   virtual void GetUsableKeyIds(uint32_t promise_id,
                                const std::string& web_session_id);
   virtual void Decrypt(
index 72afa90..f11672c 100644 (file)
@@ -56,12 +56,14 @@ class CdmWrapper {
                              uint32_t web_session_id_size,
                              const uint8_t* response,
                              uint32_t response_size) = 0;
-  virtual void CloseSession(uint32_t promise_id,
+  // TODO(jrummell): Remove return value when CDM4/5 are removed.
+  virtual bool CloseSession(uint32_t promise_id,
                             const char* web_session_id,
                             uint32_t web_session_id_size) = 0;
-  virtual bool RemoveSession(uint32_t promise_id,
+  virtual void RemoveSession(uint32_t promise_id,
                              const char* web_session_id,
                              uint32_t web_session_id_size) = 0;
+  // TODO(jrummell): Remove return value when CDM4/5 are removed.
   virtual bool GetUsableKeyIds(uint32_t promise_id,
                                const char* web_session_id,
                                uint32_t web_session_id_size) = 0;
@@ -226,17 +228,17 @@ class CdmWrapperImpl : public CdmWrapper {
     return true;
   }
 
-  virtual void CloseSession(uint32_t promise_id,
+  virtual bool CloseSession(uint32_t promise_id,
                             const char* web_session_id,
                             uint32_t web_session_id_size) OVERRIDE {
     cdm_->CloseSession(promise_id, web_session_id, web_session_id_size);
+    return true;
   }
 
-  virtual bool RemoveSession(uint32_t promise_id,
+  virtual void RemoveSession(uint32_t promise_id,
                              const char* web_session_id,
                              uint32_t web_session_id_size) OVERRIDE {
     cdm_->RemoveSession(promise_id, web_session_id, web_session_id_size);
-    return true;
   }
 
   virtual void TimerExpired(void* context) OVERRIDE {
@@ -454,22 +456,22 @@ void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::UpdateSession(
 }
 
 template <>
-void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::CloseSession(
+bool CdmWrapperImpl<cdm::ContentDecryptionModule_4>::CloseSession(
     uint32_t promise_id,
     const char* web_session_id,
     uint32_t web_session_id_size) {
-  std::string web_session_str(web_session_id, web_session_id_size);
-  uint32_t session_id = LookupSessionId(web_session_str);
-  RegisterPromise(session_id, promise_id);
-  cdm_->ReleaseSession(session_id);
+  return false;
 }
 
 template <>
-bool CdmWrapperImpl<cdm::ContentDecryptionModule_4>::RemoveSession(
+void CdmWrapperImpl<cdm::ContentDecryptionModule_4>::RemoveSession(
     uint32_t promise_id,
     const char* web_session_id,
     uint32_t web_session_id_size) {
-  return false;
+  std::string web_session_str(web_session_id, web_session_id_size);
+  uint32_t session_id = LookupSessionId(web_session_str);
+  RegisterPromise(session_id, promise_id);
+  cdm_->ReleaseSession(session_id);
 }
 
 template <>
@@ -572,19 +574,19 @@ void CdmWrapperImpl<cdm::ContentDecryptionModule_5>::UpdateSession(
 }
 
 template <>
-void CdmWrapperImpl<cdm::ContentDecryptionModule_5>::CloseSession(
+bool CdmWrapperImpl<cdm::ContentDecryptionModule_5>::CloseSession(
     uint32_t promise_id,
     const char* web_session_id,
     uint32_t web_session_id_size) {
-  cdm_->ReleaseSession(promise_id, web_session_id, web_session_id_size);
+  return false;
 }
 
 template <>
-bool CdmWrapperImpl<cdm::ContentDecryptionModule_5>::RemoveSession(
+void CdmWrapperImpl<cdm::ContentDecryptionModule_5>::RemoveSession(
     uint32_t promise_id,
     const char* web_session_id,
     uint32_t web_session_id_size) {
-  return false;
+  cdm_->ReleaseSession(promise_id, web_session_id, web_session_id_size);
 }
 
 template <>
index 15b6a51..d515230 100644 (file)
@@ -305,6 +305,12 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) {
       start_time = base::TimeDelta();
     }
 
+    // Don't rebase timestamps for positive start times, the HTML Media Spec
+    // details this in section "4.8.10.6 Offsets into the media resource." We
+    // will still need to rebase timestamps before seeking with FFmpeg though.
+    if (start_time > base::TimeDelta())
+      start_time = base::TimeDelta();
+
     buffer->set_timestamp(stream_timestamp - start_time);
 
     // If enabled, mark audio packets with negative timestamps for post-decode
@@ -557,8 +563,12 @@ FFmpegDemuxer::~FFmpegDemuxer() {}
 
 void FFmpegDemuxer::Stop(const base::Closure& callback) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  url_protocol_->Abort();
+
+  // The order of Stop() and Abort() is important here.  If Abort() is called
+  // first, control may pass into FFmpeg where it can destruct buffers that are
+  // in the process of being fulfilled by the DataSource.
   data_source_->Stop();
+  url_protocol_->Abort();
 
   // This will block until all tasks complete. Note that after this returns it's
   // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this
@@ -585,7 +595,15 @@ void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
   // we know we're going to drop it on the floor.
 
   // FFmpeg requires seeks to be adjusted according to the lowest starting time.
-  const base::TimeDelta seek_time = time + start_time_;
+  // Since EnqueuePacket() rebased negative timestamps by the start time, we
+  // must correct the shift here.
+  //
+  // Additionally, to workaround limitations in how we expose seekable ranges to
+  // Blink (http://crbug.com/137275), we also want to clamp seeks before the
+  // start time to the start time.
+  const base::TimeDelta seek_time =
+      start_time_ < base::TimeDelta() ? time + start_time_
+                                      : time < start_time_ ? start_time_ : time;
 
   // Choose the seeking stream based on whether it contains the seek time, if no
   // match can be found prefer the preferred stream.
index 76ccba2..dedb3ae 100644 (file)
@@ -441,17 +441,9 @@ TEST_F(FFmpegDemuxerTest, Read_VideoPositiveStartTime) {
 
   // Run the test twice with a seek in between.
   for (int i = 0; i < 2; ++i) {
-    // Check first buffer in video stream.  It should have been adjusted such
-    // that it starts 400ms after the first audio buffer.
-    video->Read(
-        NewReadCB(FROM_HERE,
-                  5636,
-                  (video_start_time - audio_start_time).InMicroseconds()));
+    video->Read(NewReadCB(FROM_HERE, 5636, video_start_time.InMicroseconds()));
     message_loop_.Run();
-
-    // Since the audio buffer has a lower first timestamp, it should become
-    // zero.
-    audio->Read(NewReadCB(FROM_HERE, 165, 0));
+    audio->Read(NewReadCB(FROM_HERE, 165, audio_start_time.InMicroseconds()));
     message_loop_.Run();
 
     // Verify that the start time is equal to the lowest timestamp (ie the
index 16a33ea..3954e09 100644 (file)
@@ -422,8 +422,22 @@ void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
   }
   const PictureBuffer& pb = it->second;
 
+  // Validate picture rectangle from GPU. This is for sanity/security check
+  // even the rectangle is not used in this class.
+  if (picture.visible_rect().IsEmpty() ||
+      !gfx::Rect(pb.size()).Contains(picture.visible_rect())) {
+    NOTREACHED() << "Invalid picture size from VDA: "
+                 << picture.visible_rect().ToString() << " should fit in "
+                 << pb.size().ToString();
+    NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
+    return;
+  }
+
   // Update frame's timestamp.
   base::TimeDelta timestamp;
+  // Some of the VDAs don't support and thus don't provide us with visible
+  // size in picture.size, passing coded size instead, so always drop it and
+  // use config information instead.
   gfx::Rect visible_rect;
   gfx::Size natural_size;
   GetBufferData(picture.bitstream_buffer_id(), &timestamp, &visible_rect,
index fe1bfde..003c195 100644 (file)
@@ -190,6 +190,7 @@ void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame,
                                   SkCanvas* canvas,
                                   const gfx::RectF& dest_rect,
                                   uint8 alpha,
+                                  SkXfermode::Mode mode,
                                   VideoRotation video_rotation) {
   if (alpha == 0) {
     return;
@@ -233,13 +234,21 @@ void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame,
     last_frame_timestamp_ = video_frame->timestamp();
   }
 
-  // Use SRC mode so we completely overwrite the buffer (in case we have alpha)
-  // this means we don't need the extra cost of clearing the buffer first.
-  paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode));
+  paint.setXfermodeMode(mode);
 
   // Paint using |last_frame_|.
   paint.setFilterLevel(SkPaint::kLow_FilterLevel);
   canvas->drawBitmapRect(last_frame_, NULL, dest, &paint);
 }
 
+void SkCanvasVideoRenderer::Copy(media::VideoFrame* video_frame,
+                                 SkCanvas* canvas) {
+  Paint(video_frame,
+        canvas,
+        video_frame->visible_rect(),
+        0xff,
+        SkXfermode::kSrc_Mode,
+        media::VIDEO_ROTATION_0);
+}
+
 }  // namespace media
index 0e5c520..3d1f4da 100644 (file)
@@ -9,6 +9,7 @@
 #include "media/base/media_export.h"
 #include "media/base/video_rotation.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkXfermode.h"
 #include "ui/gfx/rect.h"
 
 class SkCanvas;
@@ -32,8 +33,12 @@ class MEDIA_EXPORT SkCanvasVideoRenderer {
              SkCanvas* canvas,
              const gfx::RectF& dest_rect,
              uint8 alpha,
+             SkXfermode::Mode mode,
              VideoRotation video_rotation);
 
+  // Copy |video_frame| on |canvas|.
+  void Copy(media::VideoFrame* video_frame, SkCanvas* canvas);
+
  private:
   // An RGB bitmap and corresponding timestamp of the previously converted
   // video frame data.
index 2a8b174..358ce0a 100644 (file)
@@ -56,8 +56,11 @@ class SkCanvasVideoRendererTest : public testing::Test {
   void PaintRotated(VideoFrame* video_frame,
                     SkCanvas* canvas,
                     Color color,
+                    SkXfermode::Mode mode,
                     VideoRotation video_rotation);
 
+  void Copy(VideoFrame* video_frame, SkCanvas* canvas);
+
   // Getters for various frame sizes.
   VideoFrame* natural_frame() { return natural_frame_.get(); }
   VideoFrame* larger_frame() { return larger_frame_.get(); }
@@ -189,18 +192,25 @@ SkCanvasVideoRendererTest::SkCanvasVideoRendererTest()
 SkCanvasVideoRendererTest::~SkCanvasVideoRendererTest() {}
 
 void SkCanvasVideoRendererTest::PaintWithoutFrame(SkCanvas* canvas) {
-  renderer_.Paint(NULL, canvas, kNaturalRect, 0xFF, VIDEO_ROTATION_0);
+  renderer_.Paint(NULL,
+                  canvas,
+                  kNaturalRect,
+                  0xFF,
+                  SkXfermode::kSrcOver_Mode,
+                  VIDEO_ROTATION_0);
 }
 
 void SkCanvasVideoRendererTest::Paint(VideoFrame* video_frame,
                                       SkCanvas* canvas,
                                       Color color) {
-  PaintRotated(video_frame, canvas, color, VIDEO_ROTATION_0);
+  PaintRotated(
+      video_frame, canvas, color, SkXfermode::kSrcOver_Mode, VIDEO_ROTATION_0);
 }
 
 void SkCanvasVideoRendererTest::PaintRotated(VideoFrame* video_frame,
                                              SkCanvas* canvas,
                                              Color color,
+                                             SkXfermode::Mode mode,
                                              VideoRotation video_rotation) {
   switch (color) {
     case kNone:
@@ -215,7 +225,13 @@ void SkCanvasVideoRendererTest::PaintRotated(VideoFrame* video_frame,
       media::FillYUV(video_frame, 29, 255, 107);
       break;
   }
-  renderer_.Paint(video_frame, canvas, kNaturalRect, 0xFF, video_rotation);
+  renderer_.Paint(
+      video_frame, canvas, kNaturalRect, 0xFF, mode, video_rotation);
+}
+
+void SkCanvasVideoRendererTest::Copy(VideoFrame* video_frame,
+                                     SkCanvas* canvas) {
+  renderer_.Copy(video_frame, canvas);
 }
 
 TEST_F(SkCanvasVideoRendererTest, NoFrame) {
@@ -226,11 +242,31 @@ TEST_F(SkCanvasVideoRendererTest, NoFrame) {
 }
 
 TEST_F(SkCanvasVideoRendererTest, TransparentFrame) {
-  // Test that we don't blend with existing canvas contents.
   FillCanvas(target_canvas(), SK_ColorRED);
-  Paint(VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)),
-        target_canvas(),
-        kNone);
+  PaintRotated(VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)),
+               target_canvas(),
+               kNone,
+               SkXfermode::kSrcOver_Mode,
+               VIDEO_ROTATION_0);
+  EXPECT_EQ(static_cast<SkColor>(SK_ColorRED), GetColor(target_canvas()));
+}
+
+TEST_F(SkCanvasVideoRendererTest, TransparentFrameSrcMode) {
+  FillCanvas(target_canvas(), SK_ColorRED);
+  // SRC mode completely overwrites the buffer.
+  PaintRotated(VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)),
+               target_canvas(),
+               kNone,
+               SkXfermode::kSrc_Mode,
+               VIDEO_ROTATION_0);
+  EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
+            GetColor(target_canvas()));
+}
+
+TEST_F(SkCanvasVideoRendererTest, CopyTransparentFrame) {
+  FillCanvas(target_canvas(), SK_ColorRED);
+  Copy(VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)),
+       target_canvas());
   EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
             GetColor(target_canvas()));
 }
@@ -325,7 +361,11 @@ TEST_F(SkCanvasVideoRendererTest, CroppedFrame_NoScaling) {
 TEST_F(SkCanvasVideoRendererTest, Video_Rotation_90) {
   SkCanvas canvas(AllocBitmap(kWidth, kHeight));
   const gfx::Rect crop_rect = cropped_frame()->visible_rect();
-  PaintRotated(cropped_frame(), &canvas, kNone, VIDEO_ROTATION_90);
+  PaintRotated(cropped_frame(),
+               &canvas,
+               kNone,
+               SkXfermode::kSrcOver_Mode,
+               VIDEO_ROTATION_90);
   // Check the corners.
   EXPECT_EQ(SK_ColorGREEN, GetColorAt(&canvas, 0, 0));
   EXPECT_EQ(SK_ColorBLACK, GetColorAt(&canvas, kWidth - 1, 0));
@@ -336,7 +376,11 @@ TEST_F(SkCanvasVideoRendererTest, Video_Rotation_90) {
 TEST_F(SkCanvasVideoRendererTest, Video_Rotation_180) {
   SkCanvas canvas(AllocBitmap(kWidth, kHeight));
   const gfx::Rect crop_rect = cropped_frame()->visible_rect();
-  PaintRotated(cropped_frame(), &canvas, kNone, VIDEO_ROTATION_180);
+  PaintRotated(cropped_frame(),
+               &canvas,
+               kNone,
+               SkXfermode::kSrcOver_Mode,
+               VIDEO_ROTATION_180);
   // Check the corners.
   EXPECT_EQ(SK_ColorBLUE, GetColorAt(&canvas, 0, 0));
   EXPECT_EQ(SK_ColorGREEN, GetColorAt(&canvas, kWidth - 1, 0));
@@ -347,7 +391,11 @@ TEST_F(SkCanvasVideoRendererTest, Video_Rotation_180) {
 TEST_F(SkCanvasVideoRendererTest, Video_Rotation_270) {
   SkCanvas canvas(AllocBitmap(kWidth, kHeight));
   const gfx::Rect crop_rect = cropped_frame()->visible_rect();
-  PaintRotated(cropped_frame(), &canvas, kNone, VIDEO_ROTATION_270);
+  PaintRotated(cropped_frame(),
+               &canvas,
+               kNone,
+               SkXfermode::kSrcOver_Mode,
+               VIDEO_ROTATION_270);
   // Check the corners.
   EXPECT_EQ(SK_ColorRED, GetColorAt(&canvas, 0, 0));
   EXPECT_EQ(SK_ColorBLUE, GetColorAt(&canvas, kWidth - 1, 0));
index 7b32563..f051013 100644 (file)
@@ -22,9 +22,12 @@ PictureBuffer::PictureBuffer(int32 id,
       texture_mailbox_(texture_mailbox) {
 }
 
-Picture::Picture(int32 picture_buffer_id, int32 bitstream_buffer_id)
+Picture::Picture(int32 picture_buffer_id,
+                 int32 bitstream_buffer_id,
+                 const gfx::Rect& visible_rect)
     : picture_buffer_id_(picture_buffer_id),
-      bitstream_buffer_id_(bitstream_buffer_id) {
+      bitstream_buffer_id_(bitstream_buffer_id),
+      visible_rect_(visible_rect) {
 }
 
 }  // namespace media
index d5be227..844e629 100644 (file)
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "media/base/media_export.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/size.h"
 
 namespace media {
@@ -54,7 +55,9 @@ class MEDIA_EXPORT PictureBuffer {
 // This is the media-namespace equivalent of PP_Picture_Dev.
 class MEDIA_EXPORT Picture {
  public:
-  Picture(int32 picture_buffer_id, int32 bitstream_buffer_id);
+  Picture(int32 picture_buffer_id,
+          int32 bitstream_buffer_id,
+          const gfx::Rect& visible_rect);
 
   // Returns the id of the picture buffer where this picture is contained.
   int32 picture_buffer_id() const {
@@ -70,9 +73,15 @@ class MEDIA_EXPORT Picture {
     bitstream_buffer_id_ = bitstream_buffer_id;
   }
 
+  // Returns the visible rectangle of the picture. Its size may be smaller
+  // than the size of the PictureBuffer, as it is the only visible part of the
+  // Picture contained in the PictureBuffer.
+  gfx::Rect visible_rect() const { return visible_rect_; }
+
  private:
   int32 picture_buffer_id_;
   int32 bitstream_buffer_id_;
+  gfx::Rect visible_rect_;
 };
 
 }  // namespace media
index 804737f..334812b 100644 (file)
@@ -232,7 +232,7 @@ env.AddNodeToTestSuite(node, ['small_tests'],
 nacl_host_desc_big_file_nexe = env.ComponentProgram(
   'nacl_host_desc_big_file_test',
   ['nacl_host_desc_big_file_test.c'],
-  EXTRA_LIBS=['platform'])
+  EXTRA_LIBS=['platform', 'nrd_xfer'])
 
 d = os.path.join(str(env.Dir('${TARGET_ROOT}')), 'large_temporary_files')
 try:
index 8a156e0..b075b3b 100644 (file)
@@ -28,6 +28,7 @@
 #include "native_client/src/shared/platform/nacl_sync_checked.h"
 #include "native_client/src/shared/platform/win/xlate_system_error.h"
 #include "native_client/src/trusted/desc/nacl_desc_effector.h"
+#include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h"
 
 #include "native_client/src/trusted/service_runtime/nacl_config.h"
 #include "native_client/src/trusted/service_runtime/internal_errno.h"
@@ -828,13 +829,34 @@ uintptr_t NaClHostDescMap(struct NaClHostDesc *d,
             ", addr + chunk_offset %"NACL_PRIxPTR"\n",
             map_result, chunk_addr, (addr + chunk_offset));
     if ((addr + chunk_offset) != map_result) {
+      /*
+       * MapViewOfFileEx() failed.  If we are mapping into untrusted
+       * address space, we opened an mmap hole.  We didn't expect the
+       * failure, and it's difficult to restore the old mappings that we
+       * removed, so for safety we must abort with LOG_FATAL.
+       *
+       * Otherwise, if this is a trusted mapping, we can return an error
+       * gracefully.  NaClElfFileMapSegment() currently triggers errors
+       * here by mapping beyond the file's extent: see
+       * https://crbug.com/406632.
+       */
+      int log_type =
+          effp == NaClDescEffectorTrustedMem() ? LOG_ERROR : LOG_FATAL;
       DWORD err = GetLastError();
-      NaClLog(LOG_FATAL,
+      size_t unmap_offset;
+      NaClLog(log_type,
               "MapViewOfFileEx failed at 0x%08"NACL_PRIxPTR
               ", got 0x%08"NACL_PRIxPTR", err %x\n",
               addr + chunk_offset,
               map_result,
               err);
+      for (unmap_offset = 0;
+           unmap_offset < chunk_offset;
+           unmap_offset += NACL_MAP_PAGESIZE) {
+        (void) UnmapViewOfFile((void *) (addr + unmap_offset));
+      }
+      retval = (uintptr_t) -NaClXlateSystemError(err);
+      goto cleanup;
     }
     if (!VirtualProtect((void *) map_result,
                         NaClRoundPage(chunk_size),
index 9128e14..64275cd 100644 (file)
@@ -21,4 +21,5 @@ env.Append(CCFLAGS=['-DNACL_TRUSTED_BUT_NOT_TCB'])
 env.ComponentProgram(
     'ncval_stubout',
     'ncstubout.c',
-    EXTRA_LIBS=['validators', env.NaClTargetArchSuffix('ncvalidate_verbose')])
+    EXTRA_LIBS=['validators', env.NaClTargetArchSuffix('ncvalidate_verbose'),
+                'nrd_xfer'])
index 471076f..2779725 100644 (file)
 #include "gtest/gtest.h"
 
 #include "native_client/src/include/portability_io.h"
+#include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h"
 #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
 #include "native_client/src/trusted/desc/nacl_desc_io.h"
 #include "native_client/src/trusted/desc/nrd_all_modules.h"
 #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
+#include "native_client/src/trusted/service_runtime/include/sys/errno.h"
 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
 #include "native_client/src/trusted/service_runtime/mmap_test_check.h"
 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
@@ -27,6 +29,8 @@
 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
 #include "native_client/src/trusted/service_runtime/sys_memory.h"
 
+static const int kTestFillByte = 0x42;
+
 class MmapTest : public testing::Test {
  protected:
   virtual void SetUp();
@@ -41,6 +45,46 @@ void MmapTest::TearDown() {
   NaClNrdAllModulesFini();
 }
 
+// Creates a temporary file and returns an FD for it.
+static int MakeTempFileFd() {
+  int host_fd;
+#if NACL_WINDOWS
+  // Open temporary file that is deleted automatically.
+  const char *temp_prefix = "nacl_mmap_test_temp_";
+  char *temp_filename = _tempnam("C:\\Windows\\Temp", temp_prefix);
+  EXPECT_EQ(_sopen_s(&host_fd, temp_filename,
+                     _O_RDWR | _O_CREAT | _O_TEMPORARY,
+                     _SH_DENYNO, _S_IREAD | _S_IWRITE), 0);
+#else
+  char temp_filename[] = "/tmp/nacl_mmap_test_temp_XXXXXX";
+  host_fd = mkstemp(temp_filename);
+  EXPECT_GE(host_fd, 0);
+#endif
+  EXPECT_EQ(remove(temp_filename), 0);
+  return host_fd;
+}
+
+// Creates a temporary file of the given size and returns a NaClDesc for it.
+static struct NaClDesc *MakeTempFileNaClDesc(size_t file_size) {
+  int host_fd = MakeTempFileFd();
+
+  struct NaClHostDesc *host_desc =
+      (struct NaClHostDesc *) malloc(sizeof(*host_desc));
+  EXPECT_TRUE(host_desc);
+  EXPECT_EQ(NaClHostDescPosixTake(host_desc, host_fd, NACL_ABI_O_RDWR), 0);
+  struct NaClDesc *desc = (struct NaClDesc *) NaClDescIoDescMake(host_desc);
+
+  // Fill the file.  On Windows, this is necessary to ensure that NaCl
+  // gives us mappings from the file instead of PROT_NONE-fill.
+  char *buf = new char[file_size];
+  memset(buf, kTestFillByte, file_size);
+  ssize_t written = NACL_VTBL(NaClDesc, desc)->Write(desc, buf, file_size);
+  EXPECT_EQ(written, (ssize_t) file_size);
+  delete[] buf;
+
+  return desc;
+}
+
 // These tests are disabled for ARM/MIPS because the ARM/MIPS sandboxes are
 // zero-based, and sel_addrspace_(arm/mips).c do not work when allocating a
 // non-zero-based region.
@@ -84,35 +128,7 @@ void MapShmFd(struct NaClApp *nap, uintptr_t addr, size_t shm_size) {
 }
 
 void MapFileFd(struct NaClApp *nap, uintptr_t addr, size_t file_size) {
-  int host_fd;
-#if NACL_WINDOWS
-  // Open temporary file that is deleted automatically.
-  const char *temp_prefix = "nacl_mmap_test_temp_";
-  char *temp_filename = _tempnam("C:\\Windows\\Temp", temp_prefix);
-  ASSERT_EQ(_sopen_s(&host_fd, temp_filename,
-                     _O_RDWR | _O_CREAT | _O_TEMPORARY,
-                     _SH_DENYNO, _S_IREAD | _S_IWRITE), 0);
-#else
-  char temp_filename[] = "/tmp/nacl_mmap_test_temp_XXXXXX";
-  host_fd = mkstemp(temp_filename);
-  ASSERT_GE(host_fd, 0);
-#endif
-  ASSERT_EQ(remove(temp_filename), 0);
-
-  struct NaClHostDesc *host_desc =
-      (struct NaClHostDesc *) malloc(sizeof(*host_desc));
-  ASSERT_TRUE(host_desc);
-  ASSERT_EQ(NaClHostDescPosixTake(host_desc, host_fd, NACL_ABI_O_RDWR), 0);
-  struct NaClDesc *desc = (struct NaClDesc *) NaClDescIoDescMake(host_desc);
-
-  // Fill the file.  On Windows, this is necessary to ensure that NaCl
-  // gives us mappings from the file instead of PROT_NONE-fill.
-  char *buf = new char[file_size];
-  memset(buf, 0, file_size);
-  ssize_t written = NACL_VTBL(NaClDesc, desc)->Write(desc, buf, file_size);
-  ASSERT_EQ(written, (ssize_t) file_size);
-  delete[] buf;
-
+  struct NaClDesc *desc = MakeTempFileNaClDesc(file_size);
   int fd = NaClAppSetDescAvail(nap, desc);
 
   uintptr_t mapping_addr = (uint32_t) NaClSysMmapIntern(
@@ -398,3 +414,56 @@ TEST_F(MmapTest, TestProtectAnonymousMemory) {
 }
 
 #endif /* NACL_ARCH(NACL_BUILD_ARCH) != NACL_arm */
+
+static void AssertArrayFilled(const char *array, size_t size) {
+  for (size_t i = 0; i < size; ++i)
+    EXPECT_EQ(array[i], kTestFillByte);
+}
+
+TEST_F(MmapTest, TestTrustedMapBeyondFileExtent) {
+  int file_size = 0x10099;
+  int file_size_rounded_up = 0x20000;
+  int file_offset = 0;
+  struct NaClDesc *desc = MakeTempFileNaClDesc(file_size);
+  uintptr_t map_result;
+
+  // Map() should work with a non-page-aligned size.
+  map_result = NACL_VTBL(NaClDesc, desc)->Map(
+      desc,
+      NaClDescEffectorTrustedMem(),
+      (void *) NULL,
+      file_size,
+      NACL_ABI_PROT_READ,
+      NACL_ABI_MAP_PRIVATE,
+      file_offset);
+  ASSERT_FALSE(NaClPtrIsNegErrno(&map_result));
+  AssertArrayFilled((char *) map_result, file_size);
+  NaClDescUnmapUnsafe(desc, (void *) map_result, file_size);
+
+  // Check the behaviour of Map() when given a rounded-up (page-aligned)
+  // size that goes beyond the file's extent.
+  map_result = NACL_VTBL(NaClDesc, desc)->Map(
+      desc,
+      NaClDescEffectorTrustedMem(),
+      (void *) NULL,
+      file_size_rounded_up,
+      NACL_ABI_PROT_READ,
+      NACL_ABI_MAP_PRIVATE,
+      file_offset);
+  if (NACL_WINDOWS) {
+    // On Windows, using a size beyond the file's extent is not allowed,
+    // even within a page, so we expect an error.
+    //
+    // This tests that we get a graceful error rather than a LOG_FATAL.
+    // This is a partial regression test for https://crbug.com/406632:
+    // NaClElfFileMapSegment() currently depends on the error being
+    // graceful.
+    ASSERT_TRUE(NaClPtrIsNegErrno(&map_result));
+    ASSERT_EQ(-(intptr_t) map_result, NACL_ABI_EACCES);
+  } else {
+    // On Unix, the Map() should succeed.
+    ASSERT_FALSE(NaClPtrIsNegErrno(&map_result));
+    AssertArrayFilled((char *) map_result, file_size);
+    NaClDescUnmapUnsafe(desc, (void *) map_result, file_size_rounded_up);
+  }
+}
index 281d608..7311a68 100644 (file)
@@ -34,7 +34,7 @@ vdiff = test_env.ComponentProgram(
               'validators',
               env.NaClTargetArchSuffix('ncvalidate'),
               env.NaClTargetArchSuffix('dfa_validate_caller'),
-              'platform', 'gio', 'utils',
+              'platform', 'nrd_xfer', 'gio', 'utils',
              ])
 
 # NOTE: can't use stdout_golden here because the test runs too long,
index c44f214..923bb69 100644 (file)
@@ -4,6 +4,7 @@ Welcome to the Native Client SDK
 Native Client Tools Bundle
 Version: ${VERSION}
 Chrome Revision: ${CHROME_REVISION}
+Chrome Commit Position: ${CHROME_COMMIT_POSITION}
 Native Client Revision: ${NACL_REVISION}
 Build Date: ${DATE}
 
index d4e7f0c..ccc52b7 100755 (executable)
@@ -182,6 +182,8 @@ def BuildStepCopyTextFiles(pepperdir, pepper_ver, chrome_revision,
   readme_text = open(os.path.join(SDK_SRC_DIR, 'README')).read()
   readme_text = readme_text.replace('${VERSION}', pepper_ver)
   readme_text = readme_text.replace('${CHROME_REVISION}', chrome_revision)
+  readme_text = readme_text.replace('${CHROME_COMMIT_POSITION}',
+                                    build_version.ChromeCommitPosition())
   readme_text = readme_text.replace('${NACL_REVISION}', nacl_revision)
 
   # Year/Month/Day Hour:Minute:Second
index 6e0aaa7..014b86e 100644 (file)
@@ -6,6 +6,7 @@
 """
 
 import os
+import re
 import sys
 
 # pylint: disable=E0602
@@ -27,11 +28,12 @@ def ChromeVersion():
   Returns:
     Chrome version string or trunk + svn rev.
   '''
-  info = lastchange.FetchVersionInfo(None)
-  if info.url.startswith('/trunk/'):
-    return 'trunk.%s' % info.revision
-  else:
-    return ChromeVersionNoTrunk()
+  info = FetchGitCommitPosition()
+  if info.url == 'git':
+    _, ref, revision = ParseCommitPosition(info.revision)
+    if ref == 'refs/heads/master':
+      return 'trunk.%s' % revision
+  return ChromeVersionNoTrunk()
 
 
 def ChromeVersionNoTrunk():
@@ -58,10 +60,26 @@ def ChromeMajorVersion():
 def ChromeRevision():
   '''Extract chrome revision from svn.
 
+     Now that the Chrome source-of-truth is git, this will return the
+     Cr-Commit-Position instead. Fortunately, this value is equal to the SVN
+     revision if one exists.
+
   Returns:
     The Chrome revision as a string. e.g. "12345"
   '''
-  return lastchange.FetchVersionInfo(None).revision
+  version = FetchGitCommitPosition()
+  return ParseCommitPosition(version.revision)[2]
+
+
+def ChromeCommitPosition():
+  '''Return the full git sha and commit position.
+
+  Returns:
+    A value like:
+    0178d4831bd36b5fb9ff477f03dc43b11626a6dc-refs/heads/master@{#292238}
+  '''
+  return FetchGitCommitPosition().revision
+
 
 def NaClRevision():
   '''Extract NaCl revision from svn.
@@ -70,4 +88,49 @@ def NaClRevision():
     The NaCl revision as a string. e.g. "12345"
   '''
   nacl_dir = os.path.join(SRC_DIR, 'native_client')
-  return lastchange.FetchVersionInfo(None, nacl_dir).revision
+  return lastchange.FetchVersionInfo(None, nacl_dir, 'native_client').revision
+
+
+def FetchGitCommitPosition(directory=None):
+  '''Return the "commit-position" of the Chromium git repo. This should be
+  equivalent to the SVN revision if one exists.
+  '''
+  SEARCH_LIMIT = 100
+  for i in xrange(SEARCH_LIMIT):
+    cmd = ['show', '-s', '--format=%H%n%B', 'HEAD~%d' % i]
+    proc = lastchange.RunGitCommand(directory, cmd)
+    if not proc:
+      break
+
+    output = proc.communicate()[0]
+    if not (proc.returncode == 0 and output):
+      break
+
+    lines = output.splitlines()
+
+    # First line is the hash.
+    hsh = lines[0]
+    if not re.match(r'[0-9a-fA-F]+', hsh):
+      break
+
+    for line in reversed(lines):
+      if line.startswith('Cr-Commit-Position:'):
+        pos = line.rsplit()[-1].strip()
+        return lastchange.VersionInfo('git', '%s-%s' % (hsh, pos))
+
+  raise Exception('Unable to fetch a Git Commit Position.')
+
+
+
+def ParseCommitPosition(commit_position):
+  '''Parse a Chrome commit position into its components.
+
+  Given a commit position like:
+    0178d4831bd36b5fb9ff477f03dc43b11626a6dc-refs/heads/master@{#292238}
+  Returns:
+    ("0178d4831bd36b5fb9ff477f03dc43b11626a6dc", "refs/heads/master", "292238")
+  '''
+  m = re.match(r'([0-9a-fA-F]+)(?:-([^@]+)@{#(\d+)})?', commit_position)
+  if m:
+    return m.groups()
+  return None
diff --git a/src/native_client_sdk/src/build_tools/tests/build_version_test.py b/src/native_client_sdk/src/build_tools/tests/build_version_test.py
new file mode 100755 (executable)
index 0000000..f8f60a2
--- /dev/null
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+import collections
+import unittest
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+BUILD_TOOLS_DIR = os.path.dirname(SCRIPT_DIR)
+CHROME_SRC = os.path.dirname(os.path.dirname(os.path.dirname(BUILD_TOOLS_DIR)))
+MOCK_DIR = os.path.join(CHROME_SRC, "third_party", "pymock")
+
+# For the mock library
+sys.path.append(MOCK_DIR)
+import mock
+
+sys.path.append(BUILD_TOOLS_DIR)
+import build_version
+
+ProcInfo = collections.namedtuple('ProcInfo', ['returncode', 'output'])
+
+class TestCase(unittest.TestCase):
+  def setUp(self):
+    self.fetch_svn = mock.patch('lastchange.FetchSVNRevision').start()
+    self.fetch_git_svn = mock.patch('lastchange.FetchGitSVNRevision').start()
+    self.run_git = mock.patch('lastchange.RunGitCommand').start()
+
+    self.fetch_svn.return_value = None
+    self.fetch_git_svn.return_value = None
+
+  def tearDown(self):
+    mock.patch.stopall()
+
+  def mockGitCommand(self, *args):
+    side_effects = []
+    for proc_info in args:
+      mock_proc = mock.MagicMock()
+      mock_proc.returncode = proc_info.returncode
+      comm_result = mock_proc.MagicMock()
+      comm_result.__getitem__.return_value = proc_info.output
+      mock_proc.communicate.return_value = comm_result
+      side_effects.append(mock_proc)
+
+    self.run_git.side_effect = side_effects
+
+  def mockDefaultGitCommand(self):
+    output = """\
+6a8b61d6be4656e682eba005a1dd7f129789129c
+[NaCl SDK] Update build_sdk.py to display Cr-Commit-Position in README.
+
+BUG=none
+R=bradnelson@google.com, bradnelson@chromium.org
+
+Review URL: https://codereview.chromium.org/495423010
+
+Cr-Commit-Position: refs/heads/master@{#292480}"""
+    self.mockGitCommand(ProcInfo(0, output))
+
+  def mockDepthTwoGitCommand(self):
+    output0 = """\
+ae4b444a0aa09a1fa73e59b180d7d957b9a36bf2
+."""
+
+    output1 = """\
+6a8b61d6be4656e682eba005a1dd7f129789129c
+[NaCl SDK] Update build_sdk.py to display Cr-Commit-Position in README.
+
+BUG=none
+R=bradnelson@google.com, bradnelson@chromium.org
+
+Review URL: https://codereview.chromium.org/495423010
+
+Cr-Commit-Position: refs/heads/master@{#292480}"""
+    self.mockGitCommand(ProcInfo(0, output0), ProcInfo(0, output1))
+
+
+  def assertGitShowCalled(self, depth=0):
+    cmd = ['show', '-s', '--format=%H%n%B', 'HEAD~%d' % depth]
+    self.run_git.assert_called_with(None, cmd)
+
+  def testChromeVersion(self):
+    self.mockDefaultGitCommand()
+    result = build_version.ChromeVersion()
+    self.assertGitShowCalled()
+    self.assertEqual(result, 'trunk.292480')
+
+  def testChromeRevision(self):
+    self.mockDefaultGitCommand()
+    result = build_version.ChromeRevision()
+    self.assertGitShowCalled()
+    self.assertEqual(result, '292480')
+
+  def testChromeCommitPosition(self):
+    self.mockDefaultGitCommand()
+    result = build_version.ChromeCommitPosition()
+    self.assertGitShowCalled()
+    self.assertEqual(
+        result,
+        '6a8b61d6be4656e682eba005a1dd7f129789129c-refs/heads/master@{#292480}')
+
+  def testChromeCommitPositionDepthTwo(self):
+    self.mockDepthTwoGitCommand()
+    result = build_version.ChromeCommitPosition()
+    self.assertEqual(
+        result,
+        '6a8b61d6be4656e682eba005a1dd7f129789129c-refs/heads/master@{#292480}')
+
+
+if __name__ == '__main__':
+  unittest.main()
index 9f468b4..6f2113a 100755 (executable)
@@ -30,6 +30,7 @@ EXTRACT_PACKAGES = ['nacl_x86_glibc']
 TOOLCHAIN_OUT = os.path.join(build_paths.OUT_DIR, 'sdk_tests', 'toolchain')
 
 TEST_MODULES = [
+    'build_version_test',
     'create_html_test',
     'create_nmf_test',
     'easy_template_test',
index c4e31c3..e71c68f 100755 (executable)
@@ -68,6 +68,7 @@ def GetSDKVersion():
 
   version = None
   revision = None
+  commit_position = None
   for line in open(readme):
     if ':' in line:
       name, value = line.split(':', 1)
@@ -75,8 +76,10 @@ def GetSDKVersion():
         version = value.strip()
       if name == "Chrome Revision":
         revision = value.strip()
+      if name == "Chrome Commit Position":
+        commit_position = value.strip()
 
-  if revision == None or version == None:
+  if revision is None or version is None or commit_position is None:
     raise Error("error parsing SDK README: %s" % readme)
 
   try:
@@ -85,7 +88,7 @@ def GetSDKVersion():
   except ValueError:
     raise Error("error parsing SDK README: %s" % readme)
 
-  return (version, revision)
+  return (version, revision, commit_position)
 
 
 def GetSystemArch(platform):
@@ -205,6 +208,8 @@ def main(args):
       help='Print major version of the NaCl SDK.')
   parser.add_option('--sdk-revision', action='store_true',
       help='Print revision number of the NaCl SDK.')
+  parser.add_option('--sdk-commit-position', action='store_true',
+      help='Print commit position of the NaCl SDK.')
   parser.add_option('--check-version',
       help='Check that the SDK version is at least as great as the '
            'version passed in.')
@@ -230,6 +235,8 @@ def main(args):
     out = GetSDKVersion()[0]
   elif options.sdk_revision:
     out = GetSDKVersion()[1]
+  elif options.sdk_commit_position:
+    out = GetSDKVersion()[2]
   elif options.check_version:
     required_version = ParseVersion(options.check_version)
     version = GetSDKVersion()
index 498c52a..acdd68f 100755 (executable)
@@ -117,10 +117,11 @@ class TestGetosWithTempdir(TestCaseExtended):
 
   def testGetSDKVersion(self):
     """correctly parses README to find SDK version."""
-    expected_version = (16, 196)
+    expected_version = (16, 196, 'f00baacabba6e-refs/heads/master@{#100}')
     with open(os.path.join(self.tempdir, 'README'), 'w') as out:
       out.write('Version: %s\n' % expected_version[0])
       out.write('Chrome Revision: %s\n' % expected_version[1])
+      out.write('Chrome Commit Position: %s\n' % expected_version[2])
 
     version = getos.GetSDKVersion()
     self.assertEqual(version, expected_version)
index 7dd51a2..5e9be15 100644 (file)
@@ -471,6 +471,8 @@ static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) {
     case MimeUtil::MPEG4_AAC_LC:
     case MimeUtil::MPEG4_AAC_SBRv1:
     case MimeUtil::H264_BASELINE:
+    case MimeUtil::H264_MAIN:
+    case MimeUtil::H264_HIGH:
     case MimeUtil::VP8:
     case MimeUtil::VORBIS:
       return true;
@@ -481,11 +483,6 @@ static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) {
       // MPEG-2 variants of AAC are not supported on Android.
       return false;
 
-    case MimeUtil::H264_MAIN:
-    case MimeUtil::H264_HIGH:
-      // H.264 Main and High profiles are not supported on Android.
-      return false;
-
     case MimeUtil::VP9:
       // VP9 is supported only in KitKat+ (API Level 19).
       return base::android::BuildInfo::GetInstance()->sdk_int() >= 19;
index dbaa431..76d94ab 100644 (file)
@@ -33,10 +33,9 @@ void NetworkDelegate::NotifyResolveProxy(
 
 void NetworkDelegate::NotifyProxyFallback(
     const ProxyServer& bad_proxy,
-    int net_error,
-    bool did_fallback) {
+    int net_error) {
   DCHECK(CalledOnValidThread());
-  OnProxyFallback(bad_proxy, net_error, did_fallback);
+  OnProxyFallback(bad_proxy, net_error);
 }
 
 int NetworkDelegate::NotifyBeforeSendHeaders(
@@ -181,8 +180,7 @@ void NetworkDelegate::OnResolveProxy(
 }
 
 void NetworkDelegate::OnProxyFallback(const ProxyServer& bad_proxy,
-                                      int net_error,
-                                      bool did_fallback) {
+                                      int net_error) {
 }
 
 int NetworkDelegate::OnBeforeSendHeaders(URLRequest* request,
index 2a0c9f0..a290d16 100644 (file)
@@ -68,8 +68,7 @@ class NET_EXPORT NetworkDelegate : public base::NonThreadSafe {
                           const ProxyService& proxy_service,
                           ProxyInfo* result);
   void NotifyProxyFallback(const ProxyServer& bad_proxy,
-                           int net_error,
-                           bool did_fallback);
+                           int net_error);
   int NotifyBeforeSendHeaders(URLRequest* request,
                               const CompletionCallback& callback,
                               HttpRequestHeaders* headers);
@@ -138,12 +137,12 @@ class NET_EXPORT NetworkDelegate : public base::NonThreadSafe {
                               const ProxyService& proxy_service,
                               ProxyInfo* result);
 
-  // Called when use of |bad_proxy| fails due to |net_error|. |did_fallback| is
-  // true if the proxy service was able to fallback to another proxy
-  // configuration.
+  // Called when use of |bad_proxy| fails due to |net_error|. |net_error| is
+  // the network error encountered, if any, and OK if the fallback was
+  // for a reason other than a network error (e.g. the proxy service was
+  // explicitly directed to skip a proxy).
   virtual void OnProxyFallback(const ProxyServer& bad_proxy,
-                               int net_error,
-                               bool did_fallback);
+                               int net_error);
 
   // Called right before the HTTP headers are sent. Allows the delegate to
   // read/write |headers| before they get sent out. |callback| and |headers| are
index 04f4bda..74d88a8 100644 (file)
@@ -143,6 +143,12 @@ static const EVMetadata ev_root_ca_metadata[] = {
         0x2c, 0x50, 0xb6, 0x56, 0x3b, 0x8e, 0x2d, 0x93, 0xc3, 0x11 } },
     {"1.3.6.1.4.1.6449.1.2.1.5.1", ""},
   },
+  // COMODO RSA Certification Authority
+  // https://comodorsacertificationauthority-ev.comodoca.com/
+  { { { 0xaf, 0xe5, 0xd2, 0x44, 0xa8, 0xd1, 0x19, 0x42, 0x30, 0xff,
+        0x47, 0x9f, 0xe2, 0xf8, 0x97, 0xbb, 0xcd, 0x7a, 0x8c, 0xb4 } },
+    {"1.3.6.1.4.1.6449.1.2.1.5.1", ""},
+  },
   // Cybertrust Global Root
   // https://evup.cybertrust.ne.jp/ctj-ev-upgrader/evseal.gif
   { { { 0x5f, 0x43, 0xe5, 0xb1, 0xbf, 0xf8, 0x78, 0x8c, 0xac, 0x1c,
@@ -365,6 +371,18 @@ static const EVMetadata ev_root_ca_metadata[] = {
         0x74, 0x70, 0x19, 0x9d, 0x2a, 0xbe, 0x11, 0xe3, 0x81, 0xd1 } },
     {"1.3.6.1.4.1.7879.13.24.1", "" },
   },
+  // USERTrust ECC Certification Authority
+  // https://usertrustecccertificationauthority-ev.comodoca.com/
+  { { { 0xd1, 0xcb, 0xca, 0x5d, 0xb2, 0xd5, 0x2a, 0x7f, 0x69, 0x3b,
+        0x67, 0x4d, 0xe5, 0xf0, 0x5a, 0x1d, 0x0c, 0x95, 0x7d, 0xf0 } },
+    {"1.3.6.1.4.1.6449.1.2.1.5.1", ""},
+  },
+  // USERTrust RSA Certification Authority
+  // https://usertrustrsacertificationauthority-ev.comodoca.com/
+  { { { 0x2b, 0x8f, 0x1b, 0x57, 0x33, 0x0d, 0xbb, 0xa2, 0xd0, 0x7a,
+        0x6c, 0x51, 0xf7, 0x0e, 0xe9, 0x0d, 0xda, 0xb9, 0xad, 0x8e } },
+    {"1.3.6.1.4.1.6449.1.2.1.5.1", ""},
+  },
   // UTN - DATACorp SGC
   { { { 0x58, 0x11, 0x9f, 0x0e, 0x12, 0x82, 0x87, 0xea, 0x50, 0xfd,
         0xd9, 0x87, 0x45, 0x6f, 0x4f, 0x78, 0xdc, 0xfa, 0xd6, 0xd4 } },
index 359f725..a94f6fb 100644 (file)
@@ -3179,6 +3179,38 @@ TEST_F(DiskCacheEntryTest, SimpleCacheDoomCreateDoom) {
   // This test passes if it doesn't crash.
 }
 
+TEST_F(DiskCacheEntryTest, SimpleCacheDoomCloseCreateCloseOpen) {
+  // Test sequence: Create, Doom, Close, Create, Close, Open.
+  SetSimpleCacheMode();
+  InitCache();
+
+  disk_cache::Entry* null = NULL;
+
+  const char key[] = "this is a key";
+
+  disk_cache::Entry* entry1 = NULL;
+  ASSERT_EQ(net::OK, CreateEntry(key, &entry1));
+  ScopedEntryPtr entry1_closer(entry1);
+  EXPECT_NE(null, entry1);
+
+  entry1->Doom();
+  entry1_closer.reset();
+  entry1 = NULL;
+
+  disk_cache::Entry* entry2 = NULL;
+  ASSERT_EQ(net::OK, CreateEntry(key, &entry2));
+  ScopedEntryPtr entry2_closer(entry2);
+  EXPECT_NE(null, entry2);
+
+  entry2_closer.reset();
+  entry2 = NULL;
+
+  disk_cache::Entry* entry3 = NULL;
+  ASSERT_EQ(net::OK, OpenEntry(key, &entry3));
+  ScopedEntryPtr entry3_closer(entry3);
+  EXPECT_NE(null, entry3);
+}
+
 // Checks that an optimistic Create would fail later on a racing Open.
 TEST_F(DiskCacheEntryTest, SimpleCacheOptimisticCreateFailsOnOpen) {
   SetSimpleCacheMode();
index 5e8c3f2..a762620 100644 (file)
@@ -197,6 +197,34 @@ void RecordIndexLoad(net::CacheType cache_type,
 
 }  // namespace
 
+class SimpleBackendImpl::ActiveEntryProxy
+    : public SimpleEntryImpl::ActiveEntryProxy {
+ public:
+  virtual ~ActiveEntryProxy() {
+    if (backend_) {
+      DCHECK_EQ(1U, backend_->active_entries_.count(entry_hash_));
+      backend_->active_entries_.erase(entry_hash_);
+    }
+  }
+
+  static scoped_ptr<SimpleEntryImpl::ActiveEntryProxy> Create(
+      int64 entry_hash,
+      SimpleBackendImpl* backend) {
+    scoped_ptr<SimpleEntryImpl::ActiveEntryProxy>
+        proxy(new ActiveEntryProxy(entry_hash, backend));
+    return proxy.Pass();
+  }
+
+ private:
+  ActiveEntryProxy(uint64 entry_hash,
+                   SimpleBackendImpl* backend)
+      : entry_hash_(entry_hash),
+        backend_(backend->AsWeakPtr()) {}
+
+  uint64 entry_hash_;
+  base::WeakPtr<SimpleBackendImpl> backend_;
+};
+
 SimpleBackendImpl::SimpleBackendImpl(const FilePath& path,
                                      int max_bytes,
                                      net::CacheType cache_type,
@@ -250,10 +278,6 @@ int SimpleBackendImpl::GetMaxFileSize() const {
   return index_->max_size() / kMaxFileRatio;
 }
 
-void SimpleBackendImpl::OnDeactivated(const SimpleEntryImpl* entry) {
-  active_entries_.erase(entry->entry_hash());
-}
-
 void SimpleBackendImpl::OnDoomStart(uint64 entry_hash) {
   // TODO(ttuttle): Revert to DCHECK once http://crbug.com/317138 is fixed.
   CHECK_EQ(0u, entries_pending_doom_.count(entry_hash));
@@ -511,18 +535,17 @@ scoped_refptr<SimpleEntryImpl> SimpleBackendImpl::CreateOrFindActiveEntry(
     const std::string& key) {
   DCHECK_EQ(entry_hash, simple_util::GetEntryHashKey(key));
   std::pair<EntryMap::iterator, bool> insert_result =
-      active_entries_.insert(std::make_pair(entry_hash,
-                                            base::WeakPtr<SimpleEntryImpl>()));
+      active_entries_.insert(EntryMap::value_type(entry_hash, NULL));
   EntryMap::iterator& it = insert_result.first;
-  if (insert_result.second)
-    DCHECK(!it->second.get());
-  if (!it->second.get()) {
-    SimpleEntryImpl* entry = new SimpleEntryImpl(
-        cache_type_, path_, entry_hash, entry_operations_mode_, this, net_log_);
+  const bool did_insert = insert_result.second;
+  if (did_insert) {
+    SimpleEntryImpl* entry = it->second =
+        new SimpleEntryImpl(cache_type_, path_, entry_hash,
+                            entry_operations_mode_,this, net_log_);
     entry->SetKey(key);
-    it->second = entry->AsWeakPtr();
+    entry->SetActiveEntryProxy(ActiveEntryProxy::Create(entry_hash, this));
   }
-  DCHECK(it->second.get());
+  DCHECK(it->second);
   // It's possible, but unlikely, that we have an entry hash collision with a
   // currently active entry.
   if (key != it->second->key()) {
@@ -530,7 +553,7 @@ scoped_refptr<SimpleEntryImpl> SimpleBackendImpl::CreateOrFindActiveEntry(
     DCHECK_EQ(0U, active_entries_.count(entry_hash));
     return CreateOrFindActiveEntry(entry_hash, key);
   }
-  return make_scoped_refptr(it->second.get());
+  return make_scoped_refptr(it->second);
 }
 
 int SimpleBackendImpl::OpenEntryFromHash(uint64 entry_hash,
@@ -639,19 +662,19 @@ void SimpleBackendImpl::OnEntryOpenedFromHash(
   }
   DCHECK(*entry);
   std::pair<EntryMap::iterator, bool> insert_result =
-      active_entries_.insert(std::make_pair(hash,
-                                            base::WeakPtr<SimpleEntryImpl>()));
+      active_entries_.insert(EntryMap::value_type(hash, simple_entry));
   EntryMap::iterator& it = insert_result.first;
   const bool did_insert = insert_result.second;
   if (did_insert) {
-    // There is no active entry corresponding to this hash. The entry created
-    // is put in the map of active entries and returned to the caller.
-    it->second = simple_entry->AsWeakPtr();
-    callback.Run(error_code);
+    // There was no active entry corresponding to this hash. We've already put
+    // the entry opened from hash in the |active_entries_|. We now provide the
+    // proxy object to the entry.
+    it->second->SetActiveEntryProxy(ActiveEntryProxy::Create(hash, this));
+    callback.Run(net::OK);
   } else {
-    // The entry was made active with the key while the creation from hash
-    // occurred. The entry created from hash needs to be closed, and the one
-    // coming from the key returned to the caller.
+    // The entry was made active while we waiting for the open from hash to
+    // finish. The entry created from hash needs to be closed, and the one
+    // in |active_entries_| can be returned to the caller.
     simple_entry->Close();
     it->second->OpenEntry(entry, callback);
   }
index eb14de8..996cfd2 100644 (file)
@@ -64,10 +64,6 @@ class NET_EXPORT_PRIVATE SimpleBackendImpl : public Backend,
   // Returns the maximum file size permitted in this backend.
   int GetMaxFileSize() const;
 
-  // Removes |entry| from the |active_entries_| set, forcing future Open/Create
-  // operations to construct a new object.
-  void OnDeactivated(const SimpleEntryImpl* entry);
-
   // Flush our SequencedWorkerPool.
   static void FlushWorkerPoolForTesting();
 
@@ -107,11 +103,14 @@ class NET_EXPORT_PRIVATE SimpleBackendImpl : public Backend,
   virtual void OnExternalCacheHit(const std::string& key) OVERRIDE;
 
  private:
-  typedef base::hash_map<uint64, base::WeakPtr<SimpleEntryImpl> > EntryMap;
+  typedef base::hash_map<uint64, SimpleEntryImpl*> EntryMap;
 
   typedef base::Callback<void(base::Time mtime, uint64 max_size, int result)>
       InitializeIndexCallback;
 
+  class ActiveEntryProxy;
+  friend class ActiveEntryProxy;
+
   // Return value of InitCacheStructureOnDisk().
   struct DiskStatResult {
     base::Time cache_dir_mtime;
index 166c34b..b0ff383 100644 (file)
@@ -160,6 +160,8 @@ class SimpleEntryImpl::ScopedOperationRunner {
   SimpleEntryImpl* const entry_;
 };
 
+SimpleEntryImpl::ActiveEntryProxy::~ActiveEntryProxy() {}
+
 SimpleEntryImpl::SimpleEntryImpl(net::CacheType cache_type,
                                  const FilePath& path,
                                  const uint64 entry_hash,
@@ -195,6 +197,12 @@ SimpleEntryImpl::SimpleEntryImpl(net::CacheType cache_type,
       CreateNetLogSimpleEntryConstructionCallback(this));
 }
 
+void SimpleEntryImpl::SetActiveEntryProxy(
+    scoped_ptr<ActiveEntryProxy> active_entry_proxy) {
+  DCHECK(!active_entry_proxy_);
+  active_entry_proxy_.reset(active_entry_proxy.release());
+}
+
 int SimpleEntryImpl::OpenEntry(Entry** out_entry,
                                const CompletionCallback& callback) {
   DCHECK(backend_.get());
@@ -525,7 +533,6 @@ SimpleEntryImpl::~SimpleEntryImpl() {
   DCHECK_EQ(0U, pending_operations_.size());
   DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_FAILURE);
   DCHECK(!synchronous_entry_);
-  RemoveSelfFromBackend();
   net_log_.EndEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY);
 }
 
@@ -567,18 +574,12 @@ void SimpleEntryImpl::ReturnEntryToCaller(Entry** out_entry) {
   *out_entry = this;
 }
 
-void SimpleEntryImpl::RemoveSelfFromBackend() {
-  if (!backend_.get())
-    return;
-  backend_->OnDeactivated(this);
-}
-
 void SimpleEntryImpl::MarkAsDoomed() {
   doomed_ = true;
   if (!backend_.get())
     return;
   backend_->index()->Remove(entry_hash_);
-  RemoveSelfFromBackend();
+  active_entry_proxy_.reset();
 }
 
 void SimpleEntryImpl::RunNextOperationIfNeeded() {
index 2d78d8b..2dfb757 100644 (file)
@@ -11,7 +11,6 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "net/base/cache_type.h"
 #include "net/base/net_export.h"
@@ -40,8 +39,7 @@ struct SimpleEntryCreationResults;
 // disk cache. It proxies for the SimpleSynchronousEntry, which performs IO
 // on the worker thread.
 class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry,
-    public base::RefCounted<SimpleEntryImpl>,
-    public base::SupportsWeakPtr<SimpleEntryImpl> {
+    public base::RefCounted<SimpleEntryImpl> {
   friend class base::RefCounted<SimpleEntryImpl>;
  public:
   enum OperationsMode {
@@ -49,6 +47,14 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry,
     OPTIMISTIC_OPERATIONS,
   };
 
+  // The Backend provides an |ActiveEntryProxy| instance to this entry when it
+  // is active, meaning it's the canonical entry for this |entry_hash_|. The
+  // entry can make itself inactive by deleting its proxy.
+  class ActiveEntryProxy {
+   public:
+    virtual ~ActiveEntryProxy() = 0;
+  };
+
   SimpleEntryImpl(net::CacheType cache_type,
                   const base::FilePath& path,
                   uint64 entry_hash,
@@ -56,6 +62,9 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry,
                   SimpleBackendImpl* backend,
                   net::NetLog* net_log);
 
+  void SetActiveEntryProxy(
+      scoped_ptr<ActiveEntryProxy> active_entry_proxy);
+
   // Adds another reader/writer to this entry, if possible, returning |this| to
   // |entry|.
   int OpenEntry(Entry** entry, const CompletionCallback& callback);
@@ -150,10 +159,6 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry,
   // count.
   void ReturnEntryToCaller(Entry** out_entry);
 
-  // Ensures that |this| is no longer referenced by our |backend_|, this
-  // guarantees that this entry cannot have OpenEntry/CreateEntry called again.
-  void RemoveSelfFromBackend();
-
   // An error occured, and the SimpleSynchronousEntry should have Doomed
   // us at this point. We need to remove |this| from the Backend and the
   // index.
@@ -297,6 +302,8 @@ class NET_EXPORT_PRIVATE SimpleEntryImpl : public Entry,
                   int length,
                   int stream_index);
 
+  scoped_ptr<ActiveEntryProxy> active_entry_proxy_;
+
   // All nonstatic SimpleEntryImpl methods should always be called on the IO
   // thread, in all cases. |io_thread_checker_| documents and enforces this.
   base::ThreadChecker io_thread_checker_;
index cad818b..53a377b 100644 (file)
@@ -1137,7 +1137,8 @@ int HttpStreamFactoryImpl::Job::DoCreateStreamComplete(int result) {
   if (result < 0)
     return result;
 
-  session_->proxy_service()->ReportSuccess(proxy_info_);
+  session_->proxy_service()->ReportSuccess(proxy_info_,
+                                           session_->network_delegate());
   next_state_ = STATE_NONE;
   return OK;
 }
index ad6ff57..fd8c2ed 100644 (file)
@@ -1081,7 +1081,6 @@ static const struct HSTSPreload kPreloadedSTS[] = {
   {7, true, "\002" "ed" "\002" "gs", true, kNoPins, DOMAIN_NOT_PINNED },
   {21, true, "\017" "forewordreviews" "\003" "com", true, kNoPins, DOMAIN_NOT_PINNED },
   {21, true, "\020" "giacomopelagatti" "\002" "it", true, kNoPins, DOMAIN_NOT_PINNED },
-  {16, true, "\010" "globalcs" "\002" "co" "\002" "uk", true, kNoPins, DOMAIN_NOT_PINNED },
   {13, true, "\010" "helichat" "\002" "de", true, kNoPins, DOMAIN_NOT_PINNED },
   {23, true, "\022" "hostinginnederland" "\002" "nl", true, kNoPins, DOMAIN_NOT_PINNED },
   {19, true, "\015" "isitchristmas" "\003" "com", true, kNoPins, DOMAIN_NOT_PINNED },
index ac3566a..6551384 100644 (file)
     { "name": "ed.gs", "include_subdomains": true, "mode": "force-https" },
     { "name": "forewordreviews.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "giacomopelagatti.it", "include_subdomains": true, "mode": "force-https" },
-    { "name": "globalcs.co.uk", "include_subdomains": true, "mode": "force-https" },
     { "name": "helichat.de", "include_subdomains": true, "mode": "force-https" },
     { "name": "hostinginnederland.nl", "include_subdomains": true, "mode": "force-https" },
     { "name": "isitchristmas.com", "include_subdomains": true, "mode": "force-https" },
index b6fcc86..96ae3ce 100644 (file)
@@ -63,8 +63,8 @@ std::string ProxyInfo::ToPacString() const {
   return proxy_list_.ToPacString();
 }
 
-bool ProxyInfo::Fallback(const BoundNetLog& net_log) {
-  return proxy_list_.Fallback(&proxy_retry_info_, net_log);
+bool ProxyInfo::Fallback(int net_error, const BoundNetLog& net_log) {
+  return proxy_list_.Fallback(&proxy_retry_info_, net_error, net_log);
 }
 
 void ProxyInfo::DeprioritizeBadProxies(
index 336cb3a..1e4fded 100644 (file)
@@ -115,9 +115,12 @@ class NET_EXPORT ProxyInfo {
   // See description in ProxyList::ToPacString().
   std::string ToPacString() const;
 
-  // Marks the current proxy as bad. Returns true if there is another proxy
+  // Marks the current proxy as bad. |net_error| should contain the network
+  // error encountered when this proxy was tried, if any. If this fallback
+  // is not because of a network error, then |OK| should be passed in (eg. for
+  // reasons such as local policy). Returns true if there is another proxy is
   // available to try in proxy list_.
-  bool Fallback(const BoundNetLog& net_log);
+  bool Fallback(int net_error, const BoundNetLog& net_log);
 
   // De-prioritizes the proxies that we have cached as not working, by moving
   // them to the end of the proxy list.
index 377cff3..165283d 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "net/base/net_errors.h"
 #include "net/proxy/proxy_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -32,7 +33,7 @@ TEST(ProxyInfoTest, ProxyInfoIsDirectOnly) {
   EXPECT_FALSE(info.is_direct());
   EXPECT_FALSE(info.is_direct_only());
   // After falling back to direct, we shouldn't consider it DIRECT only.
-  EXPECT_TRUE(info.Fallback(BoundNetLog()));
+  EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, BoundNetLog()));
   EXPECT_TRUE(info.is_direct());
   EXPECT_FALSE(info.is_direct_only());
 }
index 2adea29..4dc4626 100644 (file)
@@ -146,6 +146,7 @@ base::ListValue* ProxyList::ToValue() const {
 }
 
 bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info,
+                         int net_error,
                          const BoundNetLog& net_log) {
 
   // TODO(eroman): It would be good if instead of removing failed proxies
@@ -171,6 +172,7 @@ bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info,
                             TimeDelta::FromMinutes(5),
                             true,
                             ProxyServer(),
+                            net_error,
                             net_log);
 
   // Remove this proxy from our list.
@@ -182,6 +184,7 @@ void ProxyList::AddProxyToRetryList(ProxyRetryInfoMap* proxy_retry_info,
                                     base::TimeDelta retry_delay,
                                     bool try_while_bad,
                                     const ProxyServer& proxy_to_retry,
+                                    int net_error,
                                     const BoundNetLog& net_log) const {
   // Mark this proxy as bad.
   std::string proxy_key = proxy_to_retry.ToURI();
@@ -195,6 +198,7 @@ void ProxyList::AddProxyToRetryList(ProxyRetryInfoMap* proxy_retry_info,
     retry_info.current_delay = retry_delay;
     retry_info.bad_until = TimeTicks().Now() + retry_info.current_delay;
     retry_info.try_while_bad = try_while_bad;
+    retry_info.net_error = net_error;
     (*proxy_retry_info)[proxy_key] = retry_info;
   }
   net_log.AddEvent(NetLog::TYPE_PROXY_LIST_FALLBACK,
@@ -206,6 +210,7 @@ void ProxyList::UpdateRetryInfoOnFallback(
     base::TimeDelta retry_delay,
     bool reconsider,
     const ProxyServer& another_proxy_to_bypass,
+    int net_error,
     const BoundNetLog& net_log) const {
   DCHECK(retry_delay != base::TimeDelta());
 
@@ -215,14 +220,22 @@ void ProxyList::UpdateRetryInfoOnFallback(
   }
 
   if (!proxies_[0].is_direct()) {
-    AddProxyToRetryList(proxy_retry_info, retry_delay, reconsider, proxies_[0],
+    AddProxyToRetryList(proxy_retry_info,
+                        retry_delay,
+                        reconsider,
+                        proxies_[0],
+                        net_error,
                         net_log);
 
     // If an additional proxy to bypass is specified, add it to the retry map
     // as well.
     if (another_proxy_to_bypass.is_valid()) {
-      AddProxyToRetryList(proxy_retry_info, retry_delay, reconsider,
-                          another_proxy_to_bypass, net_log);
+      AddProxyToRetryList(proxy_retry_info,
+                          retry_delay,
+                          reconsider,
+                          another_proxy_to_bypass,
+                          net_error,
+                          net_log);
     }
   }
 }
index ac9635a..d57743e 100644 (file)
@@ -78,10 +78,14 @@ class NET_EXPORT_PRIVATE ProxyList {
   // Returns a serialized value for the list. The caller takes ownership of it.
   base::ListValue* ToValue() const;
 
-  // Marks the current proxy server as bad and deletes it from the list.  The
-  // list of known bad proxies is given by proxy_retry_info.  Returns true if
-  // there is another server available in the list.
+  // Marks the current proxy server as bad and deletes it from the list. The
+  // list of known bad proxies is given by |proxy_retry_info|. |net_error|
+  // should contain the network error encountered when this proxy was tried, if
+  // any. If this fallback is not because of a network error, then |OK| should
+  // be passed in (eg. for reasons such as local policy). Returns true if there
+  // is another server available in the list.
   bool Fallback(ProxyRetryInfoMap* proxy_retry_info,
+                int net_error,
                 const BoundNetLog& net_log);
 
   // Updates |proxy_retry_info| to indicate that the first proxy in the list
@@ -90,22 +94,28 @@ class NET_EXPORT_PRIVATE ProxyList {
   // retry after |retry_delay| if positive, and will use the default proxy retry
   // duration otherwise. It may reconsider the proxy beforehand if |reconsider|
   // is true. Additionally updates |proxy_retry_info| with
-  // |another_proxy_to_bypass| if non-empty.
+  // |another_proxy_to_bypass| if non-empty. |net_error| should contain the
+  // network error countered when this proxy was tried, or OK if the proxy retry
+  // info is being updated for a non-network related reason (e.g. local policy).
   void UpdateRetryInfoOnFallback(
       ProxyRetryInfoMap* proxy_retry_info,
       base::TimeDelta retry_delay,
       bool reconsider,
       const ProxyServer& another_proxy_to_bypass,
+      int net_error,
       const BoundNetLog& net_log) const;
 
  private:
   // Updates |proxy_retry_info| to indicate that the |proxy_to_retry| in
   // |proxies_| is bad for |retry_delay|, but may be reconsidered earlier if
-  // |try_while_bad| is true.
+  // |try_while_bad| is true. |net_error| should contain the network error
+  // countered when this proxy was tried, or OK if the proxy retry info is
+  // being updated for a non-network related reason (e.g. local policy).
   void AddProxyToRetryList(ProxyRetryInfoMap* proxy_retry_info,
                            base::TimeDelta retry_delay,
                            bool try_while_bad,
                            const ProxyServer& proxy_to_retry,
+                           int net_error,
                            const BoundNetLog& net_log) const;
 
   // List of proxies.
index 9ccf9c4..23b823f 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "net/proxy/proxy_list.h"
 
+#include "net/base/net_errors.h"
 #include "net/base/net_log.h"
 #include "net/proxy/proxy_retry_info.h"
 #include "net/proxy/proxy_server.h"
@@ -172,13 +173,38 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
     ProxyList list;
     ProxyRetryInfoMap retry_info_map;
     BoundNetLog net_log;
+    ProxyServer proxy_server(
+        ProxyServer::FromURI("foopy1:80", ProxyServer::SCHEME_HTTP));
     list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
     list.UpdateRetryInfoOnFallback(&retry_info_map,
                                    base::TimeDelta::FromSeconds(60),
                                    true,
-                                   ProxyServer(),
+                                   proxy_server,
+                                   ERR_PROXY_CONNECTION_FAILED,
+                                   net_log);
+    EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
+    EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED,
+              retry_info_map[proxy_server.ToURI()].net_error);
+    EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
+    EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
+  }
+  // Retrying should put the first proxy on the retry list, even if there
+  // was no network error.
+  {
+    ProxyList list;
+    ProxyRetryInfoMap retry_info_map;
+    BoundNetLog net_log;
+    ProxyServer proxy_server(
+        ProxyServer::FromURI("foopy1:80", ProxyServer::SCHEME_HTTP));
+    list.SetFromPacString("PROXY foopy1:80;PROXY foopy2:80;PROXY foopy3:80");
+    list.UpdateRetryInfoOnFallback(&retry_info_map,
+                                   base::TimeDelta::FromSeconds(60),
+                                   true,
+                                   proxy_server,
+                                   OK,
                                    net_log);
     EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
+    EXPECT_EQ(OK, retry_info_map[proxy_server.ToURI()].net_error);
     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
   }
@@ -195,8 +221,11 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
                                    base::TimeDelta::FromSeconds(60),
                                    true,
                                    proxy_server,
+                                   ERR_NAME_RESOLUTION_FAILED,
                                    net_log);
     EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy1:80"));
+    EXPECT_EQ(ERR_NAME_RESOLUTION_FAILED,
+              retry_info_map[proxy_server.ToURI()].net_error);
     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
     EXPECT_TRUE(retry_info_map.end() != retry_info_map.find("foopy3:80"));
   }
@@ -213,6 +242,7 @@ TEST(ProxyListTest, UpdateRetryInfoOnFallback) {
                                    base::TimeDelta::FromSeconds(60),
                                    true,
                                    proxy_server,
+                                   OK,
                                    net_log);
     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy2:80"));
     EXPECT_TRUE(retry_info_map.end() == retry_info_map.find("foopy3:80"));
index 0d073b9..a36fcd9 100644 (file)
@@ -24,6 +24,11 @@ struct ProxyRetryInfo {
 
   // True if this proxy should be considered even if still bad.
   bool try_while_bad;
+
+  // The network error received when this proxy failed, or |OK| if the proxy
+  // was added to the retry list for a non-network related reason. (e.g. local
+  // policy).
+  int net_error;
 };
 
 // Map of proxy servers with the associated RetryInfo structures.
index 6bd519c..3b93bde 100644 (file)
@@ -1211,11 +1211,7 @@ int ProxyService::ReconsiderProxyAfterError(const GURL& url,
 
   // We don't have new proxy settings to try, try to fallback to the next proxy
   // in the list.
-  bool did_fallback = result->Fallback(net_log);
-
-  if (network_delegate) {
-      network_delegate->NotifyProxyFallback(bad_proxy, net_error, did_fallback);
-  }
+  bool did_fallback = result->Fallback(net_error, net_log);
 
   // Return synchronous failure if there is nothing left to fall-back to.
   // TODO(eroman): This is a yucky API, clean it up.
@@ -1227,9 +1223,11 @@ bool ProxyService::MarkProxiesAsBadUntil(
     base::TimeDelta retry_delay,
     const ProxyServer& another_bad_proxy,
     const BoundNetLog& net_log) {
-  result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, retry_delay,
+  result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_,
+                                               retry_delay,
                                                false,
                                                another_bad_proxy,
+                                               OK,
                                                net_log);
   if (another_bad_proxy.is_valid())
     return result.proxy_list_.size() > 2;
@@ -1237,7 +1235,8 @@ bool ProxyService::MarkProxiesAsBadUntil(
     return result.proxy_list_.size() > 1;
 }
 
-void ProxyService::ReportSuccess(const ProxyInfo& result) {
+void ProxyService::ReportSuccess(const ProxyInfo& result,
+                                 NetworkDelegate* network_delegate) {
   DCHECK(CalledOnValidThread());
 
   const ProxyRetryInfoMap& new_retry_info = result.proxy_retry_info();
@@ -1247,8 +1246,16 @@ void ProxyService::ReportSuccess(const ProxyInfo& result) {
   for (ProxyRetryInfoMap::const_iterator iter = new_retry_info.begin();
        iter != new_retry_info.end(); ++iter) {
     ProxyRetryInfoMap::iterator existing = proxy_retry_info_.find(iter->first);
-    if (existing == proxy_retry_info_.end())
+    if (existing == proxy_retry_info_.end()) {
       proxy_retry_info_[iter->first] = iter->second;
+      if (network_delegate) {
+        const ProxyServer& bad_proxy =
+            ProxyServer::FromURI(iter->first, ProxyServer::SCHEME_HTTP);
+        const ProxyRetryInfo& proxy_retry_info = iter->second;
+        network_delegate->NotifyProxyFallback(bad_proxy,
+                                              proxy_retry_info.net_error);
+      }
+    }
     else if (existing->second.bad_until < iter->second.bad_until)
       existing->second.bad_until = iter->second.bad_until;
   }
index 7b3e5d2..69aaf46 100644 (file)
@@ -160,7 +160,10 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
   // and will use the default proxy retry duration otherwise. Proxies marked as
   // bad will not be retried until |retry_delay| has passed. Returns true if
   // there will be at least one proxy remaining in the list after fallback and
-  // false otherwise.
+  // false otherwise. This method should be used to add proxies to the bad
+  // proxy list only for reasons other than a network error. If a proxy needs
+  // to be added to the bad proxy list because a network error was encountered
+  // when trying to connect to it, use |ReconsiderProxyAfterError|.
   bool MarkProxiesAsBadUntil(const ProxyInfo& results,
                              base::TimeDelta retry_delay,
                              const ProxyServer& another_bad_proxy,
@@ -168,8 +171,10 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
 
   // Called to report that the last proxy connection succeeded.  If |proxy_info|
   // has a non empty proxy_retry_info map, the proxies that have been tried (and
-  // failed) for this request will be marked as bad.
-  void ReportSuccess(const ProxyInfo& proxy_info);
+  // failed) for this request will be marked as bad. |network_delegate| will
+  // be notified of any proxy fallbacks.
+  void ReportSuccess(const ProxyInfo& proxy_info,
+                     NetworkDelegate* network_delegate);
 
   // Call this method with a non-null |pac_request| to cancel the PAC request.
   void CancelPacRequest(PacRequest* pac_request);
index 1d5b1c7..a222710 100644 (file)
@@ -207,17 +207,13 @@ class TestProxyFallbackNetworkDelegate : public NetworkDelegate {
  public:
   TestProxyFallbackNetworkDelegate()
       : on_proxy_fallback_called_(false),
-        proxy_fallback_net_error_(0),
-        proxy_did_fallback_(false) {
+        proxy_fallback_net_error_(OK) {
   }
 
-  virtual void OnProxyFallback(
-      const ProxyServer& proxy_server,
-      int net_error,
-      bool did_fallback) OVERRIDE {
+  virtual void OnProxyFallback(const ProxyServer& proxy_server,
+                               int net_error) OVERRIDE {
     proxy_server_ = proxy_server;
     proxy_fallback_net_error_ = net_error;
-    proxy_did_fallback_ = did_fallback;
     on_proxy_fallback_called_ = true;
   }
 
@@ -233,15 +229,10 @@ class TestProxyFallbackNetworkDelegate : public NetworkDelegate {
     return proxy_fallback_net_error_;
   }
 
-  bool proxy_did_fallback() const {
-    return proxy_did_fallback_;
-  }
-
  private:
   bool on_proxy_fallback_called_;
   ProxyServer proxy_server_;
   int proxy_fallback_net_error_;
-  bool proxy_did_fallback_;
 };
 
 }  // namespace
@@ -514,7 +505,7 @@ TEST_F(ProxyServiceTest, PAC_FailoverWithoutDirect) {
   // Now, imagine that connecting to foopy:8080 fails: there is nothing
   // left to fallback to, since our proxy list was NOT terminated by
   // DIRECT.
-  TestProxyFallbackNetworkDelegate network_delegate;
+  NetworkDelegate network_delegate;
   TestCompletionCallback callback2;
   ProxyServer expected_proxy_server = info.proxy_server();
   rv = service.ReconsiderProxyAfterError(
@@ -523,11 +514,6 @@ TEST_F(ProxyServiceTest, PAC_FailoverWithoutDirect) {
   // ReconsiderProxyAfterError returns error indicating nothing left.
   EXPECT_EQ(ERR_FAILED, rv);
   EXPECT_TRUE(info.is_empty());
-  EXPECT_TRUE(network_delegate.on_proxy_fallback_called());
-  EXPECT_EQ(expected_proxy_server, network_delegate.proxy_server());
-  EXPECT_EQ(net::ERR_PROXY_CONNECTION_FAILED,
-            network_delegate.proxy_fallback_net_error());
-  EXPECT_FALSE(network_delegate.proxy_did_fallback());
 }
 
 // Test that if the execution of the PAC script fails (i.e. javascript runtime
@@ -620,7 +606,6 @@ TEST_F(ProxyServiceTest, PAC_FailoverAfterDirect) {
   EXPECT_TRUE(info.is_direct());
 
   // Fallback 1.
-  TestProxyFallbackNetworkDelegate network_delegate2;
   TestCompletionCallback callback2;
   rv = service.ReconsiderProxyAfterError(url, net::LOAD_NORMAL,
                                          net::ERR_PROXY_CONNECTION_FAILED,
@@ -629,57 +614,38 @@ TEST_F(ProxyServiceTest, PAC_FailoverAfterDirect) {
   EXPECT_EQ(OK, rv);
   EXPECT_FALSE(info.is_direct());
   EXPECT_EQ("foobar:10", info.proxy_server().ToURI());
-  // No network delegate provided.
-  EXPECT_FALSE(network_delegate2.on_proxy_fallback_called());
 
   // Fallback 2.
-  TestProxyFallbackNetworkDelegate network_delegate3;
+  NetworkDelegate network_delegate;
   ProxyServer expected_proxy_server3 = info.proxy_server();
   TestCompletionCallback callback3;
   rv = service.ReconsiderProxyAfterError(url, net::LOAD_NORMAL,
                                          net::ERR_PROXY_CONNECTION_FAILED,
                                          &info, callback3.callback(), NULL,
-                                         &network_delegate3, BoundNetLog());
+                                         &network_delegate, BoundNetLog());
   EXPECT_EQ(OK, rv);
   EXPECT_TRUE(info.is_direct());
-  EXPECT_TRUE(network_delegate3.on_proxy_fallback_called());
-  EXPECT_EQ(expected_proxy_server3, network_delegate3.proxy_server());
-  EXPECT_EQ(net::ERR_PROXY_CONNECTION_FAILED,
-            network_delegate3.proxy_fallback_net_error());
-  EXPECT_TRUE(network_delegate3.proxy_did_fallback());
 
   // Fallback 3.
-  TestProxyFallbackNetworkDelegate network_delegate4;
   ProxyServer expected_proxy_server4 = info.proxy_server();
   TestCompletionCallback callback4;
   rv = service.ReconsiderProxyAfterError(url, net::LOAD_NORMAL,
                                          net::ERR_PROXY_CONNECTION_FAILED,
                                          &info, callback4.callback(), NULL,
-                                         &network_delegate4, BoundNetLog());
+                                         &network_delegate, BoundNetLog());
   EXPECT_EQ(OK, rv);
   EXPECT_FALSE(info.is_direct());
   EXPECT_EQ("foobar:20", info.proxy_server().ToURI());
-  EXPECT_TRUE(network_delegate4.on_proxy_fallback_called());
-  EXPECT_EQ(expected_proxy_server4, network_delegate4.proxy_server());
-  EXPECT_EQ(net::ERR_PROXY_CONNECTION_FAILED,
-            network_delegate4.proxy_fallback_net_error());
-  EXPECT_TRUE(network_delegate4.proxy_did_fallback());
 
   // Fallback 4 -- Nothing to fall back to!
-  TestProxyFallbackNetworkDelegate network_delegate5;
   ProxyServer expected_proxy_server5 = info.proxy_server();
   TestCompletionCallback callback5;
   rv = service.ReconsiderProxyAfterError(url, net::LOAD_NORMAL,
                                          net::ERR_PROXY_CONNECTION_FAILED,
                                          &info, callback5.callback(), NULL,
-                                         &network_delegate5, BoundNetLog());
+                                         &network_delegate, BoundNetLog());
   EXPECT_EQ(ERR_FAILED, rv);
   EXPECT_TRUE(info.is_empty());
-  EXPECT_TRUE(network_delegate5.on_proxy_fallback_called());
-  EXPECT_EQ(expected_proxy_server5, network_delegate5.proxy_server());
-  EXPECT_EQ(net::ERR_PROXY_CONNECTION_FAILED,
-            network_delegate5.proxy_fallback_net_error());
-  EXPECT_FALSE(network_delegate5.proxy_did_fallback());
 }
 
 TEST_F(ProxyServiceTest, PAC_ConfigSourcePropagates) {
@@ -994,7 +960,11 @@ TEST_F(ProxyServiceTest, ProxyFallback) {
   EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
   // Report back that the second proxy worked.  This will globally mark the
   // first proxy as bad.
-  service.ReportSuccess(info);
+  TestProxyFallbackNetworkDelegate test_delegate;
+  service.ReportSuccess(info, &test_delegate);
+  EXPECT_EQ("foopy1:8080", test_delegate.proxy_server().ToURI());
+  EXPECT_EQ(net::ERR_PROXY_CONNECTION_FAILED,
+            test_delegate.proxy_fallback_net_error());
 
   TestCompletionCallback callback3;
   rv = service.ResolveProxy(
index 36eac6a..3ddfa06 100644 (file)
@@ -102,12 +102,15 @@ void QuicHttpStream::OnStreamReady(int rv) {
 int QuicHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
                                 HttpResponseInfo* response,
                                 const CompletionCallback& callback) {
-  CHECK(stream_);
   CHECK(!request_body_stream_);
   CHECK(!response_info_);
   CHECK(!callback.is_null());
   CHECK(response);
 
+   if (!stream_) {
+    return ERR_CONNECTION_CLOSED;
+  }
+
   QuicPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
   stream_->set_priority(priority);
   // Store the serialized request headers.
@@ -215,6 +218,8 @@ void QuicHttpStream::Close(bool not_reusable) {
     stream_->SetDelegate(NULL);
     stream_->Reset(QUIC_STREAM_CANCELLED);
     stream_ = NULL;
+    response_status_ = was_handshake_confirmed_ ?
+        ERR_CONNECTION_CLOSED : ERR_QUIC_HANDSHAKE_FAILED;
   }
 }
 
@@ -352,6 +357,7 @@ void QuicHttpStream::OnCryptoHandshakeConfirmed() {
 }
 
 void QuicHttpStream::OnSessionClosed(int error) {
+  Close(false);
   session_error_ = error;
   session_.reset();
 }
index 932f566..96ce8d3 100644 (file)
@@ -427,6 +427,44 @@ TEST_P(QuicHttpStreamTest, GetRequestLargeResponse) {
   EXPECT_TRUE(AtEof());
 }
 
+// Regression test for http://crbug.com/409101
+TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendRequest) {
+  SetRequest("GET", "/", DEFAULT_PRIORITY);
+  Initialize();
+
+  request_.method = "GET";
+  request_.url = GURL("http://www.google.com/");
+
+  EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+                                          net_log_, callback_.callback()));
+
+  session_->connection()->CloseConnection(QUIC_NO_ERROR, true);
+
+  EXPECT_EQ(ERR_CONNECTION_CLOSED,
+            stream_->SendRequest(headers_, &response_,
+                                 callback_.callback()));
+}
+
+// Regression test for http://crbug.com/409871
+TEST_P(QuicHttpStreamTest, SessionClosedBeforeReadResponseHeaders) {
+  SetRequest("GET", "/", DEFAULT_PRIORITY);
+  AddWrite(ConstructRequestHeadersPacket(1, kFin));
+  Initialize();
+
+  request_.method = "GET";
+  request_.url = GURL("http://www.google.com/");
+
+  EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+                                          net_log_, callback_.callback()));
+
+  EXPECT_EQ(OK, stream_->SendRequest(headers_, &response_,
+                                     callback_.callback()));
+
+  session_->connection()->CloseConnection(QUIC_NO_ERROR, true);
+
+  EXPECT_NE(OK, stream_->ReadResponseHeaders(callback_.callback()));
+}
+
 TEST_P(QuicHttpStreamTest, SendPostRequest) {
   SetRequest("POST", "/", DEFAULT_PRIORITY);
   AddWrite(ConstructRequestHeadersPacket(1, !kFin));
index 8f5109b..f2d542b 100644 (file)
@@ -452,8 +452,10 @@ void VaapiVideoDecodeAccelerator::OutputPicture(
   TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_);
   DVLOG(4) << "Notifying output picture id " << output_id
            << " for input "<< input_id << " is ready";
+  // TODO(posciak): Use visible size from decoder here instead
+  // (crbug.com/402760).
   if (client_)
-    client_->PictureReady(media::Picture(output_id, input_id));
+    client_->PictureReady(media::Picture(output_id, input_id, gfx::Rect(tfp_picture->size())));
 }
 
 void VaapiVideoDecodeAccelerator::TryOutputSurface() {
index d9472f9..b6c9b4f 100644 (file)
@@ -169,9 +169,14 @@ Emf::Emf() : emf_(NULL), hdc_(NULL), page_count_(0) {
 }
 
 Emf::~Emf() {
+  Close();
+}
+
+void Emf::Close() {
   DCHECK(!hdc_);
   if (emf_)
     DeleteEnhMetaFile(emf_);
+  emf_ = NULL;
 }
 
 bool Emf::InitToFile(const base::FilePath& metafile_path) {
index fa27409..e31e204 100644 (file)
@@ -42,6 +42,9 @@ class PRINTING_EXPORT Emf : public Metafile {
   Emf();
   virtual ~Emf();
 
+  // Closes metafile.
+  void Close();
+
   // Generates a new metafile that will record every GDI command, and will
   // be saved to |metafile_path|.
   virtual bool InitToFile(const base::FilePath& metafile_path);
index b9f0778..744b302 100644 (file)
             ],
           },
           'dependencies': [
-            'android_support_v4_javalib_no_res',
             '../base/base.gyp:base_java',
             '../ui/android/ui_android.gyp:ui_java',
             'remoting_android_resources',
             '../third_party/android_tools/android_tools.gyp:android_support_v7_appcompat_javalib',
             '../third_party/android_tools/android_tools.gyp:android_support_v7_mediarouter_javalib',
+            '../third_party/android_tools/android_tools.gyp:android_support_v13_javalib',
           ],
           'includes': [ '../build/java.gypi' ],
           'conditions' : [
           },
           'includes': [ '../build/java_apk.gypi' ],
         },  # end of target 'remoting_test_apk'
-        {
-          # This jar contains the Android support v4 libary. It does not have
-          # any associated resources.
-          'target_name': 'android_support_v4_javalib_no_res',
-          'type': 'none',
-          'variables': {
-            'jar_path': '../third_party/android_tools/sdk/extras/android/support/v4/android-support-v4.jar',
-          },
-          'includes': ['../build/java_prebuilt.gypi'],
-        }, # end of target 'android_support_v4_javalib_no_res'
       ], # end of 'targets'
       'conditions': [
         ['enable_cast==1', {
index d4c5708..85610cd 100644 (file)
@@ -1330,9 +1330,6 @@ remoting.ClientSession.prototype.onShowOptionsMenu_ = function() {
  * @private
  */
 remoting.ClientSession.prototype.scroll_ = function(dx, dy) {
-  var plugin = this.plugin_.element();
-  var style = plugin.style;
-
   /**
    * Helper function for x- and y-scrolling
    * @param {number|string} curr The current margin, eg. "10px".
@@ -1352,6 +1349,9 @@ remoting.ClientSession.prototype.scroll_ = function(dx, dy) {
     return result + 'px';
   };
 
+  var plugin = this.plugin_.element();
+  var style = this.container_.style;
+
   var stopX = { stop: false };
   var clientArea = this.getClientArea_();
   style.marginLeft = adjustMargin(style.marginLeft, dx, clientArea.width,
@@ -1365,11 +1365,8 @@ remoting.ClientSession.prototype.scroll_ = function(dx, dy) {
 };
 
 remoting.ClientSession.prototype.resetScroll_ = function() {
-  if (this.plugin_) {
-    var plugin = this.plugin_.element();
-    plugin.style.marginTop = '0px';
-    plugin.style.marginLeft = '0px';
-  }
+  this.container_.style.marginTop = '0px';
+  this.container_.style.marginLeft = '0px';
 };
 
 /**
@@ -1532,8 +1529,7 @@ remoting.ClientSession.prototype.updateMouseCursorImage_ =
  * @return {{top: number, left:number}} The top-left corner of the plugin.
  */
 remoting.ClientSession.prototype.getPluginPositionForTesting = function() {
-  var plugin = this.plugin_.element();
-  var style = plugin.style;
+  var style = this.container_.style;
   return {
     top: parseFloat(style.marginTop),
     left: parseFloat(style.marginLeft)
index b2a6877..5989cc2 100644 (file)
@@ -94,7 +94,7 @@ public enum ModelType {
     }
 
     private boolean isNonInvalidationType() {
-      if (this == SESSION && LibraryLoader.isInitialized()) {
+      if ((this == SESSION || this == FAVICON_TRACKING) && LibraryLoader.isInitialized()) {
         return FieldTrialList
             .findFullName("AndroidSessionNotifications")
             .equals("Disabled");
index 8b5168c..6dad046 100644 (file)
@@ -1,4 +1,3 @@
-
 # This directly has manual tests that don't have to run with run-webkit-tests
 crbug.com/359838 http/tests/ManualTests/ [ Skip ]
 
@@ -56,6 +55,8 @@ crbug.com/377013 [ Mac Debug ] fast/repaint/4776765.html [ Pass Failure ]
 
 crbug.com/304953 fast/css/font-face-download-error.html [ Pass Timeout ]
 
+#crbug.com/411175 [ XP ] svg/custom/svg-fonts-without-missing-glyph.xhtml [ Failure Pass ]
+
 # This batch were marked as NeedsRebaseline for crbug.com/133097 but are flaky:
 crbug.com/310679 [ Mac ] compositing/fixed-body-background-positioned.html [ Failure Pass ]
 crbug.com/310679 [ Mac ] compositing/rubberbanding/transform-overhang-e.html [ ImageOnlyFailure Pass ]
@@ -271,6 +272,9 @@ crbug.com/237270 http/tests/images/png-partial-load-no-alpha.html [ Pass Timeout
 
 crbug.com/341435 http/tests/images/image-with-origin-header.html [ Pass Timeout ]
 
+Bug(vollick) compositing/overflow/nested-border-radius-clipping.html [ NeedsRebaseline ]
+Bug(vollick) virtual/gpu/compositedscrolling/overflow/nested-border-radius-clipping.html [ NeedsRebaseline ]
+
 crbug.com/248938 virtual/threaded/animations/3d/transform-origin-vs-functions.html [ Pass Failure ]
 crbug.com/248938 [ Linux Win ] virtual/threaded/animations/animation-border-overflow.html [ Pass Timeout ]
 crbug.com/248938 virtual/threaded/animations/animation-direction-normal.html [ Pass ImageOnlyFailure Timeout ]
@@ -356,9 +360,6 @@ crbug.com/364640 animations/compositor-start-event-timing.html [ Pass Failure ]
 
 crbug.com/320477 [ Debug ] inspector/sources/debugger/debugger-pause-in-internal.html [ Pass Crash ]
 
-crbug.com/403819 compositing/ancestor-painted-layer-should-appear.html [ ImageOnlyFailure ]
-crbug.com/403819 virtual/softwarecompositing/ancestor-painted-layer-should-appear.html [ ImageOnlyFailure ]
-
 # Printing Layout broken in these tests.
 crbug.com/377696 printing/setPrinting.html [ Skip ]
 crbug.com/377696 printing/width-overflow.html [ Skip ]
@@ -1072,6 +1073,546 @@ crbug.com/350853 fast/multicol/widows2.html [ Skip ]
 crbug.com/350853 fast/pagination/auto-height.html [ Skip ]
 crbug.com/350853 fast/pagination/auto-height-with-break.html [ Skip ]
 
+crbug.com/408075 compositing/direct-image-compositing.html [ NeedsRebaseline ]
+crbug.com/408075 compositing/generated-content.html [ NeedsRebaseline ]
+crbug.com/408075 compositing/geometry/root-layer-update.html [ NeedsRebaseline ]
+crbug.com/408075 compositing/geometry/transfrom-origin-on-zero-size-layer.html [ NeedsRebaseline ]
+crbug.com/408075 compositing/gestures/gesture-tapHighlight-pixel-rotated-link.html [ NeedsRebaseline ]
+crbug.com/408075 compositing/repaint/become-overlay-composited-layer.html [ NeedsRebaseline ]
+crbug.com/408075 compositing/sibling-positioning.html [ NeedsRebaseline ]
+crbug.com/408075 css1/basic/containment.html [ NeedsRebaseline ]
+crbug.com/408075 css1/basic/inheritance.html [ NeedsRebaseline ]
+crbug.com/408075 css1/box_properties/acid_test.html [ NeedsRebaseline ]
+crbug.com/408075 css1/color_and_background/background_repeat.html [ NeedsRebaseline ]
+crbug.com/408075 css1/pseudo/anchor.html [ NeedsRebaseline ]
+crbug.com/408075 css1/text_properties/text_decoration.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/20110323/c543-txt-decor-000.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t051103-c21-activ-ln-00-e-i.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t051103-c21-focus-ln-00-e-i.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t051103-c21-hover-ln-00-e-i.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t0511-c21-pseud-link-00-e.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t0511-c21-pseud-link-01-e.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t0511-c21-pseud-link-02-e.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t0511-c21-pseud-link-03-e.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t0602-c13-inh-underlin-00-e.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t060403-c21-pseu-cls-00-e-i.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t060403-c21-pseu-id-00-e-i.html [ NeedsRebaseline ]
+crbug.com/408075 css2.1/t09-c5526c-display-00-e.html [ NeedsRebaseline ]
+crbug.com/408075 css3/flexbox/button.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-16.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-17.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-18a.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-18.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-19.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-20.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-21.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-61.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-62.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-64.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-65.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/html/css3-modsel-66.html [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-16.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-17.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-18a.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-18.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-19.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-20.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-21.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-61.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-62.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-64.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-65.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xhtml/css3-modsel-66.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-16.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-17.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-18a.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-18.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-19.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-20.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-21.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-61.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-62.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-64.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-65.xml [ NeedsRebaseline ]
+crbug.com/408075 css3/selectors3/xml/css3-modsel-66.xml [ NeedsRebaseline ]
+crbug.com/408075 editing/deleting/delete-4083333-fix.html [ NeedsRebaseline ]
+crbug.com/408075 editing/deleting/delete-br-013.html [ NeedsRebaseline ]
+crbug.com/408075 editing/execCommand/5142012-1.html [ NeedsRebaseline ]
+crbug.com/408075 editing/execCommand/5142012-2.html [ NeedsRebaseline ]
+crbug.com/408075 editing/execCommand/5190926.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/4840662.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/4959067.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/5156401-2.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/insert-div-022.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/insert-div-023.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/insert-div-024.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/insert-div-026.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/insert-paragraph-05.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/return-key-with-selection-001.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/return-key-with-selection-002.html [ NeedsRebaseline ]
+crbug.com/408075 editing/inserting/return-key-with-selection-003.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/5071074-2.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/5071074.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/5075944.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/5134759.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/5156401-1.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/5601583-1.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/drop-text-without-selection.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-4038267-fix.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-001.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-002.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-003.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-004.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-005.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-006.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-007.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-008.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-009.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-line-endings-010.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-match-style-002.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-text-013.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-text-014.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-text-016.html [ NeedsRebaseline ]
+crbug.com/408075 editing/pasteboard/paste-text-019.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/4402375.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/6476.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/7152-1.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/7152-2.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/after-line-wrap.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/click-start-of-line.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/contains-boundaries.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/editable-links.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/inline-closest-leaf-child.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/leave-requested-block.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/line-wrap-2.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/previous-line-position.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/range-between-block-and-inline.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/replace-selection-1.html [ NeedsRebaseline ]
+crbug.com/408075 editing/selection/select-text-overflow-ellipsis.html [ NeedsRebaseline ]
+crbug.com/408075 editing/style/block-styles-007.html [ NeedsRebaseline ]
+crbug.com/408075 editing/style/smoosh-styles-003.html [ NeedsRebaseline ]
+crbug.com/408075 editing/style/style-3998892-fix.html [ NeedsRebaseline ]
+crbug.com/408075 fast/backgrounds/background-clip-text.html [ NeedsRebaseline ]
+crbug.com/408075 fast/backgrounds/background-inherit-color-bug.html [ NeedsRebaseline ]
+crbug.com/408075 fast/backgrounds/body-generated-image-propagated-to-root.html [ NeedsRebaseline ]
+crbug.com/408075 fast/backgrounds/repeat/mask-negative-offset-repeat.html [ NeedsRebaseline ]
+crbug.com/408075 fast/backgrounds/repeat/negative-offset-repeat.html [ NeedsRebaseline ]
+crbug.com/408075 fast/backgrounds/repeat/negative-offset-repeat-transformed.html [ NeedsRebaseline ]
+crbug.com/408075 fast/backgrounds/size/zero.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/basic/011.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/basic/018.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/basic/adding-near-anonymous-block.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/basic/text-indent-rtl.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/basic/truncation-rtl.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/basic/white-space-pre-wraps.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/001.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/002.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/centered-float-avoidance-complexity.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/float-in-float-hit-testing.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/float-in-float-painting.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/independent-align-positioning.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/intruding-painted-twice.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/marquee-shrink-to-avoid-floats.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/nopaint-after-layer-destruction2.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/nopaint-after-layer-destruction.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/shrink-to-fit-width.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/table-relayout.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/float/vertical-move-relayout.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/001.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/005.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/010.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/011.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/012.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/015.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/016.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/017.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/019.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/020.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/056.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/059.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/001.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/005.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/010.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/011.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/012.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/015.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/016.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/017.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/019.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/margin-collapse/block-inside-inline/020.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/positioning/001.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/positioning/auto/007.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/positioning/auto/vertical-lr/007.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/positioning/auto/vertical-rl/007.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/positioning/height-change.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/positioning/relayout-on-position-change.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/positioning/vertical-lr/001.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/positioning/vertical-rl/001.html [ NeedsRebaseline ]
+crbug.com/408075 fast/block/positioning/window-height-change.html [ NeedsRebaseline ]
+crbug.com/408075 fast/borders/border-radius-huge-assert.html [ NeedsRebaseline ]
+crbug.com/408075 fast/box-shadow/spread-multiple-inset.html [ NeedsRebaseline ]
+crbug.com/408075 fast/canvas/setWidthResetAfterForcedRender.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css3-text/css3-text-decoration/repaint/repaint-text-decoration-style.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css3-text/css3-text-decoration/text-decoration-style.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-all.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-auto.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under-out-of-flow.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/acid2.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/beforeSelectorOnCodeElement.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/border-radius-outline-offset.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/child-style-can-override-visited-style.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/clip-zooming.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/compare-content-style.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/css1_forward_compatible_parsing.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/css-imports.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/css-properties-position-relative-as-parent-fixed.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/empty-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/error-in-last-decl.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/ex-after-font-variant.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/find-next-layer.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-child-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-letter-capitalized.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-letter-detach.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-letter-float-after-float.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-letter-float.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-letter-hover.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-letter-recalculation.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-letter-visibility.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-line-text-decoration.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-line-text-decoration-inherited-from-parent.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/first-of-type-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/focus-ring-detached.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/focus-ring-multiline.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/focus-ring-outline-color.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/focus-ring-outline-offset.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/focus-ring-outline-width.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/font-face-opentype.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/font-face-synthetic-bold-italic.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/font-face-weight-matching.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/font-shorthand-weight-only.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css-generated-content/001.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css-generated-content/010.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css-generated-content/016.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css-generated-content/after-duplicated-after-split.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css-generated-content/beforeAfter-interdocument.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css-generated-content/before-with-first-letter.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css-generated-content/hover-style-change.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css-generated-content/wbr-with-before-content.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/hover-subselector.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/import-rule-regression-11590.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/invalidation-errors-2.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/invalidation-errors-3.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/invalidation-errors.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/invalid-percentage-property.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/last-child-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/last-of-type-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/layerZOrderCrash.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/line-height.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/line-thickness-underline-strikethrough-overline.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/nth-child-dynamic.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/only-child-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/only-of-type-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/resize-corner-tracking.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/resize-corner-tracking-transformed.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/resize-corner-tracking-transformed-iframe.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/rtl-ordering.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/text-overflow-ellipsis.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/text-overflow-ellipsis-strict.html [ NeedsRebaseline ]
+crbug.com/408075 fast/css/universal-hover-quirk.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dom/34176.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dom/anchor-text.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dom/children-nodes.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dom/clone-node-dynamic-style.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dom/Element/class-attribute-whitespace.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dom/HTMLHeadElement/head-link-style-href-check.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dom/HTMLLinkElement/pending-stylesheet-count.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/anonymous-block-orphaned-lines.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/containing-block-change.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/create-renderer-for-whitespace-only-text.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/float-in-trailing-whitespace-after-last-line-break.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/float-withdrawal.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/insert-before-table-part-in-continuation.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/layer-hit-test-crash.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/outerHTML-doc.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/outerHTML-img.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/selection-highlight-adjust.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/staticY-marking-parents-regression.html [ NeedsRebaseline ]
+crbug.com/408075 fast/dynamic/view-overflow.html [ NeedsRebaseline ]
+crbug.com/408075 fast/events/reveal-link-when-focused.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/button-cannot-be-nested.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/button-inner-block-reuse.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/button-text-transform.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/button-white-space.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/control-clip-overflow.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/datalist/input-appearance-range-with-padding-with-datalist.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/fieldset-legend-padding-unclipped-fieldset-border.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/floating-textfield-relayout.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/form-hides-table.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/input-readonly-autoscroll.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/listbox-scrollbar-incremental-load.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/menulist-clip.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/menulist-option-wrap.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/plaintext-mode-2.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/range/slider-thumb-shared-style.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/search-rtl.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/select-change-listbox-size.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/select-disabled-appearance.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/select-display-none-style-resolve.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/select-item-background-clip.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/select-writing-direction-natural.html [ NeedsRebaseline ]
+crbug.com/408075 fast/forms/visual-hebrew-text-field.html [ NeedsRebaseline ]
+crbug.com/408075 fast/frames/frameset-style-recalc.html [ NeedsRebaseline ]
+crbug.com/408075 fast/html/marquee-scroll.html [ NeedsRebaseline ]
+crbug.com/408075 fast/images/animated-gif-with-offsets.html [ NeedsRebaseline ]
+crbug.com/408075 fast/images/image-map-anchor-children.html [ NeedsRebaseline ]
+crbug.com/408075 fast/images/imagemap-focus-ring-outline-color-not-inherited-from-map.html [ NeedsRebaseline ]
+crbug.com/408075 fast/inline-block/14498-positionForCoordinates.html [ NeedsRebaseline ]
+crbug.com/408075 [ Mac Win Linux ] fast/inline-block/overflow-clip.html [ NeedsRebaseline ]
+crbug.com/408075 fast/inline/br-text-decoration.html [ NeedsRebaseline ]
+crbug.com/408075 fast/inline/drawStyledEmptyInlines.html [ NeedsRebaseline ]
+crbug.com/408075 fast/inline/drawStyledEmptyInlinesWithWS.html [ NeedsRebaseline ]
+crbug.com/408075 fast/inline/inline-box-background.html [ NeedsRebaseline ]
+crbug.com/408075 fast/inline/inline-box-background-long-image.html [ NeedsRebaseline ]
+crbug.com/408075 fast/inline/inline-box-background-repeat-x.html [ NeedsRebaseline ]
+crbug.com/408075 fast/inline/inline-box-background-repeat-y.html [ NeedsRebaseline ]
+crbug.com/408075 fast/inline/inline-focus-ring.html [ NeedsRebaseline ]
+crbug.com/408075 fast/invalid/021.html [ NeedsRebaseline ]
+crbug.com/408075 fast/invalid/missing-address-end-tag.html [ NeedsRebaseline ]
+crbug.com/408075 fast/invalid/missing-dl-end-tag.html [ NeedsRebaseline ]
+crbug.com/408075 fast/invalid/missing-dt-end-tag.html [ NeedsRebaseline ]
+crbug.com/408075 fast/invalid/missing-font-end-tag.html [ NeedsRebaseline ]
+crbug.com/408075 fast/layers/inline-dirty-z-order-lists.html [ NeedsRebaseline ]
+crbug.com/408075 fast/layers/normal-flow-hit-test.html [ NeedsRebaseline ]
+crbug.com/408075 fast/layers/opacity-outline.html [ NeedsRebaseline ]
+crbug.com/408075 fast/layers/opacity-transforms.html [ NeedsRebaseline ]
+crbug.com/408075 fast/layers/scroll-rect-to-visible.html [ NeedsRebaseline ]
+crbug.com/408075 fast/layers/video-layer.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/002.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/002-vertical.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/003.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/003-vertical.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/006.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/006-vertical.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/list-style-none-crash.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/marker-before-empty-inline.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/marker-image-error.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/markers-in-selection.html [ NeedsRebaseline ]
+crbug.com/408075 fast/lists/scrolled-marker-paint.html [ NeedsRebaseline ]
+crbug.com/408075 fast/multicol/float-multicol.html [ NeedsRebaseline ]
+crbug.com/408075 fast/multicol/vertical-lr/float-multicol.html [ NeedsRebaseline ]
+crbug.com/408075 fast/multicol/vertical-rl/float-multicol.html [ NeedsRebaseline ]
+crbug.com/408075 fast/overflow/float-in-relpositioned.html [ NeedsRebaseline ]
+crbug.com/408075 fast/overflow/hit-test-overflow-controls.html [ NeedsRebaseline ]
+crbug.com/408075 fast/overflow/image-selection-highlight.html [ NeedsRebaseline ]
+crbug.com/408075 fast/overflow/line-clamp.html [ NeedsRebaseline ]
+crbug.com/408075 fast/overflow/overflow-rtl-inline-scrollbar.html [ NeedsRebaseline ]
+crbug.com/408075 fast/overflow/position-fixed-transform-clipping.html [ NeedsRebaseline ]
+crbug.com/408075 fast/overflow/scrollbar-position-update.html [ NeedsRebaseline ]
+crbug.com/408075 fast/parser/broken-comments-vs-parsing-mode.html [ NeedsRebaseline ]
+crbug.com/408075 fast/parser/nofoo-tags-inside-paragraph.html [ NeedsRebaseline ]
+crbug.com/408075 fast/reflections/inline-crash.html [ NeedsRebaseline ]
+crbug.com/408075 fast/reflections/reflection-overflow-hidden.html [ NeedsRebaseline ]
+crbug.com/408075 fast/repaint/flexible-box-overflow-horizontal.html [ NeedsRebaseline ]
+crbug.com/408075 fast/repaint/flexible-box-overflow.html [ NeedsRebaseline ]
+crbug.com/408075 fast/repaint/focus-layers.html [ NeedsRebaseline ]
+crbug.com/408075 fast/repaint/layer-outline-horizontal.html [ NeedsRebaseline ]
+crbug.com/408075 fast/repaint/layer-outline.html [ NeedsRebaseline ]
+crbug.com/408075 fast/repaint/list-marker.html [ NeedsRebaseline ]
+crbug.com/408075 fast/repaint/shadow-multiple.html [ NeedsRebaseline ]
+crbug.com/408075 fast/repaint/text-shadow-horizontal.html [ NeedsRebaseline ]
+crbug.com/408075 fast/repaint/text-shadow.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/absolute-position-percentage-height.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/applet-disabled-positioned.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/applet-rendering-java-disabled.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/image-resize-width.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/image-solid-color-with-alpha.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/inline-box-wrapper-handover.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/max-width-percent.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/percent-height-in-anonymous-block-in-table.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/selection-rect-in-table-cell.html [ NeedsRebaseline ]
+crbug.com/408075 fast/replaced/selection-rect-transform.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/016.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/017.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/018.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/019.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/020.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/021.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/061.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/062.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/064.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/065.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/066.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/166.html [ NeedsRebaseline ]
+crbug.com/408075 fast/selectors/visited-descendant.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/100-percent-cell-width.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/absolute-table-at-bottom.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/add-before-anonymous-child.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/border-collapsing/003.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/border-collapsing/003-vertical.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/border-collapsing/004.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/border-collapsing/004-vertical.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/border-collapsing/border-collapsing-head-foot.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/border-collapsing/border-collapsing-head-foot-vertical.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/border-collapsing/rtl-border-collapsing.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/border-collapsing/rtl-border-collapsing-vertical.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/cell-absolute-child.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/click-near-anonymous-table.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/edge-offsets.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/fixed-table-non-cell-in-row.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/form-with-table-style.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/generated-caption.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/insert-before-anonymous-ancestors.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/insert-cell-before-form.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/insert-row-before-form.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/prepend-in-anonymous-table.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/row-height-recalc.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/rtl-cell-display-none-assert.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/stale-grid-crash.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/text-field-baseline.html [ NeedsRebaseline ]
+crbug.com/408075 fast/table/unused-percent-heights.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/atsui-partial-selection.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/atsui-small-caps-punctuation-size.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/atsui-spacing-features.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text-autosizing/hackernews-comments.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/basic/008.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/basic/015.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/break-word.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/capitalize-boundaries.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/capitalize-empty-generated-string.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/capitalize-preserve-nbsp.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/complex-text-opacity.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/decorations-transformed.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/decorations-with-text-combine.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/delete-hard-break-character.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/fallback-for-custom-font.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/fallback-traits-fixup.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/font-initial.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/fractional-word-and-letter-spacing-with-kerning.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/in-rendered-text-rtl.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/001.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/003.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/bidi-AN-after-empty-run.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/bidi-LDB-2-CSS.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/bidi-LDB-2-formatting-characters.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/bidi-LDB-2-HTML.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/bidi-neutral-directionality-paragraph-start.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/danda-space.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/khmer-selection.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/rtl-caret.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/rtl-white-space-pre-wrap.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/international/thai-baht-space.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/justified-selection.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/line-breaks.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/midword-break-after-breakable-char.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/midword-break-hang.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/monospace-width-cache.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/reset-emptyRun.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/selection-hard-linebreak.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/stroking-decorations.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/trailing-white-space-2.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/trailing-white-space.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/wbr.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/wbr-in-pre-crash.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/whitespace/020.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/whitespace/024.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/whitespace/pre-wrap-last-char.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/whitespace/pre-wrap-overflow-selection.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/whitespace/pre-wrap-spaces-after-newline.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/whitespace/span-in-word-space-causes-overflow.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/wide-zero-width-space.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/word-break-run-rounding.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/word-break-soft-hyphen.html [ NeedsRebaseline ]
+crbug.com/408075 fast/text/word-space.html [ NeedsRebaseline ]
+crbug.com/408075 fast/transforms/transformed-caret.html [ NeedsRebaseline ]
+crbug.com/408075 fast/transforms/transform-positioned-ancestor.html [ NeedsRebaseline ]
+crbug.com/408075 fast/transforms/transforms-with-zoom.html [ NeedsRebaseline ]
+crbug.com/408075 fast/writing-mode/english-lr-text.html [ NeedsRebaseline ]
+crbug.com/408075 http/tests/misc/acid2.html [ NeedsRebaseline ]
+crbug.com/408075 http/tests/misc/iframe404.html [ NeedsRebaseline ]
+crbug.com/408075 http/tests/multipart/invalid-image-data.html [ NeedsRebaseline ]
+crbug.com/408075 http/tests/uri/css-href.php [ NeedsRebaseline ]
+crbug.com/408075 ietestcenter/css3/text/textshadow-002.htm [ NeedsRebaseline ]
+crbug.com/408075 svg/custom/dominant-baseline-hanging.svg [ NeedsRebaseline ]
+crbug.com/408075 svg/custom/foreign-object-skew.svg [ NeedsManualRebaseline ]
+crbug.com/408075 svg/custom/rootmost-svg-xy-attrs.xhtml [ NeedsRebaseline ]
+crbug.com/408075 svg/custom/svg-fonts-without-missing-glyph.xhtml [ NeedsManualRebaseline ]
+crbug.com/408075 svg/wicd/test-rightsizing-a.xhtml [ NeedsRebaseline ]
+crbug.com/408075 svg/wicd/test-scalable-background-image1.xhtml [ NeedsRebaseline ]
+crbug.com/408075 svg/wicd/test-scalable-background-image2.xhtml [ NeedsRebaseline ]
+crbug.com/408075 svg/zoom/page/zoom-foreignObject.svg [ NeedsRebaseline ]
+crbug.com/408075 svg/zoom/text/zoom-foreignObject.svg [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug10633.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug109043.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug126742.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug128229.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug17130-1.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug17130-2.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug17138.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug18664.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug20579.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug20804.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug22019.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug23235.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug2479-1.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug2479-3.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug2479-4.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug275625.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug2962.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug3309-1.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug4849-2.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug51140.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug5538.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug59354.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug73321.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug7342.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug88035-1.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug88035-2.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug8950.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/bugs/bug92868.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/collapsing_borders/bug41262-3.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/core/bloomberg.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/bugs/bug1010.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/bugs/bug1055-2.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/bugs/bug2479-5.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_border-table-cell.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_border-table-column-group.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_border-table-column.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_border-table.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_border-table-quirks.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_border-table-row-group.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_border-table-row.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_fixed-bg.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_layers-hide.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_position-table-cell.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_position-table-column-group.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_position-table-column.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_position-table-row-group.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla_expected_failures/marvin/backgr_position-table-row.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/marvin/backgr_index.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/marvin/backgr_layers-opacity.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/marvin/backgr_position-table.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/marvin/backgr_simple-table-cell.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/marvin/backgr_simple-table-column-group.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/marvin/backgr_simple-table-column.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/marvin/backgr_simple-table.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/marvin/backgr_simple-table-row-group.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/marvin/backgr_simple-table-row.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/other/wa_table_thtd_rowspan.html [ NeedsRebaseline ]
+crbug.com/408075 tables/mozilla/other/wa_table_tr_align.html [ NeedsRebaseline ]
+crbug.com/408075 transforms/2d/hindi-rotated.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/antialiasedtext/fast/text/decorations-transformed.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/antialiasedtext/fast/text/decorations-with-text-combine.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/antialiasedtext/fast/text/international/rtl-white-space-pre-wrap.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/antialiasedtext/fast/text/line-breaks.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/antialiasedtext/fast/text/stroking-decorations.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/antialiasedtext/fast/text/trailing-white-space-2.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/antialiasedtext/fast/text/trailing-white-space.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/deferred/fast/images/animated-gif-with-offsets.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/deferred/fast/images/image-map-anchor-children.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/deferred/fast/images/imagemap-focus-ring-outline-color-not-inherited-from-map.html [ NeedsRebaseline ]
+crbug.com/408075 virtual/gpu/fast/canvas/setWidthResetAfterForcedRender.html [ NeedsRebaseline ]
+
 crbug.com/374569 [ Win ] http/tests/navigation/beacon-cross-origin.html [ Pass Failure Timeout ]
 crbug.com/374572 svg/filters/feImage-target-reappend-to-document.svg [ Pass Failure ]
 crbug.com/374572 svg/dynamic-updates/SVGImageElement-svgdom-preserveAspectRatio-prop.html [ Pass ImageOnlyFailure ]
@@ -1134,7 +1675,7 @@ crbug.com/374936 [ Mac Debug ] svg/dynamic-updates/SVGImageElement-svgdom-width-
 crbug.com/313438 svg/custom/relative-sized-use-on-symbol.xhtml [ NeedsManualRebaseline ]
 crbug.com/313438 svg/custom/relative-sized-use-without-attributes-on-symbol.xhtml [ NeedsManualRebaseline ]
 
-crbug.com/390488 [ SnowLeopard Debug ] svg/custom/foreign-object-skew.svg [ ImageOnlyFailure ]
+#crbug.com/390488 [ SnowLeopard Debug ] svg/custom/foreign-object-skew.svg [ ImageOnlyFailure ]
 
 crbug.com/375565 [ Mac ] fast/repaint/caret-with-transformation.html [ Pass Failure ]
 
@@ -1224,12 +1765,1171 @@ crbug.com/394762 inspector/timeline/timeline-flame-chart-automatically-size-wind
 crbug.com/394762 virtual/deferred/inspector/timeline/timeline-flame-chart-automatically-size-window.html [ Skip ]
 crbug.com/394762 virtual/implsidepainting/inspector/timeline/timeline-flame-chart-automatically-size-window.html [ Skip ]
 
+crbug.com/408031 svg/batik/filters/feTile.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/batik/filters/filterRegions.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/batik/text/smallFonts.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/batik/text/textFeatures.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/custom/text-filter.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/dynamic-updates/SVGFEImageElement-dom-preserveAspectRatio-attr.html [ NeedsRebaseline ]
+crbug.com/408031 svg/dynamic-updates/SVGFEImageElement-svgdom-preserveAspectRatio-prop.html [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/feComposite.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/feGaussianBlur.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/feOffset.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/feTile.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/filter-on-tspan.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/filter-placement-issue.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/filter-rounding-issues.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/filterRes.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/filterRes2.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/feImage-subregions.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/feImage-subregions-preseveAspectRatio-none.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/feImage-subregions-preseveAspectRatio-none-with-viewBox.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/subRegion-two-effects.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/parent-children-with-same-filter.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/filters/subRegion-one-effect.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/repaint/filter-repaint.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/repaint/paintorder-filtered.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/W3C-SVG-1.1/filters-color-01-b.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/W3C-SVG-1.1/filters-gauss-01-b.svg [ NeedsRebaseline ]
+crbug.com/408031 svg/W3C-SVG-1.1/filters-morph-01-f.svg [ NeedsRebaseline ]
+
 # Assertion failures seen only on Slow Leopard.
 crbug.com/374961 [ SnowLeopard Debug ] inspector/sources/debugger/frameworks-skip-step-in.html [ Crash ]
 crbug.com/374961 [ SnowLeopard Debug ] inspector/sources/debugger/frameworks-steppings.html [ Crash ]
 crbug.com/374961 [ SnowLeopard Debug ] inspector/sources/debugger/frameworks-with-async-callstack.html [ Crash ]
 crbug.com/374961 [ SnowLeopard Debug ] inspector/sources/debugger/async-callstack-get-as-string.html [ Crash ]
 
+crbug.com/395425 [ Win7 ] css1/basic/class_as_selector.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/basic/comments.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/basic/containment.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/basic/contextual_selectors.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/basic/grouping.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/basic/id_as_selector.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/basic/inheritance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/acid_test.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_bottom.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_bottom_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_bottom_width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_bottom_width_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_color.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_color_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_left.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_left_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_left_width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_left_width_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_right.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_right_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_right_width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_right_width_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_style.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_style_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_top.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_top_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_top_width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_top_width_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/border_width_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/clear.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/clear_float.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/float.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/float_elements_in_series.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/float_margin.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin_bottom.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin_bottom_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin_left.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin_left_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin_right.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin_right_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin_top.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/margin_top_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding_bottom.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding_bottom_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding_left.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding_left_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding_right.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding_right_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding_top.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/padding_top_inline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/box_properties/width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/cascade/cascade_order.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/cascade/important.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/classification/display.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/classification/list_style.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/classification/list_style_image.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/classification/list_style_position.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/classification/list_style_type.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/classification/white_space.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/color_and_background/background.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/color_and_background/background_attachment.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/color_and_background/background_color.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/color_and_background/background_image.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/color_and_background/background_position.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/color_and_background/background_repeat.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/color_and_background/color.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/conformance/forward_compatible_parsing.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/font_properties/font.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/font_properties/font_family.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/font_properties/font_size.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/font_properties/font_style.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/font_properties/font_variant.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/font_properties/font_weight.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/formatting_model/canvas.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/formatting_model/floating_elements.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/formatting_model/height_of_lines.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/formatting_model/inline_elements.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/formatting_model/replaced_elements.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/formatting_model/vertical_formatting.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/pseudo/anchor.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/pseudo/firstletter.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/pseudo/firstline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/pseudo/multiple_pseudo_elements.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/pseudo/pseudo_elements_in_selectors.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/text_properties/letter_spacing.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/text_properties/line_height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/text_properties/text_align.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/text_properties/text_decoration.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/text_properties/text_indent.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/text_properties/text_transform.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/text_properties/vertical_align.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/text_properties/word_spacing.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/units/color_units.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/units/length_units.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/units/percentage_units.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/units/urls.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/20110323/replaced-elements-001.htm [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/20110323/table-height-algorithm-023.htm [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/20110323/table-height-algorithm-024.htm [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t050803-c14-classes-00-e.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t0509-c15-ids-01-e.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t051201-c23-first-line-00-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t051202-c26-psudo-nest-00-c.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t0602-c13-inh-underlin-00-e.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t09-c5526c-display-00-e.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t0905-c5525-fltwidth-00-c-g.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1503-c522-font-family-00-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1505-c524-font-var-00-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1507-c526-font-sz-00-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1508-c527-font-00-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1508-c527-font-04-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1508-c527-font-05-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1508-c527-font-06-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1508-c527-font-07-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1508-c527-font-09-b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css2.1/t1508-c527-font-10-c.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/filters/effect-reference-zoom-hw.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/filters/effect-reference-zoom.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/flexbox/button.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/html/css3-modsel-161.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/html/css3-modsel-18b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/html/css3-modsel-19b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/html/css3-modsel-23.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/html/css3-modsel-24.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/html/css3-modsel-64.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/html/css3-modsel-68.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/html/css3-modsel-69.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xhtml/css3-modsel-161.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xhtml/css3-modsel-18b.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xhtml/css3-modsel-19b.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xhtml/css3-modsel-23.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xhtml/css3-modsel-24.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xhtml/css3-modsel-64.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xhtml/css3-modsel-68.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xhtml/css3-modsel-69.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xml/css3-modsel-161.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xml/css3-modsel-18b.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xml/css3-modsel-19b.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xml/css3-modsel-23.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xml/css3-modsel-24.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xml/css3-modsel-64.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xml/css3-modsel-68.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/selectors3/xml/css3-modsel-69.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/caret/caret-position.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/deleting/merge-whitespace-pre.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/execCommand/format-block-with-trailing-br.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/input/caret-at-the-edge-of-input.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/input/reveal-caret-of-multiline-input.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/inserting/4278698.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/inserting/4960120-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/inserting/before-after-input-element.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/inserting/paragraph-separator-03.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/inserting/typing-at-end-of-line.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/pasteboard/4641033.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/pasteboard/4806874.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/pasteboard/4944770-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/pasteboard/4944770-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/pasteboard/drop-text-without-selection.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/pasteboard/innerText-inline-table.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/pasteboard/input-field-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/pasteboard/pasting-tabs.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/3690703-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/3690703.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/3690719.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/4397952.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/4975120.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/5240265.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/caret-before-select.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/designmode-no-caret.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/doubleclick-crash.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/drag-select-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/replaced-boundaries-3.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/select-box.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/select-element-paragraph-boundary.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/selection-3748164-fix.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/selection-button-text.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/triple-click-in-pre.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/style/font-family-with-space.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/backgrounds/quirks-mode-line-box-backgrounds.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/basic/011.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/basic/014.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/basic/015.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/basic/minheight.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/float/float-avoidance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/float/shrink-to-avoid-float-complexity.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/margin-collapse/103.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/positioning/047.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/positioning/inline-block-relposition.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/borders/border-fit.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/box-sizing/percentage-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css-generated-content/011.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css-generated-content/014.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/beforeSelectorOnCodeElement.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/continuationCrash.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/css-properties-position-relative-as-parent-fixed.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/empty-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/first-child-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/first-of-type-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/font-size-negative.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/h1-in-section-elements.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/hover-subselector.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/imageTileOpacity.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/invalidation-errors-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/invalidation-errors.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/last-child-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/last-of-type-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/line-height-determined-by-primary-font.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/line-height-font-order.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/line-height-negative.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/line-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/margin-top-bottom-dynamic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/only-child-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/only-of-type-pseudo-class.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/outline-auto-empty-rects.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/rem-dynamic-scaling.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/resize-corner-tracking.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/rtl-ordering.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/text-overflow-input.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/universal-hover-quirk.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/word-space-extra.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/dom/HTMLInputElement/input-image-alt-text.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/dom/HTMLTableColElement/resize-table-using-col-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/dom/HTMLTextAreaElement/reset-textarea.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/dom/row-inner-text.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/dynamic/008.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/encoding/utf-16-big-endian.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/encoding/utf-16-little-endian.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/events/autoscroll.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/events/context-no-deselect.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/files/file-in-input-display.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/flexbox/023.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/flexbox/024.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/001.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/003.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/004.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/HTMLOptionElement_label01.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/HTMLOptionElement_label02.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/HTMLOptionElement_label03.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/HTMLOptionElement_label04.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/HTMLOptionElement_label05.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/HTMLOptionElement_label06.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/HTMLOptionElement_label07.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/basic-buttons.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/basic-inputs.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/basic-selects.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/basic-textareas-quirks.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/basic-textareas.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/blankbuttons.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button-align.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button-cannot-be-nested.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button-default-title.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button-positioned.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button-sizes.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button-style-color.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button-table-styles.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button-text-transform.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button-white-space.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/button/button-reset-focus-by-mouse-then-keydown.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/control-clip-overflow.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/control-clip.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/control-restrict-line-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/disabled-select-change-index.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/encoding-test.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/fieldset-align.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/file/file-input-direction.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/file/file-input-disabled.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/file/input-file-re-render.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/floating-textfield-relayout.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/form-element-geometry.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/formmove3.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-align.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-bkcolor.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-default-bkcolor.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-disabled.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-focus.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-preventDefault.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-readonly.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-selection.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-visibility.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-appearance-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-baseline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-button-sizes.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-disabled-color.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-double-click-selection-gap-bug.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-field-text-truncated.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-first-letter.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-placeholder-visibility-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-placeholder-visibility-3.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-readonly-autoscroll.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-readonly-dimmed.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-readonly-empty.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-spaces.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-tab-shows-caret.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-table.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-text-click-inside.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-text-click-outside.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-text-double-click.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-text-drag-down.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-text-option-delete.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-text-scroll-left-on-blur.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-text-self-emptying-click.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-text-word-wrap.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-type-text-min-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-value.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/input-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/listbox-bidi-align.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/listbox-hit-test-zoomed.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/listbox-scrollbar-incremental-load.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/listbox-width-change.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/menulist-deselect-update.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/menulist-narrow-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/menulist-no-overflow.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/menulist-option-wrap.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/menulist-restrict-line-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/menulist-separator-painting.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/menulist-style-color.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/menulist-width-change.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/minWidthPercent.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/negativeLineHeight.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/number/number-appearance-datalist.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/number/number-appearance-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/number/number-appearance-spinbutton-layer.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/option-script.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/option-strip-whitespace.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/option-text-clip.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/placeholder-appearance-textarea.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/placeholder-position.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/placeholder-pseudo-style.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/plaintext-mode-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/search-cancel-button-style-sharing.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/search-display-none-cancel-button.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/search-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/search-vertical-alignment.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/search/search-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/searchfield-heights.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-align.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-background-none.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-baseline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-block-background.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-change-listbox-size.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-change-listbox-to-popup.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-change-popup-to-listbox.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-dirty-parent-pref-widths.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-disabled-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-empty-option-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-initial-position.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-item-background-clip.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-list-box-with-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-listbox-multiple-no-focusring.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-multiple-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-overflow-scroll-inherited.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-overflow-scroll.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-selected.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-size.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-style.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-visual-hebrew.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select-writing-direction-natural.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select/listbox-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select/listbox-with-display-none-option.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select/menulist-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/select/optgroup-rendering.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/selectlist-minsize.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/stuff-on-my-optgroup.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/submit/submit-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/submit/submit-focus-by-mouse-then-keydown.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/tabbing-input-iframe.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/targeted-frame-submission.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/text-style-color.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/text/text-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/text/text-appearance-datalist.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textAreaLineHeight.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea-align.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea-placeholder-pseudo-style.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea-placeholder-visibility-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea-placeholder-visibility-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea-scroll-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea-scrollbar.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea-scrolled-type.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea-setinnerhtml.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textarea/textarea-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textfield-focus-ring.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/visual-hebrew-text-field.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/frames/iframe-scrolling-attribute.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/hidpi/resize-corner-hidpi.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/hidpi/video-controls-in-hidpi.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/html/details-no-summary4.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/html/details-open-javascript.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/html/details-open2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/html/details-open4.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/html/details-replace-summary-child.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/html/details-replace-text.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/html/keygen.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/html/listing.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/inline/nested-top-alignment.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/inline/vertical-align-text-bottom.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/invalid/014.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/invalid/019.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/invalid/junk-data.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/invalid/missing-end-tag.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/layers/video-layer.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/lists/003-vertical.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/lists/003.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/lists/dynamic-marker-crash.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/loader/text-document-wrapping.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/multicol/overflow-across-columns-percent-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/multicol/overflow-across-columns.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/multicol/overflow-unsplittable.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/multicol/positive-leading.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/overflow/003.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/overflow/005.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/overflow/007.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/overflow/clip-rects-fixed-ancestor.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/overflow/infiniteRecursion.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/overflow/overflow-auto-table.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/overflow/overflow-x-y.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/overflow/scroll-nested-positioned-layer-in-overflow.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/overflow/scrollRevealButton.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/parser/001.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/parser/document-write-option.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/parser/entity-comment-in-textarea.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/parser/open-comment-in-textarea.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/parser/xhtml-alternate-entities.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/repaint/renderer-destruction-by-invalidateSelection-crash.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/replaced/replaced-breaking-mixture.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/replaced/replaced-breaking.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/replaced/three-selects-break.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/replaced/width100percent-button.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/replaced/width100percent-menulist.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/replaced/width100percent-searchfield.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/replaced/width100percent-textarea.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/replaced/width100percent-textfield.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/nested-ruby.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-beforeafter.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-empty-rt.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-inline-table.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-length.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-run-break.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-runs-spans.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-runs.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-simple-rp.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-simple.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/ruby-trailing.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/rubyDOM-insert-rt.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/rubyDOM-insert-text1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/rubyDOM-insert-text2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/rubyDOM-insert-text3.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/rubyDOM-remove-rt1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/rubyDOM-remove-rt2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/rubyDOM-remove-text1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/ruby/rubyDOM-remove-text2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/selectors/018b.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/selectors/064.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/spatial-navigation/snav-multiple-select-focusring.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/003.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/018.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/022.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/append-cells2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/border-collapsing/004-vertical.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/border-collapsing/004.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/colspanMinWidth-vertical.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/colspanMinWidth.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/frame-and-rules.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/invisible-cell-background.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/prepend-in-anonymous-table.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/remove-td-display-none.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/rowindex.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/spanOverlapRepaint.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/text-field-baseline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/hackernews-comments.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/css-table-lots-of-text-many-cells.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/css-table-single-cell-lots-of-text.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/fixed-table-lots-of-text-many-cells.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/fixed-table-single-cell-lots-of-text.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/lots-of-text-many-cells.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/narrow-percentage-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/narrow-specified-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/nested-table-wrapping.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/nested-tables.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/single-cell-lots-of-text.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/single-percent-width-cell-lots-of-text.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/table-cell-inflation.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/table-for-layout.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/wide-percentage-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text-autosizing/tables/wide-specified-width.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/atsui-multiple-renderers.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/basic/001.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/basic/011.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/basic/013.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/basic/generic-family-changes.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/basic/generic-family-reset.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/break-word.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/capitalize-boundaries.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/drawBidiText.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/emphasis-complex.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/emphasis-vertical.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/emphasis.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/font-stretch.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/font-weight.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/international/bidi-listbox-atsui.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/international/bidi-listbox.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/international/bidi-menulist.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/international/hindi-spacing.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/international/khmer-selection.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/international/pop-up-button-text-alignment-and-direction.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/international/unicode-bidi-plaintext-in-textarea.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/international/unicode-bidi-plaintext.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/international/wrap-CJK-001.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/justify-ideograph-complex.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/justify-ideograph-simple.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/justify-ideograph-vertical.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/large-text-composed-char.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/selection-hard-linebreak.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/selection-rect-rounding.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/sub-pixel/text-scaling-pixel.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/textIteratorNilRenderer.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/updateNewFont.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/wbr-pre.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/wbr-styled.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/001.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/019.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/023.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/024.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/029.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/030.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/pre-wrap-overflow-selection.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/pre-wrap-spaces-after-newline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/word-break.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/transforms/bounding-rect-zoom.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/transforms/transformed-focused-text-input.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/writing-mode/Kusa-Makura-background-canvas.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/writing-mode/text-orientation-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/writing-mode/vertical-baseline-alignment.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/xsl/xslt-extra-content-at-end.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fonts/monospace.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] http/tests/filesystem/input-display.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] http/tests/misc/object-embedding-svg-delayed-size-negotiation-2.htm [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/audio-controls-rendering.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/audio-repaint.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/controls-after-reload.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/controls-strict.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/controls-styling-strict.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/controls-styling.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/controls-without-preload.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/media-controls-clone.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/media-document-audio-repaint.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/track/track-cue-rendering-horizontal.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/track/track-cue-rendering-vertical.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/video-controls-rendering.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/video-display-toggle.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/video-empty-source.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/video-no-audio.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] plugins/mouse-click-plugin-clears-selection.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] scrollbars/custom-scrollbar-with-incomplete-style.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] scrollbars/listbox-scrollbar-combinations.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] scrollbars/overflow-scrollbar-combinations.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/g-dirLTR-ubNone.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/g-dirLTR-ubOverride.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/g-dirRTL-ubNone.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/g-dirRTL-ubOverride.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-dirLTR-anchorEnd.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-dirLTR-anchorMiddle.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-dirLTR-anchorStart.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-dirNone-anchorEnd.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-dirNone-anchorMiddle.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-dirNone-anchorStart.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-dirRTL-anchorEnd.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-dirRTL-anchorMiddle.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-dirRTL-anchorStart.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorEnd.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorMiddle.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-inherited-dirLTR-anchorStart.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorEnd.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorMiddle.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-inherited-dirRTL-anchorStart.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-anchor-no-markup.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-dirLTR-ubNone.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-dirLTR-ubOverride.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-dirRTL-ubNone.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/text-dirRTL-ubOverride.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirLTR-ubEmbed-in-rtl-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirLTR-ubNone-in-rtl-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirLTR-ubOverride-in-default-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirLTR-ubOverride-in-ltr-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirLTR-ubOverride-in-rtl-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirNone-ubOverride-in-default-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirNone-ubOverride-in-ltr-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirNone-ubOverride-in-rtl-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-default-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirRTL-ubEmbed-in-ltr-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirRTL-ubNone-in-default-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirRTL-ubNone-in-ltr-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirRTL-ubOverride-in-default-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirRTL-ubOverride-in-ltr-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-dirRTL-ubOverride-in-rtl-context.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-direction-ltr.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-I18N/tspan-direction-rtl.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/coords-dom-03-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/coords-units-03-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/filters-image-05-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/interact-pointer-03-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/linking-uri-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/painting-marker-05-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/painting-marker-06-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/styling-pres-02-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/text-tspan-02-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/types-dom-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/types-dom-02-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/types-dom-04-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/types-dom-05-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1-SE/types-dom-07-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-08-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-22-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-23-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-25-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-27-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-32-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-41-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-46-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-60-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-61-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-62-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-63-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-64-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-65-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-66-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-67-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-68-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-69-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-70-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-78-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/animate-elem-84-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/color-prof-01-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/coords-units-03-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/coords-viewattr-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/coords-viewattr-02-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/coords-viewattr-03-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/extend-namespace-01-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/filters-diffuse-01-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/filters-displace-01-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/filters-image-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/filters-light-01-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/filters-light-04-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/filters-specular-01-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/filters-tile-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/filters-turb-01-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/fonts-elem-05-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/fonts-elem-06-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/fonts-kern-01-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/linking-a-04-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/linking-a-05-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/linking-a-07-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/linking-uri-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/linking-uri-02-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/linking-uri-03-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/masking-mask-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/masking-path-05-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/metadata-example-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/painting-marker-01-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/painting-marker-02-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/paths-data-01-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/paths-data-02-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/paths-data-03-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/pservers-grad-09-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/pservers-grad-10-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/pservers-grad-11-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/pservers-grad-12-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/pservers-pattern-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/shapes-intro-01-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/struct-image-06-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/styling-css-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/styling-css-02-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/styling-css-03-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/text-intro-03-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/text-intro-04-t.svg [ Crash NeedsManualRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/text-text-06-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/types-basicDOM-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/filters/filterRegions.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/paints/patternRegions-positioned-objects.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/paints/patternRegions.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/smallFonts.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textAnchor.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textAnchor2.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textAnchor3.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textDecoration2.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textEffect.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textEffect2.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textEffect3.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textFeatures.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textLayout.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textLayout2.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textLength.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textOnPath.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textOnPath2.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textOnPath3.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textOnPathSpaces.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textPosition.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textPosition2.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textProperties.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/textProperties2.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/verticalText.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/verticalTextOnPath.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/batik/text/xmlSpace.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/carto.net/button.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/carto.net/colourpicker.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/carto.net/combobox.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/carto.net/scrollbar.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/carto.net/selectionlist.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/carto.net/slider.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/carto.net/tabgroup.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/carto.net/textbox.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/carto.net/window.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/altglyph.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/bug45331.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/clip-mask-negative-scale.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/coords-relative-units-transforms.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/dominant-baseline-hanging.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/foreign-object-skew.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/getscreenctm-in-mixed-content.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/glyph-selection-arabic-forms.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/glyph-selection-non-bmp.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/inline-svg-in-xhtml.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/junk-data.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/linking-a-03-b-preserveAspectRatio.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/linking-a-03-b-transform.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/linking-a-03-b-viewTarget.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/linking-a-03-b-zoomAndPan.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/load-non-wellformed.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/missing-xlink.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/object-sizing.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/path-bad-data.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/pattern-rotate-gaps.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/pattern-rotate.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/preserve-aspect-ratio-syntax.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/rootmost-svg-xy-attrs.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/stroked-pattern.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/style-attribute-font-size.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/svg-fonts-in-html.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/text-dom-01-f.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/text-match-highlight.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/use-dynamic-append.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/use-events-crash.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/use-font-face-crash.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/viewbox-syntax.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/hixie/error/002.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/hixie/error/012.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/hixie/mixed/003.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/hixie/mixed/009.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/text/append-text-node-to-tspan.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/text/font-size-below-point-five-2.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/text/foreignObject-text-clipping-bug.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/text/kerning.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/text/multichar-glyph.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/text/scaling-font-with-geometric-precision.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/text/textPathBoundsBug.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/transforms/text-with-mask-with-svg-transform.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/transforms/text-with-pattern-inside-transformed-html.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/transforms/text-with-pattern-with-svg-transform.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/wicd/test-rightsizing-a.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/wicd/test-rightsizing-b.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/wicd/test-scalable-background-image1.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/wicd/test-scalable-background-image2.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-background-images.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-coords-viewattr-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-hixie-mixed-009.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-replaced-intrinsic-ratio-001.htm [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-svg-through-object-with-absolute-size-2.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-svg-through-object-with-absolute-size.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-svg-through-object-with-auto-size.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-svg-through-object-with-huge-size.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-svg-through-object-with-override-size.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-svg-through-object-with-percentage-size.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/text/zoom-hixie-mixed-009.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/45621.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug10269-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug10296-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug1055-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug106158-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug10633.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug113235-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug113235-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug113424.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug1188.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug12384.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug13105.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug13118.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug1318.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug138725.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug139524-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug157890.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug16012.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug16252.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug17138.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug18359.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug19061-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug19061-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug194024.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug20579.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug22019.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug23151.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug23235.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug24200.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug2479-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug2479-3.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug26178.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug28928.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug29326.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug30559.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug30692.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug33855.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug39209.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug4093.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug43204.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug4382.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug4429.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug44505.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug4527.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug46368-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug46368-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug46623-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug48028-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug51037.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug51727.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug52505.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug52506.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug55545.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug57828-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug59354.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug60749.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug60804.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug60807.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug647.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug68912.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug7112-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug7112-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug7121-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug73321.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug7342.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug83786.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug8381.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug8858.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug8950.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug92647-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug96334.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug99948.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/collapsing_borders/bug41262-3.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/collapsing_borders/bug41262-4.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/core/bloomberg.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/core/margins.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/dom/tableDom.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/marvin/backgr_index.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/marvin/backgr_layers-opacity.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/marvin/backgr_position-table.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/marvin/backgr_simple-table-cell.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/marvin/backgr_simple-table-column-group.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/marvin/backgr_simple-table-column.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/marvin/backgr_simple-table-row-group.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/marvin/backgr_simple-table-row.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/marvin/backgr_simple-table.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/other/move_row.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/other/ms.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/other/slashlogo.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/other/test6.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/other/wa_table_thtd_rowspan.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/other/wa_table_tr_align.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug1055-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug1128.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug11331.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug1725.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug21518.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug22122.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug2479-5.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug45621.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug46268-4.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug58402-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug7121-2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug89315.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/bugs/bug92647-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/collapsing_borders/bug41262-5.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/collapsing_borders/bug41262-6.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_border-table-cell.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_border-table-column-group.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_border-table-column.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_border-table-quirks.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_border-table-row-group.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_border-table-row.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_border-table.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_fixed-bg.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_layers-hide.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_layers-show.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_position-table-cell.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_position-table-column-group.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_position-table-column.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_position-table-row-group.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/backgr_position-table-row.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_cell_sibling.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_row.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/marvin/table_overflow_style_reflow_row_sibling.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] transforms/3d/general/perspective-non-layer.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/basic/001.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/basic/011.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/basic/013.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/basic/generic-family-changes.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/basic/generic-family-reset.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/break-word.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/chromium-linux-fontconfig-renderstyle.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/drawBidiText.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/font-stretch.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/font-weight.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/international/bidi-listbox-atsui.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/international/bidi-listbox.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/international/bidi-menulist.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/international/hindi-spacing.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/international/khmer-selection.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/international/pop-up-button-text-alignment-and-direction.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/international/unicode-bidi-plaintext-in-textarea.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/international/unicode-bidi-plaintext.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/international/wrap-CJK-001.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/justify-ideograph-simple.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/justify-ideograph-vertical.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/large-text-composed-char.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/selection-hard-linebreak.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/selection-rect-rounding.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/sub-pixel/text-scaling-pixel.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/textIteratorNilRenderer.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/updateNewFont.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/wbr-pre.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/wbr-styled.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/001.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/019.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/023.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/024.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/029.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/030.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/pre-wrap-overflow-selection.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/pre-wrap-spaces-after-newline.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/word-break.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/scrollbars/custom-scrollbar-with-incomplete-style.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/scrollbars/listbox-scrollbar-combinations.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/scrollbars/overflow-scrollbar-combinations.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/gestures/gesture-tapHighlight-pixel-rotated-div.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/gestures/gesture-tapHighlight-pixel-rotated-link.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/gestures/gesture-tapHighlight-pixel-transparent.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/overflow/nested-render-surfaces-with-intervening-clip.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/overflow/nested-render-surfaces-with-rotation.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/overflow/nested-render-surfaces.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/video/video-controls-layer-creation.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/spelling/grammar-markers-hidpi.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/spelling/grammar-markers.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/spelling/inline-spelling-markers-hidpi-composited.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/spelling/inline-spelling-markers-hidpi.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/spelling/inline_spelling_markers.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/canvas/alpha.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/canvas/canvas-text-space-characters.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/events/scale-and-scroll-body.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/calendar-picker-appearance-ar.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/calendar-picker-appearance-minimum-date.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/calendar-picker-appearance-required-ar.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/calendar-picker-appearance-required.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/calendar-picker-appearance-ru.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/calendar-picker-appearance-step.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/calendar-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/month-picker-appearance-step.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/month-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/week-picker-appearance-step.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/calendar-picker/week-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/color/color-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/color/color-suggestion-picker-one-row-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/color/color-suggestion-picker-two-row-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/color/color-suggestion-picker-with-scrollbar-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/datalist/input-appearance-range-with-datalist-zoomed.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/date/date-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/date/date-appearance-pseudo-elements.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/datetimelocal/datetimelocal-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/datetimelocal/datetimelocal-appearance-l10n.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/file/file-input-pressed-state.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/month/month-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/month/month-appearance-l10n.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/month/month-appearance-pseudo-elements.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/date-suggestion-picker-appearance-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/date-suggestion-picker-appearance-with-scroll-bar.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/date-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-with-scroll-bar.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/month-suggestion-picker-appearance-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/month-suggestion-picker-appearance-with-scroll-bar.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/month-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/time-suggestion-picker-appearance-locale-hebrew.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/time-suggestion-picker-appearance-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/time-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/week-suggestion-picker-appearance-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/week-suggestion-picker-appearance-with-scroll-bar.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/suggestion-picker/week-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/time/time-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/time/time-appearance-pseudo-elements.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/week/week-appearance-basic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/week/week-appearance-pseudo-elements.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/images/12-55.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/images/182.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/images/2-dht.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/images/23-55.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/images/55.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/sub-pixel/selection/selection-rect-in-sub-pixel-table.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/atsui-small-caps-punctuation-size.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/020.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] http/tests/media/video-buffered-range-contains-currentTime.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/controls-layout-direction.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] plugins/embed-attributes-style.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/as-background-image/svg-as-background-1.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/as-background-image/svg-as-background-5.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/as-background-image/svg-as-background-6.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/as-object/embedded-svg-immediate-offsetWidth-query.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/as-object/embedded-svg-size-changes.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/as-object/nested-embedded-svg-size-changes.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/use-instanceRoot-event-bubbling.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGLengthList-appendItem.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGLengthList-getItem.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGLengthList-initialize.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGLengthList-insertItemBefore.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGLengthList-removeItem.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGLengthList-replaceItem.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGLengthList-xml-dom-modifications.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGLocatable-getCTM-svg-root.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGPathSegList-appendItem.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGPathSegList-clear-and-initialize.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGPathSegList-insertItemBefore.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGPathSegList-removeItem.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGPathSegList-replaceItem.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGPathSegList-xml-dom-synchronization.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/SVGStringList-basics.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/dom/css-transforms.xhtml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/hixie/perf/001.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/hixie/perf/002.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/hixie/perf/003.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/hixie/perf/007.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/text/text-layout-crash.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/text/zoom-coords-viewattr-01-b.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug22513.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/atsui-multiple-renderers.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/atsui-small-caps-punctuation-size.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/capitalize-boundaries.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/emphasis-complex.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/emphasis.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/justify-ideograph-complex.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/020.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/deferred/fast/images/12-55.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/deferred/fast/images/182.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/deferred/fast/images/23-55.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/deferred/fast/images/55.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/overflow/do-not-paint-outline-into-composited-scrolling-contents.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/overflow/nested-render-surfaces-with-intervening-clip.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/overflow/nested-render-surfaces-with-rotation.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/overflow/nested-render-surfaces.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/scrollbars/rtl/overflow-scroll-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/fast/canvas/alpha.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/fast/canvas/canvas-text-space-characters.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/geometry/layer-due-to-layer-children-deep-switch.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/geometry/layer-due-to-layer-children-switch.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/geometry/limit-layer-bounds-overflow-root.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/geometry/preserve-3d-switching.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/layer-creation/no-compositing-for-preserve-3d.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/overflow/selection-gaps-after-removing-scrolling-contents.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/overflow/selection-gaps-toggling-with-scrolling-contents.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/overflow/selection-gaps-toggling.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/squashing/no-squashing-into-another-clip-layer.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/video/video-poster.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] compositing/visibility/visibility-image-layers-dynamic.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css1/formatting_model/horizontal_formatting.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] css3/compositing/mix-blend-mode-composited-layers.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/caret/caret-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/move-by-word-visually-mac.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] editing/selection/move-by-word-visually-multi-line.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/float/032.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/block/float/overhanging-tall-block.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/canvas/canvas-text-ideographic-space.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/acid2-pixel.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/acid2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/css/bidi-override-in-anonymous-block.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/dynamic/positioned-movement-with-positioned-children.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/focus-selection-textarea.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/hidden-listbox.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/text-control-intrinsic-widths.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/forms/textfield-overflow.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/frames/onlyCommentInIFrame.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/repaint/control-clip.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/repaint/multi-layout-one-frame.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/repaint/search-field-cancel.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/repaint/subtree-root-skipped.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/replaced/table-percent-height.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/table/table-all-rowspans-height-distribution-in-rows-except-overlapped.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/sub-pixel/text-scaling-ltr.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/sub-pixel/text-scaling-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/sub-pixel/text-scaling-vertical.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] fast/text/whitespace/pre-newline-box-test.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] http/tests/misc/acid2-pixel.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] http/tests/misc/acid2.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] media/video-paint-invalidation.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/W3C-SVG-1.1/struct-group-03-t.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/animations/svglength-animation-px-to-exs.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/custom/path-textPath-simulation.svg [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/hixie/error/013.xml [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/text/text-rescale.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-svg-as-background-with-relative-size-and-viewBox.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] svg/zoom/page/zoom-svg-as-background-with-relative-size.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla/bugs/bug2479-4.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] tables/mozilla_expected_failures/other/test4.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] touchadjustment/html-label.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/sub-pixel/text-scaling-ltr.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/sub-pixel/text-scaling-rtl.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/sub-pixel/text-scaling-vertical.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/antialiasedtext/fast/text/whitespace/pre-newline-box-test.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/overflow/selection-gaps-after-removing-scrolling-contents.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/overflow/selection-gaps-toggling-with-scrolling-contents.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/compositedscrolling/overflow/selection-gaps-toggling.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/gpu/fast/canvas/canvas-text-ideographic-space.html [ NeedsRebaseline ]
+crbug.com/395425 [ Win7 ] virtual/threaded/compositing/visibility/visibility-image-layers-dynamic.html [ NeedsRebaseline ]
+
 # Ahem font is sometimes not loaded on Windows.
 crbug.com/392046 [ Win ] fast/inline/justify-emphasis-inline-box.html [ Pass Failure ]
 crbug.com/392046 [ Win ] fast/text/whitespace/002.html [ Pass Failure ]
@@ -1281,10 +2981,51 @@ crbug.com/401381 [ XP ] http/tests/serviceworker/fetch-event.html [ Pass Timeout
 crbug.com/397321 compositing/repaint/should-not-repaint-composited-opacity.html [ Crash Pass ]
 crbug.com/397321 svg/custom/pattern-3-step-cycle.html [ Crash Pass ]
 crbug.com/397321 svg/filters/filter-refresh.svg [ Crash Pass ]
-crbug.com/397321 virtual/softwarecompositing/repaint/repaint-into-ancestor-after-layout.html [ Crash Pass ]
-crbug.com/399507 inspector/timeline/tracing/update-layer-tree.html [ Failure Pass ]
-crbug.com/399507 virtual/deferred/inspector/timeline/tracing/update-layer-tree.html [ Failure Pass ]
-crbug.com/399507 virtual/implsidepainting/inspector/timeline/tracing/update-layer-tree.html [ Failure Pass ]
+crbug.com/399507 inspector/tracing/update-layer-tree.html [ Failure Pass ]
+crbug.com/399507 virtual/deferred/inspector/tracing/update-layer-tree.html [ Failure Pass ]
+crbug.com/399507 virtual/implsidepainting/inspector/tracing/update-layer-tree.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] http/tests/inspector/tracing/timeline-xhr-event.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] inspector/tracing/timeline-event-dispatch.html [ Failure Pass ]
+crbug.com/407915 [ Release ] virtual/deferred/inspector/tracing/timeline-event-dispatch.html [ Failure Pass ]
+crbug.com/407915 virtual/implsidepainting/inspector/tracing/timeline-event-dispatch.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] inspector/tracing/timeline-layout-reason.html [ Failure Pass ]
+crbug.com/407915 [ Win Mac Release ] inspector/tracing/timeline-parse-html.html [ Failure Pass ]
+crbug.com/407915 [ Win Mac Release ] virtual/deferred/inspector/tracing/timeline-parse-html.html [ Failure Pass ]
+crbug.com/407915 [ Win Mac ] virtual/implsidepainting/inspector/tracing/timeline-parse-html.html [ Failure Pass ]
+crbug.com/407915 [ Release ] inspector/tracing/timeline-script-tag-1.html [ Failure Pass ]
+crbug.com/407915 [ Release ] virtual/deferred/inspector/tracing/timeline-script-tag-1.html [ Failure Pass ]
+crbug.com/407915 [ Release ] virtual/implsidepainting/inspector/tracing/timeline-script-tag-1.html [ Failure Pass ]
+crbug.com/407915 [ Release ] inspector/tracing/decode-resize.html [ Failure Pass Timeout ]
+crbug.com/407915 [ Win Release ] http/tests/inspector/tracing/timeline-xhr-response-type-blob-event.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] inspector/tracing/timeline-injected-script-eval.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] inspector/tracing/timeline-layout.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] inspector/tracing/timeline-recalculate-styles.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] inspector/tracing/timeline-time.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/deferred/inspector/tracing/decode-resize.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/deferred/inspector/tracing/timeline-injected-script-eval.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/deferred/inspector/tracing/timeline-layout-reason.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/deferred/inspector/tracing/timeline-layout.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/deferred/inspector/tracing/timeline-recalculate-styles.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/deferred/inspector/tracing/timeline-time.html [ Failure Pass Timeout ]
+crbug.com/407915 virtual/implsidepainting/inspector/timeline/timeline-frames.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/implsidepainting/inspector/tracing/timeline-injected-script-eval.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/implsidepainting/inspector/tracing/timeline-layout.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/implsidepainting/inspector/tracing/timeline-recalculate-styles.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/implsidepainting/inspector/tracing/timeline-time.html [ Failure Pass ]
+crbug.com/407915 [ Mac Release ] virtual/implsidepainting/inspector/tracing/timeline-timer.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/implsidepainting/inspector/tracing/paint-command-log-nodes.html [ Failure Pass ]
+crbug.com/407915 [ Win Release ] virtual/implsidepainting/inspector/tracing/timeline-layout-reason.html [ Failure Pass ]
+crbug.com/409580 inspector/device-emulation/device-emulation-320-2x.html [ Crash Pass ]
+crbug.com/407993 [ Win Release ] media/encrypted-media/encrypted-media-waiting-for-a-key.html [ Pass Timeout ]
+crbug.com/407993 [ Win Release ] media/encrypted-media/encrypted-media-v2-events.html [ Pass Timeout ]
+crbug.com/407993 [ Mac Win Release ] media/encrypted-media/encrypted-media-playback-multiple-sessions.html [ Pass Timeout ]
+crbug.com/407993 [ Win Release ] media/encrypted-media/encrypted-media-playback-setmediakeys-before-src.html [ Timeout Pass ]
+crbug.com/407993 [ Win ] media/encrypted-media/prefixed/encrypted-media-events.html [ Crash Pass ]
+crbug.com/409579 http/tests/security/javascriptURL/xss-DENIED-to-javascript-url-in-foreign-domain-subframe.html [ Pass Timeout ]
+#crbug.com/409715 [ Win ] svg/W3C-SVG-1.1/text-intro-04-t.svg [ Crash Pass ]
+crbug.com/409713 [ Linux Win Release ] fast/dom/Window/window-early-properties-xhr.html [ Pass Timeout ]
+crbug.com/409712 http/tests/filesystem/workers/resolve-url.html [ Pass Timeout ]
+crbug.com/409767 crypto/worker-subtle-crypto-concurrent.html [ Crash Pass Timeout ]
 
 crbug.com/357462 http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html [ Failure Pass Timeout ]
 crbug.com/357462 http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html [ Failure Pass Timeout ]
diff --git a/src/third_party/WebKit/LayoutTests/accessibility/adopt-node-causes-crash-expected.txt b/src/third_party/WebKit/LayoutTests/accessibility/adopt-node-causes-crash-expected.txt
new file mode 100644 (file)
index 0000000..7dc42eb
--- /dev/null
@@ -0,0 +1,9 @@
+Ensure that if we have an AXNodeObject with a raw pointer to a Node, the accessible object gets correctly detached if we adopt the node into a new document.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/accessibility/adopt-node-causes-crash.html b/src/third_party/WebKit/LayoutTests/accessibility/adopt-node-causes-crash.html
new file mode 100644 (file)
index 0000000..f052b04
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="../resources/js-test.js"></script>
+
+<!-- Nodes inside a canvas get an AXNodeObject, not an AXRenderObject. -->
+<canvas>
+    <div id=node2></div>
+</canvas>
+
+<script>
+    description("Ensure that if we have an AXNodeObject with a raw pointer to a Node, the accessible object gets correctly detached if we adopt the node into a new document.");
+
+    // This triggers an asynchronous accessibility notification.
+    document.getElementById("node2").setAttribute("aria-label", "Label");
+
+    // Adopt the node into a new document, then garbage-collect it.
+    // Make sure the notification doesn't try to access the invalid node.
+    document.implementation.createDocument("", null).adoptNode(node2);
+    gc();
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/accessibility/inline-text-word-boundary-causes-crash-expected.txt b/src/third_party/WebKit/LayoutTests/accessibility/inline-text-word-boundary-causes-crash-expected.txt
new file mode 100644 (file)
index 0000000..9367927
--- /dev/null
@@ -0,0 +1,12 @@
+Heading
+
+Makes sure that accessing the word boundaries of an AXStaticText object doesn't cause a crash when it has an inline text box of length zero.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Word start for index -1: 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/accessibility/inline-text-word-boundary-causes-crash.html b/src/third_party/WebKit/LayoutTests/accessibility/inline-text-word-boundary-causes-crash.html
new file mode 100644 (file)
index 0000000..785740a
--- /dev/null
@@ -0,0 +1,28 @@
+<html>
+<head>
+<script src="../resources/js-test.js"></script>
+<style>
+    h1:first-letter {
+        text-transform:uppercase;
+    }
+</style>
+</head>
+<body>
+
+    <h1 id="heading">
+        heading
+    </h1>
+
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Makes sure that accessing the word boundaries of an AXStaticText object doesn't cause a crash when it has an inline text box of length zero.");
+if (window.accessibilityController) {
+    var axHeading = accessibilityController.accessibleElementById('heading');
+    var axStaticText = axHeading.childAtIndex(0);
+    debug('Word start for index -1: ' + axStaticText.wordStart(-1));
+}
+</script>   
+</body>
+</html>
diff --git a/src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-ancestor-reason-expected.txt b/src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-ancestor-reason-expected.txt
new file mode 100644 (file)
index 0000000..824a8bd
--- /dev/null
@@ -0,0 +1,54 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "children": [
+        {
+          "position": [8, 8],
+          "bounds": [100, 100],
+          "children": [
+            {
+              "bounds": [100, 100],
+              "contentsOpaque": true,
+              "drawsContent": true,
+              "backgroundColor": "#D3D3D3",
+              "repaintRects": [
+                [0, 0, 100, 100]
+              ],
+              "children": [
+                {
+                  "bounds": [100, 100],
+                  "shouldFlattenTransform": false,
+                  "transform": [
+                    [1, 0, 0, 0],
+                    [0, 1, 0, 0],
+                    [0, 0, 1, -0.05],
+                    [0, 0, 0, 1]
+                  ],
+                  "children": [
+                    {
+                      "bounds": [50, 50],
+                      "contentsOpaque": true,
+                      "drawsContent": true,
+                      "backgroundColor": "#FFFF00",
+                      "transform": [
+                        [1, 0, 0, 0],
+                        [0, 1, 0, 0],
+                        [0, 0, 1, 0],
+                        [0, 0, 1, 1]
+                      ]
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-ancestor-reason.html b/src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-ancestor-reason.html
new file mode 100644 (file)
index 0000000..a18a75f
--- /dev/null
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<div id="target" style="transform: translateZ(0); width: 100px; height: 100px; background-color: lightblue">
+  <div style="perspective: 20px; width: 100px; height: 100px; background-color: lightgray">
+     <div style="width: 50px; height: 50px; transform: translateZ(1px); background-color: yellow">
+     </div>
+  </div>
+</div>
+<script src="../fast/repaint/resources/text-based-repaint.js"></script>
+<script>
+// Tests that transitioning  the container div from "composited but paints into ancestor" into "composited into own backing"
+// for ancestor reasons (in this case due to opacity change) correctly invalidates the old paint invalidation backing (document)
+// before the change. In this case, the reason it can no longer paint into its ancestor is because the ancestor has no visible content
+// (since the background color is removed).
+function repaintTest() {
+    target.style.backgroundColor = '';
+}
+runRepaintTest()
+</script>
\ No newline at end of file
diff --git a/src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-intrinsic-reason-expected.txt b/src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-intrinsic-reason-expected.txt
new file mode 100644 (file)
index 0000000..0ac95fe
--- /dev/null
@@ -0,0 +1,49 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [8, 8, 784, 100]
+      ],
+      "children": [
+        {
+          "position": [8, 8],
+          "bounds": [784, 100],
+          "opacity": 0,
+          "contentsOpaque": true,
+          "drawsContent": true,
+          "backgroundColor": "#FF0000",
+          "repaintRects": [
+            [0, 0, 784, 100],
+            [0, 0, 784, 100]
+          ],
+          "children": [
+            {
+              "bounds": [784, 100],
+              "shouldFlattenTransform": false,
+              "transform": [
+                [1, 0, 0, 0],
+                [0, 1, 0, 0],
+                [0, 0, 1, -1],
+                [0, 0, 0, 1]
+              ],
+              "children": [
+                {
+                  "bounds": [100, 100],
+                  "contentsOpaque": true,
+                  "drawsContent": true,
+                  "backfaceVisibility": "hidden",
+                  "backgroundColor": "#0000FF"
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-intrinsic-reason.html b/src/third_party/WebKit/LayoutTests/compositing/change-from-paints-into-ancestor-to-paints-into-own-backing-for-intrinsic-reason.html
new file mode 100644 (file)
index 0000000..feefdc6
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<style>
+.spinner {
+  backface-visibility: hidden;
+  background-color: blue;
+  height: 100px;
+  width: 100px;
+}
+.transparent {
+  opacity: 0;
+}
+#container {
+  -webkit-perspective: 1px;
+  background-color: red;
+  overflow: hidden;
+}
+</style>
+<script src="../fast/repaint/resources/text-based-repaint.js"></script>
+<div id="container">
+  <div class="spinner"></div>
+</div>
+<script>
+// Tests that transitioning  the container div from "composited but paints into ancestor" into "composited into own backing"
+// for intrinsic reasons (in this case due to opacity change) correctly invalidates the old paint invalidation backing (document)
+// before the change.
+function repaintTest() {
+    document.getElementById('container').classList.add('transparent');
+}
+if (window.testRunner)
+    runRepaintTest();
+</script>
index 6e44c21..db2d1e6 100644 (file)
@@ -7,19 +7,16 @@
       "drawsContent": true,
       "children": [
         {
-          "children": [
-            {
-              "position": [205, 205],
-              "transformOrigin": [175, 175],
-              "bounds": [225, 225],
-              "drawsContent": true,
-              "backgroundColor": "#000000"
-            },
-            {
-              "bounds": [225, 225],
-              "drawsContent": true
-            }
-          ]
+          "position": [205, 205],
+          "transformOrigin": [175, 175],
+          "bounds": [225, 225],
+          "drawsContent": true,
+          "backgroundColor": "#000000"
+        },
+        {
+          "bounds": [225, 225],
+          "drawsContent": true,
+          "backgroundColor": "#008000"
         }
       ]
     }
index ca4bae1..fdf59d3 100644 (file)
@@ -7,19 +7,16 @@
       "drawsContent": true,
       "children": [
         {
-          "children": [
-            {
-              "position": [105, 105],
-              "bounds": [100, 100],
-              "contentsOpaque": true,
-              "drawsContent": true,
-              "backgroundColor": "#000000"
-            },
-            {
-              "bounds": [125, 125],
-              "drawsContent": true
-            }
-          ]
+          "position": [105, 105],
+          "bounds": [100, 100],
+          "contentsOpaque": true,
+          "drawsContent": true,
+          "backgroundColor": "#000000"
+        },
+        {
+          "bounds": [125, 125],
+          "drawsContent": true,
+          "backgroundColor": "#008000"
         }
       ]
     }
index 421cfcf..f01b495 100644 (file)
@@ -7,19 +7,16 @@
       "drawsContent": true,
       "children": [
         {
-          "children": [
-            {
-              "position": [105, 105],
-              "transformOrigin": [75, 75],
-              "bounds": [125, 125],
-              "drawsContent": true,
-              "backgroundColor": "#000000"
-            },
-            {
-              "bounds": [125, 125],
-              "drawsContent": true
-            }
-          ]
+          "position": [105, 105],
+          "transformOrigin": [75, 75],
+          "bounds": [125, 125],
+          "drawsContent": true,
+          "backgroundColor": "#000000"
+        },
+        {
+          "bounds": [125, 125],
+          "drawsContent": true,
+          "backgroundColor": "#008000"
         }
       ]
     }
diff --git a/src/third_party/WebKit/LayoutTests/compositing/gestures/gesture-tapHighlight-adjustment-clipping-expected.html b/src/third_party/WebKit/LayoutTests/compositing/gestures/gesture-tapHighlight-adjustment-clipping-expected.html
new file mode 100644 (file)
index 0000000..dcfee4b
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<script src="../../resources/js-test.js"></script>
+<script src="resources/link-highlight-helper.js"></script>
+<link rel="stylesheet" type="text/css" href="resources/link-highlight-style.css">
+<style>
+#highlightTarget {
+  position: absolute;
+  height: 200px;
+  left: 50px;
+  top: 180px;
+  width: 20px;
+  background-color: red;
+}
+
+#clip {
+  position: absolute;
+  top: 200px;
+  left: 0;
+  width: 50px;
+  height: 150px;
+  overflow: hidden;
+}
+
+#fakeTarget {
+  width: 150px;
+  height: 150px;
+  background-color: lightblue;
+}
+
+</style>
+
+<div id=highlightTarget class=target></div>
+<div id=clip>
+  <div id=fakeTarget class=target></div>
+</div>
+
+<script>
+description('This test is successful if the red box is completely covered in a green rectangle with square corners.');
+createHighlight(highlightTarget);
+testRunner.dumpAsTextWithPixelResults();
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/compositing/gestures/gesture-tapHighlight-adjustment-clipping.html b/src/third_party/WebKit/LayoutTests/compositing/gestures/gesture-tapHighlight-adjustment-clipping.html
new file mode 100644 (file)
index 0000000..1d963ef
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<script src="../../resources/js-test.js"></script>
+<script src="resources/link-highlight-helper.js"></script>
+<link rel="stylesheet" type="text/css" href="resources/link-highlight-style.css">
+<style>
+#highlightTarget {
+  position: absolute;
+  height: 200px;
+  left: 50px;
+  top: 180px;
+  width: 20px;
+  background-color: red;
+}
+
+#clip {
+  position: absolute;
+  top: 200px;
+  left: 0;
+  width: 50px;
+  height: 150px;
+  overflow: hidden;
+}
+
+#fakeTarget {
+  width: 150px;
+  height: 150px;
+  background-color: lightblue;
+}
+
+</style>
+
+<div id=highlightTarget class=target></div>
+<div id=clip>
+  <div id=fakeTarget class=target></div>
+</div>
+
+<script>
+description('This test is successful if the red box is completely covered in a green rectangle with square corners.');
+onload = testHighlightTarget;
+</script>
index 45c2e48..9fa8c95 100644 (file)
@@ -33,3 +33,22 @@ function useMockHighlight() {
     internals.settings.setMockGestureTapHighlightsEnabled(true);
 }
 
+function testHighlightTarget(id) {
+    useMockHighlight();
+
+    var clientRect = document.getElementById('highlightTarget').getBoundingClientRect();
+    x = (clientRect.left + clientRect.right) / 2;
+    y = (clientRect.top + clientRect.bottom) / 2;
+    if (window.testRunner) {
+        testRunner.dumpAsTextWithPixelResults();
+        testRunner.waitUntilDone();
+    }
+
+    if (window.eventSender) {
+        eventSender.gestureTapDown(x, y, 30, 30);
+        eventSender.gestureShowPress(x, y, 30, 30);
+        window.setTimeout(function() { window.testRunner.notifyDone(); }, 0);
+    } else {
+        debug("This test requires eventSender");
+    }
+}
index 818ae98..1256974 100644 (file)
   -webkit-tap-highlight-color: rgb(0, 255, 0);
 }
 
+.target {
+  cursor: pointer;  /* enables link highlighting */
+  -webkit-tap-highlight-color: rgb(0, 255, 0);
+  border: 2px solid grey;
+  box-sizing: border-box;
+}
+/* touch adjustment candidate */
+.target:active {
+  border-color: red;
+}
+
 .transparentHighlight {
   -webkit-tap-highlight-color: rgba(0, 255, 0, 0.5);
 }
diff --git a/src/third_party/WebKit/LayoutTests/compositing/overflow/do-not-crash-use-after-free-update-widget-positions-expected.txt b/src/third_party/WebKit/LayoutTests/compositing/overflow/do-not-crash-use-after-free-update-widget-positions-expected.txt
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/src/third_party/WebKit/LayoutTests/compositing/overflow/do-not-crash-use-after-free-update-widget-positions.html b/src/third_party/WebKit/LayoutTests/compositing/overflow/do-not-crash-use-after-free-update-widget-positions.html
new file mode 100644 (file)
index 0000000..8f4d71c
--- /dev/null
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<!-- This test is to catch a flakey use-after-free for ASAN bots. (see crbug.com/402407) -->
+<script>
+  function start() {
+    svgIframe = document.createElement('iframe');
+    svgIframe.src = 'resources/do-not-crash-use-after-free-update-widget-positions.svg';
+
+    bodyElement = document.body;
+
+    articleElement = document.createElement('article');
+    acronymElement = document.createElement('acronym');
+
+    bodyElement.style.overflow = 'scroll';
+
+    selectionRange = document.createRange();
+    selectionRange.selectNodeContents(articleElement);
+    selectionRange.surroundContents(bodyElement);
+
+    w3Iframe = document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe');
+    w3Iframe.src = 'resources/do-not-crash-use-after-free-update-widget-positions-iframe.html';
+    w3Iframe.onload = iframeOnLoad;
+    document.documentElement.appendChild(w3Iframe);
+
+    selectionRange.insertNode(svgIframe);
+    bodyElement.style.position = 'fixed';
+
+    while (svgIframe.parentNode) {
+      svgIframe = svgIframe.parentNode;
+    }
+
+    svgIframe.createElement;
+
+    document.documentElement.appendChild(svgIframe);
+
+    acronymElement.style.position = 'absolute';
+  }
+
+  function iframeOnLoad() {
+    bodyElement.appendChild(acronymElement);
+    acronymElement.offsetWidth;
+
+    acronymElement.appendChild(w3Iframe);
+    w3Iframe.offsetWidth;
+
+    window.setTimeout('window.iframeCallback()', 50);
+  }
+
+  function iframeCallback() {
+    bodyElement.style.cssText = null;
+
+    w3Iframe.contentDocument.location.hash = 'element0';
+  }
+
+  if (window.testRunner) {
+    testRunner.dumpAsText();
+  }
+</script>
+<body onload = "start()">
+  This test passes if it doesn't crash.
+</body>
diff --git a/src/third_party/WebKit/LayoutTests/compositing/overflow/resources/do-not-crash-use-after-free-update-widget-positions-iframe.html b/src/third_party/WebKit/LayoutTests/compositing/overflow/resources/do-not-crash-use-after-free-update-widget-positions-iframe.html
new file mode 100644 (file)
index 0000000..93cd657
--- /dev/null
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<body id="element0">
+</body>
+
diff --git a/src/third_party/WebKit/LayoutTests/compositing/overflow/resources/do-not-crash-use-after-free-update-widget-positions.svg b/src/third_party/WebKit/LayoutTests/compositing/overflow/resources/do-not-crash-use-after-free-update-widget-positions.svg
new file mode 100644 (file)
index 0000000..bb5dd22
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<svg id="element0" xmlns="http://www.w3.org/2000/svg">
+  <rect>
+    <animate from="10px"  to="100px" />
+    <animate attributeName="height" to="10px" dur="10s" />
+  </rect>
+</svg>
diff --git a/src/third_party/WebKit/LayoutTests/compositing/overflow/scroller-with-border-radius-expected.txt b/src/third_party/WebKit/LayoutTests/compositing/overflow/scroller-with-border-radius-expected.txt
new file mode 100644 (file)
index 0000000..decd541
--- /dev/null
@@ -0,0 +1,3 @@
+No border radius (should be using composited scrolling): Pass.
+Has border radius (should not be using composited scrolling): Pass.
+
diff --git a/src/third_party/WebKit/LayoutTests/compositing/overflow/scroller-with-border-radius.html b/src/third_party/WebKit/LayoutTests/compositing/overflow/scroller-with-border-radius.html
new file mode 100644 (file)
index 0000000..3f40890
--- /dev/null
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<style>
+#scroller {
+    overflow: scroll;
+    height: 300px;
+    width: 300px;
+    background-color: red;
+}
+
+#scrolled {
+    height: 1000px;
+    width: 250px;
+    background-color: green;
+}
+
+#fixed {
+    position: fixed;
+    height: 100px;
+    width: 100px;
+    background-color: green;
+    top: 400px;
+    left: 100px;
+}
+</style>
+<div id="scroller">
+    <div id="scrolled"></div>
+    <div id="fixed"></div>
+</div>
+<script>
+function isUsingCompositedScrolling(layer) {
+    if (layer.bounds[1] == 1000)
+        return true;
+    if (layer.children) {
+        for (var i = 0; i < layer.children.length; i++) {
+            if (isUsingCompositedScrolling(layer.children[i]))
+                return true;
+        }
+    }
+    return false;
+}
+
+if (window.internals)
+    window.internals.settings.setPreferCompositingToLCDTextEnabled(true);
+
+if (window.testRunner) {
+    window.testRunner.dumpAsText();
+    window.testRunner.waitUntilDone();
+}
+
+var result = "";
+
+onload = function() {
+    if (window.internals) {
+        result += "No border radius (should be using composited scrolling): ";
+        if (isUsingCompositedScrolling(JSON.parse(window.internals.layerTreeAsText(document))))
+            result += "Pass.\n";
+        else
+            result += "Fail.\n"
+    }
+    document.getElementById("scroller").style.borderRadius = '5px';
+    requestAnimationFrame(function() {
+        if (window.internals) {
+            result += "Has border radius (should not be using composited scrolling): ";
+            if (!isUsingCompositedScrolling(JSON.parse(window.internals.layerTreeAsText(document))))
+                result += "Pass.\n";
+            else
+                result += "Fail.\n"
+        }
+
+        if (window.testRunner) {
+            window.testRunner.setCustomTextOutput(result);
+            window.testRunner.notifyDone();
+        }
+    });
+};
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt b/src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer-expected.txt
new file mode 100644 (file)
index 0000000..0316f02
--- /dev/null
@@ -0,0 +1,68 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "children": [
+        {
+          "position": [8, 8],
+          "bounds": [500, 500],
+          "drawsContent": true,
+          "repaintRects": [
+            [0, 0, 500, 500],
+            [0, 0, 500, 500]
+          ],
+          "children": [
+            {
+              "bounds": [485, 485],
+              "children": [
+                {
+                  "bounds": [5000, 5000],
+                  "shouldFlattenTransform": false,
+                  "drawsContent": true,
+                  "repaintRects": [
+                    [2000, 2000, 3000, 3000],
+                    [0, 0, 5000, 5000]
+                  ],
+                  "children": [
+                    {
+                      "shouldFlattenTransform": false
+                    }
+                  ]
+                }
+              ]
+            },
+            {
+              "children": [
+                {
+                  "position": [0, 485],
+                  "bounds": [485, 15],
+                  "drawsContent": true,
+                  "repaintRects": [
+                    [0, 0, 485, 15]
+                  ]
+                },
+                {
+                  "position": [485, 0],
+                  "bounds": [15, 485],
+                  "drawsContent": true,
+                  "repaintRects": [
+                    [0, 0, 15, 485]
+                  ]
+                },
+                {
+                  "position": [485, 485],
+                  "bounds": [15, 15],
+                  "drawsContent": true
+                }
+              ]
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer.html b/src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-overflow-scrolling-layer.html
new file mode 100644 (file)
index 0000000..7da12d6
--- /dev/null
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<script src="../../fast/repaint/resources/text-based-repaint.js"></script>
+<script>
+if (window.internals)
+  internals.settings.setPreferCompositingToLCDTextEnabled(true);
+function repaintTest() {
+  document.getElementById('content').style.backgroundColor = 'green';
+  var container = document.getElementById('container');
+  container.scrollLeft = 2000;
+  container.scrollTop = 2000;
+}
+window.onload = runRepaintTest;
+</script>
+<style>
+#container {
+  width: 500px;
+  height: 500px;
+  overflow: scroll;
+}
+#content {
+  width: 5000px;
+  height: 5000px;
+  background-color: red;
+}
+</style>
+<div id="container">
+  <div id="content">
+  Tests invalidation of scrolling layer. Passes if the repaint rect is not clipped,
+  and there is no red when the scrolling container is scrolled.<br>
+  Note for manual testing: must run with --enable-prefer-compositing-to-lcd-text
+  on non-high-dpi machines to enable composited scrolling.
+  </div>
+</div>
diff --git a/src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-viewport-scrolling-layer-expected.txt b/src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-viewport-scrolling-layer-expected.txt
new file mode 100644 (file)
index 0000000..439f190
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "bounds": [5008, 5016],
+  "children": [
+    {
+      "bounds": [5008, 5016],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "repaintRects": [
+        [8, 8, 5000, 5000]
+      ]
+    }
+  ]
+}
+
diff --git a/src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-viewport-scrolling-layer.html b/src/third_party/WebKit/LayoutTests/compositing/repaint/should-not-clip-composited-viewport-scrolling-layer.html
new file mode 100644 (file)
index 0000000..f9206e0
--- /dev/null
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<script src="../../fast/repaint/resources/text-based-repaint.js"></script>
+<script>
+if (window.internals)
+  internals.settings.setPreferCompositingToLCDTextEnabled(true);
+function repaintTest() {
+  document.getElementById('content').style.backgroundColor = 'green';
+  window.scrollTo(2000, 2000);
+}
+window.onload = runRepaintTest;
+</script>
+<style>
+#content {
+  width: 5000px;
+  height: 5000px;
+  background-color: red;
+}
+</style>
+<div id="content">
+Tests invalidation of scrolling layer. Passes if the repaint rect is not clipped,
+and there is no red when the scrolling container is scrolled.<br>
+Note for manual testing: must run with --enable-prefer-compositing-to-lcd-text
+on non-high-dpi machines to enable composited scrolling.
+</div>
index a6d45c4..448892d 100644 (file)
@@ -5,6 +5,9 @@
       "bounds": [800, 600],
       "contentsOpaque": true,
       "drawsContent": true,
+      "repaintRects": [
+        [0, 0, 200, 200]
+      ],
       "children": [
         {
           "children": [
diff --git a/src/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters-expected.txt b/src/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters-expected.txt
new file mode 100644 (file)
index 0000000..ecd61c4
--- /dev/null
@@ -0,0 +1,35 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "children": [
+        {
+          "position": [8, 8],
+          "bounds": [100, 100],
+          "contentsOpaque": true,
+          "drawsContent": true,
+          "backgroundColor": "#ADD8E6"
+        },
+        {
+          "children": [
+            {
+              "position": [-5, -5],
+              "bounds": [62, 62],
+              "drawsContent": true,
+              "backgroundColor": "#D3D3D3"
+            },
+            {
+              "position": [50, 50],
+              "bounds": [50, 50],
+              "drawsContent": true
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/src/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters.html b/src/third_party/WebKit/LayoutTests/compositing/squashing/no-squashing-for-filters.html
new file mode 100644 (file)
index 0000000..d775fa5
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<style>
+.trysquashed {
+    width: 50px; height: 50px; background: lightgray
+}
+</style>
+<div style="width: 100px; height: 100px; transform: translateZ(0); background: lightblue"></div>
+<div class="trysquashed" style="position: absolute; top: 0px; left: 0px; -webkit-filter: drop-shadow(1px 1px 2px #000)"></div>
+<div class="trysquashed" style="position: absolute; top: 50px; left: 50px;"></div>
+
+<pre id="layers"></pre>
+<script>
+// Tests that layers with filters are not squashed.
+if (window.testRunner)
+    window.testRunner.dumpAsText();
+var layersResult = document.getElementById('layers');
+if (window.internals)
+    layersResult.innerText = window.internals.layerTreeAsText(document);
+</script>
\ No newline at end of file
index c8f9145..5085e8c 100644 (file)
@@ -51,6 +51,7 @@ CASE 2, scrolling y to 80, new layers will be squashed, so things repaint:
         [0, 200, 200, 100],
         [0, 100, 200, 100],
         [0, 100, 200, 100],
+        [0, 0, 200, 100],
         [0, 0, 200, 100]
       ],
       "children": [
@@ -138,6 +139,7 @@ CASE 4, scrolling y to 170 new layers will be squashed, so things repaint:
         [0, 200, 200, 100],
         [0, 200, 200, 100],
         [0, 100, 200, 100],
+        [0, 0, 200, 100],
         [0, 0, 200, 100]
       ],
       "children": [
diff --git a/src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt b/src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-expected.txt
new file mode 100644 (file)
index 0000000..dbe6f6d
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "bounds": [800, 600],
+  "children": [
+    {
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "children": [
+        {
+          "position": [8, 8],
+          "children": [
+            {
+              "shouldFlattenTransform": false,
+              "transform": [
+                [1, 0, 0, 0],
+                [0, 1, 0, 0],
+                [0, 0, 1, -0.001],
+                [0, 0, 0, 1]
+              ],
+              "children": [
+                {
+                  "bounds": [200, 200],
+                  "contentsOpaque": true,
+                  "drawsContent": true,
+                  "backgroundColor": "#00008B",
+                  "transform": [
+                    [1, 0, 0, 0],
+                    [0, 1, 0, 0],
+                    [0, 0, 1, 0],
+                    [0, 74, 200, 1]
+                  ]
+                }
+              ]
+            }
+          ]
+        },
+        {
+          "position": [8, 8]
+        }
+      ]
+    }
+  ]
+}
+
diff --git a/src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-with-reparented-scrolling-expected.html b/src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-with-reparented-scrolling-expected.html
new file mode 100644 (file)
index 0000000..abf257b
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<!--
+    This test ensures that the offset from renderer is correctly applied
+    to reparented overflow controls, even if they are unclipped.
+-->
+<style>
+#scroller {
+    overflow: scroll;
+    width: 300px;
+    height: 300px;
+    position: relative;
+    top: 10px;
+}
+
+#fixed {
+    position: fixed;
+    background: blue;
+    left: 90px;
+    width: 10px;
+    height: 10px;
+}
+
+#scrolled {
+    position: relative;
+    background: green;
+    width: 80px;
+    height: 500px;
+}
+</style>
+<div style="z-index: 1; position: absolute"></div>
+<div style="z-index: 0; perspective: 1000px; position: absolute;">
+    <div id='scroller'>
+        <div id='fixed'></div>
+        <div id='scrolled'></div>
+    </div>
+</div>
+<script>
+if (window.internals) {
+    window.internals.settings.setOverlayScrollbarsEnabled(true);
+    window.internals.settings.setPreferCompositingToLCDTextEnabled(true);
+    window.internals.settings.setLayerSquashingEnabled(false);
+}
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-with-reparented-scrolling.html b/src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective-with-reparented-scrolling.html
new file mode 100644 (file)
index 0000000..ddeed46
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<!--
+    This test ensures that the offset from renderer is correctly applied
+    to reparented overflow controls, even if they are unclipped.
+-->
+<style>
+#scroller {
+    overflow: scroll;
+    width: 300px;
+    height: 300px;
+    position: relative;
+    top: 10px;
+}
+
+#fixed {
+    position: fixed;
+    background: blue;
+    left: 90px;
+    width: 10px;
+    height: 10px;
+}
+
+#scrolled {
+    position: relative;
+    background: green;
+    width: 80px;
+    height: 500px;
+}
+</style>
+<div style="z-index: 1; position: absolute"></div>
+<div style="z-index: 0; perspective: 1000px; position: absolute;">
+    <div id='scroller'>
+        <div id='fixed'></div>
+        <div id='scrolled'></div>
+    </div>
+</div>
+<script>
+// Check that a case with a reparented overflow control and a containing perspective node
+// paints the same with and without layer squashing.
+if (window.internals) {
+    window.internals.settings.setOverlayScrollbarsEnabled(true);
+    window.internals.settings.setPreferCompositingToLCDTextEnabled(true);
+    window.internals.settings.setLayerSquashingEnabled(true);
+}
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective.html b/src/third_party/WebKit/LayoutTests/compositing/squashing/squashing-inside-perspective.html
new file mode 100644 (file)
index 0000000..ce6b3ce
--- /dev/null
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+
+<div style="z-index: 1; position: absolute"></div>
+<div style="z-index: 0; perspective: 1000px; position: absolute;">
+    <div style="position: absolute; width: 200px; height: 200px; background-color: darkBlue; transform: translate3d(0px, 74px, 200px);">
+    </div>
+</div>
+<script>
+// Tests that a squashed layer that is the child of an element with perspective on it uses that element as its transform ancestor.
+
+if (window.internals)
+    internals.settings.setLayerSquashingEnabled(true);
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.setCustomTextOutput(window.internals.layerTreeAsText(document));
+}
+</script>
\ No newline at end of file
index 3a77f78..861b6d8 100644 (file)
       "drawsContent": true,
       "children": [
         {
-          "children": [
-            {
-              "position": [250, 250],
-              "bounds": [100, 100],
-              "contentsOpaque": true,
-              "drawsContent": true,
-              "backgroundColor": "#0000FF"
-            },
-            {
-              "position": [100, 100],
-              "bounds": [200, 200],
-              "drawsContent": true
-            }
-          ]
+          "position": [250, 250],
+          "bounds": [100, 100],
+          "contentsOpaque": true,
+          "drawsContent": true,
+          "backgroundColor": "#0000FF"
+        },
+        {
+          "position": [100, 100],
+          "bounds": [200, 200],
+          "drawsContent": true,
+          "backgroundColor": "#000000"
         }
       ]
     }
index 3a77f78..861b6d8 100644 (file)
       "drawsContent": true,
       "children": [
         {
-          "children": [
-            {
-              "position": [250, 250],
-              "bounds": [100, 100],
-              "contentsOpaque": true,
-              "drawsContent": true,
-              "backgroundColor": "#0000FF"
-            },
-            {
-              "position": [100, 100],
-              "bounds": [200, 200],
-              "drawsContent": true
-            }
-          ]
+          "position": [250, 250],
+          "bounds": [100, 100],
+          "contentsOpaque": true,
+          "drawsContent": true,
+          "backgroundColor": "#0000FF"
+        },
+        {
+          "position": [100, 100],
+          "bounds": [200, 200],
+          "drawsContent": true,
+          "backgroundColor": "#000000"
         }
       ]
     }
diff --git a/src/third_party/WebKit/LayoutTests/editing/selection/collapse-null-expected.txt b/src/third_party/WebKit/LayoutTests/editing/selection/collapse-null-expected.txt
new file mode 100644 (file)
index 0000000..6741530
--- /dev/null
@@ -0,0 +1,13 @@
+Ensure that collapse with null clears selection
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS selection.rangeCount is 1
+PASS selection.rangeCount is 0
+PASS selection.rangeCount is 1
+PASS selection.rangeCount is 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+hello
diff --git a/src/third_party/WebKit/LayoutTests/editing/selection/collapse-null.html b/src/third_party/WebKit/LayoutTests/editing/selection/collapse-null.html
new file mode 100644 (file)
index 0000000..10aec6a
--- /dev/null
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script src="../../resources/js-test.js"></script>
+
+<div id="div" contenteditable="true">hello</div>
+<script>
+description("Ensure that collapse with null clears selection");
+
+var selection = getSelection();
+selection.selectAllChildren(div);
+    selection.rangeCount
+    shouldBe("selection.rangeCount", "1");
+    selection.collapse(null);
+    shouldBe("selection.rangeCount", "0");
+    selection.collapse(div.firstChild, 2);
+    shouldBe("selection.rangeCount", "1");
+    selection.collapse(null);
+    shouldBe("selection.rangeCount", "0");
+</script>
+
+</body>
+</html>
index d870a13..454f940 100644 (file)
         <script>
             description("When drawing an animated image to a canvas, the poster frame (or the first frame) should be printed.<br/>This test passes if the canvas is filled with the color rgb(64, 4, 30).");
 
+            if (window.testRunner) {
+                testRunner.waitUntilDone();
+            }
+
+
             function ready() {
                 var canvas = document.getElementById("canvas");
                 var image = document.getElementById("image");
 
                 var canvasContext = canvas.getContext("2d");
 
-                canvasContext.drawImage(image, 0, 0);
+                window.setTimeout(function() {
+
+                    canvasContext.drawImage(image, 0, 0);
+
+                    imageData = canvasContext.getImageData(0, 0, 1, 1);
+
+                    shouldBe("imageData.data[0]", "64");
+                    shouldBe("imageData.data[1]", "4");
+                    shouldBe("imageData.data[2]", "30");
 
-                imageData = canvasContext.getImageData(0, 0, 1, 1);
+                    if (window.testRunner)
+                        testRunner.notifyDone();
 
-                shouldBe("imageData.data[0]", "64");
-                shouldBe("imageData.data[1]", "4");
-                shouldBe("imageData.data[2]", "30");
+                }, 200);
             }
         </script>
 
diff --git a/src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPoint-expected.txt b/src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPoint-expected.txt
new file mode 100644 (file)
index 0000000..690ebe2
--- /dev/null
@@ -0,0 +1,200 @@
+Test 1 - This is a H1 heading.
+
+Test 2 - This is a simple paragraph.
+
+Test 3 - This is a paragraph with a nested element.
+
+Test 4 - This is a paragraph with a nested element that has a border.
+
+Test 5 - This is a transformed paragraph with a nested element that has a border.
+
+Test 6 - This is a transformed paragraph with a nested element that has a border.
+And then a second line.
+
+Test 7 - This is a paragraph inside something that does not have a compositing layer.
+
+Test 8 - This is raw text inside something that does not have a compositing layer.
+Test 9 - This is raw text inside something that has a compositing layer.
+Test 10 - This is raw text inside something that does not have a compositing layer.
+Test 11 - This is a rotated and scaled paragraph
+
+Test 12 - This is a rotated and scaled paragraph with a nested element that has a border.
+
+Test 13 - This is a paragraph with a nested element that has a border.
+
+This test exercises the webkitConvertPointFromNodeToPage() function
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Test parameter passing - should not crash
+PASS Missing parameter test
+Test did not crash and therefore was successful
+
+PASS null parameter test a
+Test did not crash and therefore was successful
+
+PASS null parameter test b
+Test did not crash and therefore was successful
+
+Test 1
+PASS x is 8
+PASS y is 13
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+PASS y is 53
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 2
+PASS x is 8
+PASS y is 51
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+PASS y is 91
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 3
+PASS x is 8
+PASS y is 85
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+PASS y is 125
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 4
+PASS x is 8
+PASS y is 119
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+PASS y is 159
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 5
+PASS x is 28
+PASS y is 153
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+PASS y is 193
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 6
+PASS x is 28
+PASS y is 187
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+PASS y is 227
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 7
+PASS x is 8
+PASS y is 239
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+PASS y is 279
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 8
+PASS x is 8
+PASS y is 273
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+PASS y is 313
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 9
+PASS x is 28
+PASS y is 291
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+PASS y is 331
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 10
+PASS x is 28
+PASS y is 309
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+PASS y is 349
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 11
+PASS x is 158
+FAIL y should be 376. Was 355.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 174
+FAIL y should be 394. Was 373.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 12
+PASS x is 168
+FAIL y should be 451. Was 428.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 184
+FAIL y should be 469. Was 446.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 13
+PASS x is 28
+PASS y is 487
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+PASS y is 527
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPoint.html b/src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPoint.html
new file mode 100644 (file)
index 0000000..4675bde
--- /dev/null
@@ -0,0 +1,187 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+  "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+  <head>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+    <title>Test of webkitConvertPointFromNodeToPage function</title>
+    <script src="../../../resources/js-test.js"></script>
+    <style type="text/css" media="screen">
+      body {
+          height: 1000px;
+      }
+      
+      h1 {
+          font-size: 14pt;
+      }
+      .layer {
+        position: relative;
+        width: 600px;
+        height: 500px;
+        -webkit-transform: translate(0px);
+      }
+      .dot {
+         position: absolute;
+         background-color: #0f0;
+         width: 10px;
+         height: 10px;
+         left: 0px;
+         top: 0px;
+         visibility: hidden;
+       }
+       b.border {
+         border: 5px solid blue;
+       }
+       
+       .a {
+         position: relative;
+         left: 10px;
+         background: #cbc;
+         width: 800px;
+         -webkit-transform-origin: top left;
+         -webkit-transform: translate(130px, 20px) rotate(-35deg) scale(0.6);
+         padding: 5px;
+         margin-bottom: 20px;
+       }
+       .b {
+         position: relative;
+         background: #bcc;
+         -webkit-transform: translate(20px);
+       }
+       .c {
+         position: relative;
+         -webkit-transform: translate(20px);
+         background: #99c;
+       }
+       .d {
+         position: relative;
+         background: #cc9;
+       }
+       
+    </style>
+    <script>
+        function runTest(name, id, x1, y1, x2, y2)
+        {
+            debug("");
+            debug(name);
+            var node = document.getElementById(id);
+            p = webkitConvertPointFromNodeToPage(node, new WebKitPoint(0, 0));
+            x = Math.round(p.x);
+            y = Math.round(p.y);
+            shouldBe('x', x1+"");
+            shouldBe('y', y1+"");
+            
+            debug("Round Trip of (0,0)");
+            p2 = webkitConvertPointFromPageToNode(node, p);
+            x = Math.round(p2.x);
+            y = Math.round(p2.y);
+            if (x == -0)
+                x = 0;
+            if (y == -0)
+                y = 0;
+            shouldBe('x', '0');
+            shouldBe('y', '0');
+            
+            p = webkitConvertPointFromNodeToPage(node, new WebKitPoint(5, 40));
+            x = Math.round(p.x);
+            y = Math.round(p.y);
+            if (x == -0)
+                x = 0;
+            if (y == -0)
+                y = 0;
+            shouldBe('x', x2+"");
+            shouldBe('y', y2+"");
+            
+            debug("Round Trip of (5,40)");
+            p2 = webkitConvertPointFromPageToNode(node, p);
+            x = Math.round(p2.x);
+            y = Math.round(p2.y);
+            if (x == -0)
+                x = 0;
+            if (y == -0)
+                y = 0;
+            shouldBe('x', '5');
+            shouldBe('y', '40');
+        }
+        
+        function run() {
+            description("This test exercises the webkitConvertPointFromNodeToPage() function");
+            
+            debug("Test parameter passing - should not crash");
+            var point = webkitConvertPointFromNodeToPage(new WebKitPoint(0, 0));
+            if (point == null)
+                testPassed("Missing parameter test");
+            else
+                testFailed("Missing parameter test");
+            debug("Test did not crash and therefore was successful");
+            debug("");
+            point = webkitConvertPointFromNodeToPage(null, new WebKitPoint(0, 0));
+            if (point == null)
+                testPassed("null parameter test a");
+            else
+                testFailed("null parameter test a");
+            debug("Test did not crash and therefore was successful");
+            debug("");
+            point = webkitConvertPointFromNodeToPage(null, null);
+            if (point == null)
+                testPassed("null parameter test b");
+            else
+                testFailed("null parameter test b");
+            debug("Test did not crash and therefore was successful");
+
+            runTest("Test 1",  "test1",  8, 13, 13, 53);
+            runTest("Test 2",  "test2",  8, 51, 13, 91);
+            runTest("Test 3",  "test3",  8, 85, 13, 125);
+            runTest("Test 4",  "test4",  8, 119, 13, 159);
+            runTest("Test 5",  "test5",  28, 153, 33, 193);
+            runTest("Test 6",  "test6",  28, 187, 33, 227);
+            runTest("Test 7",  "test7",  8, 239, 13, 279);
+            runTest("Test 8",  "test8",  8, 273, 13, 313);
+            runTest("Test 9",  "test9",  28, 291, 33, 331);
+            runTest("Test 10", "test10", 28, 309, 33, 349);
+            runTest("Test 11", "test11", 158, 376, 174, 394);
+            runTest("Test 12", "test12", 168, 451, 184, 469);
+            runTest("Test 13", "test13", 28, 487, 33, 527);
+            
+            isSuccessfullyParsed();
+        }
+
+        window.onload = run;
+
+    </script>
+    </head>
+    <body>
+        <h1 id="test1">Test 1 - This is a H1 heading.</h1>
+        <p id="test2">Test 2 - This is a simple paragraph.</p>
+        <p id="test3">Test 3 - This is a paragraph with a <b>nested</b> element.</p>
+        <p id="test4">Test 4 - This is a paragraph with a <b class="border">nested</b> element that has a border.</p>
+        <p id="test5" class="c">Test 5 - This is a transformed paragraph with a <b class="border">nested</b> element that has a border.</p>
+        <p id="test6" class="c">Test 6 - This is a transformed paragraph with a <b class="border">nested</b> element that has a border.<br>And then a second line.</p>
+        <div class="d">
+            <p id="test7">Test 7 - This is a paragraph inside something that does not have a compositing layer.</p>
+        </div>
+        <div id="test8" class="d">
+            Test 8 - This is raw text inside something that does not have a compositing layer.
+        </div>
+      
+        <div id="test9" class="b">
+            Test 9 - This is raw text inside something that has a compositing layer.
+            <div id="test10" class="d">
+                Test 10 - This is raw text inside something that does not have a compositing layer.
+            </div>
+        </div>
+
+        <div class="a">
+            <p id="test11">Test 11 - This is a rotated and scaled paragraph</p>
+        </div>
+        <div class="a">
+            <div class="b">
+                <p id="test12">Test 12 - This is a rotated and scaled paragraph with a <b class="border">nested</b> element that has a border.</p>
+            </div>
+        </div>
+        <div class="b">
+            <p id="test13">Test 13 - This is a paragraph with a <b class="border">nested</b> element that has a border.</p>
+        </div>
+        <div id="description"></div>
+        <div id="console"></div>
+    </body>
+</html>
diff --git a/src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPointUpdateLayout-expected.txt b/src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPointUpdateLayout-expected.txt
new file mode 100644 (file)
index 0000000..1ab4e93
--- /dev/null
@@ -0,0 +1,13 @@
+This test exercises the webkitConvertPointFromNodeToPage() function after changing the transform.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+PASS x is 60
+PASS y is 70
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPointUpdateLayout.html b/src/third_party/WebKit/LayoutTests/fast/dom/Window/webkitConvertPointUpdateLayout.html
new file mode 100644 (file)
index 0000000..0e42d43
--- /dev/null
@@ -0,0 +1,44 @@
+<html>
+  <head>
+    <title>webkitConvertPointFromNodeToPage Test</title>
+    <script src="../../../resources/js-test.js"></script>
+    <style type="text/css" media="screen">
+
+      #test {
+        position: absolute;
+        left: 10px;
+        top: 10px;
+        width: 50px;
+        height: 50px;
+        background-color: blue;
+      }
+
+    </style>
+
+    <script type="text/javascript" charset="utf-8">
+      function doTest()
+      {
+        description("This test exercises the webkitConvertPointFromNodeToPage() function after changing the transform.");
+
+        var node = document.getElementById('test');
+        node.style.webkitTransform = 'translate(50px, 60px)';
+        var p = webkitConvertPointFromNodeToPage(node, new WebKitPoint(0, 0));
+        x = Math.round(p.x);
+        y = Math.round(p.y);
+        shouldBe('x', 60 + "");
+        shouldBe('y', 70 + "");
+        
+        isSuccessfullyParsed();
+      }
+      
+      window.onload = doTest;
+    </script>
+
+  </head>
+  <body>
+    <div id="test"></div>
+
+    <div id="description" style="margin-top: 200px"></div>
+    <div id="console"></div>
+  </body>
+</html>
index fe7004e..a8b96fa 100644 (file)
@@ -16,8 +16,8 @@ Wheel: 1
 TouchStart: 1
 TouchMove: 0
 TouchEnd: 0
-GestureTapDown: 1
-GestureShowPress: 2
+GestureTapDown: 2
+GestureShowPress: 4
 GestureTap: 7
 GestureScrollBegin: 1
 GestureTapCancel: 1
@@ -34,8 +34,8 @@ Wheel: 1 1 1
 TouchStart: 1 1 1
 TouchMove: 0 0 0
 TouchEnd: 0 0 0
-GestureTapDown: 1 1 1
-GestureShowPress: 2 2 2
+GestureTapDown: 1 1 2
+GestureShowPress: 2 2 4
 GestureTap: 3 3 7
 GestureScrollBegin: 1 1 1
 GestureTapCancel: 1 1 1
@@ -54,7 +54,7 @@ TouchMove: 0 0 0
 TouchEnd: 0 0 0
 GestureTapDown: 1 4 16
 GestureShowPress: 2 8 32
-GestureTap: 3 12 32
+GestureTap: 4 12 32
 GestureScrollBegin: 1 1 0
 GestureTapCancel: 1 1 0
 GestureScrollUpdate: 0 0 0
diff --git a/src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scrollbar-mainframe-expected.txt b/src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scrollbar-mainframe-expected.txt
new file mode 100644 (file)
index 0000000..31f043c
--- /dev/null
@@ -0,0 +1,15 @@
+This tests scroll gesture events on main frame scroll bars. The document should be slightly scrolled down if successful.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.innerWidth - document.body.clientWidth is > 5
+PASS window.scrollY is 0
+PASS window.scrollY is 0
+PASS window.scrollY is > 20
+PASS window.scrollY is > 85
+PASS window.scrollY is > 85
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scrollbar-mainframe.html b/src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/gesture-scrollbar-mainframe.html
new file mode 100644 (file)
index 0000000..bc85307
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<script src="../../../../resources/js-test.js"></script>
+<style>
+::-webkit-scrollbar {
+  background-color: #ccc;
+  /* fixed size for consistent touch adjustment behavior across platforms */
+  width: 15px;
+}
+
+::-webkit-scrollbar-button {
+  display: none;
+}
+
+::-webkit-scrollbar-thumb {
+  background-color: #777;
+  width: 15px;
+}
+
+body {
+    margin: 0;
+}
+
+.large {
+    height: 2000px;
+    width: 600px;
+}
+</style>
+<div id="console"></div>
+<div class="large">
+
+<script type="text/javascript">
+
+// Ensure there's a candidate for touch adjustment.
+document.addEventListener("click", function() {});
+
+function scrollTest() {
+    shouldBeGreaterThan("window.innerWidth - document.body.clientWidth", "5");
+    var scrollbarX = document.body.clientWidth + 5;
+    var scrollbarY = 50;
+
+    // Ensure we use a touch with an area to test under touch adjustment
+    var touchWidth = 25;
+    var touchHeight = 25;
+
+    shouldBe('window.scrollY', '0');
+    eventSender.gestureTapDown(scrollbarX, scrollbarY, touchWidth, touchHeight);
+    eventSender.gestureShowPress(scrollbarX, scrollbarY, touchWidth, touchHeight);
+    eventSender.gestureScrollBegin(scrollbarX - 20, scrollbarY, touchWidth, touchHeight);
+    eventSender.gestureTapCancel(scrollbarX, scrollbarY, touchWidth, touchHeight);
+    shouldBe('window.scrollY', '0');
+    eventSender.gestureScrollUpdate(0, 20);
+    shouldBeGreaterThan('window.scrollY', '20');
+    eventSender.gestureScrollUpdate(0, 60);
+    shouldBeGreaterThan('window.scrollY', '85');
+    eventSender.gestureScrollEnd(0, 0);
+    shouldBeGreaterThan('window.scrollY', '85');
+}
+
+//if (window.internals)
+//    internals.settings.setMockScrollbarsEnabled(true);
+
+description('This tests scroll gesture events on main frame scroll bars. ' +
+    'The document should be slightly scrolled down if successful.');
+
+if (window.eventSender) {
+   scrollTest();
+} else {
+    debug("This test requires eventSender");
+}
+</script>
index fea1412..536d40b 100644 (file)
@@ -44,6 +44,10 @@ var movingDiv;
 
 function scrollTest() {
     movingDiv = document.getElementById('scrollable');
+
+    // Ensure the div is a target for touch adjustment.
+    movingDiv.addEventListener('click', function() {});
+
     var scrollbarX = movingDiv.offsetLeft + movingDiv.offsetWidth - 5;
     var scrollThumbSafeOffset = 80;
     var scrollbarY = movingDiv.offsetTop + scrollThumbSafeOffset;
diff --git a/src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/tap-target-matches-active-expected.txt b/src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/tap-target-matches-active-expected.txt
new file mode 100644 (file)
index 0000000..41a76ef
--- /dev/null
@@ -0,0 +1,15 @@
+Verifies that the element receiving the :active style is the same as the element receiving the click event, even in the presence of difficult touch adjustment scenarios
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Sending gestureTapDown
+PASS getHoverActiveState(target) is "default"
+Sending gestureShowPress
+PASS getHoverActiveState(target) is "hoveredAndActive"
+Sending gestureTap
+PASS clickTarget.id is "target"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/tap-target-matches-active.html b/src/third_party/WebKit/LayoutTests/fast/events/touch/gesture/tap-target-matches-active.html
new file mode 100644 (file)
index 0000000..695ab98
--- /dev/null
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<script src="../../../../resources/js-test.js"></script>
+<script src="../resources/touch-hover-active-tests.js"></script>
+<link rel="stylesheet" href="../resources/touch-hover-active-tests.css">
+<style>
+#target {
+  position: absolute;
+  height: 100px;
+  left: 50px;
+  top: 100px;
+  width: 20px;
+}
+
+#clip {
+  position: absolute;
+  top: 110px;
+  left: 0;
+  width: 50px;
+  height: 80px;
+  overflow: hidden;
+}
+
+#fakeTarget {
+  width: 150px;
+  height: 150px;
+  background-color: lightblue;
+}
+
+#console {
+  margin-top: 200px;
+}
+</style>
+
+<div id=target class=touch-interactive></div>
+<div id=clip>
+  <div id=fakeTarget class=touch-interactive></div>
+</div>
+
+<div id=console></div>
+
+</style>
+<script>
+description("Verifies that the element receiving the :active style is the same as the element receiving the click event, even in the presence of difficult touch adjustment scenarios");
+
+var clickTarget;
+document.addEventListener('click', function(e) {
+    if (clickTarget)
+        testFailed('Saw unexpected duplicate click event');
+    clickTarget = e.target;
+});
+
+var rect = target.getBoundingClientRect();
+var x = rect.left + rect.width / 2;
+var y = rect.top + rect.height / 2;
+
+debug('Sending gestureTapDown');
+eventSender.gestureTapDown(x, y, 30, 30);
+shouldBeDefault('getHoverActiveState(target)');
+
+debug('Sending gestureShowPress');
+eventSender.gestureShowPress(x, y, 30, 30);
+shouldBeHoveredAndActive('getHoverActiveState(target)');
+
+debug('Sending gestureTap');
+eventSender.gestureTap(x, y, 1, 30, 30);
+shouldBeEqualToString("clickTarget.id", "target");
+
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-gc-iframe-expected.txt b/src/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-gc-iframe-expected.txt
new file mode 100644 (file)
index 0000000..186ad57
--- /dev/null
@@ -0,0 +1,10 @@
+Verify that an aborted and stopping FileReader doesn't crash
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS No crash
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-gc-iframe.html b/src/third_party/WebKit/LayoutTests/fast/files/file-reader-abort-gc-iframe.html
new file mode 100644 (file)
index 0000000..3fba069
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="../../resources/js-test.js"></script>
+<script>
+description("Verify that an aborted and stopping FileReader doesn't crash");
+
+window.jsTestIsAsync = true;
+
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+var reader;
+function setReader(r) {
+    reader = r;
+}
+
+function runTest() {
+    reader.readAsText(new Blob());
+    reader.abort();
+    document.body.removeChild(document.getElementById('ifr'));
+    reader = null;
+    gc();
+    testPassed("No crash");
+    finishJSTest();
+}
+</script>
+<iframe id=ifr src="resources/file-reader-abort-gc-iframe.html"></iframe>
diff --git a/src/third_party/WebKit/LayoutTests/fast/files/resources/file-reader-abort-gc-iframe.html b/src/third_party/WebKit/LayoutTests/fast/files/resources/file-reader-abort-gc-iframe.html
new file mode 100644 (file)
index 0000000..2161d72
--- /dev/null
@@ -0,0 +1,4 @@
+<script>
+window.parent.setReader(new FileReader());
+window.parent.runTest();
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/fast/forms/form-associated-element-crash4-expected.txt b/src/third_party/WebKit/LayoutTests/fast/forms/form-associated-element-crash4-expected.txt
new file mode 100644 (file)
index 0000000..6ab3ede
--- /dev/null
@@ -0,0 +1 @@
+PASS; no crash.
diff --git a/src/third_party/WebKit/LayoutTests/fast/forms/form-associated-element-crash4.html b/src/third_party/WebKit/LayoutTests/fast/forms/form-associated-element-crash4.html
new file mode 100644 (file)
index 0000000..fc3ec20
--- /dev/null
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<body>
+<div>
+<div><form></div>
+<button id=b></button>
+</div>
+</body>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+var b = document.getElementById('b');
+document.body.innerHTML = '';
+setTimeout(function() {
+    if (window.GCController)
+        GCController.collectAll();
+    document.body.appendChild(b);
+    document.body.innerHTML = 'PASS; no crash.';
+    if (window.testRunner)
+        testRunner.notifyDone();
+}, 0);
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/fast/forms/input-appearance-autocomplete-expected.html b/src/third_party/WebKit/LayoutTests/fast/forms/input-appearance-autocomplete-expected.html
new file mode 100644 (file)
index 0000000..56c7f15
--- /dev/null
@@ -0,0 +1,5 @@
+<input id="input" value="hello" style="width: 99px" >
+<script>
+input.select();
+internals.setAutofilled(input, true);
+</script>
\ No newline at end of file
diff --git a/src/third_party/WebKit/LayoutTests/fast/forms/input-appearance-autocomplete.html b/src/third_party/WebKit/LayoutTests/fast/forms/input-appearance-autocomplete.html
new file mode 100644 (file)
index 0000000..da7fbe9
--- /dev/null
@@ -0,0 +1,9 @@
+<input id="input" >
+<script>
+input.focus();
+internals.setSuggestedValue(input, '');
+internals.setSuggestedValue(input, 'hello');
+internals.setAutofilled(input, true);
+input.style.width = '99px';
+input.setSelectionRange(0, 5);
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/fast/forms/select/listbox-tap-input-change-event-expected.txt b/src/third_party/WebKit/LayoutTests/fast/forms/select/listbox-tap-input-change-event-expected.txt
new file mode 100644 (file)
index 0000000..56e8b5a
--- /dev/null
@@ -0,0 +1,13 @@
+Tapping on listbox items should fire an input and a change event.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS changeEventCounter is 0
+PASS inputEventCounter is 0
+PASS changeEventCounter is 1
+PASS inputEventCounter is 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/fast/forms/select/listbox-tap-input-change-event.html b/src/third_party/WebKit/LayoutTests/fast/forms/select/listbox-tap-input-change-event.html
new file mode 100644 (file)
index 0000000..fe9bfe9
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../../resources/js-test.js"></script>
+<select id="select1" multiple size="4">
+<option>1</option>
+<option>2</option>
+<option>3</option>
+</select>
+
+<script>
+description('Tapping on listbox items should fire an input and a change event.');
+
+function tapOption(select, index) {
+    var itemHeight = Math.floor(select.offsetHeight / select.size);
+    var border = 1;
+    var y = border + index * itemHeight;
+
+    select.focus();
+    if (window.eventSender) {
+        eventSender.gestureTap(select.offsetLeft + border, select.offsetTop + y - window.pageYOffset + itemHeight / 2);
+    }
+}
+
+var select = document.getElementById('select1');
+var changeEventCounter = 0;
+var inputEventCounter = 0;
+
+select.addEventListener('change', function () {
+    changeEventCounter++;
+}, false);
+
+select.addEventListener('input', function () {
+    inputEventCounter++;
+}, false);
+
+if (window.eventSender) {
+    shouldBe('changeEventCounter', '0');
+    shouldBe('inputEventCounter', '0');
+    tapOption(select, 0);
+    shouldBe('changeEventCounter', '1');
+    shouldBe('inputEventCounter', '1');
+}
+</script>
+
+</html>
index 5f51ed4..5fe8e98 100644 (file)
@@ -11,7 +11,7 @@
                 src: url('../../../resources/opensans/OpenSans-Regular.woff') format('woff');
             }
             section > div > div {
-                font-family: 'Open Sans';
+                font-family: 'Open Sans', 'Segoe UI';
             }
         </style>
         <script src="resources/text-scaling.js"></script>
index 52b70e5..91c35ab 100644 (file)
@@ -36,10 +36,10 @@ function runTest() {
         var id2 = "b";
         var element1 = document.getElementById(id1);
         var element2 = document.getElementById(id2);
-        var x1 = element1.getBoundingClientRect().left;
-        var y1 = element1.getBoundingClientRect().top;
-        var x2 = element2.getBoundingClientRect().left;
-        var y2 = element2.getBoundingClientRect().top;
+        var x1 = webkitConvertPointFromNodeToPage(element1, new WebKitPoint(0,0)).x;
+        var y1 = webkitConvertPointFromNodeToPage(element1, new WebKitPoint(0,0)).y;
+        var x2 = webkitConvertPointFromNodeToPage(element2, new WebKitPoint(0,0)).x;
+        var y2 = webkitConvertPointFromNodeToPage(element2, new WebKitPoint(0,0)).y;
 
         var resultString = '';
         if (x1 == x2 && y1 == y2) {
diff --git a/src/third_party/WebKit/LayoutTests/http/tests/dom/crash-on-querying-event-path-expected.txt b/src/third_party/WebKit/LayoutTests/http/tests/dom/crash-on-querying-event-path-expected.txt
new file mode 100644 (file)
index 0000000..35ccbad
--- /dev/null
@@ -0,0 +1,11 @@
+This is a regression test for crbug.com/400476. It should not crash and then brag about it.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+[object NodeList]
+PASS totally did not crash.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/http/tests/dom/crash-on-querying-event-path.html b/src/third_party/WebKit/LayoutTests/http/tests/dom/crash-on-querying-event-path.html
new file mode 100644 (file)
index 0000000..657bf25
--- /dev/null
@@ -0,0 +1,48 @@
+<html>
+<head>
+<script src="/js-test-resources/js-test.js"></script>
+</head>
+<body>
+<script>
+var jsTestIsAsync = true;
+description('This is a regression test for crbug.com/400476. It should not crash and then brag about it.')
+
+var root = document.documentElement;
+var iframe = root.ownerDocument.createElement('iframe');
+var timeouts = [];
+iframe.onload = iframeOnload;
+root.appendChild(iframe);
+
+function iframeOnload() {
+    var defaultView = iframe.contentDocument.defaultView;
+    defaultView.onpageshow = onPageShow;
+    iframe.src = null;
+    timeouts[timeouts.length] = window.setTimeout(nextIframeLoaded, 100);
+}
+
+function onPageShow() {
+    eventObj = arguments[0];
+}
+
+function nextIframeLoaded() {
+    timeouts.forEach(window.clearTimeout);
+
+    // Access of eventObj.path caused the crash.
+    // The test is somewhat flaky, in that the test may pass as correct
+    // despite the bug being the code. The exact conditions
+    // are unclear, but 1, asan helps detect the crash and 2, the
+    // preceeding gc()s increase the likelihood of it occurring.
+    gc();
+    gc();
+    gc();
+    gc();
+    gc();
+    var path = eventObj.path;
+    debug(path);
+
+    testPassed('totally did not crash.');
+    finishJSTest();
+}
+</script>
+</body>
+</html>
diff --git a/src/third_party/WebKit/LayoutTests/http/tests/security/referrer-policy-conflicting-policies-expected.html b/src/third_party/WebKit/LayoutTests/http/tests/security/referrer-policy-conflicting-policies-expected.html
new file mode 100644 (file)
index 0000000..f834b09
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<style>
+test {
+    content: url("http://127.0.0.1:8080/security/resources/green250x50.png");
+}
+</style>
+<body>
+<p>
+Checks that an CSS image that was created before a referrer policy was set is
+loaded with the correct referrer, in this case, without a referrer.
+</p>
+<p>
+The test passes, if a green rectangle is displayed below.
+</p>
+<test/>
+</body>
diff --git a/src/third_party/WebKit/LayoutTests/http/tests/security/referrer-policy-conflicting-policies.html b/src/third_party/WebKit/LayoutTests/http/tests/security/referrer-policy-conflicting-policies.html
new file mode 100644 (file)
index 0000000..380d564
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+document.location = "https://127.0.0.1:8443/security/resources/referrer-policy-conflicting-policies.html";
+</script>
diff --git a/src/third_party/WebKit/LayoutTests/http/tests/security/resources/green-if-no-referrer.php b/src/third_party/WebKit/LayoutTests/http/tests/security/resources/green-if-no-referrer.php
new file mode 100644 (file)
index 0000000..f2f46ef
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+header('Content-Type: image/png');
+if ($_SERVER['HTTP_REFERER'] != '') {
+    $img = 'red200x100.png';
+} else {
+    $img = 'green250x50.png';
+}
+echo file_get_contents($img);
+?>
diff --git a/src/third_party/WebKit/LayoutTests/http/tests/security/resources/referrer-policy-conflicting-policies.html b/src/third_party/WebKit/LayoutTests/http/tests/security/resources/referrer-policy-conflicting-policies.html
new file mode 100644 (file)
index 0000000..2a14dc6
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<script>
+if (window.testRunner)
+    testRunner.setAllowDisplayOfInsecureContent();
+
+function done()
+{
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+</script>
+<style>
+test {
+    content: url("http://127.0.0.1:8080/security/resources/green-if-no-referrer.php");
+}
+</style>
+<meta name="referrer" content="origin" />
+<body onload="done();">
+<p>
+Checks that an CSS image that was created before a referrer policy was set is
+loaded with the correct referrer, in this case, without a referrer.
+</p>
+<p>
+The test passes, if a green rectangle is displayed below.
+</p>
+<test/>
+</body>
index ca23727..4fe242b 100644 (file)
@@ -16,7 +16,7 @@
     var audio = document.getElementById("audio");
     audio.addEventListener("playing", function()
     {
-        runAfterControlsHidden(function()
+        runAfterHideMediaControlsTimerFired(function()
         {
             controls = mediaControlsButton(audio, "panel");
             testExpected("getComputedStyle(controls).opacity", 1);
index 63b9a67..b8159a6 100644 (file)
@@ -118,7 +118,7 @@ function clickCCButton()
     eventSender.mouseUp();
 }
 
-function runAfterControlsHidden(func, mediaElement)
+function runAfterHideMediaControlsTimerFired(func, mediaElement)
 {
     if (mediaElement.paused)
         throw "The media element is not playing";
diff --git a/src/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered-expected.txt b/src/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered-expected.txt
new file mode 100644 (file)
index 0000000..8765b6a
--- /dev/null
@@ -0,0 +1,10 @@
+Test video element control visibility after click on control. After the click the mouse does not move, so the control is still hovered and it should remain visible.
+
+This test only runs in DRT!
+
+EXPECTED (video.paused == 'true') OK
+EXPECTED (video.paused == 'false') OK
+EXPECTED (getComputedStyle(controls).opacity == '1') OK
+
+END OF TEST
+
diff --git a/src/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered.html b/src/third_party/WebKit/LayoutTests/media/video-controls-always-visible-when-control-hovered.html
new file mode 100644 (file)
index 0000000..6816241
--- /dev/null
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<style>
+#no-video-media {
+  width: 320px;
+  height: 240px;
+}
+</style>
+<script src=video-test.js></script>
+<script src=media-file.js></script>
+<script src=media-controls.js></script>
+<script>
+var controls;
+
+function runTest()
+{
+    video = document.getElementById("no-video-media");
+
+    testExpected("video.paused", true);
+    if (!window.testRunner)
+        return;
+
+    // Click the play button.
+    var playCoords = mediaControlsButtonCoordinates(video, "play-button");
+    var clickX = playCoords[0];
+    var clickY = playCoords[1];
+    eventSender.mouseMoveTo(clickX, clickY);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    testExpected("video.paused", false);
+
+    runAfterHideMediaControlsTimerFired(function()
+    {
+        controls = mediaControlsButton(video, "panel");
+        testExpected("getComputedStyle(controls).opacity", 1);
+
+        consoleWrite("");
+        endTest();
+    }, video);
+}
+</script>
+<body>
+    <p>Test video element control visibility after click on control. After the click
+       the mouse does not move, so the control is still hovered and it should
+       remain visible.</p>
+    <p>This test only runs in DRT!</p>
+
+    <video id="no-video-media" controls loop oncanplaythrough="runTest()"></video>
+    <script>
+        setSrcById("no-video-media", findMediaFile("video", "content/test"));
+    </script>
+</body>
+</html>
index 38d37d4..d01c491 100644 (file)
@@ -21,7 +21,7 @@ video.addEventListener("canplay", function()
 
     testExpected("document.activeElement", video);
 
-    runAfterControlsHidden(function()
+    runAfterHideMediaControlsTimerFired(function()
     {
         controls = mediaControlsButton(video, "panel");
         testExpected("getComputedStyle(controls).opacity", 0);
diff --git a/src/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control-expected.txt b/src/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control-expected.txt
new file mode 100644 (file)
index 0000000..d8a3722
--- /dev/null
@@ -0,0 +1,10 @@
+Test video element control visibility after touch on control. After a delay the controls must be hidden.
+
+This test only runs in DRT!
+
+EXPECTED (video.paused == 'true') OK
+EXPECTED (video.paused == 'false') OK
+EXPECTED (getComputedStyle(controls).opacity == '0') OK
+
+END OF TEST
+
diff --git a/src/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control.html b/src/third_party/WebKit/LayoutTests/media/video-controls-hide-after-touch-on-control.html
new file mode 100644 (file)
index 0000000..7715602
--- /dev/null
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<style>
+#no-video-media {
+  width: 320px;
+  height: 240px;
+}
+</style>
+<script src=video-test.js></script>
+<script src=media-file.js></script>
+<script src=media-controls.js></script>
+<script>
+var controls;
+
+function runTest()
+{
+    video = document.getElementById("no-video-media");
+
+    testExpected("video.paused", true);
+    if (!window.testRunner)
+        return;
+
+    // Click the play button.
+    var playCoords = mediaControlsButtonCoordinates(video, "play-button");
+    var clickX = playCoords[0];
+    var clickY = playCoords[1];
+    eventSender.mouseMoveTo(clickX, clickY);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+    testExpected("video.paused", false);
+
+    runAfterHideMediaControlsTimerFired(function()
+    {
+        controls = mediaControlsButton(video, "panel");
+        testExpected("getComputedStyle(controls).opacity", 0);
+
+        consoleWrite("");
+        endTest();
+    }, video);
+}
+</script>
+<body>
+    <p>Test video element control visibility after touch on control. After a delay the
+       controls must be hidden.</p>
+    <p>This test only runs in DRT!</p>
+
+    <video id="no-video-media" controls loop oncanplaythrough="runTest()"></video>
+    <script>
+        window.internals.settings.setDeviceSupportsMouse(false);
+        setSrcById("no-video-media", findMediaFile("video", "content/test"));
+    </script>
+</body>
+</html>
index bbd2724..1e0cff1 100644 (file)
@@ -29,7 +29,7 @@ function runTest()
     eventSender.mouseUp();
     testExpected("video.paused", false);
 
-    runAfterControlsHidden(function()
+    runAfterHideMediaControlsTimerFired(function()
     {
         controls = mediaControlsButton(video, "panel");
         testExpected("getComputedStyle(controls).opacity", 0);
index 42e3691..402c33a 100644 (file)
@@ -13,7 +13,7 @@ var video = document.querySelector("video");
 
 video.addEventListener("playing", function()
 {
-    runAfterControlsHidden(function()
+    runAfterHideMediaControlsTimerFired(function()
     {
         controls = mediaControlsButton(video, "panel");
 
index 55d6d92..dc7f19b 100644 (file)
@@ -51,7 +51,7 @@
         {
             switch (count) {
                 case 0:
-                    runAfterControlsHidden(continueTest, video);
+                    runAfterHideMediaControlsTimerFired(continueTest, video);
                     break;
                 case 1:
                     consoleWrite("");
diff --git a/src/third_party/WebKit/LayoutTests/platform/linux/fast/dom/Window/webkitConvertPoint-expected.txt b/src/third_party/WebKit/LayoutTests/platform/linux/fast/dom/Window/webkitConvertPoint-expected.txt
new file mode 100644 (file)
index 0000000..63ceabf
--- /dev/null
@@ -0,0 +1,200 @@
+Test 1 - This is a H1 heading.
+
+Test 2 - This is a simple paragraph.
+
+Test 3 - This is a paragraph with a nested element.
+
+Test 4 - This is a paragraph with a nested element that has a border.
+
+Test 5 - This is a transformed paragraph with a nested element that has a border.
+
+Test 6 - This is a transformed paragraph with a nested element that has a border.
+And then a second line.
+
+Test 7 - This is a paragraph inside something that does not have a compositing layer.
+
+Test 8 - This is raw text inside something that does not have a compositing layer.
+Test 9 - This is raw text inside something that has a compositing layer.
+Test 10 - This is raw text inside something that does not have a compositing layer.
+Test 11 - This is a rotated and scaled paragraph
+
+Test 12 - This is a rotated and scaled paragraph with a nested element that has a border.
+
+Test 13 - This is a paragraph with a nested element that has a border.
+
+This test exercises the webkitConvertPointFromNodeToPage() function
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Test parameter passing - should not crash
+PASS Missing parameter test
+Test did not crash and therefore was successful
+
+PASS null parameter test a
+Test did not crash and therefore was successful
+
+PASS null parameter test b
+Test did not crash and therefore was successful
+
+Test 1
+PASS x is 8
+PASS y is 13
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+PASS y is 53
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 2
+PASS x is 8
+FAIL y should be 51. Was 52.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 91. Was 92.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 3
+PASS x is 8
+FAIL y should be 85. Was 88.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 125. Was 128.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 4
+PASS x is 8
+FAIL y should be 119. Was 124.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 159. Was 164.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 5
+PASS x is 28
+FAIL y should be 153. Was 160.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 193. Was 200.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 6
+PASS x is 28
+FAIL y should be 187. Was 196.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 227. Was 236.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 7
+PASS x is 8
+FAIL y should be 239. Was 252.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 279. Was 292.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 8
+PASS x is 8
+FAIL y should be 273. Was 288.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 313. Was 328.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 9
+PASS x is 28
+FAIL y should be 291. Was 308.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 331. Was 348.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 10
+PASS x is 28
+FAIL y should be 309. Was 328.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 349. Was 368.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 11
+PASS x is 158
+PASS y is 376
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 174
+PASS y is 394
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 12
+PASS x is 168
+PASS y is 451
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 184
+PASS y is 469
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 13
+PASS x is 28
+FAIL y should be 487. Was 512.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 527. Was 552.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/platform/win-xp/fast/dom/Window/webkitConvertPoint-expected.txt b/src/third_party/WebKit/LayoutTests/platform/win-xp/fast/dom/Window/webkitConvertPoint-expected.txt
new file mode 100644 (file)
index 0000000..63ceabf
--- /dev/null
@@ -0,0 +1,200 @@
+Test 1 - This is a H1 heading.
+
+Test 2 - This is a simple paragraph.
+
+Test 3 - This is a paragraph with a nested element.
+
+Test 4 - This is a paragraph with a nested element that has a border.
+
+Test 5 - This is a transformed paragraph with a nested element that has a border.
+
+Test 6 - This is a transformed paragraph with a nested element that has a border.
+And then a second line.
+
+Test 7 - This is a paragraph inside something that does not have a compositing layer.
+
+Test 8 - This is raw text inside something that does not have a compositing layer.
+Test 9 - This is raw text inside something that has a compositing layer.
+Test 10 - This is raw text inside something that does not have a compositing layer.
+Test 11 - This is a rotated and scaled paragraph
+
+Test 12 - This is a rotated and scaled paragraph with a nested element that has a border.
+
+Test 13 - This is a paragraph with a nested element that has a border.
+
+This test exercises the webkitConvertPointFromNodeToPage() function
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Test parameter passing - should not crash
+PASS Missing parameter test
+Test did not crash and therefore was successful
+
+PASS null parameter test a
+Test did not crash and therefore was successful
+
+PASS null parameter test b
+Test did not crash and therefore was successful
+
+Test 1
+PASS x is 8
+PASS y is 13
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+PASS y is 53
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 2
+PASS x is 8
+FAIL y should be 51. Was 52.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 91. Was 92.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 3
+PASS x is 8
+FAIL y should be 85. Was 88.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 125. Was 128.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 4
+PASS x is 8
+FAIL y should be 119. Was 124.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 159. Was 164.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 5
+PASS x is 28
+FAIL y should be 153. Was 160.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 193. Was 200.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 6
+PASS x is 28
+FAIL y should be 187. Was 196.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 227. Was 236.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 7
+PASS x is 8
+FAIL y should be 239. Was 252.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 279. Was 292.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 8
+PASS x is 8
+FAIL y should be 273. Was 288.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 13
+FAIL y should be 313. Was 328.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 9
+PASS x is 28
+FAIL y should be 291. Was 308.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 331. Was 348.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 10
+PASS x is 28
+FAIL y should be 309. Was 328.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 349. Was 368.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 11
+PASS x is 158
+PASS y is 376
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 174
+PASS y is 394
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 12
+PASS x is 168
+PASS y is 451
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 184
+PASS y is 469
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+
+Test 13
+PASS x is 28
+FAIL y should be 487. Was 512.
+Round Trip of (0,0)
+PASS x is 0
+PASS y is 0
+PASS x is 33
+FAIL y should be 527. Was 552.
+Round Trip of (5,40)
+PASS x is 5
+PASS y is 40
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/src/third_party/WebKit/LayoutTests/plugins/page-scale-does-not-affect-plugin-height-expected.txt b/src/third_party/WebKit/LayoutTests/plugins/page-scale-does-not-affect-plugin-height-expected.txt
new file mode 100644 (file)
index 0000000..e9af805
--- /dev/null
@@ -0,0 +1,6 @@
+This test checks that page scale does not affect a plugin object's height when it depends on the window height. The test scales the page and is considered to pass if the embed object occupies the full height of the window.
+
+EXPECTED:
+layer at (0,0) size 800x600 RenderEmbeddedObject {EMBED} at (0,0) size 800x600
+ACTUAL:
+layer at (0,0) size 800x600 RenderEmbeddedObject {EMBED} at (0,0) size 800x600
diff --git a/src/third_party/WebKit/LayoutTests/plugins/page-scale-does-not-affect-plugin-height.html b/src/third_party/WebKit/LayoutTests/plugins/page-scale-does-not-affect-plugin-height.html
new file mode 100644 (file)
index 0000000..2bed464
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script>
+  function runTest() {
+    if (window.testRunner)
+      testRunner.dumpAsText();
+
+    if (window.eventSender)
+      window.eventSender.setPageScaleFactor(1.5, 0, 0);
+
+    document.body.innerHTML =
+      "This test checks that page scale does not affect a plugin object's height when it depends on the window height."
+      + " The test scales the page and is considered to pass if the embed object occupies the full height of the window."
+      + "<br>"
+      + "<br>"
+      + "EXPECTED:<br>"
+      + "layer at (0,0) size 800x600 RenderEmbeddedObject {EMBED} at (0,0) size 800x600<br>"
+      + "ACTUAL:<br>"
+      + internals.elementRenderTreeAsText(document.getElementById('box'));
+  }
+</script>
+<style>
+html, body {
+  height: 100%;
+}
+</style>
+<body style="margin: 0px; overflow: hidden" onload="runTest()">
+  <embed id="box" width="100%" height="100%" name="plugin" src="fileDoesNotExist.pdf" type="application/pdf"></embed>
+</body>
index 3e3ead5..f65fd62 100644 (file)
@@ -35,10 +35,10 @@ function runTest() {
         var id2 = "b";
         var element1 = document.getElementById(id1);
         var element2 = document.getElementById(id2);
-        var x1 = element1.getBoundingClientRect().left;
-        var y1 = element1.getBoundingClientRect().top;
-        var x2 = element2.getBoundingClientRect().left;
-        var y2 = element2.getBoundingClientRect().top;
+        var x1 = webkitConvertPointFromNodeToPage(element1, new WebKitPoint(0,0)).x;
+        var y1 = webkitConvertPointFromNodeToPage(element1, new WebKitPoint(0,0)).y;
+        var x2 = webkitConvertPointFromNodeToPage(element2, new WebKitPoint(0,0)).x;
+        var y2 = webkitConvertPointFromNodeToPage(element2, new WebKitPoint(0,0)).y;
 
         var resultString = '';
         if (x1 == x2 && y1 == y2) {
index bf5a173..3ab525f 100644 (file)
@@ -14,7 +14,7 @@
 
 function checkPosition(id) {
     var element = document.getElementById(id);
-    var y = element.getBoundingClientRect().top;
+    var y = webkitConvertPointFromNodeToPage(element, new WebKitPoint(0,0)).y;
 
     var resultString = '';
     if (y > 250) {
index 3280112..a9ce8b0 100644 (file)
@@ -35,10 +35,10 @@ function runTest() {
         var id2 = "b";
         var element1 = document.getElementById(id1);
         var element2 = document.getElementById(id2);
-        var x1 = element1.getBoundingClientRect().left;
-        var y1 = element1.getBoundingClientRect().top;
-        var x2 = element2.getBoundingClientRect().left;
-        var y2 = element2.getBoundingClientRect().top;
+        var x1 = webkitConvertPointFromNodeToPage(element1, new WebKitPoint(0,0)).x;
+        var y1 = webkitConvertPointFromNodeToPage(element1, new WebKitPoint(0,0)).y;
+        var x2 = webkitConvertPointFromNodeToPage(element2, new WebKitPoint(0,0)).x;
+        var y2 = webkitConvertPointFromNodeToPage(element2, new WebKitPoint(0,0)).y;
 
         var resultString = '';
         if (x1 == x2 && y1 == y2) {
index 59f585b..d163f4f 100644 (file)
@@ -37,10 +37,10 @@ function runTest() {
         var id2 = "b";
         var element1 = document.getElementById(id1);
         var element2 = document.getElementById(id2);
-        var x1 = element1.getBoundingClientRect().left;
-        var y1 = element1.getBoundingClientRect().top;
-        var x2 = element2.getBoundingClientRect().left;
-        var y2 = element2.getBoundingClientRect().top;
+        var x1 = webkitConvertPointFromNodeToPage(element1, new WebKitPoint(0,0)).x;
+        var y1 = webkitConvertPointFromNodeToPage(element1, new WebKitPoint(0,0)).y;
+        var x2 = webkitConvertPointFromNodeToPage(element2, new WebKitPoint(0,0)).x;
+        var y2 = webkitConvertPointFromNodeToPage(element2, new WebKitPoint(0,0)).y;
 
         var resultString = '';
         if (x1 == x2 && y1 == y2) {
index 7f86d7e..4b57020 100644 (file)
@@ -1602,6 +1602,34 @@ unsigned short Node::compareDocumentPosition(const Node* otherNode, ShadowTreesT
                DOCUMENT_POSITION_PRECEDING | DOCUMENT_POSITION_CONTAINS | connection;
 }
 
+FloatPoint Node::convertToPage(const FloatPoint& p) const
+{
+    // If there is a renderer, just ask it to do the conversion
+    if (renderer())
+        return renderer()->localToAbsolute(p, UseTransforms);
+
+    // Otherwise go up the tree looking for a renderer
+    if (Element* parent = parentElement())
+        return parent->convertToPage(p);
+
+    // No parent - no conversion needed
+    return p;
+}
+
+FloatPoint Node::convertFromPage(const FloatPoint& p) const
+{
+    // If there is a renderer, just ask it to do the conversion
+    if (renderer())
+        return renderer()->absoluteToLocal(p, UseTransforms);
+
+    // Otherwise go up the tree looking for a renderer
+    if (Element* parent = parentElement())
+        return parent->convertFromPage(p);
+
+    // No parent - no conversion needed
+    return p;
+}
+
 String Node::debugName() const
 {
     StringBuilder name;
index 43d17ee..a6ec7bf 100644 (file)
@@ -486,6 +486,10 @@ public:
     // Whether or not a selection can be started in this object
     virtual bool canStartSelection() const;
 
+    // Getting points into and out of screen space
+    FloatPoint convertToPage(const FloatPoint&) const;
+    FloatPoint convertFromPage(const FloatPoint&) const;
+
     // -----------------------------------------------------------------------------
     // Integration with rendering tree
 
index 471396f..60a3a47 100644 (file)
@@ -25,6 +25,7 @@
 #include "config.h"
 #include "core/dom/TreeScopeAdopter.h"
 
+#include "core/accessibility/AXObjectCache.h"
 #include "core/dom/Attr.h"
 #include "core/dom/NodeRareData.h"
 #include "core/dom/NodeTraversal.h"
@@ -48,15 +49,18 @@ void TreeScopeAdopter::moveTreeToNewScope(Node& root) const
     Document& oldDocument = oldScope().document();
     Document& newDocument = newScope().document();
     bool willMoveToNewDocument = oldDocument != newDocument;
+    AXObjectCache* axObjectCache = oldDocument.existingAXObjectCache();
     if (willMoveToNewDocument)
         oldDocument.incDOMTreeVersion();
 
     for (Node* node = &root; node; node = NodeTraversal::next(*node, &root)) {
         updateTreeScope(*node);
 
-        if (willMoveToNewDocument)
+        if (willMoveToNewDocument) {
+            if (axObjectCache)
+                axObjectCache->remove(node);
             moveNodeToNewDocument(*node, oldDocument, newDocument);
-        else if (node->hasRareData()) {
+        else if (node->hasRareData()) {
             NodeRareData* rareData = node->rareData();
             if (rareData->nodeLists())
                 rareData->nodeLists()->adoptTreeScope();
index 06424f2..8bdff9f 100644 (file)
@@ -192,7 +192,7 @@ IntRect CaretBase::absoluteBoundsForLocalRect(Node* node, const LayoutRect& rect
     return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
 }
 
-void CaretBase::repaintCaretForLocalRect(Node* node, const LayoutRect& rect)
+void CaretBase::invalidateLocalCaretRect(Node* node, const LayoutRect& rect)
 {
     RenderBlock* caretPainter = caretRenderer(node);
     if (!caretPainter)
@@ -237,7 +237,7 @@ void CaretBase::invalidateCaretRect(Node* node, bool caretRectChanged)
 
     if (RenderView* view = node->document().renderView()) {
         if (shouldRepaintCaret(view, node->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable)))
-            repaintCaretForLocalRect(node, localCaretRectWithoutUpdate());
+            invalidateLocalCaretRect(node, localCaretRectWithoutUpdate());
     }
 }
 
index 674adf0..fa2b36c 100644 (file)
@@ -68,7 +68,7 @@ protected:
 
 protected:
     static RenderBlock* caretRenderer(Node*);
-    static void repaintCaretForLocalRect(Node*, const LayoutRect&);
+    static void invalidateLocalCaretRect(Node*, const LayoutRect&);
 
 private:
     LayoutRect m_caretLocalRect; // caret rect in coords local to the renderer responsible for painting the caret
index 68f9d09..cd4cb26 100644 (file)
@@ -197,10 +197,14 @@ int DOMSelection::rangeCount() const
 
 void DOMSelection::collapse(Node* node, int offset, ExceptionState& exceptionState)
 {
-    ASSERT(node);
     if (!m_frame)
         return;
 
+    if (!node) {
+        m_frame->selection().clear();
+        return;
+    }
+
     if (offset < 0) {
         exceptionState.throwDOMException(IndexSizeError, String::number(offset) + " is not a valid offset.");
         return;
index 7427627..e347a61 100644 (file)
@@ -1252,15 +1252,6 @@ static LayoutRect localCaretRect(const VisibleSelection& m_selection, const Posi
     return localCaretRectOfPosition(caretPosition, renderer);
 }
 
-static void invalidateLocalCaretRect(RenderObject* renderer, const LayoutRect& caretRect)
-{
-    // FIXME: Need to over-paint 1 pixel to workaround some rounding problems.
-    // https://bugs.webkit.org/show_bug.cgi?id=108283
-    LayoutRect inflatedRect = caretRect;
-    inflatedRect.inflate(1);
-    renderer->invalidatePaintRectangle(inflatedRect);
-}
-
 void FrameSelection::invalidateCaretRect()
 {
     if (!m_caretRectDirty)
@@ -1276,9 +1267,9 @@ void FrameSelection::invalidateCaretRect()
 
     RenderView* view = m_frame->document()->renderView();
     if (m_previousCaretNode && shouldRepaintCaret(view, m_previousCaretNode->isContentEditable()))
-        invalidateLocalCaretRect(m_previousCaretNode->renderer(), m_previousCaretRect);
+        invalidateLocalCaretRect(m_previousCaretNode.get(), m_previousCaretRect);
     if (newNode && shouldRepaintCaret(view, newNode->isContentEditable()))
-        invalidateLocalCaretRect(newNode->renderer(), newRect);
+        invalidateLocalCaretRect(newNode, newRect);
 
     m_previousCaretNode = newNode;
     m_previousCaretRect = newRect;
@@ -1588,6 +1579,8 @@ void FrameSelection::updateAppearance(ResetCaretBlinkOption option)
         return;
     }
 
+    m_frame->document()->updateLayoutIgnorePendingStylesheets();
+
     // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
     // Example: foo <a>bar</a>.  Imagine that a line wrap occurs after 'foo', and that 'bar' is selected.   If we pass [foo, 3]
     // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
index 826203a..0327f5a 100644 (file)
@@ -9,6 +9,7 @@
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
 #include "core/dom/Text.h"
+#include "core/frame/FrameView.h"
 #include "core/html/HTMLBodyElement.h"
 #include "core/html/HTMLDocument.h"
 #include "core/testing/DummyPageHolder.h"
@@ -29,7 +30,7 @@ protected:
 
     HTMLDocument& document() const;
     void setSelection(const VisibleSelection&);
-    const FrameSelection& selection() const;
+    FrameSelection& selection() const;
     Text* textNode() { return m_textNode.get(); }
 
 private:
@@ -57,7 +58,7 @@ void FrameSelectionTest::setSelection(const VisibleSelection& newSelection)
     m_dummyPageHolder->frame().selection().setSelection(newSelection);
 }
 
-const FrameSelection& FrameSelectionTest::selection() const
+FrameSelection& FrameSelectionTest::selection() const
 {
     return m_dummyPageHolder->frame().selection();
 }
@@ -89,4 +90,23 @@ TEST_F(FrameSelectionTest, SetInvalidSelection)
     EXPECT_TRUE(selection().isNone());
 }
 
+TEST_F(FrameSelectionTest, InvalidateCaretRect)
+{
+    document().view()->updateLayoutAndStyleIfNeededRecursive();
+
+    VisibleSelection validSelection(Position(textNode(), 0), Position(textNode(), 0));
+    setSelection(validSelection);
+    selection().setCaretRectNeedsUpdate();
+    EXPECT_TRUE(selection().isCaretBoundsDirty());
+    selection().invalidateCaretRect();
+    EXPECT_FALSE(selection().isCaretBoundsDirty());
+
+    document().body()->removeChild(textNode());
+    document().updateLayoutIgnorePendingStylesheets();
+    selection().setCaretRectNeedsUpdate();
+    EXPECT_TRUE(selection().isCaretBoundsDirty());
+    selection().invalidateCaretRect();
+    EXPECT_FALSE(selection().isCaretBoundsDirty());
+}
+
 }
index 08778f4..9737d82 100644 (file)
@@ -331,6 +331,9 @@ void InputMethodController::setCompositionFromExistingText(const Vector<Composit
 
         m_compositionNode = toText(baseNode);
         RefPtrWillBeRawPtr<Range> range = PlainTextRange(compositionStart, compositionEnd).createRange(*editable);
+        if (!range)
+            return;
+
         m_compositionStart = range->startOffset();
         m_compositionEnd = range->endOffset();
         m_customCompositionUnderlines = underlines;
index c191bac..cf3a678 100644 (file)
@@ -129,4 +129,15 @@ TEST_F(InputMethodControllerTest, SetCompositionFromExistingTextWithCollapsedWhi
     EXPECT_EQ(5u, plainTextRange.end());
 }
 
+TEST_F(InputMethodControllerTest, SetCompositionFromExistingTextWithInvalidOffsets)
+{
+    insertHTMLElement("<div id='sample' contenteditable='true'>test</div>", "sample");
+
+    Vector<CompositionUnderline> underlines;
+    underlines.append(CompositionUnderline(7, 8, Color(255, 0, 0), false, 0));
+    controller().setCompositionFromExistingText(underlines, 7, 8);
+
+    EXPECT_FALSE(controller().compositionRange());
+}
+
 } // namespace
index dc27b0d..bd333da 100644 (file)
@@ -45,7 +45,7 @@
     readonly attribute long focusOffset;
 
     readonly attribute boolean isCollapsed;
-    [RaisesException, TypeChecking=Interface] void collapse(Node node, optional long offset);
+    [RaisesException] void collapse(Node? node, optional long offset);
     [RaisesException] void collapseToStart();
     [RaisesException] void collapseToEnd();
 
@@ -87,8 +87,7 @@
                                                                                  [Default=Undefined] optional long baseOffset,
                                                                                  [Default=Undefined] optional Node extentNode,
                                                                                  [Default=Undefined] optional long extentOffset);
-    [ImplementedAs=collapse, MeasureAs=SelectionSetPosition, RaisesException, TypeChecking=Interface] void setPosition(Node node,
-                                                                                                                       optional long offset);
+    [ImplementedAs=collapse, MeasureAs=SelectionSetPosition, RaisesException] void setPosition(Node? node, optional long offset);
 
     // IE extensions
     // http://msdn.microsoft.com/en-us/library/ms535869(VS.85).aspx
index f39236e..ea99d75 100644 (file)
@@ -255,7 +255,7 @@ EventTarget* Event::currentTarget() const
         if (SVGElement* svgElement = toSVGElement(node)->correspondingElement())
             return svgElement;
     }
-    return m_currentTarget;
+    return m_currentTarget.get();
 }
 
 void Event::trace(Visitor* visitor)
index 2a91721..0220d7a 100644 (file)
@@ -204,7 +204,7 @@ private:
     bool m_cancelBubble;
 
     unsigned short m_eventPhase;
-    RawPtrWillBeMember<EventTarget> m_currentTarget;
+    RefPtrWillBeMember<EventTarget> m_currentTarget;
     RefPtrWillBeMember<EventTarget> m_target;
     DOMTimeStamp m_createTime;
     RefPtrWillBeMember<Event> m_underlyingEvent;
index a7d1d80..800a6da 100644 (file)
@@ -141,10 +141,10 @@ File::File(const String& name, double modificationTime, PassRefPtr<BlobDataHandl
     ScriptWrappable::init(this);
 }
 
-File::File(const String& name, const FileMetadata& metadata)
+File::File(const String& name, const FileMetadata& metadata, UserVisibility userVisibility)
     : Blob(BlobDataHandle::create(createBlobDataForFileWithMetadata(name, metadata), metadata.length))
     , m_hasBackingFile(true)
-    , m_userVisibility(File::IsNotUserVisible)
+    , m_userVisibility(userVisibility)
     , m_path(metadata.platformPath)
     , m_name(name)
     , m_snapshotSize(metadata.length)
index 9b195a3..166a3eb 100644 (file)
@@ -76,9 +76,9 @@ public:
     // If filesystem files live in the remote filesystem, the port might pass the valid metadata (whose length field is non-negative) and cache in the File object.
     //
     // Otherwise calling size(), lastModifiedTime() and slice() will synchronously query the file metadata.
-    static PassRefPtrWillBeRawPtr<File> createForFileSystemFile(const String& name, const FileMetadata& metadata)
+    static PassRefPtrWillBeRawPtr<File> createForFileSystemFile(const String& name, const FileMetadata& metadata, UserVisibility userVisibility)
     {
-        return adoptRefWillBeNoop(new File(name, metadata));
+        return adoptRefWillBeNoop(new File(name, metadata, userVisibility));
     }
 
     static PassRefPtrWillBeRawPtr<File> createForFileSystemFile(const KURL& url, const FileMetadata& metadata)
@@ -139,7 +139,7 @@ private:
     File(const String& path, const String& name, ContentTypeLookupPolicy, UserVisibility);
     File(const String& path, const String& name, const String& relativePath, UserVisibility, bool hasSnaphotData, uint64_t size, double lastModified, PassRefPtr<BlobDataHandle>);
     File(const String& name, double modificationTime, PassRefPtr<BlobDataHandle>);
-    File(const String& name, const FileMetadata&);
+    File(const String& name, const FileMetadata&, UserVisibility);
     File(const KURL& fileSystemURL, const FileMetadata&);
 
     void invalidateSnapshotMetadata() { m_snapshotSize = -1; }
index 36361c2..9ca0c46 100644 (file)
@@ -243,6 +243,10 @@ const AtomicString& FileReader::interfaceName() const
 
 void FileReader::stop()
 {
+    // The delayed abort task tidies up and advances to the DONE state.
+    if (m_loadingState == LoadingStateAborted)
+        return;
+
     if (hasPendingActivity())
         ThrottlingController::finishReader(executionContext(), this, ThrottlingController::removeReader(executionContext(), this));
     terminate();
index 3b686e1..c97e3b1 100644 (file)
@@ -121,6 +121,7 @@ FrameView::FrameView(LocalFrame* frame)
     , m_inputEventsScaleFactorForEmulation(1)
     , m_layoutSizeFixedToFrameSize(true)
     , m_didScrollTimer(this, &FrameView::didScrollTimerFired)
+    , m_needsUpdateWidgetPositions(false)
 {
     ASSERT(m_frame);
     init();
@@ -2649,6 +2650,16 @@ void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& hori
     ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
 }
 
+void FrameView::updateWidgetPositionsIfNeeded()
+{
+    if (!m_needsUpdateWidgetPositions)
+        return;
+
+    m_needsUpdateWidgetPositions = false;
+
+    updateWidgetPositions();
+}
+
 void FrameView::updateLayoutAndStyleForPainting()
 {
     // Updating layout can run script, which can tear down the FrameView.
@@ -2656,6 +2667,8 @@ void FrameView::updateLayoutAndStyleForPainting()
 
     updateLayoutAndStyleIfNeededRecursive();
 
+    updateWidgetPositionsIfNeeded();
+
     if (RenderView* view = renderView()) {
         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateLayerTree", "frame", m_frame.get());
         // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
index f9c4758..0593976 100644 (file)
@@ -102,6 +102,8 @@ public:
     bool needsLayout() const;
     void setNeedsLayout();
 
+    void setNeedsUpdateWidgetPositions() { m_needsUpdateWidgetPositions = true; }
+
     // Methods for getting/setting the size Blink should use to layout the contents.
     IntSize layoutSize(IncludeScrollbarsInRect = ExcludeScrollbars) const;
     void setLayoutSize(const IntSize&);
@@ -369,6 +371,8 @@ private:
     virtual IntPoint convertToContainingView(const IntPoint&) const OVERRIDE;
     virtual IntPoint convertFromContainingView(const IntPoint&) const OVERRIDE;
 
+    void updateWidgetPositionsIfNeeded();
+
     void sendResizeEventIfNeeded();
 
     void updateScrollableAreaSet();
@@ -498,6 +502,8 @@ private:
     Timer<FrameView> m_didScrollTimer;
 
     Vector<IntRect> m_tickmarks;
+
+    bool m_needsUpdateWidgetPositions;
 };
 
 inline void FrameView::incrementVisuallyNonEmptyCharacterCount(unsigned count)
index 913ae18..fedf3d1 100644 (file)
@@ -69,6 +69,7 @@
 #include "core/frame/Navigator.h"
 #include "core/frame/Screen.h"
 #include "core/frame/Settings.h"
+#include "core/frame/WebKitPoint.h"
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/inspector/InspectorInstrumentation.h"
@@ -1341,6 +1342,36 @@ PassRefPtrWillBeRawPtr<CSSRuleList> LocalDOMWindow::getMatchedCSSRules(Element*
     return m_frame->document()->ensureStyleResolver().pseudoCSSRulesForElement(element, pseudoId, rulesToInclude);
 }
 
+PassRefPtrWillBeRawPtr<WebKitPoint> LocalDOMWindow::webkitConvertPointFromNodeToPage(Node* node, const WebKitPoint* p) const
+{
+    if (!node || !p)
+        return nullptr;
+
+    if (!document())
+        return nullptr;
+
+    document()->updateLayoutIgnorePendingStylesheets();
+
+    FloatPoint pagePoint(p->x(), p->y());
+    pagePoint = node->convertToPage(pagePoint);
+    return WebKitPoint::create(pagePoint.x(), pagePoint.y());
+}
+
+PassRefPtrWillBeRawPtr<WebKitPoint> LocalDOMWindow::webkitConvertPointFromPageToNode(Node* node, const WebKitPoint* p) const
+{
+    if (!node || !p)
+        return nullptr;
+
+    if (!document())
+        return nullptr;
+
+    document()->updateLayoutIgnorePendingStylesheets();
+
+    FloatPoint nodePoint(p->x(), p->y());
+    nodePoint = node->convertFromPage(nodePoint);
+    return WebKitPoint::create(nodePoint.x(), nodePoint.y());
+}
+
 double LocalDOMWindow::devicePixelRatio() const
 {
     if (!m_frame)
index 9a587cd..1521dd7 100644 (file)
@@ -44,6 +44,7 @@ namespace blink {
     class CSSRuleList;
     class CSSStyleDeclaration;
     class Console;
+    class WebKitPoint;
     class DOMSelection;
     class DOMURL;
     class DOMWindowProperty;
@@ -218,6 +219,9 @@ enum PageshowEventPersistence {
         PassRefPtrWillBeRawPtr<CSSRuleList> getMatchedCSSRules(Element*, const String& pseudoElt) const;
         double devicePixelRatio() const;
 
+        PassRefPtrWillBeRawPtr<WebKitPoint> webkitConvertPointFromPageToNode(Node*, const WebKitPoint*) const;
+        PassRefPtrWillBeRawPtr<WebKitPoint> webkitConvertPointFromNodeToPage(Node*, const WebKitPoint*) const;
+
         Console& console() const;
         FrameConsole* frameConsole() const;
 
index 2ab44fc..eb171ce 100644 (file)
@@ -206,6 +206,7 @@ public:
         InputTypeTextMaxLength = 191,
         InputTypePassword = 192,
         InputTypePasswordMaxLength = 193,
+        SVGInstanceRoot = 194,
         ShowModalDialog = 195,
         PrefixedPageVisibility = 196,
         CSSStyleSheetInsertRuleOptionalArg = 198, // Inconsistent with the specification and other browsers.
@@ -262,9 +263,14 @@ public:
         DeprecatedWebKitRepeatingRadialGradient = 264,
         PrefixedImageSmoothingEnabled = 267,
         UnprefixedImageSmoothingEnabled = 268,
+        PromiseConstructor = 270,
+        PromiseCast = 271,
+        PromiseReject = 272,
+        PromiseResolve = 273,
         // The above items are available in M34 branch.
 
         TextAutosizing = 274,
+        TextAutosizingLayout = 275,
         HTMLAnchorElementPingAttribute = 276,
         InsertAdjacentHTML = 278,
         SVGClassName = 279,
@@ -315,6 +321,7 @@ public:
         // The above items are available in M35 branch.
 
         SVGForeignObjectElement = 325,
+        PrefixedElementRequestPointerLock = 326,
         SelectionSetPosition = 327,
         AnimationPlayerFinishEvent = 328,
         SVGSVGElementInXMLDocument = 329,
@@ -347,6 +354,8 @@ public:
         WindowOffscreenBuffering = 356,
         WindowDefaultStatus = 357,
         WindowDefaultstatus = 358,
+        PrefixedConvertPointFromPageToNode = 359,
+        PrefixedConvertPointFromNodeToPage = 360,
         PrefixedTransitionEventConstructor = 361,
         PrefixedMutationObserverConstructor = 362,
         PrefixedIDBCursorConstructor = 363,
@@ -361,6 +370,8 @@ public:
         RangeDetach = 372,
         HTMLTableElementVspace = 374,
         HTMLTableElementHspace = 375,
+        PrefixedDocumentExitPointerLock = 376,
+        PrefixedDocumentPointerLockElement = 377,
         PrefixedTouchRadiusX = 378,
         PrefixedTouchRadiusY = 379,
         PrefixedTouchRotationAngle = 380,
@@ -407,10 +418,11 @@ public:
         TextEncoderConstructor = 429,
         TextEncoderEncode = 430,
         TextDecoderConstructor = 431,
-        TextDecoderDecode = 432,
+        TextDecoderDecode= 432,
         FocusInOutEvent = 433,
         MouseEventMovementX = 434,
         MouseEventMovementY = 435,
+        MixedContentTextTrack = 436,
         MixedContentRaw = 437,
         MixedContentImage = 438,
         MixedContentMedia = 439,
@@ -419,7 +431,7 @@ public:
         FormsSubmitted = 442,
         TextInputEventOnInput = 443,
         TextInputEventOnTextArea = 444,
-        TextInputEventOnContentEditable = 445,
+        TextInputEventOnContentEditable= 445,
         TextInputEventOnNotNode = 446,
         WebkitBeforeTextInsertedOnInput = 447,
         WebkitBeforeTextInsertedOnTextArea = 448,
index f9f7d3e..e82990c 100644 (file)
 
     [Replaceable] readonly attribute double devicePixelRatio;
 
+    [MeasureAs=PrefixedConvertPointFromPageToNode] WebKitPoint webkitConvertPointFromPageToNode([Default=Undefined] optional Node node,
+                                                                                                [Default=Undefined] optional WebKitPoint p);
+    [MeasureAs=PrefixedConvertPointFromNodeToPage] WebKitPoint webkitConvertPointFromNodeToPage([Default=Undefined] optional Node node,
+                                                                                                [Default=Undefined] optional WebKitPoint p);
+
     [RuntimeEnabled=ApplicationCache, LogActivity=GetterOnly] readonly attribute ApplicationCache applicationCache;
 
     [RuntimeEnabled=SessionStorage, LogActivity=GetterOnly, RaisesException=Getter] readonly attribute Storage sessionStorage;
index a90baef..ee8aec0 100644 (file)
@@ -84,7 +84,7 @@ void FormAssociatedElement::didMoveToNewDocument(Document& oldDocument)
 
 void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
 {
-    if (!m_formWasSetByParser || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
+    if (!m_formWasSetByParser || !m_form || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
         resetFormOwner();
 
     if (!insertionPoint->inDocument())
index dc9e83c..0c278e8 100644 (file)
@@ -130,6 +130,10 @@ private:
 #endif
     OwnPtrWillBeMember<ValidityState> m_validityState;
     String m_customValidationMessage;
+    // Non-Oilpan: Even if m_formWasSetByParser is true, m_form can be null
+    // because parentNode is not a strong reference and |this| and m_form don't
+    // die together.
+    // Oilpan: If m_formWasSetByParser is true, m_form is always non-null.
     bool m_formWasSetByParser;
 };
 
index 08a21cb..18c4833 100644 (file)
@@ -236,7 +236,7 @@ void HTMLCanvasElement::didProcessTask()
         didFinalizeFrame();
     } else {
         ASSERT(hasImageBuffer());
-        m_imageBuffer->finalizeFrame();
+        m_imageBuffer->finalizeFrame(m_dirtyRect);
     }
     ASSERT(m_dirtyRect.isEmpty());
 }
index 2a353bb..371c143 100644 (file)
@@ -1407,8 +1407,10 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* event)
         GestureEvent& gestureEvent = toGestureEvent(*event);
         int listIndex = listIndexForEventTargetOption(gestureEvent);
         if (listIndex >= 0) {
-            if (!isDisabledFormControl())
+            if (!isDisabledFormControl()) {
                 updateSelectedState(listIndex, true, gestureEvent.shiftKey());
+                listBoxOnChange();
+            }
             event->setDefaultHandled();
         }
     } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton) {
index 86c46e4..d8fdc11 100644 (file)
@@ -40,6 +40,7 @@ namespace blink {
 
 BaseChooserOnlyDateAndTimeInputType::~BaseChooserOnlyDateAndTimeInputType()
 {
+    closeDateTimeChooser();
 }
 
 void BaseChooserOnlyDateAndTimeInputType::handleDOMActivateEvent(Event*)
@@ -142,12 +143,5 @@ void BaseChooserOnlyDateAndTimeInputType::accessKeyAction(bool sendMouseEvents)
     BaseClickableWithKeyInputType::accessKeyAction(element(), sendMouseEvents);
 }
 
-void BaseChooserOnlyDateAndTimeInputType::trace(Visitor* visitor)
-{
-    visitor->trace(m_dateTimeChooser);
-    BaseDateAndTimeInputType::trace(visitor);
-    DateTimeChooserClient::trace(visitor);
-}
-
 }
 #endif
index dba4e38..d641fa1 100644 (file)
@@ -36,11 +36,8 @@ namespace blink {
 
 class BaseChooserOnlyDateAndTimeInputType : public BaseDateAndTimeInputType, public DateTimeChooserClient {
     WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(BaseChooserOnlyDateAndTimeInputType);
-public:
-    virtual void trace(Visitor*) OVERRIDE;
-
 protected:
-    explicit BaseChooserOnlyDateAndTimeInputType(HTMLInputElement& element) : BaseDateAndTimeInputType(element) { }
+    BaseChooserOnlyDateAndTimeInputType(HTMLInputElement& element) : BaseDateAndTimeInputType(element) { }
     virtual ~BaseChooserOnlyDateAndTimeInputType();
 
 private:
@@ -62,7 +59,7 @@ private:
     virtual void didChooseValue(double) OVERRIDE;
     virtual void didEndChooser() OVERRIDE;
 
-    RefPtrWillBeMember<DateTimeChooser> m_dateTimeChooser;
+    RefPtr<DateTimeChooser> m_dateTimeChooser;
 };
 
 }
index 4b5c0f0..7960cac 100644 (file)
@@ -45,6 +45,11 @@ static bool fullscreenIsSupported(const Document& document)
     return !document.settings() || document.settings()->fullscreenSupported();
 }
 
+static bool deviceSupportsMouse(const Document& document)
+{
+    return !document.settings() || document.settings()->deviceSupportsMouse();
+}
+
 MediaControls::MediaControls(HTMLMediaElement& mediaElement)
     : HTMLDivElement(mediaElement.document())
     , m_mediaElement(&mediaElement)
@@ -229,9 +234,13 @@ bool MediaControls::shouldHideMediaControls(unsigned behaviorFlags) const
     // Never hide for a media element without visual representation.
     if (!mediaElement().hasVideo())
         return false;
-    // Don't hide if the controls are hovered or the mouse is over the video area.
+    // Don't hide if the mouse is over the controls.
+    const bool ignoreControlsHover = behaviorFlags & IgnoreControlsHover;
+    if (!ignoreControlsHover && m_panel->hovered())
+        return false;
+    // Don't hide if the mouse is over the video area.
     const bool ignoreVideoHover = behaviorFlags & IgnoreVideoHover;
-    if (m_panel->hovered() || (!ignoreVideoHover && m_isMouseOverControls))
+    if (!ignoreVideoHover && m_isMouseOverControls)
         return false;
     // Don't hide if focus is on the HTMLMediaElement or within the
     // controls/shadow tree. (Perform the checks separately to avoid going
@@ -399,7 +408,12 @@ void MediaControls::hideMediaControlsTimerFired(Timer<MediaControls>*)
     if (mediaElement().togglePlayStateWillPlay())
         return;
 
-    if (!shouldHideMediaControls(IgnoreFocus | IgnoreVideoHover))
+    unsigned behaviorFlags = IgnoreFocus | IgnoreVideoHover;
+    // FIXME: improve this check, see http://www.crbug.com/401177.
+    if (!deviceSupportsMouse(document())) {
+        behaviorFlags |= IgnoreControlsHover;
+    }
+    if (!shouldHideMediaControls(behaviorFlags))
         return;
 
     makeTransparent();
index 21c767a..a08c21b 100644 (file)
@@ -82,7 +82,8 @@ private:
 
     enum HideBehaviorFlags {
         IgnoreVideoHover = 1 << 0,
-        IgnoreFocus = 1 << 1
+        IgnoreFocus = 1 << 1,
+        IgnoreControlsHover = 1 << 2
     };
 
     bool shouldHideMediaControls(unsigned behaviorFlags = 0) const;
index 13ffe01..b704634 100644 (file)
@@ -62,6 +62,8 @@ PassRefPtrWillBeRawPtr<PickerIndicatorElement> PickerIndicatorElement::create(Do
 
 PickerIndicatorElement::~PickerIndicatorElement()
 {
+    closePopup();
+    ASSERT(!m_chooser);
 }
 
 RenderObject* PickerIndicatorElement::createRenderer(RenderStyle*)
@@ -152,9 +154,7 @@ bool PickerIndicatorElement::isPickerIndicatorElement() const
 void PickerIndicatorElement::trace(Visitor* visitor)
 {
     visitor->trace(m_pickerIndicatorOwner);
-    visitor->trace(m_chooser);
     HTMLDivElement::trace(visitor);
-    DateTimeChooserClient::trace(visitor);
 }
 
 }
index 5d16338..de93905 100644 (file)
@@ -42,7 +42,6 @@ class HTMLInputElement;
 class PagePopup;
 
 class PickerIndicatorElement FINAL : public HTMLDivElement, public DateTimeChooserClient {
-    WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(PickerIndicatorElement);
 public:
     // PickerIndicatorOwner implementer must call removePickerIndicatorOwner when
     // it doesn't handle event, e.g. at destruction.
@@ -80,7 +79,7 @@ private:
     HTMLInputElement* hostInput();
 
     RawPtrWillBeMember<PickerIndicatorOwner> m_pickerIndicatorOwner;
-    RefPtrWillBeMember<DateTimeChooser> m_chooser;
+    RefPtr<DateTimeChooser> m_chooser;
     bool m_isInOpenPopup;
 };
 
index 3d788dc..26cb664 100644 (file)
@@ -86,9 +86,9 @@ PassOwnPtr<ColorChooser> EmptyChromeClient::createColorChooser(LocalFrame*, Colo
     return nullptr;
 }
 
-PassRefPtrWillBeRawPtr<DateTimeChooser> EmptyChromeClient::openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&)
+PassRefPtr<DateTimeChooser> EmptyChromeClient::openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&)
 {
-    return nullptr;
+    return PassRefPtr<DateTimeChooser>();
 }
 
 void EmptyChromeClient::openTextDataListChooser(HTMLInputElement&)
index 8b8d49b..b37b7a5 100644 (file)
@@ -144,7 +144,7 @@ public:
     virtual void enumerateChosenDirectory(FileChooser*) OVERRIDE { }
 
     virtual PassOwnPtr<ColorChooser> createColorChooser(LocalFrame*, ColorChooserClient*, const Color&) OVERRIDE;
-    virtual PassRefPtrWillBeRawPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) OVERRIDE;
+    virtual PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) OVERRIDE;
     virtual void openTextDataListChooser(HTMLInputElement&) OVERRIDE;
 
     virtual void runOpenPanel(LocalFrame*, PassRefPtr<FileChooser>) OVERRIDE;
index 608a18b..da7a4df 100644 (file)
@@ -60,20 +60,23 @@ void FrameFetchContext::addAdditionalRequestHeaders(Document* document, Resource
     bool isMainResource = type == FetchMainResource;
     if (!isMainResource) {
         String outgoingReferrer;
+        ReferrerPolicy referrerPolicy;
         String outgoingOrigin;
         if (request.httpReferrer().isNull()) {
             outgoingReferrer = document->outgoingReferrer();
+            referrerPolicy = document->referrerPolicy();
             outgoingOrigin = document->outgoingOrigin();
         } else {
             outgoingReferrer = request.httpReferrer();
+            referrerPolicy = request.referrerPolicy();
             outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
         }
 
-        outgoingReferrer = SecurityPolicy::generateReferrerHeader(document->referrerPolicy(), request.url(), outgoingReferrer);
+        outgoingReferrer = SecurityPolicy::generateReferrerHeader(referrerPolicy, request.url(), outgoingReferrer);
         if (outgoingReferrer.isEmpty())
             request.clearHTTPReferrer();
-        else if (!request.httpReferrer())
-            request.setHTTPReferrer(Referrer(outgoingReferrer, document->referrerPolicy()));
+        else
+            request.setHTTPReferrer(Referrer(outgoingReferrer, referrerPolicy));
 
         request.addHTTPOriginIfNeeded(AtomicString(outgoingOrigin));
     }
index 412fcbf..e2fffaa 100644 (file)
@@ -341,7 +341,7 @@ PassOwnPtr<ColorChooser> Chrome::createColorChooser(LocalFrame* frame, ColorChoo
     return m_client->createColorChooser(frame, client, initialColor);
 }
 
-PassRefPtrWillBeRawPtr<DateTimeChooser> Chrome::openDateTimeChooser(DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
+PassRefPtr<DateTimeChooser> Chrome::openDateTimeChooser(DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
 {
     notifyPopupOpeningObservers();
     return m_client->openDateTimeChooser(client, parameters);
index 42dcc6d..d7683e8 100644 (file)
@@ -26,7 +26,6 @@
 #include "core/page/FocusType.h"
 #include "platform/Cursor.h"
 #include "platform/HostWindow.h"
-#include "platform/heap/Handle.h"
 #include "wtf/Forward.h"
 
 namespace blink {
@@ -118,7 +117,7 @@ public:
     void print(LocalFrame*);
 
     PassOwnPtr<ColorChooser> createColorChooser(LocalFrame*, ColorChooserClient*, const Color& initialColor);
-    PassRefPtrWillBeRawPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&);
+    PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&);
     void openTextDataListChooser(HTMLInputElement&);
 
     void runOpenPanel(LocalFrame*, PassRefPtr<FileChooser>);
index 48d4940..ec61965 100644 (file)
@@ -168,7 +168,7 @@ public:
     //    returns true, if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
     //  - <datalist> UI for date/time input types regardless of
     //    ENABLE(INPUT_MULTIPLE_FIELDS_UI)
-    virtual PassRefPtrWillBeRawPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) = 0;
+    virtual PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) = 0;
 
     virtual void openTextDataListChooser(HTMLInputElement&) = 0;
 
index 66c7a6b..f0166a1 100644 (file)
@@ -2097,11 +2097,6 @@ bool EventHandler::handleGestureEventInFrame(const GestureEventWithHitTestResult
     RefPtr<Scrollbar> scrollbar = targetedEvent.hitTestResult().scrollbar();
     const PlatformGestureEvent& gestureEvent = targetedEvent.event();
 
-    if (!scrollbar) {
-        FrameView* view = m_frame->view();
-        scrollbar = view ? view->scrollbarAtPoint(gestureEvent.position()) : 0;
-    }
-
     if (scrollbar) {
         bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
         if (gestureEvent.type() == PlatformEvent::GestureTapDown && eventSwallowed)
@@ -2226,55 +2221,56 @@ bool EventHandler::handleGestureTap(const GestureEventWithHitTestResults& target
         modifierFlags |= PlatformEvent::ShiftKey;
     PlatformEvent::Modifiers modifiers = static_cast<PlatformEvent::Modifiers>(modifierFlags);
 
+    HitTestResult currentHitTest = targetedEvent.hitTestResult();
+
     // We use the adjusted position so the application isn't surprised to see a event with
     // co-ordinates outside the target's bounds.
     IntPoint adjustedPoint = m_frame->view()->windowToContents(gestureEvent.position());
 
-    // Do a new hit-test at the (adjusted) gesture co-ordinates. This is necessary because
-    // touch adjustment sometimes returns a different node than what hit testing would return
-    // for the same point.
-    // FIXME: Fix touch adjustment to avoid the need for a redundant hit test. http://crbug.com/398914
-    HitTestResult newHitTest = hitTestResultInFrame(m_frame, adjustedPoint, HitTestRequest::ReadOnly);
-
     PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(),
         NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
         modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
-    dispatchMouseEvent(EventTypeNames::mousemove, newHitTest.targetNode(), 0, fakeMouseMove, true);
+    dispatchMouseEvent(EventTypeNames::mousemove, currentHitTest.innerNode(), 0, fakeMouseMove, true);
 
     // Do a new hit-test in case the mousemove event changed the DOM.
+    // Note that if the original hit test wasn't over an element (eg. was over a scrollbar) we
+    // don't want to re-hit-test because it may be in the wrong frame (and there's no way the page
+    // could have seen the event anyway).
     // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug.com/398920
-    newHitTest = hitTestResultInFrame(m_frame, adjustedPoint, HitTestRequest::ReadOnly);
-    m_clickNode = newHitTest.targetNode();
+    if (currentHitTest.innerNode())
+        currentHitTest = hitTestResultInFrame(m_frame, adjustedPoint, HitTestRequest::ReadOnly);
+    m_clickNode = currentHitTest.innerNode();
     if (m_clickNode && m_clickNode->isTextNode())
         m_clickNode = NodeRenderingTraversal::parent(m_clickNode.get());
 
     PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(),
         LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
         modifiers, PlatformMouseEvent::FromTouch,  gestureEvent.timestamp());
-    bool swallowMouseDownEvent = !dispatchMouseEvent(EventTypeNames::mousedown, newHitTest.targetNode(), gestureEvent.tapCount(), fakeMouseDown, true);
+    bool swallowMouseDownEvent = !dispatchMouseEvent(EventTypeNames::mousedown, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseDown, true);
     if (!swallowMouseDownEvent)
         swallowMouseDownEvent = handleMouseFocus(fakeMouseDown);
     if (!swallowMouseDownEvent)
-        swallowMouseDownEvent = handleMousePressEvent(MouseEventWithHitTestResults(fakeMouseDown, newHitTest));
+        swallowMouseDownEvent = handleMousePressEvent(MouseEventWithHitTestResults(fakeMouseDown, currentHitTest));
 
     // FIXME: Use a hit-test cache to avoid unnecessary hit tests. http://crbug.com/398920
-    newHitTest = hitTestResultInFrame(m_frame, adjustedPoint, HitTestRequest::ReadOnly);
+    if (currentHitTest.innerNode())
+        currentHitTest = hitTestResultInFrame(m_frame, adjustedPoint, HitTestRequest::ReadOnly);
     PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(),
         LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
         modifiers, PlatformMouseEvent::FromTouch,  gestureEvent.timestamp());
-    bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, newHitTest.targetNode(), gestureEvent.tapCount(), fakeMouseUp, false);
+    bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, currentHitTest.innerNode(), gestureEvent.tapCount(), fakeMouseUp, false);
 
     bool swallowClickEvent = false;
     if (m_clickNode) {
-        if (newHitTest.targetNode()) {
-            Node* clickTargetNode = newHitTest.targetNode()->commonAncestor(*m_clickNode, parentForClickEvent);
+        if (currentHitTest.innerNode()) {
+            Node* clickTargetNode = currentHitTest.innerNode()->commonAncestor(*m_clickNode, parentForClickEvent);
             swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, clickTargetNode, gestureEvent.tapCount(), fakeMouseUp, true);
         }
         m_clickNode = nullptr;
     }
 
     if (!swallowMouseUpEvent)
-        swallowMouseUpEvent = handleMouseReleaseEvent(MouseEventWithHitTestResults(fakeMouseUp, newHitTest));
+        swallowMouseUpEvent = handleMouseReleaseEvent(MouseEventWithHitTestResults(fakeMouseUp, currentHitTest));
 
     return swallowMouseDownEvent | swallowMouseUpEvent | swallowClickEvent;
 }
@@ -2588,11 +2584,36 @@ GestureEventWithHitTestResults EventHandler::targetGestureEvent(const PlatformGe
     // FIXME: We should not do a rect-based hit-test if touch adjustment is disabled.
     HitTestResult hitTestResult = hitTestResultAtPoint(hitTestPoint, hitType | HitTestRequest::ReadOnly, touchRadius);
 
+    // Hit-test the main frame scrollbars (in addition to the child-frame and RenderLayer
+    // scroll bars checked by the hit-test code.
+    if (!hitTestResult.scrollbar()) {
+        if (FrameView* view = m_frame->view()) {
+            hitTestResult.setScrollbar(view->scrollbarAtPoint(gestureEvent.position()));
+        }
+    }
+
     // Adjust the location of the gesture to the most likely nearby node, as appropriate for the
     // type of event.
     PlatformGestureEvent adjustedEvent = gestureEvent;
     applyTouchAdjustment(&adjustedEvent, &hitTestResult);
 
+    // Do a new hit-test at the (adjusted) gesture co-ordinates. This is necessary because
+    // rect-based hit testing and touch adjustment sometimes return a different node than
+    // what a point-based hit test would return for the same point.
+    // FIXME: Fix touch adjustment to avoid the need for a redundant hit test. http://crbug.com/398914
+    if (shouldApplyTouchAdjustment(gestureEvent)) {
+        LocalFrame* hitFrame = hitTestResult.innerNodeFrame();
+        if (!hitFrame)
+            hitFrame = m_frame;
+        hitTestResult = hitTestResultInFrame(hitFrame, hitFrame->view()->windowToContents(adjustedEvent.position()), hitType | HitTestRequest::ReadOnly);
+        // FIXME: HitTest entry points should really check for main frame scrollbars themselves.
+        if (!hitTestResult.scrollbar()) {
+            if (FrameView* view = m_frame->view()) {
+                hitTestResult.setScrollbar(view->scrollbarAtPoint(gestureEvent.position()));
+            }
+        }
+    }
+
     // Now apply hover/active state to the final target.
     // FIXME: This is supposed to send mouseenter/mouseleave events, but doesn't because we
     // aren't passing a PlatformMouseEvent.
index becc7cf..81a4004 100644 (file)
@@ -132,6 +132,11 @@ void AbstractInlineTextBox::wordBoundaries(Vector<WordBoundaries>& words) const
     String text = this->text();
     int len = text.length();
     TextBreakIterator* iterator = wordBreakIterator(text, 0, len);
+
+    // FIXME: When http://crbug.com/411764 is fixed, replace this with an ASSERT.
+    if (!iterator)
+        return;
+
     int pos = iterator->first();
     while (pos >= 0 && pos < len) {
         int next = iterator->next();
index 12753da..aef2345 100644 (file)
@@ -97,13 +97,21 @@ void PaintInvalidationState::applyClipIfNeeded(const RenderObject& renderer)
         return;
 
     const RenderBox& box = toRenderBox(renderer);
-    LayoutRect clipRect(toPoint(m_paintOffset), box.layer()->size());
-    if (m_clipped) {
-        m_clipRect.intersect(clipRect);
+
+    // Do not clip scroll layer contents because the compositor expects the whole layer
+    // to be always invalidated in-time.
+    if (box.usesCompositedScrolling()) {
+        ASSERT(!m_clipped); // The box should establish paint invalidation container, so no m_clipped inherited.
     } else {
-        m_clipRect = clipRect;
-        m_clipped = true;
+        LayoutRect clipRect(toPoint(m_paintOffset), box.layer()->size());
+        if (m_clipped) {
+            m_clipRect.intersect(clipRect);
+        } else {
+            m_clipRect = clipRect;
+            m_clipped = true;
+        }
     }
+
     m_paintOffset -= box.scrolledContentOffset();
 }
 
index 56d2f40..f50c867 100644 (file)
@@ -882,7 +882,8 @@ void RenderBox::applyCachedClipAndScrollOffsetForRepaint(LayoutRect& paintRect)
     flipForWritingMode(paintRect);
     paintRect.move(-scrolledContentOffset()); // For overflow:auto/scroll/hidden.
 
-    // Do not clip scroll layer contents to reduce the number of repaints while scrolling.
+    // Do not clip scroll layer contents because the compositor expects the whole layer
+    // to be always invalidated in-time.
     if (usesCompositedScrolling()) {
         flipForWritingMode(paintRect);
         return;
@@ -1766,7 +1767,9 @@ LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
 
     // FIXME: For now just support fixed heights.  Eventually should support percentage heights as well.
     if (!logicalHeightLength.isFixed()) {
-        LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritingMode() ? view()->frameView()->visibleHeight() : view()->frameView()->visibleWidth();
+        LayoutUnit fillFallbackExtent = containingBlockStyle->isHorizontalWritingMode()
+            ? view()->frameView()->unscaledVisibleContentSize().height()
+            : view()->frameView()->unscaledVisibleContentSize().width();
         LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding);
         return std::min(fillAvailableExtent, fillFallbackExtent);
     }
@@ -2853,7 +2856,7 @@ LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightTy
 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogicalHeightType heightType) const
 {
     if (isRenderView())
-        return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
+        return isHorizontalWritingMode() ? toRenderView(this)->frameView()->unscaledVisibleContentSize().height() : toRenderView(this)->frameView()->unscaledVisibleContentSize().width();
 
     // We need to stop here, since we don't want to increase the height of the table
     // artificially.  We're going to rely on this cell getting expanded to some new
index 6ec78b9..08a6368 100644 (file)
@@ -907,7 +907,7 @@ RenderLayer* RenderLayer::enclosingPositionedAncestor() const
 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
 {
     RenderLayer* curr = parent();
-    while (curr && !curr->isRootLayer() && !curr->transform())
+    while (curr && !curr->isRootLayer() && !curr->renderer()->hasTransform())
         curr = curr->parent();
 
     return curr;
index 9b304aa..9e060e4 100644 (file)
@@ -365,10 +365,7 @@ void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset)
         box().setPreviousPaintInvalidationRect(box().boundsRectForPaintInvalidation(repaintContainer));
         // Update regions, scrolling may change the clip of a particular region.
         frameView->updateAnnotatedRegions();
-        // FIXME: We shouldn't call updateWidgetPositions() here since it might tear down the render tree,
-        // for now we just crash to avoid allowing an attacker to use after free.
-        frameView->updateWidgetPositions();
-        RELEASE_ASSERT(frameView->renderView());
+        frameView->setNeedsUpdateWidgetPositions();
         updateCompositingLayersAfterScroll();
     }
 
@@ -1443,7 +1440,8 @@ static bool layerNeedsCompositedScrolling(const RenderLayer* layer)
     return layer->scrollsOverflow()
         && layer->compositor()->acceleratedCompositingForOverflowScrollEnabled()
         && !layer->hasDescendantWithClipPath()
-        && !layer->hasAncestorWithClipPath();
+        && !layer->hasAncestorWithClipPath()
+        && !layer->renderer()->style()->hasBorderRadius();
 }
 
 void RenderLayerScrollableArea::updateNeedsCompositedScrolling()
index 88dae63..5964f5c 100644 (file)
@@ -1327,11 +1327,16 @@ void RenderObject::addChildFocusRingRects(Vector<IntRect>& rects, const LayoutPo
                 box->addFocusRingRects(layerFocusRingRects, LayoutPoint(), box);
                 for (size_t i = 0; i < layerFocusRingRects.size(); ++i) {
                     FloatQuad quadInBox = box->localToContainerQuad(FloatRect(layerFocusRingRects[i]), paintContainer);
-                    rects.append(pixelSnappedIntRect(LayoutRect(quadInBox.boundingBox())));
+                    FloatRect rect = quadInBox.boundingBox();
+                    // Floor the location instead of using pixelSnappedIntRect to match the !hasLayer() path.
+                    // FIXME: roundedIntSize matches pixelSnappedIntRect in other places of addFocusRingRects
+                    // because we always floor the offset.
+                    // This assumption is fragile and should be replaced by better solution.
+                    rects.append(IntRect(flooredIntPoint(rect.location()), roundedIntSize(rect.size())));
                 }
             } else {
                 FloatPoint pos(additionalOffset);
-                pos.move(box->locationOffset()); // FIXME: Snap offsets? crbug.com/350474
+                pos.move(box->locationOffset());
                 box->addFocusRingRects(rects, flooredIntPoint(pos), paintContainer);
             }
         } else {
index cdcc7df..f0deb6b 100644 (file)
@@ -81,7 +81,7 @@ public:
 
     void repaint()
     {
-        m_object->invalidatePaintUsingContainer(m_repaintContainer, m_rect, InvalidationSelection);
+        m_object->invalidatePaintUsingContainer(m_repaintContainer, enclosingIntRect(m_rect), InvalidationSelection);
     }
 
     LayoutRect rect() const { return m_rect; }
@@ -111,7 +111,7 @@ public:
         // repaintContainer as the render object. Find out why it does that and fix.
         if (m_repaintContainer && m_repaintContainer->layer()->groupedMapping())
             RenderLayer::mapRectToPaintInvalidationBacking(m_repaintContainer, m_repaintContainer, repaintRect);
-        m_object->invalidatePaintUsingContainer(m_repaintContainer, repaintRect, InvalidationSelection);
+        m_object->invalidatePaintUsingContainer(m_repaintContainer, enclosingIntRect(repaintRect), InvalidationSelection);
     }
 
     RenderBlock* block() const { return toRenderBlock(m_object); }
index a65bbdd..b3ecb82 100644 (file)
@@ -54,6 +54,7 @@
 #include "platform/LengthFunctions.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/fonts/FontCache.h"
+#include "platform/geometry/TransformState.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "wtf/CurrentTime.h"
 #include "wtf/text/StringBuilder.h"
@@ -761,11 +762,12 @@ void CompositedLayerMapping::updateOverflowControlsHostLayerGeometry(const Rende
 
             m_overflowControlsHostLayer->setPosition(IntPoint(-m_overflowControlsClippingLayer->offsetFromRenderer()));
         } else {
-            ASSERT(m_owningLayer.transformAncestor() == compositingStackingContext->transformAncestor());
-            LayoutPoint localOffsetToTransformedAncestor = m_owningLayer.computeOffsetFromTransformedAncestor();
-            LayoutPoint compositingStackingContextOffsetToTransformedAncestor = compositingStackingContext->computeOffsetFromTransformedAncestor();
-
-            m_overflowControlsHostLayer->setPosition(FloatPoint(localOffsetToTransformedAncestor - compositingStackingContextOffsetToTransformedAncestor));
+            // The controls are in the same 2D space as the compositing container, so we can map them into the space of the container.
+            TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
+            m_owningLayer.renderer()->mapLocalToContainer(compositingStackingContext->renderer(), transformState, ApplyContainerFlip);
+            transformState.flatten();
+            LayoutPoint offsetFromStackingContainer = LayoutPoint(transformState.lastPlanarPoint());
+            m_overflowControlsHostLayer->setPosition(FloatPoint(offsetFromStackingContainer));
         }
     } else {
         m_overflowControlsHostLayer->setPosition(FloatPoint());
@@ -1108,6 +1110,7 @@ void CompositedLayerMapping::updateDrawsContent()
             Color bgColor(Color::transparent);
             if (contentLayerSupportsDirectBackgroundComposition(renderer())) {
                 bgColor = rendererBackgroundColor();
+                hasPaintedContent = false;
             }
             contentLayer->setBackgroundColor(bgColor.rgb());
         }
@@ -1885,11 +1888,13 @@ bool CompositedLayerMapping::updateRequiresOwnBackingStoreForAncestorReasons(con
         && (compositingAncestorLayer->compositedLayerMapping()->mainGraphicsLayer()->drawsContent()
             || compositingAncestorLayer->compositedLayerMapping()->paintsIntoCompositedAncestor());
 
-    if (paintsIntoCompositedAncestor() != previousPaintsIntoCompositedAncestor)
-        compositor()->paintInvalidationOnCompositingChange(&m_owningLayer);
-
-    // FIXME: this is bogus. We need to make this assignment before the check above.
     m_requiresOwnBackingStoreForAncestorReasons = !canPaintIntoAncestor;
+    if (paintsIntoCompositedAncestor() != previousPaintsIntoCompositedAncestor) {
+        // Back out the change temporarily while invalidating with respect to the old container.
+        m_requiresOwnBackingStoreForAncestorReasons = !m_requiresOwnBackingStoreForAncestorReasons;
+        compositor()->paintInvalidationOnCompositingChange(&m_owningLayer);
+        m_requiresOwnBackingStoreForAncestorReasons = !m_requiresOwnBackingStoreForAncestorReasons;
+    }
 
     return m_requiresOwnBackingStoreForAncestorReasons != previousRequiresOwnBackingStoreForAncestorReasons;
 }
@@ -1908,8 +1913,12 @@ bool CompositedLayerMapping::updateRequiresOwnBackingStoreForIntrinsicReasons()
         || renderer->hasReflection()
         || renderer->hasFilter();
 
-    if (paintsIntoCompositedAncestor() != previousPaintsIntoCompositedAncestor)
+    if (paintsIntoCompositedAncestor() != previousPaintsIntoCompositedAncestor) {
+        // Back out the change temporarily while invalidating with respect to the old container.
+        m_requiresOwnBackingStoreForIntrinsicReasons = !m_requiresOwnBackingStoreForIntrinsicReasons;
         compositor()->paintInvalidationOnCompositingChange(&m_owningLayer);
+        m_requiresOwnBackingStoreForIntrinsicReasons = !m_requiresOwnBackingStoreForIntrinsicReasons;
+    }
 
     return m_requiresOwnBackingStoreForIntrinsicReasons != previousRequiresOwnBackingStoreForIntrinsicReasons;
 }
index 5355a6c..1bf13b1 100644 (file)
@@ -114,7 +114,7 @@ void CompositingInputsUpdater::updateRecursive(RenderLayer* layer, UpdateType up
 
             const RenderLayer* parent = layer->parent();
             properties.opacityAncestor = parent->isTransparent() ? parent : parent->opacityAncestor();
-            properties.transformAncestor = parent->transform() ? parent : parent->transformAncestor();
+            properties.transformAncestor = parent->hasTransform() ? parent : parent->transformAncestor();
             properties.filterAncestor = parent->hasFilter() ? parent : parent->filterAncestor();
 
             if (info.hasAncestorWithClipOrOverflowClip) {
index 1708a98..c183bb9 100644 (file)
@@ -166,8 +166,8 @@ CompositingReasons CompositingLayerAssigner::getReasonsPreventingSquashing(const
     if (compositingInputs.transformAncestor != squashingLayerCompositingInputs.transformAncestor)
         return CompositingReasonSquashingTransformAncestorMismatch;
 
-    if (compositingInputs.filterAncestor != squashingLayerCompositingInputs.filterAncestor)
-        return CompositingReasonSquashingFilterAncestorMismatch;
+    if (layer->hasFilter() || compositingInputs.filterAncestor != squashingLayerCompositingInputs.filterAncestor)
+        return CompositingReasonSquashingFilterMismatch;
 
     return CompositingReasonNone;
 }
index bd59c28..2df4523 100644 (file)
@@ -165,7 +165,7 @@ static void drawDeferredFilter(GraphicsContext* context, FilterData* filterData,
     ASSERT(sourceGraphic);
     builder.setSourceGraphic(sourceGraphic);
     RefPtr<ImageFilter> imageFilter = builder.build(filterData->builder->lastEffect(), ColorSpaceDeviceRGB);
-    FloatRect boundaries = enclosingIntRect(filterData->boundaries);
+    FloatRect boundaries = filterData->boundaries;
     context->save();
 
     FloatSize deviceSize = context->getCTM().mapSize(boundaries.size());
@@ -181,8 +181,9 @@ static void drawDeferredFilter(GraphicsContext* context, FilterData* filterData,
         float scale = sqrtf(FilterEffect::maxFilterArea() / scaledArea);
         context->scale(scale, scale);
     }
-    // Clip drawing of filtered image to primitive boundaries.
-    context->clipRect(boundaries);
+    // Clip drawing of filtered image to the minimum required paint rect.
+    FilterEffect* lastEffect = filterData->builder->lastEffect();
+    context->clipRect(lastEffect->determineAbsolutePaintRect(lastEffect->maxEffectRect()));
     if (filterElement->hasAttribute(SVGNames::filterResAttr)) {
         // Get boundaries in device coords.
         // FIXME: See crbug.com/382491. Is the use of getCTM OK here, given it does not include device
index f92bae6..f43abb3 100644 (file)
@@ -107,7 +107,7 @@ WebInspector.ElementsPanel = function()
     WebInspector.targetManager.observeTargets(this);
     WebInspector.settings.showUAShadowDOM.addChangeListener(this._showUAShadowDOMChanged.bind(this));
     WebInspector.targetManager.addModelListener(WebInspector.DOMModel, WebInspector.DOMModel.Events.DocumentUpdated, this._documentUpdatedEvent, this);
-    WebInspector.targetManager.addModelListener(WebInspector.DOMModel, WebInspector.CSSStyleModel.Events.ModelWasEnabled, this._updateSidebars, this);
+    WebInspector.targetManager.addModelListener(WebInspector.CSSStyleModel, WebInspector.CSSStyleModel.Events.ModelWasEnabled, this._updateSidebars, this);
 }
 
 WebInspector.ElementsPanel.prototype = {
@@ -1162,12 +1162,9 @@ WebInspector.ElementsPanel.prototype = {
             }
         }
 
-        var element = event.target.enclosingNodeOrSelfWithClass("elements-tree-outline");
-        if (!element)
-            return;
         var treeOutline = null;
         for (var i = 0; i < this._treeOutlines.length; ++i) {
-            if (this._treeOutlines[i].element === element)
+            if (this._treeOutlines[i].selectedDOMNode() === this._lastValidSelectedNode)
                 treeOutline = this._treeOutlines[i];
         }
         if (!treeOutline)
index 0839293..41ef67a 100644 (file)
@@ -733,7 +733,7 @@ WebInspector.ElementsTreeOutline.prototype = {
     _contextMenuEventFired: function(event)
     {
         var treeElement = this._treeElementFromEvent(event);
-        if (!treeElement)
+        if (!treeElement || treeElement.treeOutline !== this)
             return;
 
         var contextMenu = new WebInspector.ContextMenu(event);
@@ -744,7 +744,7 @@ WebInspector.ElementsTreeOutline.prototype = {
     populateContextMenu: function(contextMenu, event)
     {
         var treeElement = this._treeElementFromEvent(event);
-        if (!treeElement)
+        if (!treeElement || treeElement.treeOutline !== this)
             return;
 
         var isPseudoElement = !!treeElement._node.pseudoType();
index 492424f..67d0454 100644 (file)
@@ -365,6 +365,7 @@ WebInspector.SpectrumPopupHelper.prototype = {
             this.hide(true);
         }
 
+        delete this._isHidden;
         this._anchorElement = element;
 
         this._spectrum.setColor(color);
@@ -373,6 +374,7 @@ WebInspector.SpectrumPopupHelper.prototype = {
 
         document.addEventListener("mousedown", this._hideProxy, false);
         window.addEventListener("blur", this._hideProxy, false);
+        window.addEventListener("resize", this._hideProxy, false);
         return true;
     },
 
@@ -389,12 +391,14 @@ WebInspector.SpectrumPopupHelper.prototype = {
      */
     hide: function(commitEdit)
     {
-        if (!this._popover.isShowing())
+        if (this._isHidden)
             return;
+        this._isHidden = true;
         this._popover.hide();
 
         document.removeEventListener("mousedown", this._hideProxy, false);
         window.removeEventListener("blur", this._hideProxy, false);
+        window.removeEventListener("resize", this._hideProxy, false);
 
         this.dispatchEventToListeners(WebInspector.SpectrumPopupHelper.Events.Hidden, !!commitEdit);
 
index 04adc6d..0b7a4b6 100644 (file)
@@ -503,8 +503,7 @@ body.platform-mac .help-key {
     background-color: pink;
 }
 
-input.list-column-editor,
-select.list-column-editor {
+input.list-column-editor {
     border: 1px solid rgb(213, 213, 213);
     border-radius: 2px;
     color: #444444;
@@ -512,6 +511,7 @@ select.list-column-editor {
 }
 select.list-column-editor {
     padding: 2px;
+    margin-left: 0px;
 }
 
 .settings-tab .settings-list .settings-list-item .file-system-path {
index 040c995..9177e28 100644 (file)
@@ -159,10 +159,8 @@ WebInspector.Main.prototype = {
         console.timeStamp("Main._loaded");
 
         // FIXME: Make toolbox a real app.
-        if (WebInspector.queryParam("toolbox")) {
-            new WebInspector.Toolbox();
+        if (WebInspector.queryParam("toolbox"))
             return;
-        }
 
         this._createSettings();
         this._createModuleManager();
index d252fea..b74c9f5 100644 (file)
@@ -113,7 +113,7 @@ WebInspector.OverridesView.prototype = {
     {
         this._unavailableSplashScreenElement.classList.toggle("hidden", WebInspector.overridesSupport.canEmulate());
         this._tabbedPane.element.classList.toggle("hidden", !WebInspector.overridesSupport.emulationEnabled());
-        this._splashScreenElement.classList.toggle("hidden", WebInspector.overridesSupport.emulationEnabled());
+        this._splashScreenElement.classList.toggle("hidden", WebInspector.overridesSupport.emulationEnabled() || !WebInspector.overridesSupport.canEmulate());
     },
 
     __proto__: WebInspector.VBox.prototype
index 4eb9e3d..291b19e 100644 (file)
@@ -14,7 +14,7 @@ window.addEventListener("DOMContentLoaded", windowLoaded, false);
  */
 WebInspector.Toolbox = function()
 {
-    if (!window.opener)
+    if (!window.opener || !WebInspector.queryParam("toolbox"))
         return;
 
     WebInspector.zoomManager = new WebInspector.ZoomManager(window.opener.InspectorFrontendHost);
index 16f46b6..c69c99d 100644 (file)
@@ -362,6 +362,7 @@ WebInspector.NetworkLogView.prototype = {
         });
 
         this._dataGrid = new WebInspector.SortableDataGrid(columns);
+        this._dataGrid.setStickToBottom(true);
         this._updateColumns();
         this._dataGrid.setName("networkLog");
         this._dataGrid.setResizeMethod(WebInspector.DataGrid.ResizeMethod.Last);
@@ -743,7 +744,6 @@ WebInspector.NetworkLogView.prototype = {
         }
 
         this._removeAllNodeHighlights();
-        var wasScrolledToLastRow = this._dataGrid.isScrolledToLastRow();
         var boundariesChanged = false;
         var calculator = this.calculator();
         if (calculator.updateBoundariesForEventTime) {
@@ -787,8 +787,6 @@ WebInspector.NetworkLogView.prototype = {
 
         this._staleRequestIds = {};
         this._updateSummaryBar();
-        if (wasScrolledToLastRow)
-            this._dataGrid.scrollToLastRow();
     },
 
     _onRecordButtonClicked: function()
index 2c76df2..7a88b3a 100644 (file)
@@ -937,7 +937,6 @@ WebInspector.EditableSettingsList.prototype = {
         {
             if (itemId === this._editingId)
                 return;
-            event.consume();
             console.assert(!this._editingId);
             this._editingId = validItemId;
             var listItem = this.itemForId(validItemId);
index 4764300..d281fe9 100644 (file)
@@ -147,6 +147,7 @@ WebInspector.CodeMirrorTextEditor = function(url, delegate)
     this._codeMirror.on("beforeSelectionChange", this._beforeSelectionChange.bind(this));
     this._codeMirror.on("scroll", this._scroll.bind(this));
     this._codeMirror.on("focus", this._focus.bind(this));
+    this._codeMirror.on("keyHandled", this._onKeyHandled.bind(this));
     this.element.addEventListener("contextmenu", this._contextMenu.bind(this), false);
     /**
      * @this {WebInspector.CodeMirrorTextEditor}
@@ -326,6 +327,11 @@ WebInspector.CodeMirrorTextEditor.MaximumNumberOfWhitespacesPerSingleSpan = 16;
 WebInspector.CodeMirrorTextEditor.MaxEditableTextSize = 1024 * 1024 * 10;
 
 WebInspector.CodeMirrorTextEditor.prototype = {
+    _onKeyHandled: function()
+    {
+        WebInspector.shortcutRegistry.dismissPendingShortcutAction();
+    },
+
     _onAutoAppendedSpaces: function()
     {
         this._autoAppendedSpaces = this._autoAppendedSpaces || [];
index f264169..d6e0c2e 100644 (file)
@@ -693,19 +693,6 @@ WebInspector.DataGrid.prototype = {
         return this._scrollContainer;
     },
 
-    /**
-     * @return {boolean}
-     */
-    isScrolledToLastRow: function()
-    {
-        return this._scrollContainer.isScrolledToBottom();
-    },
-
-    scrollToLastRow: function()
-    {
-        this._scrollContainer.scrollTop = this._scrollContainer.scrollHeight - this._scrollContainer.offsetHeight;
-    },
-
     _positionResizers: function()
     {
         var headerTableColumns = this._headerTableColumnGroup.children;
index fed6af5..a4e3695 100644 (file)
@@ -162,10 +162,7 @@ WebInspector.ShortcutRegistry.prototype = {
         this._defaultKeyToActions.put(String(descriptor.key), actionId);
     },
 
-    /**
-     * @param {!Event} event
-     */
-    _onInput: function(event)
+    dismissPendingShortcutAction: function()
     {
         if (this._pendingActionTimer) {
             clearTimeout(this._pendingActionTimer);
@@ -175,7 +172,7 @@ WebInspector.ShortcutRegistry.prototype = {
 
     _registerBindings: function()
     {
-        document.addEventListener("input", this._onInput.bind(this), true);
+        document.addEventListener("input", this.dismissPendingShortcutAction.bind(this), true);
         var extensions = self.runtime.extensions(WebInspector.ActionDelegate);
         extensions.forEach(registerExtension, this);
 
index 07725bc..c419210 100644 (file)
@@ -31,6 +31,13 @@ WebInspector.ViewportDataGrid = function(columnsArray, editCallback, deleteCallb
     /** @type {?Node} */
     this._hiddenWheelTarget = null;
 
+    /** @type {boolean} */
+    this._stickToBottom = false;
+    /** @type {boolean} */
+    this._atBottom = true;
+    /** @type {number} */
+    this._lastScrollTop = 0;
+
     this.setRootNode(new WebInspector.ViewportDataGridNode());
 }
 
@@ -40,10 +47,20 @@ WebInspector.ViewportDataGrid.prototype = {
      */
     onResize: function()
     {
+        if (this._stickToBottom && this._atBottom)
+            this._scrollContainer.scrollTop = this._scrollContainer.scrollHeight - this._scrollContainer.clientHeight;
         this.scheduleUpdate();
     },
 
     /**
+     * @param {boolean} stick
+     */
+    setStickToBottom: function(stick)
+    {
+        this._stickToBottom = stick;
+    },
+
+    /**
      * @param {?Event} event
      */
     _onWheel: function(event)
@@ -56,7 +73,9 @@ WebInspector.ViewportDataGrid.prototype = {
      */
     _onScroll: function(event)
     {
-        this.scheduleUpdate();
+        this._atBottom = this._scrollContainer.isScrolledToBottom();
+        if (this._lastScrollTop !== this._scrollContainer.scrollTop)
+            this.scheduleUpdate();
     },
 
     /**
@@ -81,11 +100,11 @@ WebInspector.ViewportDataGrid.prototype = {
     },
 
     /**
-     * @param {number} scrollHeight
+     * @param {number} clientHeight
      * @param {number} scrollTop
      * @return {{topPadding: number, bottomPadding: number, visibleNodes: !Array.<!WebInspector.ViewportDataGridNode>, offset: number}}
      */
-    _calculateVisibleNodes: function(scrollHeight, scrollTop)
+    _calculateVisibleNodes: function(clientHeight, scrollTop)
     {
         var nodes = this._rootNode.children;
         if (this._inline)
@@ -100,7 +119,7 @@ WebInspector.ViewportDataGrid.prototype = {
         var start = i;
         var topPadding = y;
 
-        for (; i < size && y < scrollTop + scrollHeight; ++i)
+        for (; i < size && y < scrollTop + clientHeight; ++i)
             y += nodes[i].nodeSelfHeight();
         var end = i;
 
@@ -111,11 +130,32 @@ WebInspector.ViewportDataGrid.prototype = {
         return {topPadding: topPadding, bottomPadding: bottomPadding, visibleNodes: nodes.slice(start, end), offset: start};
     },
 
+    /**
+     * @return {number}
+     */
+    _contentHeight: function()
+    {
+        var nodes = this._rootNode.children;
+        var result = 0;
+        for (var i = 0, size = nodes.length; i < size; ++i)
+            result += nodes[i].nodeSelfHeight();
+        return result;
+    },
+
     _update: function()
     {
         this._updateScheduled = false;
 
-        var viewportState = this._calculateVisibleNodes(this._scrollContainer.offsetHeight, this._scrollContainer.scrollTop);
+        var clientHeight = this._scrollContainer.clientHeight;
+        var scrollTop = this._scrollContainer.scrollTop;
+        var currentScrollTop = scrollTop;
+        var maxScrollTop = Math.max(0, this._contentHeight() - clientHeight);
+        if (this._stickToBottom && this._atBottom)
+            scrollTop = maxScrollTop;
+        scrollTop = Math.min(maxScrollTop, scrollTop);
+        this._atBottom = scrollTop === maxScrollTop;
+
+        var viewportState = this._calculateVisibleNodes(clientHeight, scrollTop);
         var visibleNodes = viewportState.visibleNodes;
         var visibleNodesSet = Set.fromArray(visibleNodes);
 
@@ -149,6 +189,9 @@ WebInspector.ViewportDataGrid.prototype = {
         }
 
         this.setVerticalPadding(viewportState.topPadding, viewportState.bottomPadding);
+        this._lastScrollTop = scrollTop;
+        if (scrollTop !== currentScrollTop)
+            this._scrollContainer.scrollTop = scrollTop;
         this._visibleNodes = visibleNodes;
     },
 
index 13f7aef..3368023 100644 (file)
@@ -32,6 +32,7 @@
 #include "modules/filesystem/DOMFileSystemBase.h"
 
 #include "core/dom/ExecutionContext.h"
+#include "core/fileapi/File.h"
 #include "core/fileapi/FileError.h"
 #include "core/html/VoidCallback.h"
 #include "modules/filesystem/DOMFilePath.h"
@@ -188,6 +189,25 @@ bool DOMFileSystemBase::pathPrefixToFileSystemType(const String& pathPrefix, Fil
     return false;
 }
 
+PassRefPtrWillBeRawPtr<File> DOMFileSystemBase::createFile(const FileMetadata& metadata, const KURL& fileSystemURL, FileSystemType type, const String name)
+{
+    // For regular filesystem types (temporary or persistent), we should not cache file metadata as it could change File semantics.
+    // For other filesystem types (which could be platform-specific ones), there's a chance that the files are on remote filesystem.
+    // If the port has returned metadata just pass it to File constructor (so we may cache the metadata).
+    // FIXME: We should use the snapshot metadata for all files.
+    // https://www.w3.org/Bugs/Public/show_bug.cgi?id=17746
+    if (type == FileSystemTypeTemporary || type == FileSystemTypePersistent)
+        return File::createForFileSystemFile(metadata.platformPath, name);
+
+    if (!metadata.platformPath.isEmpty()) {
+        // If the platformPath in the returned metadata is given, we create a File object for the path.
+        File::UserVisibility userVisibility = (type == FileSystemTypeExternal) ? File::IsUserVisible : File::IsNotUserVisible;
+        return File::createForFileSystemFile(name, metadata, userVisibility);
+    }
+
+    return File::createForFileSystemFile(fileSystemURL, metadata);
+}
+
 void DOMFileSystemBase::getMetadata(const EntryBase* entry, PassOwnPtr<MetadataCallback> successCallback, PassOwnPtr<ErrorCallback> errorCallback, SynchronousType synchronousType)
 {
     if (!fileSystem()) {
index c9f1c29..2184113 100644 (file)
@@ -49,7 +49,9 @@ class EntriesCallback;
 class EntryBase;
 class EntryCallback;
 class ErrorCallback;
+class File;
 class FileError;
+struct FileMetadata;
 class MetadataCallback;
 class ExecutionContext;
 class SecurityOrigin;
@@ -101,6 +103,7 @@ public:
     KURL createFileSystemURL(const String& fullPath) const;
     static bool pathToAbsolutePath(FileSystemType, const EntryBase*, String path, String& absolutePath);
     static bool pathPrefixToFileSystemType(const String& pathPrefix, FileSystemType&);
+    static PassRefPtrWillBeRawPtr<File> createFile(const FileMetadata&, const KURL& fileSystemURL, FileSystemType, const String name);
 
     // Actual FileSystem API implementations. All the validity checks on virtual paths are done at this level.
     void getMetadata(const EntryBase*, PassOwnPtr<MetadataCallback>, PassOwnPtr<ErrorCallback>, SynchronousType = Asynchronous);
diff --git a/src/third_party/WebKit/Source/modules/filesystem/DOMFileSystemBaseTest.cpp b/src/third_party/WebKit/Source/modules/filesystem/DOMFileSystemBaseTest.cpp
new file mode 100644 (file)
index 0000000..a5c62f0
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "modules/filesystem/DOMFileSystemBase.h"
+
+#include "core/fileapi/File.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebUnitTestSupport.h"
+#include <gtest/gtest.h>
+
+
+namespace blink {
+
+class DOMFileSystemBaseTest : public ::testing::Test {
+public:
+    DOMFileSystemBaseTest()
+    {
+        m_filePath = Platform::current()->unitTestSupport()->webKitRootDir();
+        m_filePath.append("/Source/modules/filesystem/DOMFileSystemBaseTest.cpp");
+        getFileMetadata(m_filePath, m_fileMetadata);
+        m_fileMetadata.platformPath = m_filePath;
+    }
+
+protected:
+    String m_filePath;
+    FileMetadata m_fileMetadata;
+};
+
+
+TEST_F(DOMFileSystemBaseTest, externalFilesystemFilesAreUserVisible)
+{
+    KURL rootUrl = DOMFileSystemBase::createFileSystemRootURL("http://chromium.org/", FileSystemTypeExternal);
+
+    RefPtrWillBeRawPtr<File> file = DOMFileSystemBase::createFile(m_fileMetadata, rootUrl, FileSystemTypeExternal, "DOMFileSystemBaseTest.cpp");
+    EXPECT_TRUE(file);
+    EXPECT_TRUE(file->hasBackingFile());
+    EXPECT_EQ(File::IsUserVisible, file->userVisibility());
+    EXPECT_EQ("DOMFileSystemBaseTest.cpp", file->name());
+    EXPECT_EQ(m_filePath, file->path());
+}
+
+TEST_F(DOMFileSystemBaseTest, temporaryFilesystemFilesAreNotUserVisible)
+{
+    KURL rootUrl = DOMFileSystemBase::createFileSystemRootURL("http://chromium.org/", FileSystemTypeTemporary);
+
+    RefPtrWillBeRawPtr<File> file = DOMFileSystemBase::createFile(m_fileMetadata, rootUrl, FileSystemTypeTemporary, "UserVisibleName.txt");
+    EXPECT_TRUE(file);
+    EXPECT_TRUE(file->hasBackingFile());
+    EXPECT_EQ(File::IsNotUserVisible, file->userVisibility());
+    EXPECT_EQ("UserVisibleName.txt", file->name());
+    EXPECT_EQ(m_filePath, file->path());
+}
+
+TEST_F(DOMFileSystemBaseTest, persistentFilesystemFilesAreNotUserVisible)
+{
+    KURL rootUrl = DOMFileSystemBase::createFileSystemRootURL("http://chromium.org/", FileSystemTypePersistent);
+
+    RefPtrWillBeRawPtr<File> file = DOMFileSystemBase::createFile(m_fileMetadata, rootUrl, FileSystemTypePersistent, "UserVisibleName.txt");
+    EXPECT_TRUE(file);
+    EXPECT_TRUE(file->hasBackingFile());
+    EXPECT_EQ(File::IsNotUserVisible, file->userVisibility());
+    EXPECT_EQ("UserVisibleName.txt", file->name());
+    EXPECT_EQ(m_filePath, file->path());
+}
+
+} // namespace blink
+
+
+
index 52ffdc3..df69a54 100644 (file)
@@ -133,20 +133,7 @@ public:
         // *after* we've coined a File with a new handle that has the correct type set on it. This allows the
         // blob storage system to track when a temp file can and can't be safely deleted.
 
-        // For regular filesystem types (temporary or persistent), we should not cache file metadata as it could change File semantics.
-        // For other filesystem types (which could be platform-specific ones), there's a chance that the files are on remote filesystem.
-        // If the port has returned metadata just pass it to File constructor (so we may cache the metadata).
-        // FIXME: We should use the snapshot metadata for all files.
-        // https://www.w3.org/Bugs/Public/show_bug.cgi?id=17746
-        if (m_type == FileSystemTypeTemporary || m_type == FileSystemTypePersistent) {
-            m_result->m_file = File::createForFileSystemFile(metadata.platformPath, m_name);
-        } else if (!metadata.platformPath.isEmpty()) {
-            // If the platformPath in the returned metadata is given, we create a File object for the path.
-            m_result->m_file = File::createForFileSystemFile(m_name, metadata).get();
-        } else {
-            // Otherwise create a File from the FileSystem URL.
-            m_result->m_file = File::createForFileSystemFile(m_url, metadata).get();
-        }
+        m_result->m_file = DOMFileSystemBase::createFile(metadata, m_url, m_type, m_name);
     }
 
     virtual bool shouldBlockUntilCompletion() const OVERRIDE
index 19d35e0..9e02f81 100644 (file)
@@ -304,19 +304,7 @@ void SnapshotFileCallback::didCreateSnapshotFile(const FileMetadata& metadata, P
     // *after* we've coined a File with a new handle that has the correct type set on it. This allows the
     // blob storage system to track when a temp file can and can't be safely deleted.
 
-    // For regular filesystem types (temporary or persistent), we should not cache file metadata as it could change File semantics.
-    // For other filesystem types (which could be platform-specific ones), there's a chance that the files are on remote filesystem. If the port has returned metadata just pass it to File constructor (so we may cache the metadata).
-    // FIXME: We should use the snapshot metadata for all files.
-    // https://www.w3.org/Bugs/Public/show_bug.cgi?id=17746
-    if (m_fileSystem->type() == FileSystemTypeTemporary || m_fileSystem->type() == FileSystemTypePersistent) {
-        handleEventOrScheduleCallback(m_successCallback.release(), File::createForFileSystemFile(metadata.platformPath, m_name));
-    } else if (!metadata.platformPath.isEmpty()) {
-        // If the platformPath in the returned metadata is given, we create a File object for the path.
-        handleEventOrScheduleCallback(m_successCallback.release(), File::createForFileSystemFile(m_name, metadata));
-    } else {
-        // Otherwise create a File from the FileSystem URL.
-        handleEventOrScheduleCallback(m_successCallback.release(), File::createForFileSystemFile(m_url, metadata));
-    }
+    handleEventOrScheduleCallback(m_successCallback.release(), DOMFileSystemBase::createFile(metadata, m_url, m_fileSystem->type(), m_name));
 }
 
 // VoidCallbacks --------------------------------------------------------------
index 488b33d..b2455b5 100644 (file)
       'vibration/testing/InternalsVibration.h',
     ],
     'modules_unittest_files': [
+      'filesystem/DOMFileSystemBaseTest.cpp',
       'indexeddb/IDBKeyPathTest.cpp',
       'indexeddb/IDBRequestTest.cpp',
       'indexeddb/IDBTransactionTest.cpp',
index bec4c6c..d85c331 100644 (file)
@@ -33,7 +33,6 @@
 
 #include "platform/PlatformExport.h"
 #include "platform/geometry/IntRect.h"
-#include "platform/heap/Handle.h"
 #include "wtf/RefCounted.h"
 #include "wtf/text/WTFString.h"
 
@@ -64,12 +63,12 @@ struct DateTimeChooserParameters {
     bool isAnchorElementRTL;
 };
 
-class PLATFORM_EXPORT DateTimeChooser : public RefCountedWillBeGarbageCollectedFinalized<DateTimeChooser> {
+// For pickers like color pickers and date pickers.
+class PLATFORM_EXPORT DateTimeChooser : public RefCounted<DateTimeChooser> {
 public:
     virtual ~DateTimeChooser();
 
     virtual void endChooser() = 0;
-    virtual void trace(Visitor*) { }
 };
 
 } // namespace blink
index 7b36bc5..73c6a3a 100644 (file)
@@ -33,6 +33,8 @@
 
 namespace blink {
 
-DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(DateTimeChooserClient)
+DateTimeChooserClient::~DateTimeChooserClient()
+{
+}
 
 } // namespace blink
index 24c1de6..302ca2f 100644 (file)
 #define DateTimeChooserClient_h
 
 #include "platform/PlatformExport.h"
-#include "platform/heap/Handle.h"
 #include "wtf/text/WTFString.h"
 
 namespace blink {
 
-class PLATFORM_EXPORT DateTimeChooserClient : public WillBeGarbageCollectedMixin {
-    DECLARE_EMPTY_VIRTUAL_DESTRUCTOR_WILL_BE_REMOVED(DateTimeChooserClient);
+class PLATFORM_EXPORT DateTimeChooserClient {
 public:
+    virtual ~DateTimeChooserClient();
+
     // Called when user picked a value.
     virtual void didChooseValue(const String&) = 0;
     // Called when user picked a value.
     virtual void didChooseValue(double) = 0;
     // Called when chooser has ended.
     virtual void didEndChooser() = 0;
-
-    virtual void trace(Visitor*) { }
 };
 
 } // namespace blink
index 471010c..5b99405 100644 (file)
@@ -46,6 +46,7 @@ FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
 #if OS(WIN)
     , m_paintTextFlags(0)
     , m_minSizeForAntiAlias(0)
+    , m_minSizeForSubpixel(0)
     , m_useSubpixelPositioning(false)
 #endif
 {
@@ -60,6 +61,7 @@ FontPlatformData::FontPlatformData()
 #if OS(WIN)
     , m_paintTextFlags(0)
     , m_minSizeForAntiAlias(0)
+    , m_minSizeForSubpixel(0)
     , m_useSubpixelPositioning(false)
 #endif
 {
@@ -74,6 +76,7 @@ FontPlatformData::FontPlatformData(float textSize, bool syntheticBold, bool synt
 #if OS(WIN)
     , m_paintTextFlags(0)
     , m_minSizeForAntiAlias(0)
+    , m_minSizeForSubpixel(0)
     , m_useSubpixelPositioning(false)
 #endif
 {
@@ -94,6 +97,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src)
 #if OS(WIN)
     , m_paintTextFlags(src.m_paintTextFlags)
     , m_minSizeForAntiAlias(src.m_minSizeForAntiAlias)
+    , m_minSizeForSubpixel(src.m_minSizeForSubpixel)
     , m_useSubpixelPositioning(src.m_useSubpixelPositioning)
 #endif
 {
@@ -112,6 +116,7 @@ FontPlatformData::FontPlatformData(PassRefPtr<SkTypeface> tf, const char* family
 #if OS(WIN)
     , m_paintTextFlags(0)
     , m_minSizeForAntiAlias(0)
+    , m_minSizeForSubpixel(0)
     , m_useSubpixelPositioning(subpixelTextPosition)
 #endif
 {
@@ -132,6 +137,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
 #if OS(WIN)
     , m_paintTextFlags(src.m_paintTextFlags)
     , m_minSizeForAntiAlias(src.m_minSizeForAntiAlias)
+    , m_minSizeForSubpixel(src.m_minSizeForSubpixel)
     , m_useSubpixelPositioning(src.m_useSubpixelPositioning)
 #endif
 {
@@ -157,6 +163,7 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src)
 #if OS(WIN)
     m_paintTextFlags = 0;
     m_minSizeForAntiAlias = src.m_minSizeForAntiAlias;
+    m_minSizeForSubpixel = src.m_minSizeForSubpixel;
     m_useSubpixelPositioning = src.m_useSubpixelPositioning;
 #endif
 
index 1c5c91f..4091bf7 100644 (file)
@@ -85,6 +85,8 @@ public:
 #if OS(WIN)
     void setMinSizeForAntiAlias(unsigned size) { m_minSizeForAntiAlias = size; }
     unsigned minSizeForAntiAlias() const { return m_minSizeForAntiAlias; }
+    void setMinSizeForSubpixel(float size) { m_minSizeForSubpixel = size; }
+    float minSizeForSubpixel() const { return m_minSizeForSubpixel; }
     void setHinting(SkPaint::Hinting style)
     {
         m_style.useAutoHint = 0;
@@ -135,6 +137,7 @@ private:
     int m_paintTextFlags;
     bool m_useSubpixelPositioning;
     unsigned m_minSizeForAntiAlias;
+    float m_minSizeForSubpixel;
 #endif
 };
 
index f6e9558..47e73c4 100644 (file)
@@ -131,13 +131,6 @@ void SimpleFontData::platformInit()
     m_fontMetrics.setLineGap(lineGap);
     m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap));
 
-    SkScalar underlineThickness, underlinePosition;
-    if (metrics.hasUnderlineThickness(&underlineThickness)
-        && metrics.hasUnderlinePosition(&underlinePosition)) {
-        m_fontMetrics.setUnderlineThickness(SkScalarToFloat(underlineThickness));
-        m_fontMetrics.setUnderlinePosition(SkScalarToFloat(-underlinePosition));
-    }
-
     if (platformData().orientation() == Vertical && !isTextOrientationFallback()) {
         static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a');
         static const uint32_t vorgTag = SkSetFourByteTag('V', 'O', 'R', 'G');
index 1a98655..5dc3114 100644 (file)
@@ -248,6 +248,33 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
         }
     }
 
+    // List of fonts that look bad with subpixel text rendering at smaller font
+    // sizes. This includes all fonts in the Microsoft Core fonts for the Web
+    // collection.
+    const static wchar_t* noSubpixelForSmallSizeFont[] = {
+        L"andale mono",
+        L"arial",
+        L"comic sans",
+        L"courier new",
+        L"georgia",
+        L"impact",
+        L"lucida console",
+        L"tahoma",
+        L"times new roman",
+        L"trebuchet ms",
+        L"verdana",
+        L"webdings"
+    };
+    const static float minSizeForSubpixelForFont = 16.0f;
+    numFonts = WTF_ARRAY_LENGTH(noSubpixelForSmallSizeFont);
+    for (size_t i = 0; i < numFonts; i++) {
+        const wchar_t* family = noSubpixelForSmallSizeFont[i];
+        if (typefacesMatchesFamily(tf.get(), family)) {
+            result->setMinSizeForSubpixel(minSizeForSubpixelForFont);
+            break;
+        }
+    }
+
     return result;
 }
 
index b0037c4..3980887 100644 (file)
@@ -69,7 +69,7 @@ void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) cons
         // run without font smoothing we enable it for tests to ensure we get
         // good test coverage matching the more common smoothing enabled
         // behavior.
-        if (m_useSubpixelPositioning
+        if (m_useSubpixelPositioning && ts >= m_minSizeForSubpixel
             && ((textFlags & SkPaint::kAntiAlias_Flag) || LayoutTestSupport::isRunningLayoutTest()))
             flags |= SkPaint::kSubpixelText_Flag;
 
index a090db0..4ba74c8 100644 (file)
@@ -368,7 +368,7 @@ PassRefPtr<NativeImageSkia> BitmapImage::nativeImageForCurrentFrame()
 
 PassRefPtr<Image> BitmapImage::imageForDefaultFrame()
 {
-    if (isBitmapImage() && maybeAnimated())
+    if (isAnimated())
         return BitmapImage::create(frameAtIndex(0));
 
     return Image::imageForDefaultFrame();
@@ -553,11 +553,17 @@ bool BitmapImage::maybeAnimated()
 {
     if (m_animationFinished)
         return false;
-    if (frameCount() > 1)
+    if (isAnimated())
         return true;
+
     return m_source.repetitionCount() != cAnimationNone;
 }
 
+bool BitmapImage::isAnimated()
+{
+    return frameCount() > 1;
+}
+
 void BitmapImage::advanceAnimation(Timer<BitmapImage>*)
 {
     internalAdvanceAnimation(false);
index 05dede7..d085182 100644 (file)
@@ -106,6 +106,8 @@ protected:
     virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, WebBlendMode) OVERRIDE;
     virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, WebBlendMode, RespectImageOrientationEnum) OVERRIDE;
 
+    // True if the image is animated (contains multiple frames)
+    bool isAnimated();
     size_t currentFrame() const { return m_currentFrame; }
     size_t frameCount();
     PassRefPtr<NativeImageSkia> frameAtIndex(size_t);
index cd00958..fc18234 100644 (file)
@@ -53,7 +53,7 @@ public:
     }
 
     // ImageBufferSurface implementation
-    virtual void finalizeFrame() OVERRIDE { m_layerBridge->finalizeFrame(); }
+    virtual void finalizeFrame(const FloatRect &dirtyRect) OVERRIDE { m_layerBridge->finalizeFrame(dirtyRect); }
     virtual void willAccessPixels() OVERRIDE { m_layerBridge->willAccessPixels(); }
     virtual SkCanvas* canvas() const OVERRIDE { return m_layerBridge->canvas(); }
     virtual bool isValid() const OVERRIDE { return m_layerBridge && m_layerBridge->checkSurfaceValid(); }
index f88c278..eea126b 100644 (file)
@@ -175,6 +175,8 @@ void Canvas2DLayerBridge::willAccessPixels()
 void Canvas2DLayerBridge::freeTransientResources()
 {
     ASSERT(!m_destructionInProgress);
+    if (!m_isSurfaceValid)
+        return;
     freeReleasedMailbox();
     flush();
     freeMemoryIfPossible(bytesAllocated());
@@ -424,6 +426,17 @@ bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox,
 
     ASSERT(mailboxInfo->m_mailbox.syncPoint == 0);
     ASSERT(mailboxInfo->m_image.get());
+
+    // set m_parentLayerBridge to make sure 'this' stays alive as long as it has
+    // live mailboxes
+    ASSERT(!mailboxInfo->m_parentLayerBridge);
+    mailboxInfo->m_parentLayerBridge = this;
+    *outMailbox = mailboxInfo->m_mailbox;
+
+    GrContext* grContext = m_contextProvider->grContext();
+    if (!grContext)
+        return true; // for testing: skip gl stuff when using a mock graphics context.
+
     ASSERT(mailboxInfo->m_image->getTexture());
 
     // Because of texture sharing with the compositor, we must invalidate
@@ -448,13 +461,7 @@ bool Canvas2DLayerBridge::prepareMailbox(WebExternalTextureMailbox* outMailbox,
     webContext->bindTexture(GL_TEXTURE_2D, 0);
     // Because we are changing the texture binding without going through skia,
     // we must dirty the context.
-    m_contextProvider->grContext()->resetContext(kTextureBinding_GrGLBackendState);
-
-    // set m_parentLayerBridge to make sure 'this' stays alive as long as it has
-    // live mailboxes
-    ASSERT(!mailboxInfo->m_parentLayerBridge);
-    mailboxInfo->m_parentLayerBridge = this;
-    *outMailbox = mailboxInfo->m_mailbox;
+    grContext->resetContext(kTextureBinding_GrGLBackendState);
 
     return true;
 }
@@ -505,16 +512,29 @@ void Canvas2DLayerBridge::mailboxReleased(const WebExternalTextureMailbox& mailb
                 // texture and remove the mailbox from list to avoid reusing it
                 // in future.
                 if (mailboxInfo->m_image) {
-                    mailboxInfo->m_image->getTexture()->resetFlag(
-                        static_cast<GrTextureFlags>(GrTexture::kReturnToCache_FlagBit));
-                    mailboxInfo->m_image->getTexture()->textureParamsModified();
+                    GrTexture* texture = mailboxInfo->m_image->getTexture();
+                    if (texture) {
+                        texture->resetFlag(static_cast<GrTextureFlags>(GrTexture::kReturnToCache_FlagBit));
+                        texture->textureParamsModified();
+                    }
                     mailboxInfo->m_image.clear();
                 }
-                size_t i = mailboxInfo - m_mailboxes.begin();
-                m_mailboxes.remove(i);
-                Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this);
-                // Here we need to return early since mailboxInfo removal would
-                // also clear m_parentLayerBridge reference.
+                if (m_destructionInProgress) {
+                    mailboxInfo->m_status = MailboxAvailable; // To satisfy assert in destructor
+
+                    // The following line may trigger self destruction. We do not care about
+                    // not cleaning up m_mailboxes during destruction sequence because
+                    // mailboxes will not be recycled after this point. Calling remove()
+                    // could trigger a memory use after free, so we just clear the self
+                    // reference to be safe, and we let the Canvas2DLayerBridge destructor
+                    // take care of freeing m_mailboxes.
+                    mailboxInfo->m_parentLayerBridge.clear();
+                } else {
+                    size_t i = mailboxInfo - m_mailboxes.begin();
+                    m_mailboxes.remove(i); // indirectly clears mailboxInfo->m_parentLayerBridge
+                    Canvas2DLayerManager::get().layerTransientResourceAllocationChanged(this);
+                }
+                // mailboxInfo is not valid from this point, so we return immediately.
                 return;
             } else {
                 mailboxInfo->m_status = MailboxReleased;
@@ -543,10 +563,11 @@ WebLayer* Canvas2DLayerBridge::layer() const
     return m_layer->layer();
 }
 
-void Canvas2DLayerBridge::finalizeFrame()
+void Canvas2DLayerBridge::finalizeFrame(const FloatRect &dirtyRect)
 {
     ASSERT(!m_destructionInProgress);
     Canvas2DLayerManager::get().layerDidDraw(this);
+    m_layer->layer()->invalidateRect(dirtyRect);
     m_didRecordDrawCommand = true;
 }
 
@@ -566,10 +587,11 @@ Platform3DObject Canvas2DLayerBridge::getBackingTexture()
 
 Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) {
     // This copy constructor should only be used for Vector reallocation
-    // Assuming 'other' is to be destroyed, we transfer m_image ownership
-    // rather than do a refcount dance.
+    // Assuming 'other' is to be destroyed, we transfer m_image and
+    // m_parentLayerBridge ownership rather than do a refcount dance.
     memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox));
     m_image = const_cast<MailboxInfo*>(&other)->m_image.release();
+    m_parentLayerBridge = const_cast<MailboxInfo*>(&other)->m_parentLayerBridge.release();
     m_status = other.m_status;
 }
 
index a1efa63..3b93e43 100644 (file)
@@ -66,7 +66,7 @@ public:
     virtual void skippedPendingDrawCommands() OVERRIDE;
 
     // ImageBufferSurface implementation
-    void finalizeFrame();
+    void finalizeFrame(const FloatRect &dirtyRect);
     void willAccessPixels();
     SkCanvas* canvas() const { return m_canvas.get(); }
     bool checkSurfaceValid();
index ef0fcfe..17f1411 100644 (file)
@@ -135,6 +135,39 @@ protected:
         ::testing::Mock::VerifyAndClearExpectations(&mainMock);
     }
 
+    void noDrawOnContextLostTest()
+    {
+        MockCanvasContext mainMock;
+        OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock));
+        RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(300, 150));
+        OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get()));
+
+        ::testing::Mock::VerifyAndClearExpectations(&mainMock);
+
+        {
+            Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), surface, 0, NonOpaque)));
+            ::testing::Mock::VerifyAndClearExpectations(&mainMock);
+            EXPECT_TRUE(bridge->checkSurfaceValid());
+            SkPaint paint;
+            uint32_t genID = surface->generationID();
+            bridge->canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), paint);
+            EXPECT_EQ(genID, surface->generationID());
+            mainMock.fakeContextLost();
+            EXPECT_EQ(genID, surface->generationID());
+            bridge->canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), paint);
+            EXPECT_EQ(genID, surface->generationID());
+            EXPECT_FALSE(bridge->checkSurfaceValid());
+            EXPECT_EQ(genID, surface->generationID());
+            bridge->canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), paint);
+            EXPECT_EQ(genID, surface->generationID());
+            bridge->freeTransientResources();
+            EXPECT_EQ(genID, surface->generationID());
+            ::testing::Mock::VerifyAndClearExpectations(&mainMock);
+        }
+
+        ::testing::Mock::VerifyAndClearExpectations(&mainMock);
+    }
+
     void prepareMailboxWithBitmapTest()
     {
         MockCanvasContext mainMock;
@@ -148,6 +181,40 @@ protected:
         bridge->prepareMailbox(0, &bitmap);
         EXPECT_EQ(0u, bridge->m_lastImageId);
     }
+
+    void prepareMailboxAndLoseResourceTest()
+    {
+        MockCanvasContext mainMock;
+        RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(300, 150));
+        bool lostResource = true;
+
+        // Prepare a mailbox, then report the resource as lost.
+        // This test passes by not crashing and not triggering assertions.
+        {
+            WebExternalTextureMailbox mailbox;
+            OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get()));
+            OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock));
+            Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), surface, 0, NonOpaque)));
+            bridge->prepareMailbox(&mailbox, 0);
+            bridge->mailboxReleased(mailbox, lostResource);
+        }
+
+        // Retry with mailbox released while bridge destruction is in progress
+        {
+            OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get()));
+            OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock));
+            WebExternalTextureMailbox mailbox;
+            Canvas2DLayerBridge* rawBridge;
+            {
+                Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), surface, 0, NonOpaque)));
+                bridge->prepareMailbox(&mailbox, 0);
+                rawBridge = bridge.get();
+            } // bridge goes out of scope, but object is kept alive by self references
+            // before fixing crbug.com/411864, the following line you cause a memory use after free
+            // that sometimes causes a crash in normal builds and crashes consistently with ASAN.
+            rawBridge->mailboxReleased(mailbox, lostResource); // This should self-destruct the bridge.
+        }
+    }
 };
 
 namespace {
@@ -157,9 +224,19 @@ TEST_F(Canvas2DLayerBridgeTest, testFullLifecycleSingleThreaded)
     fullLifecycleTest();
 }
 
-TEST_F(Canvas2DLayerBridgeTest, prepareMailboxWithBitmapTest)
+TEST_F(Canvas2DLayerBridgeTest, testNoDrawOnContextLost)
+{
+    noDrawOnContextLostTest();
+}
+
+TEST_F(Canvas2DLayerBridgeTest, testPrepareMailboxWithBitmap)
 {
     prepareMailboxWithBitmapTest();
 }
 
+TEST_F(Canvas2DLayerBridgeTest, testPrepareMailboxAndLoseResource)
+{
+    prepareMailboxAndLoseResourceTest();
+}
+
 } // namespace
index 47e5767..93e99f9 100644 (file)
@@ -236,12 +236,13 @@ protected:
 
     void doDeferredFrameTestTask(FakeCanvas2DLayerBridge* layer, bool skipCommands)
     {
+        FloatRect invalidationRect(0, 0, 1, 1);
         EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
-        layer->finalizeFrame();
+        layer->finalizeFrame(invalidationRect);
         layer->storageAllocatedForRecordingChanged(1);
         EXPECT_TRUE(Canvas2DLayerManager::get().m_taskObserverActive);
         if (skipCommands) {
-            layer->finalizeFrame();
+            layer->finalizeFrame(invalidationRect);
             layer->skippedPendingDrawCommands();
         }
         Platform::current()->currentThread()->exitRunLoop();
index 48725ab..f20e85d 100644 (file)
@@ -79,9 +79,9 @@ const CompositingReasonStringMap kCompositingReasonStringMap[] = {
     { CompositingReasonSquashingTransformAncestorMismatch,
         "squashingTransformAncestorMismatch",
         "Cannot be squashed because this layer has a different transform ancestor than the squashing layer" },
-    { CompositingReasonSquashingFilterAncestorMismatch,
+    { CompositingReasonSquashingFilterMismatch,
         "squashingFilterAncestorMismatch",
-        "Cannot be squashed because this layer has a different filter ancestor than the squashing layer" },
+        "Cannot be squashed because this layer has a different filter ancestor than the squashing layer, or this layer has a filter" },
     { CompositingReasonSquashingWouldBreakPaintOrder,
         "squashingWouldBreakPaintOrder",
         "Cannot be squashed without breaking paint order" },
index b9b6da9..07e1375 100644 (file)
@@ -39,7 +39,7 @@ const uint64_t CompositingReasonSquashingSparsityExceeded                = UINT6
 const uint64_t CompositingReasonSquashingClippingContainerMismatch       = UINT64_C(1) << 19;
 const uint64_t CompositingReasonSquashingOpacityAncestorMismatch         = UINT64_C(1) << 20;
 const uint64_t CompositingReasonSquashingTransformAncestorMismatch       = UINT64_C(1) << 21;
-const uint64_t CompositingReasonSquashingFilterAncestorMismatch          = UINT64_C(1) << 22;
+const uint64_t CompositingReasonSquashingFilterMismatch                  = UINT64_C(1) << 22;
 const uint64_t CompositingReasonSquashingWouldBreakPaintOrder            = UINT64_C(1) << 23;
 const uint64_t CompositingReasonSquashingVideoIsDisallowed               = UINT64_C(1) << 24;
 const uint64_t CompositingReasonSquashedLayerClipsCompositingDescendants = UINT64_C(1) << 25;
@@ -139,7 +139,7 @@ const uint64_t CompositingReasonComboReasonsThatRequireOwnBacking =
     | CompositingReasonSquashingClippingContainerMismatch
     | CompositingReasonSquashingOpacityAncestorMismatch
     | CompositingReasonSquashingTransformAncestorMismatch
-    | CompositingReasonSquashingFilterAncestorMismatch
+    | CompositingReasonSquashingFilterMismatch
     | CompositingReasonSquashingWouldBreakPaintOrder
     | CompositingReasonSquashingVideoIsDisallowed
     | CompositingReasonSquashedLayerClipsCompositingDescendants
index eb89f25..5b36b9d 100644 (file)
@@ -815,6 +815,7 @@ void GraphicsLayer::setContentsOpaque(bool opaque)
     m_contentsOpaque = opaque;
     m_layer->layer()->setOpaque(m_contentsOpaque);
     m_opaqueRectTrackingContentLayerDelegate->setOpaque(m_contentsOpaque);
+    clearContentsLayerIfUnregistered();
     if (m_contentsLayer)
         m_contentsLayer->setOpaque(opaque);
 }
index 0defbb0..4ea1880 100644 (file)
@@ -123,9 +123,9 @@ void ImageBuffer::didFinalizeFrame()
         m_client->didFinalizeFrame();
 }
 
-void ImageBuffer::finalizeFrame()
+void ImageBuffer::finalizeFrame(const FloatRect &dirtyRect)
 {
-    m_surface->finalizeFrame();
+    m_surface->finalizeFrame(dirtyRect);
     didFinalizeFrame();
 }
 
index f52516a..d4ae356 100644 (file)
@@ -90,7 +90,7 @@ public:
     GraphicsContext* context() const;
 
     // Called at the end of a task that rendered a whole frame
-    void finalizeFrame();
+    void finalizeFrame(const FloatRect &dirtyRect);
     void didFinalizeFrame();
 
     bool isDirty();
index d81ab9b..242a89d 100644 (file)
@@ -46,6 +46,7 @@ namespace blink {
 
 class ImageBuffer;
 class WebLayer;
+class FloatRect;
 
 enum OpacityMode {
     NonOpaque,
@@ -73,7 +74,7 @@ public:
     virtual void setImageBuffer(ImageBuffer*) { }
     virtual PassRefPtr<SkPicture> getPicture();
     virtual void didClearCanvas() { }
-    virtual void finalizeFrame() { }
+    virtual void finalizeFrame(const FloatRect &dirtyRect) { }
 
     OpacityMode opacityMode() const { return m_opacityMode; }
     const IntSize& size() const { return m_size; }
index 252d436..0c73332 100644 (file)
@@ -102,7 +102,7 @@ PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture()
     return nullptr;
 }
 
-void RecordingImageBufferSurface::finalizeFrame()
+void RecordingImageBufferSurface::finalizeFrame(const FloatRect &)
 {
     if (!finalizeFrameInternal() && !m_rasterCanvas) {
         fallBackToRasterCanvas();
index c8af6a0..e011f07 100644 (file)
@@ -29,7 +29,7 @@ public:
     virtual PassRefPtr<SkPicture> getPicture() OVERRIDE;
     virtual bool isValid() const OVERRIDE { return true; }
     virtual void willAccessPixels() OVERRIDE;
-    virtual void finalizeFrame() OVERRIDE;
+    virtual void finalizeFrame(const FloatRect&) OVERRIDE;
     virtual void didClearCanvas() OVERRIDE;
     virtual void setImageBuffer(ImageBuffer*) OVERRIDE;
 
index a2aedc9..e08b765 100644 (file)
@@ -52,7 +52,8 @@ public:
     virtual void didProcessTask() OVERRIDE
     {
         ASSERT_TRUE(m_isDirty);
-        m_imageBuffer->finalizeFrame();
+        FloatRect dirtyRect(0, 0, 1, 1);
+        m_imageBuffer->finalizeFrame(dirtyRect);
         ASSERT_FALSE(m_isDirty);
     }
 
index cd42b39..6e93a24 100644 (file)
@@ -37,6 +37,7 @@ class MockWebGraphicsContext3D : public WebGraphicsContext3D {
 public:
     MockWebGraphicsContext3D()
         : m_nextTextureId(1)
+        , m_contextLost(false)
     {
     }
 
@@ -48,7 +49,7 @@ public:
 
     virtual void synthesizeGLError(WGC3Denum) { }
 
-    virtual bool isContextLost() { return false; }
+    virtual bool isContextLost() { return m_contextLost; }
 
     virtual void* mapBufferSubDataCHROMIUM(WGC3Denum target, WGC3Dintptr offset, WGC3Dsizeiptr size, WGC3Denum access) { return 0; }
     virtual void unmapBufferSubDataCHROMIUM(const void*) { }
@@ -286,8 +287,10 @@ public:
 
     virtual WebString getTranslatedShaderSourceANGLE(WebGLId) { return WebString(); }
 
+    void fakeContextLost() { m_contextLost = true; }
 protected:
     unsigned m_nextTextureId;
+    bool m_contextLost;
     Attributes m_attrs;
 };
 
index 217af5d..9b4252e 100644 (file)
@@ -929,10 +929,6 @@ public:
     ~DummyBase() { }
 };
 
-// Export this instance to support WillBeGarbageCollectedMixin
-// uses by code residing in non-webcore components.
-template class PLATFORM_EXPORT DummyBase<void>;
-
 #define PassRefPtrWillBeRawPtr WTF::PassRefPtr
 #define RefCountedWillBeGarbageCollected WTF::RefCounted
 #define RefCountedWillBeGarbageCollectedFinalized WTF::RefCounted
index 6f845f5..a4c7410 100644 (file)
@@ -582,7 +582,7 @@ PassOwnPtr<ColorChooser> ChromeClientImpl::createColorChooser(LocalFrame* frame,
     return controller.release();
 }
 
-PassRefPtrWillBeRawPtr<DateTimeChooser> ChromeClientImpl::openDateTimeChooser(DateTimeChooserClient* pickerClient, const DateTimeChooserParameters& parameters)
+PassRefPtr<DateTimeChooser> ChromeClientImpl::openDateTimeChooser(DateTimeChooserClient* pickerClient, const DateTimeChooserParameters& parameters)
 {
 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
     return DateTimeChooserImpl::create(this, pickerClient, parameters);
index e5047e1..455cd6d 100644 (file)
@@ -129,7 +129,7 @@ public:
     virtual void annotatedRegionsChanged() OVERRIDE;
     virtual bool paintCustomOverhangArea(GraphicsContext*, const IntRect&, const IntRect&, const IntRect&) OVERRIDE;
     virtual PassOwnPtr<ColorChooser> createColorChooser(LocalFrame*, ColorChooserClient*, const Color&) OVERRIDE;
-    virtual PassRefPtrWillBeRawPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) OVERRIDE;
+    virtual PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) OVERRIDE;
     virtual void openTextDataListChooser(HTMLInputElement&) OVERRIDE;
     virtual void runOpenPanel(LocalFrame*, PassRefPtr<FileChooser>) OVERRIDE;
     virtual void enumerateChosenDirectory(FileChooser*) OVERRIDE;
index de6ec61..5219ead 100644 (file)
@@ -57,9 +57,9 @@ DateTimeChooserImpl::DateTimeChooserImpl(ChromeClientImpl* chromeClient, DateTim
     m_popup = m_chromeClient->openPagePopup(this, m_parameters.anchorRectInRootView);
 }
 
-PassRefPtrWillBeRawPtr<DateTimeChooserImpl> DateTimeChooserImpl::create(ChromeClientImpl* chromeClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
+PassRefPtr<DateTimeChooserImpl> DateTimeChooserImpl::create(ChromeClientImpl* chromeClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
 {
-    return adoptRefWillBeNoop(new DateTimeChooserImpl(chromeClient, client, parameters));
+    return adoptRef(new DateTimeChooserImpl(chromeClient, client, parameters));
 }
 
 DateTimeChooserImpl::~DateTimeChooserImpl()
@@ -171,7 +171,7 @@ Locale& DateTimeChooserImpl::locale()
 
 void DateTimeChooserImpl::setValueAndClosePopup(int numValue, const String& stringValue)
 {
-    RefPtrWillBeRawPtr<DateTimeChooserImpl> protector(this);
+    RefPtr<DateTimeChooserImpl> protector(this);
     if (numValue >= 0)
         setValue(stringValue);
     endChooser();
@@ -194,12 +194,6 @@ void DateTimeChooserImpl::didClosePopup()
     m_client->didEndChooser();
 }
 
-void DateTimeChooserImpl::trace(Visitor* visitor)
-{
-    visitor->trace(m_client);
-    DateTimeChooser::trace(visitor);
-}
-
 } // namespace blink
 
 #endif // ENABLE(INPUT_MULTIPLE_FIELDS_UI)
index 56bfcd5..e1ef5a8 100644 (file)
@@ -43,9 +43,8 @@ class PagePopup;
 
 class DateTimeChooserImpl FINAL : public DateTimeChooser, public PagePopupClient {
 public:
-    static PassRefPtrWillBeRawPtr<DateTimeChooserImpl> create(ChromeClientImpl*, DateTimeChooserClient*, const DateTimeChooserParameters&);
+    static PassRefPtr<DateTimeChooserImpl> create(ChromeClientImpl*, DateTimeChooserClient*, const DateTimeChooserParameters&);
     virtual ~DateTimeChooserImpl();
-    virtual void trace(Visitor*) OVERRIDE;
 
     // DateTimeChooser functions:
     virtual void endChooser() OVERRIDE;
@@ -62,7 +61,7 @@ private:
     virtual void didClosePopup() OVERRIDE;
 
     ChromeClientImpl* m_chromeClient;
-    RawPtrWillBeMember<DateTimeChooserClient> m_client;
+    DateTimeChooserClient* m_client;
     PagePopup* m_popup;
     DateTimeChooserParameters m_parameters;
     OwnPtr<Locale> m_locale;
index ca0f5af..ea5f8dc 100644 (file)
@@ -76,10 +76,10 @@ ExternalDateTimeChooser::ExternalDateTimeChooser(DateTimeChooserClient* client)
     ASSERT(client);
 }
 
-PassRefPtrWillBeRawPtr<ExternalDateTimeChooser> ExternalDateTimeChooser::create(ChromeClientImpl* chromeClient, WebViewClient* webViewClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
+PassRefPtr<ExternalDateTimeChooser> ExternalDateTimeChooser::create(ChromeClientImpl* chromeClient, WebViewClient* webViewClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
 {
     ASSERT(chromeClient);
-    RefPtrWillBeRawPtr<ExternalDateTimeChooser> chooser = adoptRefWillBeNoop(new ExternalDateTimeChooser(client));
+    RefPtr<ExternalDateTimeChooser> chooser = adoptRef(new ExternalDateTimeChooser(client));
     if (!chooser->openDateTimeChooser(chromeClient, webViewClient, parameters))
         chooser.clear();
     return chooser.release();
index 6e9dabf..ccd9b6a 100644 (file)
@@ -41,7 +41,7 @@ class WebViewClient;
 
 class ExternalDateTimeChooser FINAL : public blink::DateTimeChooser {
 public:
-    static PassRefPtrWillBeRawPtr<ExternalDateTimeChooser> create(ChromeClientImpl*, WebViewClient*, blink::DateTimeChooserClient*, const blink::DateTimeChooserParameters&);
+    static PassRefPtr<ExternalDateTimeChooser> create(ChromeClientImpl*, WebViewClient*, blink::DateTimeChooserClient*, const blink::DateTimeChooserParameters&);
     virtual ~ExternalDateTimeChooser();
 
     // The following functions are for DateTimeChooserCompletion.
index 52d6052..067830e 100644 (file)
@@ -70,7 +70,7 @@ void ExternalPopupMenu::show(const FloatQuad& controlPosition, const IntSize&, i
     }
 
     WebPopupMenuInfo info;
-    getPopupMenuInfo(&info);
+    getPopupMenuInfo(info, *m_popupMenuClient);
     if (info.items.isEmpty())
         return;
     m_webExternalPopupMenu = m_webView.client()->createExternalPopupMenu(info, this);
@@ -124,7 +124,7 @@ void ExternalPopupMenu::disconnectClient()
 void ExternalPopupMenu::didChangeSelection(int index)
 {
     if (m_popupMenuClient)
-        m_popupMenuClient->selectionChanged(toPopupMenuItemIndex(index));
+        m_popupMenuClient->selectionChanged(toPopupMenuItemIndex(index, *m_popupMenuClient));
 }
 
 void ExternalPopupMenu::didAcceptIndex(int index)
@@ -132,7 +132,7 @@ void ExternalPopupMenu::didAcceptIndex(int index)
     // Calling methods on the PopupMenuClient might lead to this object being
     // derefed. This ensures it does not get deleted while we are running this
     // method.
-    int popupMenuItemIndex = toPopupMenuItemIndex(index);
+    int popupMenuItemIndex = toPopupMenuItemIndex(index, *m_popupMenuClient);
     RefPtr<ExternalPopupMenu> guard(this);
 
     if (m_popupMenuClient) {
@@ -158,7 +158,7 @@ void ExternalPopupMenu::didAcceptIndices(const WebVector<int>& indices)
         m_popupMenuClient->valueChanged(static_cast<unsigned>(-1), true);
     else {
         for (size_t i = 0; i < indices.size(); ++i)
-            m_popupMenuClient->listBoxSelectItem(toPopupMenuItemIndex(indices[i]), (i > 0), false, (i == indices.size() - 1));
+            m_popupMenuClient->listBoxSelectItem(toPopupMenuItemIndex(indices[i], *m_popupMenuClient), (i > 0), false, (i == indices.size() - 1));
     }
 
     // The call to valueChanged above might have lead to a call to
@@ -179,49 +179,51 @@ void ExternalPopupMenu::didCancel()
     m_webExternalPopupMenu = 0;
 }
 
-void ExternalPopupMenu::getPopupMenuInfo(WebPopupMenuInfo* info)
+void ExternalPopupMenu::getPopupMenuInfo(WebPopupMenuInfo& info, PopupMenuClient& popupMenuClient)
 {
-    int itemCount = m_popupMenuClient->listSize();
+    int itemCount = popupMenuClient.listSize();
     int count = 0;
     Vector<WebMenuItemInfo> items(static_cast<size_t>(itemCount));
     for (int i = 0; i < itemCount; ++i) {
-        PopupMenuStyle style = m_popupMenuClient->itemStyle(i);
+        PopupMenuStyle style = popupMenuClient.itemStyle(i);
         if (style.isDisplayNone())
             continue;
 
         WebMenuItemInfo& popupItem = items[count++];
-        popupItem.label = m_popupMenuClient->itemText(i);
-        popupItem.toolTip = m_popupMenuClient->itemToolTip(i);
-        if (m_popupMenuClient->itemIsSeparator(i))
+        popupItem.label = popupMenuClient.itemText(i);
+        popupItem.toolTip = popupMenuClient.itemToolTip(i);
+        if (popupMenuClient.itemIsSeparator(i))
             popupItem.type = WebMenuItemInfo::Separator;
-        else if (m_popupMenuClient->itemIsLabel(i))
+        else if (popupMenuClient.itemIsLabel(i))
             popupItem.type = WebMenuItemInfo::Group;
         else
             popupItem.type = WebMenuItemInfo::Option;
-        popupItem.enabled = m_popupMenuClient->itemIsEnabled(i);
-        popupItem.checked = m_popupMenuClient->itemIsSelected(i);
+        popupItem.enabled = popupMenuClient.itemIsEnabled(i);
+        popupItem.checked = popupMenuClient.itemIsSelected(i);
         popupItem.textDirection = toWebTextDirection(style.textDirection());
         popupItem.hasTextDirectionOverride = style.hasTextDirectionOverride();
     }
 
-    info->itemHeight = m_popupMenuClient->menuStyle().font().fontMetrics().height();
-    info->itemFontSize = static_cast<int>(m_popupMenuClient->menuStyle().font().fontDescription().computedSize());
-    info->selectedIndex = toExternalPopupMenuItemIndex(m_popupMenuClient->selectedIndex());
-    info->rightAligned = m_popupMenuClient->menuStyle().textDirection() == RTL;
-    info->allowMultipleSelection = m_popupMenuClient->multiple();
-    info->items = items;
+    info.itemHeight = popupMenuClient.menuStyle().font().fontMetrics().height();
+    info.itemFontSize = static_cast<int>(popupMenuClient.menuStyle().font().fontDescription().computedSize());
+    info.selectedIndex = toExternalPopupMenuItemIndex(popupMenuClient.selectedIndex(), popupMenuClient);
+    info.rightAligned = popupMenuClient.menuStyle().textDirection() == RTL;
+    info.allowMultipleSelection = popupMenuClient.multiple();
+    if (count < itemCount)
+        items.shrink(count);
+    info.items = items;
+
 }
 
-int ExternalPopupMenu::toPopupMenuItemIndex(int externalPopupMenuItemIndex)
+int ExternalPopupMenu::toPopupMenuItemIndex(int externalPopupMenuItemIndex, PopupMenuClient& popupMenuClient)
 {
-    ASSERT(m_popupMenuClient);
     if (externalPopupMenuItemIndex < 0)
         return externalPopupMenuItemIndex;
 
-    int itemCount = m_popupMenuClient->listSize();
+    int itemCount = popupMenuClient.listSize();
     int indexTracker = 0;
     for (int i = 0; i < itemCount ; ++i) {
-        if (m_popupMenuClient->itemStyle(i).isDisplayNone())
+        if (popupMenuClient.itemStyle(i).isDisplayNone())
             continue;
         if (indexTracker++ == externalPopupMenuItemIndex)
             return i;
@@ -229,16 +231,15 @@ int ExternalPopupMenu::toPopupMenuItemIndex(int externalPopupMenuItemIndex)
     return -1;
 }
 
-int ExternalPopupMenu::toExternalPopupMenuItemIndex(int popupMenuItemIndex)
+int ExternalPopupMenu::toExternalPopupMenuItemIndex(int popupMenuItemIndex, PopupMenuClient& popupMenuClient)
 {
-    ASSERT(m_popupMenuClient);
     if (popupMenuItemIndex < 0)
         return popupMenuItemIndex;
 
-    int itemCount = m_popupMenuClient->listSize();
+    int itemCount = popupMenuClient.listSize();
     int indexTracker = 0;
     for (int i = 0; i < itemCount; ++i) {
-        if (m_popupMenuClient->itemStyle(i).isDisplayNone())
+        if (popupMenuClient.itemStyle(i).isDisplayNone())
             continue;
         if (popupMenuItemIndex == i)
             return indexTracker;
index 893cf0b..b629f4c 100644 (file)
@@ -57,6 +57,15 @@ public:
     ExternalPopupMenu(LocalFrame&, PopupMenuClient*, WebViewImpl&);
     virtual ~ExternalPopupMenu();
 
+
+    // Fills |info| with the popup menu information contained in the
+    // PopupMenuClient associated with this ExternalPopupMenu.
+    // FIXME: public only for test access. Need to revert once gtest
+    // helpers from chromium are available for blink.
+    static void getPopupMenuInfo(WebPopupMenuInfo&, PopupMenuClient&);
+    static int toPopupMenuItemIndex(int index, PopupMenuClient&);
+    static int toExternalPopupMenuItemIndex(int index, PopupMenuClient&);
+
 private:
     // PopupMenu methods:
     virtual void show(const FloatQuad& controlPosition, const IntSize&, int index) OVERRIDE;
@@ -71,11 +80,6 @@ private:
     virtual void didCancel() OVERRIDE;
 
     void dispatchEvent(Timer<ExternalPopupMenu>*);
-    // Fills |info| with the popup menu information contained in the
-    // PopupMenuClient associated with this ExternalPopupMenu.
-    void getPopupMenuInfo(WebPopupMenuInfo* info);
-    int toPopupMenuItemIndex(int index);
-    int toExternalPopupMenuItemIndex(int index);
 
     PopupMenuClient* m_popupMenuClient;
     RefPtr<FrameView> m_frameView;
diff --git a/src/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp b/src/third_party/WebKit/Source/web/ExternalPopupMenuTest.cpp
new file mode 100644 (file)
index 0000000..33a9a0a
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "web/ExternalPopupMenu.h"
+
+#include "platform/PopupMenu.h"
+#include "platform/PopupMenuClient.h"
+#include "public/web/WebPopupMenuInfo.h"
+#include <gtest/gtest.h>
+
+using namespace blink;
+
+namespace {
+
+const size_t kListSize = 7;
+
+class TestPopupMenuClient : public PopupMenuClient {
+public:
+    TestPopupMenuClient() : m_listSize(0) { }
+    virtual ~TestPopupMenuClient() { }
+
+    virtual void valueChanged(unsigned listIndex, bool fireEvents = true) OVERRIDE { }
+    virtual void selectionChanged(unsigned listIndex, bool fireEvents = true) OVERRIDE { }
+    virtual void selectionCleared() OVERRIDE { }
+
+    virtual String itemText(unsigned listIndex) const OVERRIDE { return emptyString(); }
+    virtual String itemToolTip(unsigned listIndex) const OVERRIDE { return emptyString(); }
+    virtual String itemAccessibilityText(unsigned listIndex) const OVERRIDE { return emptyString(); }
+    virtual bool itemIsEnabled(unsigned listIndex) const OVERRIDE { return true; }
+    virtual PopupMenuStyle itemStyle(unsigned listIndex) const OVERRIDE
+    {
+        FontDescription fontDescription;
+        fontDescription.setComputedSize(12.0);
+        Font font(fontDescription);
+        font.update(nullptr);
+        bool displayNone = m_displayNoneIndexSet.find(listIndex) != m_displayNoneIndexSet.end();
+        return PopupMenuStyle(Color::black, Color::white, font, true, displayNone, Length(), TextDirection(), false);
+    }
+    virtual PopupMenuStyle menuStyle() const OVERRIDE { return itemStyle(0); }
+    virtual LayoutUnit clientPaddingLeft() const OVERRIDE { return 0; }
+    virtual LayoutUnit clientPaddingRight() const OVERRIDE { return 0; }
+    virtual int listSize() const OVERRIDE { return m_listSize; }
+    virtual int selectedIndex() const OVERRIDE { return 0; }
+    virtual void popupDidHide() OVERRIDE { }
+    virtual bool itemIsSeparator(unsigned listIndex) const OVERRIDE { return false;}
+    virtual bool itemIsLabel(unsigned listIndex) const OVERRIDE { return false; }
+    virtual bool itemIsSelected(unsigned listIndex) const OVERRIDE { return listIndex == 0;}
+    virtual void setTextFromItem(unsigned listIndex) OVERRIDE { }
+    virtual bool multiple() const OVERRIDE { return false; }
+
+    void setListSize(size_t size) { m_listSize = size; }
+    void setDisplayNoneIndex(unsigned index) { m_displayNoneIndexSet.insert(index); }
+private:
+    size_t m_listSize;
+    std::set<unsigned> m_displayNoneIndexSet;
+};
+
+class ExternalPopupMenuDisplayNoneItemsTest : public testing::Test {
+public:
+    ExternalPopupMenuDisplayNoneItemsTest() { }
+
+protected:
+    virtual void SetUp() OVERRIDE
+    {
+        m_popupMenuClient.setListSize(kListSize);
+
+        // Set the 4th an 5th items to have "display: none" property
+        m_popupMenuClient.setDisplayNoneIndex(3);
+        m_popupMenuClient.setDisplayNoneIndex(4);
+    }
+
+    TestPopupMenuClient m_popupMenuClient;
+};
+
+TEST_F(ExternalPopupMenuDisplayNoneItemsTest, PopupMenuInfoSizeTest)
+{
+    WebPopupMenuInfo info;
+    ExternalPopupMenu::getPopupMenuInfo(info, m_popupMenuClient);
+    EXPECT_EQ(5U, info.items.size());
+}
+
+TEST_F(ExternalPopupMenuDisplayNoneItemsTest, IndexMappingTest)
+{
+    // 6th indexed item in popupmenu would be the 4th item in ExternalPopupMenu,
+    // and vice-versa.
+    EXPECT_EQ(4, ExternalPopupMenu::toExternalPopupMenuItemIndex(6, m_popupMenuClient));
+    EXPECT_EQ(6, ExternalPopupMenu::toPopupMenuItemIndex(4, m_popupMenuClient));
+
+    // Invalid index, methods should return -1.
+    EXPECT_EQ(-1, ExternalPopupMenu::toExternalPopupMenuItemIndex(8, m_popupMenuClient));
+    EXPECT_EQ(-1, ExternalPopupMenu::toPopupMenuItemIndex(8, m_popupMenuClient));
+}
+
+} // namespace
index 6096aec..0638063 100644 (file)
@@ -3588,6 +3588,10 @@ void WebViewImpl::extractSmartClipData(WebRect rect, WebString& clipText, WebStr
     Position startPosition = startVisiblePosition.deepEquivalent();
     Position endPosition = endVisiblePosition.deepEquivalent();
 
+    // document() will return null if -webkit-user-select is set to none.
+    if (!startPosition.document() || !endPosition.document())
+        return;
+
     RefPtrWillBeRawPtr<Range> range = Range::create(*startPosition.document(), startPosition, endPosition);
     if (!range)
         return;
index 35feefd..817e82b 100644 (file)
@@ -1624,6 +1624,23 @@ TEST_F(WebViewTest, SmartClipData)
     EXPECT_STREQ(kExpectedClipHtml, clipHtml.utf8().c_str());
 }
 
+TEST_F(WebViewTest, SmartClipReturnsEmptyStringsWhenUserSelectIsNone)
+{
+    WebString clipText;
+    WebString clipHtml;
+    WebRect clipRect;
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("Ahem.ttf"));
+    URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c_str()), WebString::fromUTF8("smartclip_user_select_none.html"));
+    WebView* webView = m_webViewHelper.initializeAndLoad(m_baseURL + "smartclip_user_select_none.html");
+    webView->setPageScaleFactorLimits(1, 1);
+    webView->resize(WebSize(500, 500));
+    webView->layout();
+    WebRect cropRect(0, 0, 100, 100);
+    webView->extractSmartClipData(cropRect, clipText, clipHtml, clipRect);
+    EXPECT_STREQ("", clipText.utf8().c_str());
+    EXPECT_STREQ("", clipHtml.utf8().c_str());
+}
+
 class CreateChildCounterFrameClient : public FrameTestHelpers::TestWebFrameClient {
 public:
     CreateChildCounterFrameClient() : m_count(0) { }
diff --git a/src/third_party/WebKit/Source/web/tests/data/smartclip_user_select_none.html b/src/third_party/WebKit/Source/web/tests/data/smartclip_user_select_none.html
new file mode 100644 (file)
index 0000000..3c576bb
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <style>
+    body {
+        -webkit-user-select:none;
+    }
+  </style>
+</head>
+
+<body>
+abcdefghijklmnopqrstuvwxyz<br>
+abcdefghijklmnopqrstuvwxyz<br>
+abcdefghijklmnopqrstuvwxyz<br>
+abcdefghijklmnopqrstuvwxyz<br>
+abcdefghijklmnopqrstuvwxyz<br>
+abcdefghijklmnopqrstuvwxyz<br>
+</body>
+
+</html>
index 4787ff8..df6879c 100644 (file)
       'win/WebFontRendering.cpp',
     ],
     'web_unittest_files': [
+      'ExternalPopupMenuTest.cpp',
       'WebNodeTest.cpp',
       # FIXME: Move the tests from web/tests/ to appropriate places.
       # crbug.com/353585
index 18d754c..84aa6d4 100644 (file)
@@ -62,6 +62,11 @@ Note: You'll need a Gerrit account, see:
 
   http://www.chromium.org/chromium-os/developer-guide/gerrit-guide
 
+You also need to add an ssh key at
+https://gerrit.chromium.org/gerrit/#/settings/ssh-keys . Generate a key
+following the GitHub guide linked from there, then copy the contents of your
+~/.ssh/id_rsa.pub file to that gerrit page.
+
 If your change adds new files to the repository, you'll need to regenerate the
 GYP defines by following the directions in chromium/scripts/generate_gyp.py.
 
index 196bb62..8ad5e3b 100644 (file)
               '-Wno-pointer-sign',
               # ffmpeg doesn't believe in exhaustive switch statements.
               '-Wno-switch',
+              # matroskadec.c has a "failed:" label that's only used if some
+              # CONFIG_ flags we don't set are set.
+              '-Wno-unused-label',
             ],
           },
           'cflags': [
                 4116, 4307, 4273, 4005, 4056, 4756,
               ],
               'conditions': [
-                ['clang == 1 or (OS == "win" and (MSVS_VERSION == "2013" or MSVS_VERSION == "2013e"))', {
+                ['clang == 1', {
+                  'msvs_settings': {
+                    'VCCLCompilerTool': {
+                      # This corresponds to msvs_disabled_warnings 4273 above.
+                      'AdditionalOptions': [ '-Wno-inconsistent-dllimport' ],
+                    },
+                  },
+                }],
+                ['clang == 1 or (MSVS_VERSION == "2013" or MSVS_VERSION == "2013e")', {
                   'defines': [
                     'inline=__inline',
                     'strtoll=_strtoi64',
index ab6ca4e..cb93ba9 100644 (file)
@@ -34,7 +34,7 @@ static int aac_sync(uint64_t state, AACAC3ParseContext *hdr_info,
     int size;
     union {
         uint64_t u64;
-        uint8_t  u8[8];
+        uint8_t  u8[8 + FF_INPUT_BUFFER_PADDING_SIZE];
     } tmp;
 
     tmp.u64 = av_be2ne64(state);
index dd6d77c..131e180 100644 (file)
@@ -166,7 +166,7 @@ static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info,
     int err;
     union {
         uint64_t u64;
-        uint8_t  u8[8];
+        uint8_t  u8[8 + FF_INPUT_BUFFER_PADDING_SIZE];
     } tmp = { av_be2ne64(state) };
     AC3HeaderInfo hdr, *phdr = &hdr;
     GetBitContext gbc;
index b01cb0a..0982c6b 100644 (file)
@@ -10,6 +10,8 @@ This consists of the components:
 * A partial copy of libjpeg-turbo 1.3.1 (r1219);
 * Revision r1188 cherry-picked from upstream trunk into config.h;
 * Revision r1220 cherry-picked from upstream trunk into jchuff.c;
+* Revisions r1108, r1109, r1333, r1375, r1386, r1389 and r1390 cherry-picked
+  from upstream trunk for Arm64;
 * A build file (libjpeg.gyp), and;
 * Patched header files used by Chromium.
 
@@ -25,6 +27,9 @@ following changes which are not merged to upstream:
 * Added the 'private_extern' flags on Mac (or the 'hidden' flags on Linux) to
   all the global symbols in '.asm' files to prevent making them external ones.
 * Supported motion-JPEG frames that do not have DHT markers.
+* Removed .func / .endfunc lines from arm assembly
+  ( https://sourceforge.net/p/libjpeg-turbo/bugs/72/ , landed at
+  https://sourceforge.net/p/libjpeg-turbo/code/1375 ).
 
 The 'google.patch' file represents our changes from the original
 libjpeg-turbo-1.2.
index 8a9179d..de6fadd 100644 (file)
@@ -1235,6 +1235,102 @@ Index: simd/jcsammmx.asm
  
  EXTN(jsimd_h2v2_downsample_mmx):
        push    ebp
+Index: simd/jsimd_arm_neon.S
+===================================================================
+--- simd/jsimd_arm_neon.S      (revision 272637)
++++ simd/jsimd_arm_neon.S      (working copy)
+@@ -41,11 +41,9 @@
+ /* Supplementary macro for setting function attributes */
+ .macro asm_function fname
+ #ifdef __APPLE__
+-    .func _\fname
+     .globl _\fname
+ _\fname:
+ #else
+-    .func \fname
+     .global \fname
+ #ifdef __ELF__
+     .hidden \fname
+@@ -670,7 +668,6 @@
+     .unreq          ROW6R
+     .unreq          ROW7L
+     .unreq          ROW7R
+-.endfunc
+ /*****************************************************************************/
+@@ -895,7 +892,6 @@
+     .unreq          TMP2
+     .unreq          TMP3
+     .unreq          TMP4
+-.endfunc
+ /*****************************************************************************/
+@@ -1108,7 +1104,6 @@
+     .unreq          TMP2
+     .unreq          TMP3
+     .unreq          TMP4
+-.endfunc
+ .purgem idct_helper
+@@ -1263,7 +1258,6 @@
+     .unreq          OUTPUT_COL
+     .unreq          TMP1
+     .unreq          TMP2
+-.endfunc
+ .purgem idct_helper
+@@ -1547,7 +1541,6 @@
+     .unreq          U
+     .unreq          V
+     .unreq          N
+-.endfunc
+ .purgem do_yuv_to_rgb
+ .purgem do_yuv_to_rgb_stage1
+@@ -1858,7 +1851,6 @@
+     .unreq          U
+     .unreq          V
+     .unreq          N
+-.endfunc
+ .purgem do_rgb_to_yuv
+ .purgem do_rgb_to_yuv_stage1
+@@ -1940,7 +1932,6 @@
+     .unreq          TMP2
+     .unreq          TMP3
+     .unreq          TMP4
+-.endfunc
+ /*****************************************************************************/
+@@ -2064,7 +2055,6 @@
+     .unreq          DATA
+     .unreq          TMP
+-.endfunc
+ /*****************************************************************************/
+@@ -2166,7 +2156,6 @@
+     .unreq          CORRECTION
+     .unreq          SHIFT
+     .unreq          LOOP_COUNT
+-.endfunc
+ /*****************************************************************************/
+@@ -2401,7 +2390,6 @@
+     .unreq          WIDTH
+     .unreq          TMP
+-.endfunc
+ .purgem upsample16
+ .purgem upsample32
 Index: simd/jsimd_i386.c
 ===================================================================
 --- simd/jsimd_i386.c  (revision 829)
@@ -1842,3 +1938,2419 @@ Index: jchuff.c
      /* if run length > 15, must emit special run-length-16 codes (0xF0) */ \
      while (r > 15) { \
        EMIT_BITS(code_0xf0, size_0xf0) \
+Index: simd/jsimd_arm64.c
+===================================================================
+--- /dev/null
++++ simd/jsimd_arm64.c
+@@ -0,0 +1,544 @@
++/*
++ * jsimd_arm64.c
++ *
++ * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
++ * Copyright 2009-2011, 2013-2014 D. R. Commander
++ *
++ * Based on the x86 SIMD extension for IJG JPEG library,
++ * Copyright (C) 1999-2006, MIYASAKA Masaru.
++ * For conditions of distribution and use, see copyright notice in jsimdext.inc
++ *
++ * This file contains the interface between the "normal" portions
++ * of the library and the SIMD implementations when running on a
++ * 64-bit ARM architecture.
++ */
++
++#define JPEG_INTERNALS
++#include "../jinclude.h"
++#include "../jpeglib.h"
++#include "../jsimd.h"
++#include "../jdct.h"
++#include "../jsimddct.h"
++#include "jsimd.h"
++
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++
++static unsigned int simd_support = ~0;
++
++/*
++ * Check what SIMD accelerations are supported.
++ *
++ * FIXME: This code is racy under a multi-threaded environment.
++ */
++
++/* 
++ * ARMv8 architectures support NEON extensions by default.
++ * It is no longer optional as it was with ARMv7.
++ */ 
++
++
++LOCAL(void)
++init_simd (void)
++{
++  char *env = NULL;
++
++  if (simd_support != ~0U)
++    return;
++
++  simd_support = 0;
++
++  simd_support |= JSIMD_ARM_NEON;
++
++  /* Force different settings through environment variables */
++  env = getenv("JSIMD_FORCENEON");
++  if ((env != NULL) && (strcmp(env, "1") == 0))
++    simd_support &= JSIMD_ARM_NEON;
++  env = getenv("JSIMD_FORCENONE");
++  if ((env != NULL) && (strcmp(env, "1") == 0))
++    simd_support = 0;
++}
++
++GLOBAL(int)
++jsimd_can_rgb_ycc (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_rgb_gray (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_ycc_rgb (void)
++{
++  init_simd();
++
++  /* The code is optimised for these values only */
++  if (BITS_IN_JSAMPLE != 8)
++    return 0;
++  if (sizeof(JDIMENSION) != 4)
++    return 0;
++  if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4))
++    return 0;
++
++  if (simd_support & JSIMD_ARM_NEON)
++    return 1;
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_ycc_rgb565 (void)
++{
++  init_simd();
++
++  /* The code is optimised for these values only */
++  if (BITS_IN_JSAMPLE != 8)
++    return 0;
++  if (sizeof(JDIMENSION) != 4)
++    return 0;
++
++  if (simd_support & JSIMD_ARM_NEON)
++    return 1;
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_rgb_ycc_convert (j_compress_ptr cinfo,
++                       JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
++                       JDIMENSION output_row, int num_rows)
++{
++}
++
++GLOBAL(void)
++jsimd_rgb_gray_convert (j_compress_ptr cinfo,
++                        JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
++                        JDIMENSION output_row, int num_rows)
++{
++}
++
++GLOBAL(void)
++jsimd_ycc_rgb_convert (j_decompress_ptr cinfo,
++                       JSAMPIMAGE input_buf, JDIMENSION input_row,
++                       JSAMPARRAY output_buf, int num_rows)
++{
++  void (*neonfct)(JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
++
++  switch(cinfo->out_color_space) {
++    case JCS_EXT_RGB:
++      neonfct=jsimd_ycc_extrgb_convert_neon;
++      break;
++    case JCS_EXT_RGBX:
++    case JCS_EXT_RGBA:
++      neonfct=jsimd_ycc_extrgbx_convert_neon;
++      break;
++    case JCS_EXT_BGR:
++      neonfct=jsimd_ycc_extbgr_convert_neon;
++      break;
++    case JCS_EXT_BGRX:
++    case JCS_EXT_BGRA:
++      neonfct=jsimd_ycc_extbgrx_convert_neon;
++      break;
++    case JCS_EXT_XBGR:
++    case JCS_EXT_ABGR:
++      neonfct=jsimd_ycc_extxbgr_convert_neon;
++      break;
++    case JCS_EXT_XRGB:
++    case JCS_EXT_ARGB:
++      neonfct=jsimd_ycc_extxrgb_convert_neon;
++      break;
++    default:
++      neonfct=jsimd_ycc_extrgb_convert_neon;
++      break;
++  }
++
++  if (simd_support & JSIMD_ARM_NEON)
++    neonfct(cinfo->output_width, input_buf, input_row, output_buf, num_rows);
++}
++
++GLOBAL(void)
++jsimd_ycc_rgb565_convert (j_decompress_ptr cinfo,
++                          JSAMPIMAGE input_buf, JDIMENSION input_row,
++                          JSAMPARRAY output_buf, int num_rows)
++{
++  if (simd_support & JSIMD_ARM_NEON)
++    jsimd_ycc_rgb565_convert_neon(cinfo->output_width, input_buf, input_row,
++                                  output_buf, num_rows);
++}
++
++GLOBAL(int)
++jsimd_can_h2v2_downsample (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_h2v1_downsample (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
++                       JSAMPARRAY input_data, JSAMPARRAY output_data)
++{
++}
++
++GLOBAL(void)
++jsimd_h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
++                       JSAMPARRAY input_data, JSAMPARRAY output_data)
++{
++}
++
++GLOBAL(int)
++jsimd_can_h2v2_upsample (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_h2v1_upsample (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_h2v2_upsample (j_decompress_ptr cinfo,
++                     jpeg_component_info * compptr,
++                     JSAMPARRAY input_data,
++                     JSAMPARRAY * output_data_ptr)
++{
++}
++
++GLOBAL(void)
++jsimd_h2v1_upsample (j_decompress_ptr cinfo,
++                     jpeg_component_info * compptr,
++                     JSAMPARRAY input_data,
++                     JSAMPARRAY * output_data_ptr)
++{
++}
++
++GLOBAL(int)
++jsimd_can_h2v2_fancy_upsample (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_h2v1_fancy_upsample (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_h2v2_fancy_upsample (j_decompress_ptr cinfo,
++                           jpeg_component_info * compptr,
++                           JSAMPARRAY input_data,
++                           JSAMPARRAY * output_data_ptr)
++{
++}
++
++GLOBAL(void)
++jsimd_h2v1_fancy_upsample (j_decompress_ptr cinfo,
++                           jpeg_component_info * compptr,
++                           JSAMPARRAY input_data,
++                           JSAMPARRAY * output_data_ptr)
++{
++}
++
++GLOBAL(int)
++jsimd_can_h2v2_merged_upsample (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_h2v1_merged_upsample (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_h2v2_merged_upsample (j_decompress_ptr cinfo,
++                            JSAMPIMAGE input_buf,
++                            JDIMENSION in_row_group_ctr,
++                            JSAMPARRAY output_buf)
++{
++}
++
++GLOBAL(void)
++jsimd_h2v1_merged_upsample (j_decompress_ptr cinfo,
++                            JSAMPIMAGE input_buf,
++                            JDIMENSION in_row_group_ctr,
++                            JSAMPARRAY output_buf)
++{
++}
++
++GLOBAL(int)
++jsimd_can_convsamp (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_convsamp_float (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_convsamp (JSAMPARRAY sample_data, JDIMENSION start_col,
++                DCTELEM * workspace)
++{
++}
++
++GLOBAL(void)
++jsimd_convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col,
++                      FAST_FLOAT * workspace)
++{
++}
++
++GLOBAL(int)
++jsimd_can_fdct_islow (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_fdct_ifast (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_fdct_float (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_fdct_islow (DCTELEM * data)
++{
++}
++
++GLOBAL(void)
++jsimd_fdct_ifast (DCTELEM * data)
++{
++}
++
++GLOBAL(void)
++jsimd_fdct_float (FAST_FLOAT * data)
++{
++}
++
++GLOBAL(int)
++jsimd_can_quantize (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_quantize_float (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_quantize (JCOEFPTR coef_block, DCTELEM * divisors,
++                DCTELEM * workspace)
++{
++}
++
++GLOBAL(void)
++jsimd_quantize_float (JCOEFPTR coef_block, FAST_FLOAT * divisors,
++                      FAST_FLOAT * workspace)
++{
++}
++
++GLOBAL(int)
++jsimd_can_idct_2x2 (void)
++{
++  init_simd();
++
++  /* The code is optimised for these values only */
++  if (DCTSIZE != 8)
++    return 0;
++  if (sizeof(JCOEF) != 2)
++    return 0;
++  if (BITS_IN_JSAMPLE != 8)
++    return 0;
++  if (sizeof(JDIMENSION) != 4)
++    return 0;
++  if (sizeof(ISLOW_MULT_TYPE) != 2)
++    return 0;
++
++  if (simd_support & JSIMD_ARM_NEON)
++    return 1;
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_idct_4x4 (void)
++{
++  init_simd();
++
++  /* The code is optimised for these values only */
++  if (DCTSIZE != 8)
++    return 0;
++  if (sizeof(JCOEF) != 2)
++    return 0;
++  if (BITS_IN_JSAMPLE != 8)
++    return 0;
++  if (sizeof(JDIMENSION) != 4)
++    return 0;
++  if (sizeof(ISLOW_MULT_TYPE) != 2)
++    return 0;
++
++  if (simd_support & JSIMD_ARM_NEON)
++    return 1;
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
++                JCOEFPTR coef_block, JSAMPARRAY output_buf,
++                JDIMENSION output_col)
++{
++  if (simd_support & JSIMD_ARM_NEON)
++    jsimd_idct_2x2_neon(compptr->dct_table, coef_block, output_buf,
++                        output_col);
++}
++
++GLOBAL(void)
++jsimd_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
++                JCOEFPTR coef_block, JSAMPARRAY output_buf,
++                JDIMENSION output_col)
++{
++  if (simd_support & JSIMD_ARM_NEON)
++    jsimd_idct_4x4_neon(compptr->dct_table, coef_block, output_buf,
++                        output_col);
++}
++
++GLOBAL(int)
++jsimd_can_idct_islow (void)
++{
++  init_simd();
++
++  /* The code is optimised for these values only */
++  if (DCTSIZE != 8)
++    return 0;
++  if (sizeof(JCOEF) != 2)
++    return 0;
++  if (BITS_IN_JSAMPLE != 8)
++    return 0;
++  if (sizeof(JDIMENSION) != 4)
++    return 0;
++  if (sizeof(ISLOW_MULT_TYPE) != 2)
++    return 0;
++
++  if (simd_support & JSIMD_ARM_NEON)
++    return 1;
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_idct_ifast (void)
++{
++  init_simd();
++
++  /* The code is optimised for these values only */
++  if (DCTSIZE != 8)
++    return 0;
++  if (sizeof(JCOEF) != 2)
++    return 0;
++  if (BITS_IN_JSAMPLE != 8)
++    return 0;
++  if (sizeof(JDIMENSION) != 4)
++    return 0;
++  if (sizeof(IFAST_MULT_TYPE) != 2)
++    return 0;
++  if (IFAST_SCALE_BITS != 2)
++    return 0;
++
++  if (simd_support & JSIMD_ARM_NEON)
++    return 1;
++
++  return 0;
++}
++
++GLOBAL(int)
++jsimd_can_idct_float (void)
++{
++  init_simd();
++
++  return 0;
++}
++
++GLOBAL(void)
++jsimd_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr,
++                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
++                  JDIMENSION output_col)
++{
++  if (simd_support & JSIMD_ARM_NEON)
++    jsimd_idct_islow_neon(compptr->dct_table, coef_block, output_buf,
++                          output_col);
++}
++
++GLOBAL(void)
++jsimd_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr,
++                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
++                  JDIMENSION output_col)
++{
++  if (simd_support & JSIMD_ARM_NEON)
++    jsimd_idct_ifast_neon(compptr->dct_table, coef_block, output_buf,
++                          output_col);
++}
++
++GLOBAL(void)
++jsimd_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,
++                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
++                  JDIMENSION output_col)
++{
++}
+Index: simd/jsimd_arm64_neon.S
+new file mode 100644
+===================================================================
+--- /dev/null
++++ simd/jsimd_arm64_neon.S
+@@ -0,0 +1,1861 @@
++/*
++ * ARMv8 NEON optimizations for libjpeg-turbo
++ *
++ * Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies).
++ * All rights reserved.
++ * Author: Siarhei Siamashka <siarhei.siamashka@nokia.com>
++ * Copyright (C) 2013-2014, Linaro Limited
++ * Author: Ragesh Radhakrishnan <ragesh.r@linaro.org>
++ *
++ * This software is provided 'as-is', without any express or implied
++ * warranty.  In no event will the authors be held liable for any damages
++ * arising from the use of this software.
++ *
++ * Permission is granted to anyone to use this software for any purpose,
++ * including commercial applications, and to alter it and redistribute it
++ * freely, subject to the following restrictions:
++ *
++ * 1. The origin of this software must not be misrepresented; you must not
++ *    claim that you wrote the original software. If you use this software
++ *    in a product, an acknowledgment in the product documentation would be
++ *    appreciated but is not required.
++ * 2. Altered source versions must be plainly marked as such, and must not be
++ *    misrepresented as being the original software.
++ * 3. This notice may not be removed or altered from any source distribution.
++ */
++
++#if defined(__linux__) && defined(__ELF__)
++.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
++#endif
++
++.text
++.arch armv8-a+fp+simd
++
++
++#define RESPECT_STRICT_ALIGNMENT 1
++
++
++/*****************************************************************************/
++
++/* Supplementary macro for setting function attributes */
++.macro asm_function fname
++#ifdef __APPLE__
++    .globl _\fname
++_\fname:
++#else
++    .global \fname
++#ifdef __ELF__
++    .hidden \fname
++    .type \fname, %function
++#endif
++\fname:
++#endif
++.endm
++
++/* Transpose elements of single 128 bit registers */
++.macro transpose_single x0,x1,xi,xilen,literal
++    ins  \xi\xilen[0],  \x0\xilen[0]
++    ins  \x1\xilen[0],  \x0\xilen[1]
++    trn1 \x0\literal,   \x0\literal, \x1\literal
++    trn2 \x1\literal,   \xi\literal, \x1\literal
++.endm
++
++/* Transpose elements of 2 differnet registers */
++.macro transpose x0,x1,xi,xilen,literal
++    mov  \xi\xilen,     \x0\xilen
++    trn1 \x0\literal,   \x0\literal, \x1\literal
++    trn2 \x1\literal,   \xi\literal, \x1\literal
++.endm
++
++/* Transpose a block of 4x4 coefficients in four 64-bit registers */
++.macro transpose_4x4_32 x0,x0len x1,x1len x2,x2len x3,x3len,xi,xilen
++    mov  \xi\xilen, \x0\xilen
++    trn1 \x0\x0len, \x0\x0len, \x2\x2len
++    trn2 \x2\x2len, \xi\x0len, \x2\x2len
++    mov  \xi\xilen, \x1\xilen
++    trn1 \x1\x1len, \x1\x1len, \x3\x3len
++    trn2 \x3\x3len, \xi\x1len, \x3\x3len
++.endm
++
++.macro transpose_4x4_16 x0,x0len x1,x1len, x2,x2len, x3,x3len,xi,xilen
++    mov  \xi\xilen, \x0\xilen
++    trn1 \x0\x0len, \x0\x0len, \x1\x1len
++    trn2 \x1\x2len, \xi\x0len, \x1\x2len
++    mov  \xi\xilen, \x2\xilen
++    trn1 \x2\x2len, \x2\x2len, \x3\x3len
++    trn2 \x3\x2len, \xi\x1len, \x3\x3len
++.endm
++
++.macro transpose_4x4 x0, x1, x2, x3,x5
++    transpose_4x4_16 \x0,.4h, \x1,.4h, \x2,.4h,\x3,.4h,\x5,.16b
++    transpose_4x4_32 \x0,.2s, \x1,.2s, \x2,.2s,\x3,.2s,\x5,.16b
++.endm
++
++
++#define CENTERJSAMPLE 128
++
++/*****************************************************************************/
++
++/*
++ * Perform dequantization and inverse DCT on one block of coefficients.
++ *
++ * GLOBAL(void)
++ * jsimd_idct_islow_neon (void * dct_table, JCOEFPTR coef_block,
++ *                        JSAMPARRAY output_buf, JDIMENSION output_col)
++ */
++
++#define FIX_0_298631336  (2446)
++#define FIX_0_390180644  (3196)
++#define FIX_0_541196100  (4433)
++#define FIX_0_765366865  (6270)
++#define FIX_0_899976223  (7373)
++#define FIX_1_175875602  (9633)
++#define FIX_1_501321110  (12299)
++#define FIX_1_847759065  (15137)
++#define FIX_1_961570560  (16069)
++#define FIX_2_053119869  (16819)
++#define FIX_2_562915447  (20995)
++#define FIX_3_072711026  (25172)
++
++#define FIX_1_175875602_MINUS_1_961570560 (FIX_1_175875602 - FIX_1_961570560)
++#define FIX_1_175875602_MINUS_0_390180644 (FIX_1_175875602 - FIX_0_390180644)
++#define FIX_0_541196100_MINUS_1_847759065 (FIX_0_541196100 - FIX_1_847759065)
++#define FIX_3_072711026_MINUS_2_562915447 (FIX_3_072711026 - FIX_2_562915447)
++#define FIX_0_298631336_MINUS_0_899976223 (FIX_0_298631336 - FIX_0_899976223)
++#define FIX_1_501321110_MINUS_0_899976223 (FIX_1_501321110 - FIX_0_899976223)
++#define FIX_2_053119869_MINUS_2_562915447 (FIX_2_053119869 - FIX_2_562915447)
++#define FIX_0_541196100_PLUS_0_765366865  (FIX_0_541196100 + FIX_0_765366865)
++
++/*
++ * Reference SIMD-friendly 1-D ISLOW iDCT C implementation.
++ * Uses some ideas from the comments in 'simd/jiss2int-64.asm'
++ */
++#define REF_1D_IDCT(xrow0, xrow1, xrow2, xrow3, xrow4, xrow5, xrow6, xrow7)   \
++{                                                                             \
++    DCTELEM row0, row1, row2, row3, row4, row5, row6, row7;                   \
++    INT32   q1, q2, q3, q4, q5, q6, q7;                                       \
++    INT32   tmp11_plus_tmp2, tmp11_minus_tmp2;                                \
++                                                                              \
++    /* 1-D iDCT input data */                                                 \
++    row0 = xrow0;                                                             \
++    row1 = xrow1;                                                             \
++    row2 = xrow2;                                                             \
++    row3 = xrow3;                                                             \
++    row4 = xrow4;                                                             \
++    row5 = xrow5;                                                             \
++    row6 = xrow6;                                                             \
++    row7 = xrow7;                                                             \
++                                                                              \
++    q5 = row7 + row3;                                                         \
++    q4 = row5 + row1;                                                         \
++    q6 = MULTIPLY(q5, FIX_1_175875602_MINUS_1_961570560) +                    \
++         MULTIPLY(q4, FIX_1_175875602);                                       \
++    q7 = MULTIPLY(q5, FIX_1_175875602) +                                      \
++         MULTIPLY(q4, FIX_1_175875602_MINUS_0_390180644);                     \
++    q2 = MULTIPLY(row2, FIX_0_541196100) +                                    \
++         MULTIPLY(row6, FIX_0_541196100_MINUS_1_847759065);                   \
++    q4 = q6;                                                                  \
++    q3 = ((INT32) row0 - (INT32) row4) << 13;                                 \
++    q6 += MULTIPLY(row5, -FIX_2_562915447) +                                  \
++          MULTIPLY(row3, FIX_3_072711026_MINUS_2_562915447);                  \
++    /* now we can use q1 (reloadable constants have been used up) */          \
++    q1 = q3 + q2;                                                             \
++    q4 += MULTIPLY(row7, FIX_0_298631336_MINUS_0_899976223) +                 \
++          MULTIPLY(row1, -FIX_0_899976223);                                   \
++    q5 = q7;                                                                  \
++    q1 = q1 + q6;                                                             \
++    q7 += MULTIPLY(row7, -FIX_0_899976223) +                                  \
++          MULTIPLY(row1, FIX_1_501321110_MINUS_0_899976223);                  \
++                                                                              \
++    /* (tmp11 + tmp2) has been calculated (out_row1 before descale) */        \
++    tmp11_plus_tmp2 = q1;                                                     \
++    row1 = 0;                                                                 \
++                                                                              \
++    q1 = q1 - q6;                                                             \
++    q5 += MULTIPLY(row5, FIX_2_053119869_MINUS_2_562915447) +                 \
++          MULTIPLY(row3, -FIX_2_562915447);                                   \
++    q1 = q1 - q6;                                                             \
++    q6 = MULTIPLY(row2, FIX_0_541196100_PLUS_0_765366865) +                   \
++         MULTIPLY(row6, FIX_0_541196100);                                     \
++    q3 = q3 - q2;                                                             \
++                                                                              \
++    /* (tmp11 - tmp2) has been calculated (out_row6 before descale) */        \
++    tmp11_minus_tmp2 = q1;                                                    \
++                                                                              \
++    q1 = ((INT32) row0 + (INT32) row4) << 13;                                 \
++    q2 = q1 + q6;                                                             \
++    q1 = q1 - q6;                                                             \
++                                                                              \
++    /* pick up the results */                                                 \
++    tmp0  = q4;                                                               \
++    tmp1  = q5;                                                               \
++    tmp2  = (tmp11_plus_tmp2 - tmp11_minus_tmp2) / 2;                         \
++    tmp3  = q7;                                                               \
++    tmp10 = q2;                                                               \
++    tmp11 = (tmp11_plus_tmp2 + tmp11_minus_tmp2) / 2;                         \
++    tmp12 = q3;                                                               \
++    tmp13 = q1;                                                               \
++}
++
++#define XFIX_0_899976223                    v0.4h[0]
++#define XFIX_0_541196100                    v0.4h[1]
++#define XFIX_2_562915447                    v0.4h[2]
++#define XFIX_0_298631336_MINUS_0_899976223  v0.4h[3]
++#define XFIX_1_501321110_MINUS_0_899976223  v1.4h[0]
++#define XFIX_2_053119869_MINUS_2_562915447  v1.4h[1]
++#define XFIX_0_541196100_PLUS_0_765366865   v1.4h[2]
++#define XFIX_1_175875602                    v1.4h[3]
++#define XFIX_1_175875602_MINUS_0_390180644  v2.4h[0]
++#define XFIX_0_541196100_MINUS_1_847759065  v2.4h[1]
++#define XFIX_3_072711026_MINUS_2_562915447  v2.4h[2]
++#define XFIX_1_175875602_MINUS_1_961570560  v2.4h[3]
++
++.balign 16
++jsimd_idct_islow_neon_consts:
++    .short FIX_0_899976223                    /* d0[0] */
++    .short FIX_0_541196100                    /* d0[1] */
++    .short FIX_2_562915447                    /* d0[2] */
++    .short FIX_0_298631336_MINUS_0_899976223  /* d0[3] */
++    .short FIX_1_501321110_MINUS_0_899976223  /* d1[0] */
++    .short FIX_2_053119869_MINUS_2_562915447  /* d1[1] */
++    .short FIX_0_541196100_PLUS_0_765366865   /* d1[2] */
++    .short FIX_1_175875602                    /* d1[3] */
++    /* reloadable constants */
++    .short FIX_1_175875602_MINUS_0_390180644  /* d2[0] */
++    .short FIX_0_541196100_MINUS_1_847759065  /* d2[1] */
++    .short FIX_3_072711026_MINUS_2_562915447  /* d2[2] */
++    .short FIX_1_175875602_MINUS_1_961570560  /* d2[3] */
++
++asm_function jsimd_idct_islow_neon
++
++    DCT_TABLE       .req x0
++    COEF_BLOCK      .req x1
++    OUTPUT_BUF      .req x2
++    OUTPUT_COL      .req x3
++    TMP1            .req x0
++    TMP2            .req x1
++    TMP3            .req x2
++    TMP4            .req x15
++
++    ROW0L           .req v16
++    ROW0R           .req v17
++    ROW1L           .req v18
++    ROW1R           .req v19
++    ROW2L           .req v20
++    ROW2R           .req v21
++    ROW3L           .req v22
++    ROW3R           .req v23
++    ROW4L           .req v24
++    ROW4R           .req v25
++    ROW5L           .req v26
++    ROW5R           .req v27
++    ROW6L           .req v28
++    ROW6R           .req v29
++    ROW7L           .req v30
++    ROW7R           .req v31
++    /* Save all NEON registers and x15 (32 NEON registers * 8 bytes + 16) */
++    sub             sp, sp, 272
++    str             x15, [sp], 16
++    adr             x15, jsimd_idct_islow_neon_consts
++    st1             {v0.8b - v3.8b}, [sp], 32
++    st1             {v4.8b - v7.8b}, [sp], 32
++    st1             {v8.8b - v11.8b}, [sp], 32
++    st1             {v12.8b - v15.8b}, [sp], 32
++    st1             {v16.8b - v19.8b}, [sp], 32
++    st1             {v20.8b - v23.8b}, [sp], 32
++    st1             {v24.8b - v27.8b}, [sp], 32
++    st1             {v28.8b - v31.8b}, [sp], 32
++    ld1             {v16.4h, v17.4h, v18.4h, v19.4h}, [COEF_BLOCK], 32
++    ld1             {v0.4h, v1.4h, v2.4h, v3.4h}, [DCT_TABLE], 32
++    ld1             {v20.4h, v21.4h, v22.4h, v23.4h}, [COEF_BLOCK], 32
++    mul             v16.4h, v16.4h, v0.4h
++    mul             v17.4h, v17.4h, v1.4h
++    ins             v16.2d[1], v17.2d[0]  /* 128 bit q8 */
++    ld1             {v4.4h, v5.4h, v6.4h, v7.4h}, [DCT_TABLE], 32
++    mul             v18.4h, v18.4h, v2.4h
++    mul             v19.4h, v19.4h, v3.4h
++    ins             v18.2d[1], v19.2d[0]  /* 128 bit q9 */
++    ld1             {v24.4h, v25.4h, v26.4h, v27.4h}, [COEF_BLOCK], 32
++    mul             v20.4h, v20.4h, v4.4h
++    mul             v21.4h, v21.4h, v5.4h
++    ins             v20.2d[1], v21.2d[0]  /* 128 bit q10 */
++    ld1             {v0.4h, v1.4h, v2.4h, v3.4h}, [DCT_TABLE], 32
++    mul             v22.4h, v22.4h, v6.4h
++    mul             v23.4h, v23.4h, v7.4h
++    ins             v22.2d[1], v23.2d[0]  /* 128 bit q11 */
++    ld1             {v28.4h, v29.4h, v30.4h, v31.4h}, [COEF_BLOCK]
++    mul             v24.4h, v24.4h, v0.4h
++    mul             v25.4h, v25.4h, v1.4h
++    ins             v24.2d[1], v25.2d[0]  /* 128 bit q12 */
++    ld1             {v4.4h, v5.4h, v6.4h, v7.4h}, [DCT_TABLE], 32
++    mul             v28.4h, v28.4h, v4.4h
++    mul             v29.4h, v29.4h, v5.4h
++    ins             v28.2d[1], v29.2d[0]  /* 128 bit q14 */
++    mul             v26.4h, v26.4h, v2.4h
++    mul             v27.4h, v27.4h, v3.4h
++    ins             v26.2d[1], v27.2d[0]  /* 128 bit q13 */
++    ld1             {v0.4h, v1.4h, v2.4h, v3.4h}, [x15]  /* load constants */
++    add             x15, x15, #16
++    mul             v30.4h, v30.4h, v6.4h
++    mul             v31.4h, v31.4h, v7.4h
++    ins             v30.2d[1], v31.2d[0]  /* 128 bit q15 */
++    /* Go to the bottom of the stack */
++    sub             sp, sp, 352
++    stp             x4, x5, [sp], 16
++    st1             {v8.4h - v11.4h}, [sp], 32  /* save NEON registers */
++    st1             {v12.4h - v15.4h}, [sp], 32
++    /* 1-D IDCT, pass 1, left 4x8 half */
++    add             v4.4h,    ROW7L.4h, ROW3L.4h
++    add             v5.4h,    ROW5L.4h, ROW1L.4h
++    smull           v12.4s,   v4.4h,    XFIX_1_175875602_MINUS_1_961570560
++    smlal           v12.4s,   v5.4h,    XFIX_1_175875602
++    smull           v14.4s,   v4.4h,    XFIX_1_175875602
++    /* Check for the zero coefficients in the right 4x8 half */
++    smlal           v14.4s,   v5.4h,    XFIX_1_175875602_MINUS_0_390180644
++    ssubl           v6.4s,    ROW0L.4h, ROW4L.4h
++      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 1 * 8))]
++    smull           v4.4s,    ROW2L.4h, XFIX_0_541196100
++    smlal           v4.4s,    ROW6L.4h, XFIX_0_541196100_MINUS_1_847759065
++      orr           x0,       x4,       x5
++    mov             v8.16b,   v12.16b
++    smlsl           v12.4s,   ROW5L.4h, XFIX_2_562915447
++      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 2 * 8))]
++    smlal           v12.4s,   ROW3L.4h, XFIX_3_072711026_MINUS_2_562915447
++    shl             v6.4s,    v6.4s,    #13
++      orr           x0,       x0,       x4
++    smlsl           v8.4s,    ROW1L.4h, XFIX_0_899976223
++      orr           x0,       x0 ,      x5
++    add             v2.4s,    v6.4s,    v4.4s
++      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 3 * 8))]
++    mov             v10.16b,  v14.16b
++    add             v2.4s,    v2.4s,    v12.4s
++      orr           x0,       x0,       x4
++    smlsl           v14.4s,   ROW7L.4h, XFIX_0_899976223
++      orr           x0,       x0,       x5
++    smlal           v14.4s,   ROW1L.4h, XFIX_1_501321110_MINUS_0_899976223
++    rshrn           ROW1L.4h, v2.4s,    #11
++      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 4 * 8))]
++    sub             v2.4s,    v2.4s,    v12.4s
++    smlal           v10.4s,   ROW5L.4h, XFIX_2_053119869_MINUS_2_562915447
++      orr           x0,       x0,       x4
++    smlsl           v10.4s,   ROW3L.4h, XFIX_2_562915447
++      orr           x0,       x0,       x5
++    sub             v2.4s,    v2.4s,    v12.4s
++    smull           v12.4s,   ROW2L.4h, XFIX_0_541196100_PLUS_0_765366865
++      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 5 * 8))]
++    smlal           v12.4s,   ROW6L.4h, XFIX_0_541196100
++    sub             v6.4s,    v6.4s,    v4.4s
++      orr           x0,       x0,       x4
++    rshrn           ROW6L.4h, v2.4s,    #11
++      orr           x0,       x0,       x5
++    add             v2.4s,    v6.4s,    v10.4s
++      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 6 * 8))]
++    sub             v6.4s,    v6.4s,    v10.4s
++    saddl           v10.4s,   ROW0L.4h, ROW4L.4h
++      orr           x0,       x0,       x4
++    rshrn           ROW2L.4h, v2.4s,    #11
++      orr           x0,       x0,       x5
++    rshrn           ROW5L.4h, v6.4s,    #11
++      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 7 * 8))]
++    shl             v10.4s,   v10.4s,   #13
++    smlal           v8.4s,    ROW7L.4h, XFIX_0_298631336_MINUS_0_899976223
++      orr           x0,       x0,       x4
++    add             v4.4s,    v10.4s,   v12.4s
++      orr           x0,       x0,       x5
++    cmp             x0, #0 /* orrs instruction removed */
++    sub             v2.4s,    v10.4s,   v12.4s
++    add             v12.4s,   v4.4s,    v14.4s
++      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 0 * 8))]
++    sub             v4.4s,    v4.4s,    v14.4s
++    add             v10.4s,   v2.4s,    v8.4s
++      orr           x0,       x4,       x5
++    sub             v6.4s,    v2.4s,    v8.4s
++      /* pop             {x4, x5} */
++      sub           sp, sp, 80
++      ldp           x4, x5, [sp], 16
++    rshrn           ROW7L.4h, v4.4s,    #11
++    rshrn           ROW3L.4h, v10.4s,   #11
++    rshrn           ROW0L.4h, v12.4s,   #11
++    rshrn           ROW4L.4h, v6.4s,    #11
++
++      beq             3f /* Go to do some special handling for the sparse right 4x8 half */
++
++    /* 1-D IDCT, pass 1, right 4x8 half */
++    ld1             {v2.4h},  [x15]    /* reload constants */
++    add             v10.4h,   ROW7R.4h, ROW3R.4h
++    add             v8.4h,    ROW5R.4h, ROW1R.4h
++    /* Transpose ROW6L <-> ROW7L   (v3 available free register) */
++    transpose       ROW6L, ROW7L, v3, .16b, .4h
++    smull           v12.4s,   v10.4h,   XFIX_1_175875602_MINUS_1_961570560
++    smlal           v12.4s,   v8.4h,    XFIX_1_175875602
++    /* Transpose ROW2L <-> ROW3L   (v3 available free register) */
++    transpose       ROW2L, ROW3L, v3, .16b, .4h
++    smull           v14.4s,   v10.4h,   XFIX_1_175875602
++    smlal           v14.4s,   v8.4h,    XFIX_1_175875602_MINUS_0_390180644
++    /* Transpose ROW0L <-> ROW1L   (v3 available free register) */
++    transpose       ROW0L, ROW1L, v3, .16b, .4h
++    ssubl           v6.4s,    ROW0R.4h, ROW4R.4h
++    smull           v4.4s,    ROW2R.4h, XFIX_0_541196100
++    smlal           v4.4s,    ROW6R.4h, XFIX_0_541196100_MINUS_1_847759065
++    /* Transpose ROW4L <-> ROW5L   (v3 available free register) */
++    transpose       ROW4L, ROW5L, v3, .16b, .4h
++    mov             v8.16b,   v12.16b
++    smlsl           v12.4s,   ROW5R.4h, XFIX_2_562915447
++    smlal           v12.4s,   ROW3R.4h, XFIX_3_072711026_MINUS_2_562915447
++    /* Transpose ROW1L <-> ROW3L   (v3 available free register) */
++    transpose       ROW1L, ROW3L, v3, .16b, .2s
++    shl             v6.4s,    v6.4s,    #13
++    smlsl           v8.4s,    ROW1R.4h, XFIX_0_899976223
++    /* Transpose ROW4L <-> ROW6L   (v3 available free register) */
++    transpose       ROW4L, ROW6L, v3, .16b, .2s
++    add             v2.4s,    v6.4s,    v4.4s
++    mov             v10.16b,  v14.16b
++    add             v2.4s,    v2.4s,    v12.4s
++    /* Transpose ROW0L <-> ROW2L   (v3 available free register) */
++    transpose       ROW0L, ROW2L, v3, .16b, .2s
++    smlsl           v14.4s,   ROW7R.4h, XFIX_0_899976223
++    smlal           v14.4s,   ROW1R.4h, XFIX_1_501321110_MINUS_0_899976223
++    rshrn           ROW1R.4h, v2.4s,    #11
++    /* Transpose ROW5L <-> ROW7L   (v3 available free register) */
++    transpose       ROW5L, ROW7L, v3, .16b, .2s
++    sub             v2.4s,    v2.4s,    v12.4s
++    smlal           v10.4s,   ROW5R.4h, XFIX_2_053119869_MINUS_2_562915447
++    smlsl           v10.4s,   ROW3R.4h, XFIX_2_562915447
++    sub             v2.4s,    v2.4s,    v12.4s
++    smull           v12.4s,   ROW2R.4h, XFIX_0_541196100_PLUS_0_765366865
++    smlal           v12.4s,   ROW6R.4h, XFIX_0_541196100
++    sub             v6.4s,    v6.4s,    v4.4s
++    rshrn           ROW6R.4h, v2.4s,    #11
++    add             v2.4s,    v6.4s,    v10.4s
++    sub             v6.4s,    v6.4s,    v10.4s
++    saddl           v10.4s,   ROW0R.4h, ROW4R.4h
++    rshrn           ROW2R.4h, v2.4s,    #11
++    rshrn           ROW5R.4h, v6.4s,    #11
++    shl             v10.4s,   v10.4s,   #13
++    smlal           v8.4s,    ROW7R.4h, XFIX_0_298631336_MINUS_0_899976223
++    add             v4.4s,    v10.4s,   v12.4s
++    sub             v2.4s,    v10.4s,   v12.4s
++    add             v12.4s,   v4.4s,    v14.4s
++    sub             v4.4s,    v4.4s,    v14.4s
++    add             v10.4s,   v2.4s,    v8.4s
++    sub             v6.4s,    v2.4s,    v8.4s
++    rshrn           ROW7R.4h, v4.4s,    #11
++    rshrn           ROW3R.4h, v10.4s,   #11
++    rshrn           ROW0R.4h, v12.4s,   #11
++    rshrn           ROW4R.4h, v6.4s,    #11
++    /* Transpose right 4x8 half */
++    transpose       ROW6R, ROW7R, v3, .16b, .4h
++    transpose       ROW2R, ROW3R, v3, .16b, .4h
++    transpose       ROW0R, ROW1R, v3, .16b, .4h
++    transpose       ROW4R, ROW5R, v3, .16b, .4h
++    transpose       ROW1R, ROW3R, v3, .16b, .2s
++    transpose       ROW4R, ROW6R, v3, .16b, .2s
++    transpose       ROW0R, ROW2R, v3, .16b, .2s
++    transpose       ROW5R, ROW7R, v3, .16b, .2s
++
++1:  /* 1-D IDCT, pass 2 (normal variant), left 4x8 half */
++    ld1             {v2.4h},  [x15]    /* reload constants */
++    smull           v12.4S,   ROW1R.4h, XFIX_1_175875602 /* ROW5L.4h <-> ROW1R.4h */
++    smlal           v12.4s,   ROW1L.4h, XFIX_1_175875602
++    smlal           v12.4s,   ROW3R.4h, XFIX_1_175875602_MINUS_1_961570560 /* ROW7L.4h <-> ROW3R.4h */
++    smlal           v12.4s,   ROW3L.4h, XFIX_1_175875602_MINUS_1_961570560
++    smull           v14.4s,   ROW3R.4h, XFIX_1_175875602 /* ROW7L.4h <-> ROW3R.4h */
++    smlal           v14.4s,   ROW3L.4h, XFIX_1_175875602
++    smlal           v14.4s,   ROW1R.4h, XFIX_1_175875602_MINUS_0_390180644 /* ROW5L.4h <-> ROW1R.4h */
++    smlal           v14.4s,   ROW1L.4h, XFIX_1_175875602_MINUS_0_390180644
++    ssubl           v6.4s,    ROW0L.4h, ROW0R.4h /* ROW4L.4h <-> ROW0R.4h */
++    smull           v4.4s,    ROW2L.4h, XFIX_0_541196100
++    smlal           v4.4s,    ROW2R.4h, XFIX_0_541196100_MINUS_1_847759065 /* ROW6L.4h <-> ROW2R.4h */
++    mov             v8.16b,   v12.16b
++    smlsl           v12.4s,   ROW1R.4h, XFIX_2_562915447 /* ROW5L.4h <-> ROW1R.4h */
++    smlal           v12.4s,   ROW3L.4h, XFIX_3_072711026_MINUS_2_562915447
++    shl             v6.4s,    v6.4s,    #13
++    smlsl           v8.4s,    ROW1L.4h, XFIX_0_899976223
++    add             v2.4s,    v6.4s,    v4.4s
++    mov             v10.16b,  v14.16b
++    add             v2.4s,    v2.4s,    v12.4s
++    smlsl           v14.4s,   ROW3R.4h, XFIX_0_899976223 /* ROW7L.4h <-> ROW3R.4h */
++    smlal           v14.4s,   ROW1L.4h, XFIX_1_501321110_MINUS_0_899976223
++    shrn            ROW1L.4h, v2.4s,    #16
++    sub             v2.4s,    v2.4s,    v12.4s
++    smlal           v10.4s,   ROW1R.4h, XFIX_2_053119869_MINUS_2_562915447 /* ROW5L.4h <-> ROW1R.4h */
++    smlsl           v10.4s,   ROW3L.4h, XFIX_2_562915447
++    sub             v2.4s,    v2.4s,    v12.4s
++    smull           v12.4s,   ROW2L.4h, XFIX_0_541196100_PLUS_0_765366865
++    smlal           v12.4s,   ROW2R.4h, XFIX_0_541196100 /* ROW6L.4h <-> ROW2R.4h */
++    sub             v6.4s,    v6.4s,    v4.4s
++    shrn            ROW2R.4h, v2.4s,    #16 /* ROW6L.4h <-> ROW2R.4h */
++    add             v2.4s,    v6.4s,    v10.4s
++    sub             v6.4s,    v6.4s,    v10.4s
++    saddl           v10.4s,   ROW0L.4h, ROW0R.4h /* ROW4L.4h <-> ROW0R.4h */
++    shrn            ROW2L.4h, v2.4s,    #16
++    shrn            ROW1R.4h, v6.4s,    #16 /* ROW5L.4h <-> ROW1R.4h */
++    shl             v10.4s,   v10.4s,   #13
++    smlal           v8.4s,    ROW3R.4h, XFIX_0_298631336_MINUS_0_899976223 /* ROW7L.4h <-> ROW3R.4h */
++    add             v4.4s,    v10.4s,   v12.4s
++    sub             v2.4s,    v10.4s,   v12.4s
++    add             v12.4s,   v4.4s,    v14.4s
++    sub             v4.4s,    v4.4s,    v14.4s
++    add             v10.4s,   v2.4s,    v8.4s
++    sub             v6.4s,    v2.4s,    v8.4s
++    shrn            ROW3R.4h, v4.4s,    #16 /* ROW7L.4h <-> ROW3R.4h */
++    shrn            ROW3L.4h, v10.4s,   #16
++    shrn            ROW0L.4h, v12.4s,   #16
++    shrn            ROW0R.4h, v6.4s,    #16 /* ROW4L.4h <-> ROW0R.4h */
++    /* 1-D IDCT, pass 2, right 4x8 half */
++    ld1             {v2.4h},  [x15]    /* reload constants */
++    smull           v12.4s,   ROW5R.4h, XFIX_1_175875602
++    smlal           v12.4s,   ROW5L.4h, XFIX_1_175875602 /* ROW5L.4h <-> ROW1R.4h */
++    smlal           v12.4s,   ROW7R.4h, XFIX_1_175875602_MINUS_1_961570560
++    smlal           v12.4s,   ROW7L.4h, XFIX_1_175875602_MINUS_1_961570560 /* ROW7L.4h <-> ROW3R.4h */
++    smull           v14.4s,   ROW7R.4h, XFIX_1_175875602
++    smlal           v14.4s,   ROW7L.4h, XFIX_1_175875602 /* ROW7L.4h <-> ROW3R.4h */
++    smlal           v14.4s,   ROW5R.4h, XFIX_1_175875602_MINUS_0_390180644
++    smlal           v14.4s,   ROW5L.4h, XFIX_1_175875602_MINUS_0_390180644 /* ROW5L.4h <-> ROW1R.4h */
++    ssubl           v6.4s,    ROW4L.4h, ROW4R.4h /* ROW4L.4h <-> ROW0R.4h */
++    smull           v4.4s,    ROW6L.4h, XFIX_0_541196100 /* ROW6L.4h <-> ROW2R.4h */
++    smlal           v4.4s,    ROW6R.4h, XFIX_0_541196100_MINUS_1_847759065
++    mov             v8.16b,   v12.16b
++    smlsl           v12.4s,   ROW5R.4h, XFIX_2_562915447
++    smlal           v12.4s,   ROW7L.4h, XFIX_3_072711026_MINUS_2_562915447 /* ROW7L.4h <-> ROW3R.4h */
++    shl             v6.4s,    v6.4s,    #13
++    smlsl           v8.4s,    ROW5L.4h, XFIX_0_899976223 /* ROW5L.4h <-> ROW1R.4h */
++    add             v2.4s,    v6.4s,    v4.4s
++    mov             v10.16b,  v14.16b
++    add             v2.4s,    v2.4s,    v12.4s
++    smlsl           v14.4s,   ROW7R.4h, XFIX_0_899976223
++    smlal           v14.4s,   ROW5L.4h, XFIX_1_501321110_MINUS_0_899976223 /* ROW5L.4h <-> ROW1R.4h */
++    shrn            ROW5L.4h, v2.4s,    #16 /* ROW5L.4h <-> ROW1R.4h */
++    sub             v2.4s,    v2.4s,    v12.4s
++    smlal           v10.4s,   ROW5R.4h, XFIX_2_053119869_MINUS_2_562915447
++    smlsl           v10.4s,   ROW7L.4h, XFIX_2_562915447 /* ROW7L.4h <-> ROW3R.4h */
++    sub             v2.4s,    v2.4s,    v12.4s
++    smull           v12.4s,   ROW6L.4h, XFIX_0_541196100_PLUS_0_765366865 /* ROW6L.4h <-> ROW2R.4h */
++    smlal           v12.4s,   ROW6R.4h, XFIX_0_541196100
++    sub             v6.4s,    v6.4s,    v4.4s
++    shrn            ROW6R.4h, v2.4s,    #16
++    add             v2.4s,    v6.4s,    v10.4s
++    sub             v6.4s,    v6.4s,    v10.4s
++    saddl           v10.4s,   ROW4L.4h, ROW4R.4h /* ROW4L.4h <-> ROW0R.4h */
++    shrn            ROW6L.4h, v2.4s,    #16 /* ROW6L.4h <-> ROW2R.4h */
++    shrn            ROW5R.4h, v6.4s,    #16
++    shl             v10.4s,   v10.4s,   #13
++    smlal           v8.4s,    ROW7R.4h, XFIX_0_298631336_MINUS_0_899976223
++    add             v4.4s,    v10.4s,   v12.4s
++    sub             v2.4s,    v10.4s,   v12.4s
++    add             v12.4s,   v4.4s,    v14.4s
++    sub             v4.4s,    v4.4s,    v14.4s
++    add             v10.4s,   v2.4s,    v8.4s
++    sub             v6.4s,    v2.4s,    v8.4s
++    shrn            ROW7R.4h, v4.4s,    #16
++    shrn            ROW7L.4h, v10.4s,   #16 /* ROW7L.4h <-> ROW3R.4h */
++    shrn            ROW4L.4h, v12.4s,   #16 /* ROW4L.4h <-> ROW0R.4h */
++    shrn            ROW4R.4h, v6.4s,    #16
++
++2:  /* Descale to 8-bit and range limit */
++    ins             v16.2d[1], v17.2d[0]
++    ins             v18.2d[1], v19.2d[0]
++    ins             v20.2d[1], v21.2d[0]
++    ins             v22.2d[1], v23.2d[0]
++    sqrshrn         v16.8b,   v16.8h,   #2
++    sqrshrn2        v16.16b,  v18.8h,   #2
++    sqrshrn         v18.8b,   v20.8h,   #2
++    sqrshrn2        v18.16b,  v22.8h,   #2
++
++    /* vpop            {v8.4h - d15.4h} */ /* restore NEON registers */
++    ld1             {v8.4h - v11.4h}, [sp], 32
++    ld1             {v12.4h - v15.4h}, [sp], 32
++    ins             v24.2d[1], v25.2d[0]
++
++    sqrshrn         v20.8b,   v24.8h,   #2
++      /* Transpose the final 8-bit samples and do signed->unsigned conversion */
++    /* trn1            v16.8h,    v16.8h,  v18.8h */
++    transpose       v16, v18, v3, .16b, .8h
++    ins             v26.2d[1], v27.2d[0]
++    ins             v28.2d[1], v29.2d[0]
++    ins             v30.2d[1], v31.2d[0]
++    sqrshrn2        v20.16b,  v26.8h,   #2
++    sqrshrn         v22.8b,   v28.8h,   #2
++    movi            v0.16b,   #(CENTERJSAMPLE)
++    sqrshrn2        v22.16b,  v30.8h,   #2
++    transpose_single v16, v17, v3, .2d, .8b
++    transpose_single v18, v19, v3, .2d, .8b
++    add             v16.8b,   v16.8b,   v0.8b
++    add             v17.8b,   v17.8b,   v0.8b
++    add             v18.8b,   v18.8b,   v0.8b
++    add             v19.8b,   v19.8b,   v0.8b
++    transpose       v20, v22, v3, .16b, .8h
++    /* Store results to the output buffer */
++    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
++    add             TMP1,     TMP1,     OUTPUT_COL
++    add             TMP2,     TMP2,     OUTPUT_COL
++    st1             {v16.8b}, [TMP1]
++    transpose_single v20, v21, v3, .2d, .8b
++    st1             {v17.8b}, [TMP2]
++    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
++    add             TMP1,     TMP1,     OUTPUT_COL
++    add             TMP2,     TMP2,     OUTPUT_COL
++    st1             {v18.8b}, [TMP1]
++    add             v20.8b,   v20.8b,   v0.8b
++    add             v21.8b,   v21.8b,   v0.8b
++    st1             {v19.8b}, [TMP2]
++    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
++    ldp             TMP3,     TMP4,     [OUTPUT_BUF]
++    add             TMP1,     TMP1,     OUTPUT_COL
++    add             TMP2,     TMP2,     OUTPUT_COL
++    add             TMP3,     TMP3,     OUTPUT_COL
++    add             TMP4,     TMP4,     OUTPUT_COL
++    transpose_single v22, v23, v3, .2d, .8b
++    st1             {v20.8b}, [TMP1]
++    add             v22.8b,   v22.8b,   v0.8b
++    add             v23.8b,   v23.8b,   v0.8b
++    st1             {v21.8b}, [TMP2]
++    st1             {v22.8b}, [TMP3]
++    st1             {v23.8b}, [TMP4]
++    ldr             x15, [sp], 16
++    ld1             {v0.8b - v3.8b}, [sp], 32
++    ld1             {v4.8b - v7.8b}, [sp], 32
++    ld1             {v8.8b - v11.8b}, [sp], 32
++    ld1             {v12.8b - v15.8b}, [sp], 32
++    ld1             {v16.8b - v19.8b}, [sp], 32
++    ld1             {v20.8b - v23.8b}, [sp], 32
++    ld1             {v24.8b - v27.8b}, [sp], 32
++    ld1             {v28.8b - v31.8b}, [sp], 32
++    blr             x30
++
++3:  /* Left 4x8 half is done, right 4x8 half contains mostly zeros */
++
++    /* Transpose left 4x8 half */
++    transpose       ROW6L, ROW7L, v3, .16b, .4h
++    transpose       ROW2L, ROW3L, v3, .16b, .4h
++    transpose       ROW0L, ROW1L, v3, .16b, .4h
++    transpose       ROW4L, ROW5L, v3, .16b, .4h
++    shl             ROW0R.4h, ROW0R.4h, #2 /* PASS1_BITS */
++    transpose       ROW1L, ROW3L, v3, .16b, .2s
++    transpose       ROW4L, ROW6L, v3, .16b, .2s
++    transpose       ROW0L, ROW2L, v3, .16b, .2s
++    transpose       ROW5L, ROW7L, v3, .16b, .2s
++    cmp             x0, #0
++    beq             4f /* Right 4x8 half has all zeros, go to 'sparse' second pass */
++
++    /* Only row 0 is non-zero for the right 4x8 half  */
++    dup             ROW1R.4h, ROW0R.4h[1]
++    dup             ROW2R.4h, ROW0R.4h[2]
++    dup             ROW3R.4h, ROW0R.4h[3]
++    dup             ROW4R.4h, ROW0R.4h[0]
++    dup             ROW5R.4h, ROW0R.4h[1]
++    dup             ROW6R.4h, ROW0R.4h[2]
++    dup             ROW7R.4h, ROW0R.4h[3]
++    dup             ROW0R.4h, ROW0R.4h[0]
++    b               1b /* Go to 'normal' second pass */
++
++4:  /* 1-D IDCT, pass 2 (sparse variant with zero rows 4-7), left 4x8 half */
++    ld1             {v2.4h},  [x15]    /* reload constants */
++    smull           v12.4s,   ROW1L.4h, XFIX_1_175875602
++    smlal           v12.4s,   ROW3L.4h, XFIX_1_175875602_MINUS_1_961570560
++    smull           v14.4s,   ROW3L.4h, XFIX_1_175875602
++    smlal           v14.4s,   ROW1L.4h, XFIX_1_175875602_MINUS_0_390180644
++    smull           v4.4s,    ROW2L.4h, XFIX_0_541196100
++    sshll           v6.4s,    ROW0L.4h, #13
++    mov             v8.16b,   v12.16b
++    smlal           v12.4s,   ROW3L.4h, XFIX_3_072711026_MINUS_2_562915447
++    smlsl           v8.4s,    ROW1L.4h, XFIX_0_899976223
++    add             v2.4s,    v6.4s,    v4.4s
++    mov             v10.16b,  v14.16b
++    smlal           v14.4s,   ROW1L.4h, XFIX_1_501321110_MINUS_0_899976223
++    add             v2.4s,    v2.4s,    v12.4s
++    add             v12.4s,   v12.4s,   v12.4s
++    smlsl           v10.4s,   ROW3L.4h, XFIX_2_562915447
++    shrn            ROW1L.4h, v2.4s,    #16
++    sub             v2.4s,    v2.4s,    v12.4s
++    smull           v12.4s,   ROW2L.4h, XFIX_0_541196100_PLUS_0_765366865
++    sub             v6.4s,    v6.4s,    v4.4s
++    shrn            ROW2R.4h, v2.4s,    #16 /* ROW6L.4h <-> ROW2R.4h */
++    add             v2.4s,    v6.4s,    v10.4s
++    sub             v6.4s,    v6.4s,    v10.4s
++    sshll           v10.4s,   ROW0L.4h, #13
++    shrn            ROW2L.4h, v2.4s,    #16
++    shrn            ROW1R.4h, v6.4s,    #16 /* ROW5L.4h <-> ROW1R.4h */
++    add             v4.4s,    v10.4s,   v12.4s
++    sub             v2.4s,    v10.4s,   v12.4s
++    add             v12.4s,   v4.4s,    v14.4s
++    sub             v4.4s,    v4.4s,    v14.4s
++    add             v10.4s,   v2.4s,    v8.4s
++    sub             v6.4s,    v2.4s,    v8.4s
++    shrn            ROW3R.4h, v4.4s,    #16 /* ROW7L.4h <-> ROW3R.4h */
++    shrn            ROW3L.4h, v10.4s,   #16
++    shrn            ROW0L.4h, v12.4s,   #16
++    shrn            ROW0R.4h, v6.4s,    #16 /* ROW4L.4h <-> ROW0R.4h */
++    /* 1-D IDCT, pass 2 (sparse variant with zero rows 4-7), right 4x8 half */
++    ld1             {v2.4h},  [x15]    /* reload constants */
++    smull           v12.4s,   ROW5L.4h, XFIX_1_175875602
++    smlal           v12.4s,   ROW7L.4h, XFIX_1_175875602_MINUS_1_961570560
++    smull           v14.4s,   ROW7L.4h, XFIX_1_175875602
++    smlal           v14.4s,   ROW5L.4h, XFIX_1_175875602_MINUS_0_390180644
++    smull           v4.4s,    ROW6L.4h, XFIX_0_541196100
++    sshll           v6.4s,    ROW4L.4h, #13
++    mov             v8.16b,   v12.16b
++    smlal           v12.4s,   ROW7L.4h, XFIX_3_072711026_MINUS_2_562915447
++    smlsl           v8.4s,    ROW5L.4h, XFIX_0_899976223
++    add             v2.4s,    v6.4s,    v4.4s
++    mov             v10.16b,  v14.16b
++    smlal           v14.4s,   ROW5L.4h, XFIX_1_501321110_MINUS_0_899976223
++    add             v2.4s,    v2.4s,    v12.4s
++    add             v12.4s,   v12.4s,   v12.4s
++    smlsl           v10.4s,   ROW7L.4h, XFIX_2_562915447
++    shrn            ROW5L.4h, v2.4s,    #16 /* ROW5L.4h <-> ROW1R.4h */
++    sub             v2.4s,    v2.4s,    v12.4s
++    smull           v12.4s,   ROW6L.4h, XFIX_0_541196100_PLUS_0_765366865
++    sub             v6.4s,    v6.4s,    v4.4s
++    shrn            ROW6R.4h, v2.4s,    #16
++    add             v2.4s,    v6.4s,    v10.4s
++    sub             v6.4s,    v6.4s,    v10.4s
++    sshll           v10.4s,   ROW4L.4h, #13
++    shrn            ROW6L.4h, v2.4s,    #16 /* ROW6L.4h <-> ROW2R.4h */
++    shrn            ROW5R.4h, v6.4s,    #16
++    add             v4.4s,    v10.4s,   v12.4s
++    sub             v2.4s,    v10.4s,   v12.4s
++    add             v12.4s,   v4.4s,    v14.4s
++    sub             v4.4s,    v4.4s,    v14.4s
++    add             v10.4s,   v2.4s,    v8.4s
++    sub             v6.4s,    v2.4s,    v8.4s
++    shrn            ROW7R.4h, v4.4s,    #16
++    shrn            ROW7L.4h, v10.4s,   #16 /* ROW7L.4h <-> ROW3R.4h */
++    shrn            ROW4L.4h, v12.4s,   #16 /* ROW4L.4h <-> ROW0R.4h */
++    shrn            ROW4R.4h, v6.4s,    #16
++    b               2b /* Go to epilogue */
++
++    .unreq          DCT_TABLE
++    .unreq          COEF_BLOCK
++    .unreq          OUTPUT_BUF
++    .unreq          OUTPUT_COL
++    .unreq          TMP1
++    .unreq          TMP2
++    .unreq          TMP3
++    .unreq          TMP4
++
++    .unreq          ROW0L
++    .unreq          ROW0R
++    .unreq          ROW1L
++    .unreq          ROW1R
++    .unreq          ROW2L
++    .unreq          ROW2R
++    .unreq          ROW3L
++    .unreq          ROW3R
++    .unreq          ROW4L
++    .unreq          ROW4R
++    .unreq          ROW5L
++    .unreq          ROW5R
++    .unreq          ROW6L
++    .unreq          ROW6R
++    .unreq          ROW7L
++    .unreq          ROW7R
++
++
++/*****************************************************************************/
++
++/*
++ * jsimd_idct_ifast_neon
++ *
++ * This function contains a fast, not so accurate integer implementation of
++ * the inverse DCT (Discrete Cosine Transform). It uses the same calculations
++ * and produces exactly the same output as IJG's original 'jpeg_idct_ifast'
++ * function from jidctfst.c
++ *
++ * Normally 1-D AAN DCT needs 5 multiplications and 29 additions.
++ * But in ARM NEON case some extra additions are required because VQDMULH
++ * instruction can't handle the constants larger than 1. So the expressions
++ * like "x * 1.082392200" have to be converted to "x * 0.082392200 + x",
++ * which introduces an extra addition. Overall, there are 6 extra additions
++ * per 1-D IDCT pass, totalling to 5 VQDMULH and 35 VADD/VSUB instructions.
++ */
++
++#define XFIX_1_082392200 v0.4h[0]
++#define XFIX_1_414213562 v0.4h[1]
++#define XFIX_1_847759065 v0.4h[2]
++#define XFIX_2_613125930 v0.4h[3]
++
++.balign 16
++jsimd_idct_ifast_neon_consts:
++    .short (277 * 128 - 256 * 128) /* XFIX_1_082392200 */
++    .short (362 * 128 - 256 * 128) /* XFIX_1_414213562 */
++    .short (473 * 128 - 256 * 128) /* XFIX_1_847759065 */
++    .short (669 * 128 - 512 * 128) /* XFIX_2_613125930 */
++
++asm_function jsimd_idct_ifast_neon
++
++    DCT_TABLE       .req x0
++    COEF_BLOCK      .req x1
++    OUTPUT_BUF      .req x2
++    OUTPUT_COL      .req x3
++    TMP1            .req x0
++    TMP2            .req x1
++    TMP3            .req x2
++    TMP4            .req x22
++    TMP5            .req x23
++
++    /* Load and dequantize coefficients into NEON registers
++     * with the following allocation:
++     *       0 1 2 3 | 4 5 6 7
++     *      ---------+--------
++     *   0 | d16     | d17     ( v8.8h  )
++     *   1 | d18     | d19     ( v9.8h  )
++     *   2 | d20     | d21     ( v10.8h )
++     *   3 | d22     | d23     ( v11.8h )
++     *   4 | d24     | d25     ( v12.8h )
++     *   5 | d26     | d27     ( v13.8h )
++     *   6 | d28     | d29     ( v14.8h )
++     *   7 | d30     | d31     ( v15.8h )
++     */
++    /* Save NEON registers used in fast IDCT */
++    sub             sp, sp, #176
++    stp             x22, x23, [sp], 16
++    adr             x23, jsimd_idct_ifast_neon_consts
++    st1             {v0.8b - v3.8b}, [sp], 32
++    st1             {v4.8b - v7.8b}, [sp], 32
++    st1             {v8.8b - v11.8b}, [sp], 32
++    st1             {v12.8b - v15.8b}, [sp], 32
++    st1             {v16.8b - v19.8b}, [sp], 32
++    ld1             {v8.8h, v9.8h}, [COEF_BLOCK], 32
++    ld1             {v0.8h, v1.8h}, [DCT_TABLE], 32
++    ld1             {v10.8h, v11.8h}, [COEF_BLOCK], 32
++    mul             v8.8h,  v8.8h,  v0.8h
++    ld1             {v2.8h, v3.8h}, [DCT_TABLE], 32
++    mul             v9.8h,  v9.8h,  v1.8h
++    ld1             {v12.8h, v13.8h}, [COEF_BLOCK], 32
++    mul             v10.8h, v10.8h, v2.8h
++    ld1             {v0.8h, v1.8h}, [DCT_TABLE], 32
++    mul             v11.8h, v11.8h, v3.8h
++    ld1             {v14.8h, v15.8h}, [COEF_BLOCK], 32
++    mul             v12.8h, v12.8h, v0.8h
++    ld1             {v2.8h, v3.8h}, [DCT_TABLE], 32
++    mul             v14.8h, v14.8h, v2.8h
++    mul             v13.8h, v13.8h, v1.8h
++    ld1             {v0.4h}, [x23]      /* load constants */
++    mul             v15.8h, v15.8h, v3.8h
++
++    /* 1-D IDCT, pass 1 */
++    sub             v2.8h,    v10.8h,   v14.8h
++    add             v14.8h,   v10.8h,   v14.8h
++    sub             v1.8h,    v11.8h,   v13.8h
++    add             v13.8h,   v11.8h,   v13.8h
++    sub             v5.8h,    v9.8h,    v15.8h
++    add             v15.8h,   v9.8h,    v15.8h
++    sqdmulh         v4.8h,    v2.8h,    XFIX_1_414213562
++    sqdmulh         v6.8h,    v1.8h,    XFIX_2_613125930
++    add             v3.8h,    v1.8h,    v1.8h
++    sub             v1.8h,    v5.8h,    v1.8h
++    add             v10.8h,   v2.8h,    v4.8h
++    sqdmulh         v4.8h,    v1.8h,    XFIX_1_847759065
++    sub             v2.8h,    v15.8h,   v13.8h
++    add             v3.8h,    v3.8h,    v6.8h
++    sqdmulh         v6.8h,    v2.8h,    XFIX_1_414213562
++    add             v1.8h,    v1.8h,    v4.8h
++    sqdmulh         v4.8h,    v5.8h,    XFIX_1_082392200
++    sub             v10.8h,   v10.8h,   v14.8h
++    add             v2.8h,    v2.8h,    v6.8h
++    sub             v6.8h,    v8.8h,    v12.8h
++    add             v12.8h,   v8.8h,    v12.8h
++    add             v9.8h,    v5.8h,    v4.8h
++    add             v5.8h,    v6.8h,    v10.8h
++    sub             v10.8h,   v6.8h,    v10.8h
++    add             v6.8h,    v15.8h,   v13.8h
++    add             v8.8h,    v12.8h,   v14.8h
++    sub             v3.8h,    v6.8h,    v3.8h
++    sub             v12.8h,   v12.8h,   v14.8h
++    sub             v3.8h,    v3.8h,    v1.8h
++    sub             v1.8h,    v9.8h,    v1.8h
++    add             v2.8h,    v3.8h,    v2.8h
++    sub             v15.8h,   v8.8h,    v6.8h
++    add             v1.8h,    v1.8h,    v2.8h
++    add             v8.8h,    v8.8h,    v6.8h
++    add             v14.8h,   v5.8h,    v3.8h
++    sub             v9.8h,    v5.8h,    v3.8h
++    sub             v13.8h,   v10.8h,   v2.8h
++    add             v10.8h,   v10.8h,   v2.8h
++    /* Transpose  q8-q9 */
++    mov             v18.16b,  v8.16b
++    trn1            v8.8h,    v8.8h,    v9.8h
++    trn2            v9.8h,    v18.8h,   v9.8h
++    sub             v11.8h,   v12.8h,   v1.8h
++    /* Transpose  q14-q15 */
++    mov             v18.16b,  v14.16b
++    trn1            v14.8h,   v14.8h,   v15.8h
++    trn2            v15.8h,   v18.8h,   v15.8h
++    add             v12.8h,   v12.8h,   v1.8h
++    /* Transpose  q10-q11 */
++    mov             v18.16b,  v10.16b
++    trn1            v10.8h,   v10.8h,   v11.8h
++    trn2            v11.8h,   v18.8h,   v11.8h
++    /* Transpose  q12-q13 */
++    mov             v18.16b,  v12.16b
++    trn1            v12.8h,   v12.8h,   v13.8h
++    trn2            v13.8h,   v18.8h,   v13.8h
++    /* Transpose  q9-q11 */
++    mov             v18.16b,  v9.16b
++    trn1            v9.4s,    v9.4s,    v11.4s
++    trn2            v11.4s,   v18.4s,   v11.4s
++    /* Transpose  q12-q14 */
++    mov             v18.16b,  v12.16b
++    trn1            v12.4s,   v12.4s,   v14.4s
++    trn2            v14.4s,   v18.4s,   v14.4s
++    /* Transpose  q8-q10 */
++    mov             v18.16b,  v8.16b
++    trn1            v8.4s,    v8.4s,    v10.4s
++    trn2            v10.4s,   v18.4s,   v10.4s
++    /* Transpose  q13-q15 */
++    mov             v18.16b,  v13.16b
++    trn1            v13.4s,   v13.4s,   v15.4s
++    trn2            v15.4s,   v18.4s,   v15.4s
++    /* vswp            v14.4h,   v10-MSB.4h */
++    umov            x22, v14.d[0]
++    ins             v14.2d[0], v10.2d[1]
++    ins             v10.2d[1], x22
++    /* vswp            v13.4h,   v9MSB.4h */
++
++    umov            x22, v13.d[0]
++    ins             v13.2d[0], v9.2d[1]
++    ins             v9.2d[1], x22
++    /* 1-D IDCT, pass 2 */
++    sub             v2.8h,    v10.8h,   v14.8h
++    /* vswp            v15.4h,   v11MSB.4h */
++    umov            x22, v15.d[0]
++    ins             v15.2d[0], v11.2d[1]
++    ins             v11.2d[1], x22
++    add             v14.8h,   v10.8h,   v14.8h
++    /* vswp            v12.4h,   v8-MSB.4h */
++    umov            x22, v12.d[0]
++    ins             v12.2d[0], v8.2d[1]
++    ins             v8.2d[1], x22
++    sub             v1.8h,    v11.8h,   v13.8h
++    add             v13.8h,   v11.8h,   v13.8h
++    sub             v5.8h,    v9.8h,    v15.8h
++    add             v15.8h,   v9.8h,    v15.8h
++    sqdmulh         v4.8h,    v2.8h,    XFIX_1_414213562
++    sqdmulh         v6.8h,    v1.8h,    XFIX_2_613125930
++    add             v3.8h,    v1.8h,    v1.8h
++    sub             v1.8h,    v5.8h,    v1.8h
++    add             v10.8h,   v2.8h,    v4.8h
++    sqdmulh         v4.8h,    v1.8h,    XFIX_1_847759065
++    sub             v2.8h,    v15.8h,   v13.8h
++    add             v3.8h,    v3.8h,    v6.8h
++    sqdmulh         v6.8h,    v2.8h,    XFIX_1_414213562
++    add             v1.8h,    v1.8h,    v4.8h
++    sqdmulh         v4.8h,    v5.8h,    XFIX_1_082392200
++    sub             v10.8h,   v10.8h,   v14.8h
++    add             v2.8h,    v2.8h,    v6.8h
++    sub             v6.8h,    v8.8h,    v12.8h
++    add             v12.8h,   v8.8h,    v12.8h
++    add             v9.8h,    v5.8h,    v4.8h
++    add             v5.8h,    v6.8h,    v10.8h
++    sub             v10.8h,   v6.8h,    v10.8h
++    add             v6.8h,    v15.8h,   v13.8h
++    add             v8.8h,    v12.8h,   v14.8h
++    sub             v3.8h,    v6.8h,    v3.8h
++    sub             v12.8h,   v12.8h,   v14.8h
++    sub             v3.8h,    v3.8h,    v1.8h
++    sub             v1.8h,    v9.8h,    v1.8h
++    add             v2.8h,    v3.8h,    v2.8h
++    sub             v15.8h,   v8.8h,    v6.8h
++    add             v1.8h,    v1.8h,    v2.8h
++    add             v8.8h,    v8.8h,    v6.8h
++    add             v14.8h,   v5.8h,    v3.8h
++    sub             v9.8h,    v5.8h,    v3.8h
++    sub             v13.8h,   v10.8h,   v2.8h
++    add             v10.8h,   v10.8h,   v2.8h
++    sub             v11.8h,   v12.8h,   v1.8h
++    add             v12.8h,   v12.8h,   v1.8h
++    /* Descale to 8-bit and range limit */
++    movi            v0.16b,   #0x80
++    sqshrn          v8.8b,    v8.8h,    #5
++    sqshrn2         v8.16b,   v9.8h,    #5
++    sqshrn          v9.8b,    v10.8h,   #5
++    sqshrn2         v9.16b,   v11.8h,   #5
++    sqshrn          v10.8b,   v12.8h,   #5
++    sqshrn2         v10.16b,  v13.8h,   #5
++    sqshrn          v11.8b,   v14.8h,   #5
++    sqshrn2         v11.16b,  v15.8h,   #5
++    add             v8.16b,   v8.16b,   v0.16b
++    add             v9.16b,   v9.16b,   v0.16b
++    add             v10.16b,  v10.16b,  v0.16b
++    add             v11.16b,  v11.16b,  v0.16b
++    /* Transpose the final 8-bit samples */
++    /* Transpose  q8-q9 */
++    mov             v18.16b,  v8.16b
++    trn1            v8.8h,    v8.8h,    v9.8h
++    trn2            v9.8h,    v18.8h,   v9.8h
++    /* Transpose  q10-q11 */
++    mov             v18.16b,  v10.16b
++    trn1            v10.8h,   v10.8h,   v11.8h
++    trn2            v11.8h,   v18.8h,   v11.8h
++    /* Transpose  q8-q10 */
++    mov             v18.16b,  v8.16b
++    trn1            v8.4s,    v8.4s,    v10.4s
++    trn2            v10.4s,   v18.4s,   v10.4s
++    /* Transpose  q9-q11 */
++    mov             v18.16b,  v9.16b
++    trn1            v9.4s,    v9.4s,    v11.4s
++    trn2            v11.4s,   v18.4s,   v11.4s
++    /* make copy */
++    ins             v17.2d[0], v8.2d[1]
++    /* Transpose  d16-d17-msb */
++    mov             v18.16b,  v8.16b
++    trn1            v8.8b,    v8.8b,    v17.8b
++    trn2            v17.8b,   v18.8b,   v17.8b
++    /* make copy */
++    ins             v19.2d[0], v9.2d[1]
++    mov             v18.16b,  v9.16b
++    trn1            v9.8b,    v9.8b,    v19.8b
++    trn2            v19.8b,   v18.8b,   v19.8b
++    /* Store results to the output buffer */
++    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
++    add             TMP1,     TMP1,     OUTPUT_COL
++    add             TMP2,     TMP2,     OUTPUT_COL
++    st1             {v8.8b},  [TMP1]
++    st1             {v17.8b}, [TMP2]
++    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
++    add             TMP1,     TMP1,     OUTPUT_COL
++    add             TMP2,     TMP2,     OUTPUT_COL
++    st1             {v9.8b},  [TMP1]
++    /* make copy */
++    ins             v7.2d[0], v10.2d[1]
++    mov             v18.16b,  v10.16b
++    trn1            v10.8b,   v10.8b,   v7.8b
++    trn2            v7.8b,    v18.8b,   v7.8b
++    st1             {v19.8b}, [TMP2]
++    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
++    ldp             TMP4,     TMP5,     [OUTPUT_BUF], 16
++    add             TMP1,     TMP1,     OUTPUT_COL
++    add             TMP2,     TMP2,     OUTPUT_COL
++    add             TMP4,     TMP4,     OUTPUT_COL
++    add             TMP5,     TMP5,     OUTPUT_COL
++    st1             {v10.8b}, [TMP1]
++    /* make copy */
++    ins             v16.2d[0], v11.2d[1]
++    mov             v18.16b,  v11.16b
++    trn1            v11.8b,   v11.8b,   v16.8b
++    trn2            v16.8b,   v18.8b,   v16.8b
++    st1             {v7.8b},  [TMP2]
++    st1             {v11.8b}, [TMP4]
++    st1             {v16.8b}, [TMP5]
++    sub             sp, sp, #176
++    ldp             x22, x23, [sp], 16
++    ld1             {v0.8b - v3.8b}, [sp], 32
++    ld1             {v4.8b - v7.8b}, [sp], 32
++    ld1             {v8.8b - v11.8b}, [sp], 32
++    ld1             {v12.8b - v15.8b}, [sp], 32
++    ld1             {v16.8b - v19.8b}, [sp], 32
++    blr             x30
++
++    .unreq          DCT_TABLE
++    .unreq          COEF_BLOCK
++    .unreq          OUTPUT_BUF
++    .unreq          OUTPUT_COL
++    .unreq          TMP1
++    .unreq          TMP2
++    .unreq          TMP3
++    .unreq          TMP4
++
++
++/*****************************************************************************/
++
++/*
++ * jsimd_idct_4x4_neon
++ *
++ * This function contains inverse-DCT code for getting reduced-size
++ * 4x4 pixels output from an 8x8 DCT block. It uses the same  calculations
++ * and produces exactly the same output as IJG's original 'jpeg_idct_4x4'
++ * function from jpeg-6b (jidctred.c).
++ *
++ * NOTE: jpeg-8 has an improved implementation of 4x4 inverse-DCT, which
++ *       requires much less arithmetic operations and hence should be faster.
++ *       The primary purpose of this particular NEON optimized function is
++ *       bit exact compatibility with jpeg-6b.
++ *
++ * TODO: a bit better instructions scheduling can be achieved by expanding
++ *       idct_helper/transpose_4x4 macros and reordering instructions,
++ *       but readability will suffer somewhat.
++ */
++
++#define CONST_BITS  13
++
++#define FIX_0_211164243  (1730)  /* FIX(0.211164243) */
++#define FIX_0_509795579  (4176)  /* FIX(0.509795579) */
++#define FIX_0_601344887  (4926)  /* FIX(0.601344887) */
++#define FIX_0_720959822  (5906)  /* FIX(0.720959822) */
++#define FIX_0_765366865  (6270)  /* FIX(0.765366865) */
++#define FIX_0_850430095  (6967)  /* FIX(0.850430095) */
++#define FIX_0_899976223  (7373)  /* FIX(0.899976223) */
++#define FIX_1_061594337  (8697)  /* FIX(1.061594337) */
++#define FIX_1_272758580  (10426) /* FIX(1.272758580) */
++#define FIX_1_451774981  (11893) /* FIX(1.451774981) */
++#define FIX_1_847759065  (15137) /* FIX(1.847759065) */
++#define FIX_2_172734803  (17799) /* FIX(2.172734803) */
++#define FIX_2_562915447  (20995) /* FIX(2.562915447) */
++#define FIX_3_624509785  (29692) /* FIX(3.624509785) */
++
++.balign 16
++jsimd_idct_4x4_neon_consts:
++    .short     FIX_1_847759065     /* v0.4h[0] */
++    .short     -FIX_0_765366865    /* v0.4h[1] */
++    .short     -FIX_0_211164243    /* v0.4h[2] */
++    .short     FIX_1_451774981     /* v0.4h[3] */
++    .short     -FIX_2_172734803    /* d1[0] */
++    .short     FIX_1_061594337     /* d1[1] */
++    .short     -FIX_0_509795579    /* d1[2] */
++    .short     -FIX_0_601344887    /* d1[3] */
++    .short     FIX_0_899976223     /* v2.4h[0] */
++    .short     FIX_2_562915447     /* v2.4h[1] */
++    .short     1 << (CONST_BITS+1) /* v2.4h[2] */
++    .short     0                   /* v2.4h[3] */
++
++.macro idct_helper x4, x6, x8, x10, x12, x14, x16, shift, y26, y27, y28, y29
++    smull           v28.4s, \x4,    v2.4h[2]
++    smlal           v28.4s, \x8,    v0.4h[0]
++    smlal           v28.4s, \x14,   v0.4h[1]
++
++    smull           v26.4s, \x16,   v1.4h[2]
++    smlal           v26.4s, \x12,   v1.4h[3]
++    smlal           v26.4s, \x10,   v2.4h[0]
++    smlal           v26.4s, \x6,    v2.4h[1]
++
++    smull           v30.4s, \x4,    v2.4h[2]
++    smlsl           v30.4s, \x8,    v0.4h[0]
++    smlsl           v30.4s, \x14,   v0.4h[1]
++
++    smull           v24.4s, \x16,   v0.4h[2]
++    smlal           v24.4s, \x12,   v0.4h[3]
++    smlal           v24.4s, \x10,   v1.4h[0]
++    smlal           v24.4s, \x6,    v1.4h[1]
++
++    add             v20.4s, v28.4s, v26.4s
++    sub             v28.4s, v28.4s, v26.4s
++
++.if \shift > 16
++    srshr           v20.4s, v20.4s, #\shift
++    srshr           v28.4s, v28.4s, #\shift
++    xtn             \y26,   v20.4s
++    xtn             \y29,   v28.4s
++.else
++    rshrn           \y26,   v20.4s, #\shift
++    rshrn           \y29,   v28.4s, #\shift
++.endif
++
++    add             v20.4s, v30.4s, v24.4s
++    sub             v30.4s, v30.4s, v24.4s
++
++.if \shift > 16
++    srshr           v20.4s, v20.4s, #\shift
++    srshr           v30.4s, v30.4s, #\shift
++    xtn             \y27,   v20.4s
++    xtn             \y28,   v30.4s
++.else
++    rshrn           \y27,   v20.4s, #\shift
++    rshrn           \y28,   v30.4s, #\shift
++.endif
++
++.endm
++
++asm_function jsimd_idct_4x4_neon
++
++    DCT_TABLE       .req x0
++    COEF_BLOCK      .req x1
++    OUTPUT_BUF      .req x2
++    OUTPUT_COL      .req x3
++    TMP1            .req x0
++    TMP2            .req x1
++    TMP3            .req x2
++    TMP4            .req x15
++
++    /* Save all used NEON registers */
++    sub             sp, sp, 272
++    str             x15, [sp], 16
++    /* Load constants (v3.4h is just used for padding) */
++    adr             TMP4, jsimd_idct_4x4_neon_consts
++    st1             {v0.8b - v3.8b}, [sp], 32
++    st1             {v4.8b - v7.8b}, [sp], 32
++    st1             {v8.8b - v11.8b}, [sp], 32
++    st1             {v12.8b - v15.8b}, [sp], 32
++    st1             {v16.8b - v19.8b}, [sp], 32
++    st1             {v20.8b - v23.8b}, [sp], 32
++    st1             {v24.8b - v27.8b}, [sp], 32
++    st1             {v28.8b - v31.8b}, [sp], 32
++    ld1             {v0.4h, v1.4h, v2.4h, v3.4h}, [TMP4]
++
++    /* Load all COEF_BLOCK into NEON registers with the following allocation:
++     *       0 1 2 3 | 4 5 6 7
++     *      ---------+--------
++     *   0 | v4.4h   | v5.4h
++     *   1 | v6.4h   | v7.4h
++     *   2 | v8.4h   | v9.4h
++     *   3 | v10.4h  | v11.4h
++     *   4 | -       | -
++     *   5 | v12.4h  | v13.4h
++     *   6 | v14.4h  | v15.4h
++     *   7 | v16.4h  | v17.4h
++     */
++    ld1             {v4.4h, v5.4h, v6.4h, v7.4h}, [COEF_BLOCK], 32
++    ld1             {v8.4h, v9.4h, v10.4h, v11.4h}, [COEF_BLOCK], 32
++    add             COEF_BLOCK, COEF_BLOCK, #16
++    ld1             {v12.4h, v13.4h, v14.4h, v15.4h}, [COEF_BLOCK], 32
++    ld1             {v16.4h, v17.4h}, [COEF_BLOCK], 16
++    /* dequantize */
++    ld1             {v18.4h, v19.4h, v20.4h, v21.4h}, [DCT_TABLE], 32
++    mul             v4.4h, v4.4h, v18.4h
++    mul             v5.4h, v5.4h, v19.4h
++    ins             v4.2d[1], v5.2d[0]    /* 128 bit q4 */
++    ld1             {v22.4h, v23.4h, v24.4h, v25.4h}, [DCT_TABLE], 32
++    mul             v6.4h, v6.4h, v20.4h
++    mul             v7.4h, v7.4h, v21.4h
++    ins             v6.2d[1], v7.2d[0]    /* 128 bit q6 */
++    mul             v8.4h, v8.4h, v22.4h
++    mul             v9.4h, v9.4h, v23.4h
++    ins             v8.2d[1], v9.2d[0]    /* 128 bit q8 */
++    add             DCT_TABLE, DCT_TABLE, #16
++    ld1             {v26.4h, v27.4h, v28.4h, v29.4h}, [DCT_TABLE], 32
++    mul             v10.4h, v10.4h, v24.4h
++    mul             v11.4h, v11.4h, v25.4h
++    ins             v10.2d[1], v11.2d[0]  /* 128 bit q10 */
++    mul             v12.4h, v12.4h, v26.4h
++    mul             v13.4h, v13.4h, v27.4h
++    ins             v12.2d[1], v13.2d[0]  /* 128 bit q12 */
++    ld1             {v30.4h, v31.4h}, [DCT_TABLE], 16
++    mul             v14.4h, v14.4h, v28.4h
++    mul             v15.4h, v15.4h, v29.4h
++    ins             v14.2d[1], v15.2d[0]  /* 128 bit q14 */
++    mul             v16.4h, v16.4h, v30.4h
++    mul             v17.4h, v17.4h, v31.4h
++    ins             v16.2d[1], v17.2d[0]  /* 128 bit q16 */
++
++    /* Pass 1 */
++    idct_helper     v4.4h, v6.4h, v8.4h, v10.4h, v12.4h, v14.4h, v16.4h, 12, v4.4h, v6.4h, v8.4h, v10.4h
++    transpose_4x4   v4, v6, v8, v10, v3
++    ins             v10.2d[1], v11.2d[0]
++    idct_helper     v5.4h, v7.4h, v9.4h, v11.4h, v13.4h, v15.4h, v17.4h, 12, v5.4h, v7.4h, v9.4h, v11.4h
++    transpose_4x4   v5, v7, v9, v11, v3
++    ins             v10.2d[1], v11.2d[0]
++    /* Pass 2 */
++    idct_helper     v4.4h, v6.4h, v8.4h, v10.4h, v7.4h, v9.4h, v11.4h, 19, v26.4h, v27.4h, v28.4h, v29.4h
++    transpose_4x4   v26, v27, v28, v29, v3
++
++    /* Range limit */
++    movi            v30.8h, #0x80
++    ins             v26.2d[1], v27.2d[0]
++    ins             v28.2d[1], v29.2d[0]
++    add             v26.8h, v26.8h, v30.8h
++    add             v28.8h, v28.8h, v30.8h
++    sqxtun          v26.8b, v26.8h
++    sqxtun          v27.8b, v28.8h
++
++    /* Store results to the output buffer */
++    ldp             TMP1, TMP2, [OUTPUT_BUF], 16
++    ldp             TMP3, TMP4, [OUTPUT_BUF]
++    add             TMP1, TMP1, OUTPUT_COL
++    add             TMP2, TMP2, OUTPUT_COL
++    add             TMP3, TMP3, OUTPUT_COL
++    add             TMP4, TMP4, OUTPUT_COL
++
++#if defined(__ARMEL__) && !RESPECT_STRICT_ALIGNMENT
++    /* We can use much less instructions on little endian systems if the
++     * OS kernel is not configured to trap unaligned memory accesses
++     */
++    st1             {v26.s}[0], [TMP1], 4
++    st1             {v27.s}[0], [TMP3], 4
++    st1             {v26.s}[1], [TMP2], 4
++    st1             {v27.s}[1], [TMP4], 4
++#else
++    st1             {v26.b}[0], [TMP1], 1
++    st1             {v27.b}[0], [TMP3], 1
++    st1             {v26.b}[1], [TMP1], 1
++    st1             {v27.b}[1], [TMP3], 1
++    st1             {v26.b}[2], [TMP1], 1
++    st1             {v27.b}[2], [TMP3], 1
++    st1             {v26.b}[3], [TMP1], 1
++    st1             {v27.b}[3], [TMP3], 1
++
++    st1             {v26.b}[4], [TMP2], 1
++    st1             {v27.b}[4], [TMP4], 1
++    st1             {v26.b}[5], [TMP2], 1
++    st1             {v27.b}[5], [TMP4], 1
++    st1             {v26.b}[6], [TMP2], 1
++    st1             {v27.b}[6], [TMP4], 1
++    st1             {v26.b}[7], [TMP2], 1
++    st1             {v27.b}[7], [TMP4], 1
++#endif
++
++    /* vpop            {v8.4h - v15.4h}    ;not available */
++    sub             sp, sp, #272
++    ldr             x15, [sp], 16
++    ld1             {v0.8b - v3.8b}, [sp], 32
++    ld1             {v4.8b - v7.8b}, [sp], 32
++    ld1             {v8.8b - v11.8b}, [sp], 32
++    ld1             {v12.8b - v15.8b}, [sp], 32
++    ld1             {v16.8b - v19.8b}, [sp], 32
++    ld1             {v20.8b - v23.8b}, [sp], 32
++    ld1             {v24.8b - v27.8b}, [sp], 32
++    ld1             {v28.8b - v31.8b}, [sp], 32
++    blr             x30
++
++    .unreq          DCT_TABLE
++    .unreq          COEF_BLOCK
++    .unreq          OUTPUT_BUF
++    .unreq          OUTPUT_COL
++    .unreq          TMP1
++    .unreq          TMP2
++    .unreq          TMP3
++    .unreq          TMP4
++
++.purgem idct_helper
++
++
++/*****************************************************************************/
++
++/*
++ * jsimd_idct_2x2_neon
++ *
++ * This function contains inverse-DCT code for getting reduced-size
++ * 2x2 pixels output from an 8x8 DCT block. It uses the same  calculations
++ * and produces exactly the same output as IJG's original 'jpeg_idct_2x2'
++ * function from jpeg-6b (jidctred.c).
++ *
++ * NOTE: jpeg-8 has an improved implementation of 2x2 inverse-DCT, which
++ *       requires much less arithmetic operations and hence should be faster.
++ *       The primary purpose of this particular NEON optimized function is
++ *       bit exact compatibility with jpeg-6b.
++ */
++
++.balign 8
++jsimd_idct_2x2_neon_consts:
++    .short     -FIX_0_720959822    /* v14[0] */
++    .short     FIX_0_850430095     /* v14[1] */
++    .short     -FIX_1_272758580    /* v14[2] */
++    .short     FIX_3_624509785     /* v14[3] */
++
++.macro idct_helper x4, x6, x10, x12, x16, shift, y26, y27
++    sshll      v15.4s, \x4,    #15
++    smull      v26.4s, \x6,    v14.4h[3]
++    smlal      v26.4s, \x10,   v14.4h[2]
++    smlal      v26.4s, \x12,   v14.4h[1]
++    smlal      v26.4s, \x16,   v14.4h[0]
++
++    add        v20.4s, v15.4s, v26.4s
++    sub        v15.4s, v15.4s, v26.4s
++
++.if \shift > 16
++    srshr      v20.4s, v20.4s, #\shift
++    srshr      v15.4s, v15.4s, #\shift
++    xtn        \y26,   v20.4s
++    xtn        \y27,   v15.4s
++.else
++    rshrn      \y26,   v20.4s, #\shift
++    rshrn      \y27,   v15.4s, #\shift
++.endif
++
++.endm
++
++asm_function jsimd_idct_2x2_neon
++
++    DCT_TABLE       .req x0
++    COEF_BLOCK      .req x1
++    OUTPUT_BUF      .req x2
++    OUTPUT_COL      .req x3
++    TMP1            .req x0
++    TMP2            .req x15
++
++    /* vpush           {v8.4h - v15.4h}            ; not available */
++    sub             sp, sp, 208
++    str             x15, [sp], 16
++
++    /* Load constants */
++    adr             TMP2, jsimd_idct_2x2_neon_consts
++    st1             {v4.8b - v7.8b}, [sp], 32
++    st1             {v8.8b - v11.8b}, [sp], 32
++    st1             {v12.8b - v15.8b}, [sp], 32
++    st1             {v16.8b - v19.8b}, [sp], 32
++    st1             {v21.8b - v22.8b}, [sp], 16
++    st1             {v24.8b - v27.8b}, [sp], 32
++    st1             {v30.8b - v31.8b}, [sp], 16
++    ld1             {v14.4h}, [TMP2]
++
++    /* Load all COEF_BLOCK into NEON registers with the following allocation:
++     *       0 1 2 3 | 4 5 6 7
++     *      ---------+--------
++     *   0 | v4.4h   | v5.4h
++     *   1 | v6.4h   | v7.4h
++     *   2 | -       | -
++     *   3 | v10.4h  | v11.4h
++     *   4 | -       | -
++     *   5 | v12.4h  | v13.4h
++     *   6 | -       | -
++     *   7 | v16.4h  | v17.4h
++     */
++    ld1             {v4.4h, v5.4h, v6.4h, v7.4h}, [COEF_BLOCK], 32
++    add             COEF_BLOCK, COEF_BLOCK, #16
++    ld1             {v10.4h, v11.4h}, [COEF_BLOCK], 16
++    add             COEF_BLOCK, COEF_BLOCK, #16
++    ld1             {v12.4h, v13.4h}, [COEF_BLOCK], 16
++    add             COEF_BLOCK, COEF_BLOCK, #16
++    ld1             {v16.4h, v17.4h}, [COEF_BLOCK], 16
++    /* Dequantize */
++    ld1             {v18.4h, v19.4h, v20.4h, v21.4h}, [DCT_TABLE], 32
++    mul             v4.4h, v4.4h, v18.4h
++    mul             v5.4h, v5.4h, v19.4h
++    ins             v4.2d[1], v5.2d[0]
++    mul             v6.4h, v6.4h, v20.4h
++    mul             v7.4h, v7.4h, v21.4h
++    ins             v6.2d[1], v7.2d[0]
++    add             DCT_TABLE, DCT_TABLE, #16
++    ld1             {v24.4h, v25.4h}, [DCT_TABLE], 16
++    mul             v10.4h, v10.4h, v24.4h
++    mul             v11.4h, v11.4h, v25.4h
++    ins             v10.2d[1], v11.2d[0]
++    add             DCT_TABLE, DCT_TABLE, #16
++    ld1             {v26.4h, v27.4h}, [DCT_TABLE], 16
++    mul             v12.4h, v12.4h, v26.4h
++    mul             v13.4h, v13.4h, v27.4h
++    ins             v12.2d[1], v13.2d[0]
++    add             DCT_TABLE, DCT_TABLE, #16
++    ld1             {v30.4h, v31.4h}, [DCT_TABLE], 16
++    mul             v16.4h, v16.4h, v30.4h
++    mul             v17.4h, v17.4h, v31.4h
++    ins             v16.2d[1], v17.2d[0]
++
++    /* Pass 1 */
++#if 0
++    idct_helper     v4.4h, v6.4h, v10.4h, v12.4h, v16.4h, 13, v4.4h, v6.4h
++    transpose_4x4   v4.4h, v6.4h, v8.4h,  v10.4h
++    idct_helper     v5.4h, v7.4h, v11.4h, v13.4h, v17.4h, 13, v5.4h, v7.4h
++    transpose_4x4   v5.4h, v7.4h, v9.4h,  v11.4h
++#else
++    smull           v26.4s, v6.4h,  v14.4h[3]
++    smlal           v26.4s, v10.4h, v14.4h[2]
++    smlal           v26.4s, v12.4h, v14.4h[1]
++    smlal           v26.4s, v16.4h, v14.4h[0]
++    smull           v24.4s, v7.4h,  v14.4h[3]
++    smlal           v24.4s, v11.4h, v14.4h[2]
++    smlal           v24.4s, v13.4h, v14.4h[1]
++    smlal           v24.4s, v17.4h, v14.4h[0]
++    sshll           v15.4s, v4.4h,  #15
++    sshll           v30.4s, v5.4h,  #15
++    add             v20.4s, v15.4s, v26.4s
++    sub             v15.4s, v15.4s, v26.4s
++    rshrn           v4.4h,  v20.4s, #13
++    rshrn           v6.4h,  v15.4s, #13
++    add             v20.4s, v30.4s, v24.4s
++    sub             v15.4s, v30.4s, v24.4s
++    rshrn           v5.4h,  v20.4s, #13
++    rshrn           v7.4h,  v15.4s, #13
++    ins             v4.2d[1], v5.2d[0]
++    ins             v6.2d[1], v7.2d[0]
++    transpose       v4, v6, v3, .16b, .8h
++    transpose       v6, v10, v3, .16b, .4s
++    ins             v11.2d[0], v10.2d[1]
++    ins             v7.2d[0], v6.2d[1]
++#endif
++
++    /* Pass 2 */
++    idct_helper     v4.4h, v6.4h, v10.4h, v7.4h, v11.4h, 20, v26.4h, v27.4h
++
++    /* Range limit */
++    movi            v30.8h, #0x80
++    ins             v26.2d[1], v27.2d[0]
++    add             v26.8h, v26.8h, v30.8h
++    sqxtun          v30.8b, v26.8h
++    ins             v26.2d[0], v30.2d[0]
++    sqxtun          v27.8b, v26.8h
++
++    /* Store results to the output buffer */
++    ldp             TMP1, TMP2, [OUTPUT_BUF]
++    add             TMP1, TMP1, OUTPUT_COL
++    add             TMP2, TMP2, OUTPUT_COL
++
++    st1             {v26.b}[0], [TMP1], 1
++    st1             {v27.b}[4], [TMP1], 1
++    st1             {v26.b}[1], [TMP2], 1
++    st1             {v27.b}[5], [TMP2], 1
++
++    sub             sp, sp, #208
++    ldr             x15, [sp], 16
++    ld1             {v4.8b - v7.8b}, [sp], 32
++    ld1             {v8.8b - v11.8b}, [sp], 32
++    ld1             {v12.8b - v15.8b}, [sp], 32
++    ld1             {v16.8b - v19.8b}, [sp], 32
++    ld1             {v21.8b - v22.8b}, [sp], 16
++    ld1             {v24.8b - v27.8b}, [sp], 32
++    ld1             {v30.8b - v31.8b}, [sp], 16
++    blr             x30
++
++    .unreq          DCT_TABLE
++    .unreq          COEF_BLOCK
++    .unreq          OUTPUT_BUF
++    .unreq          OUTPUT_COL
++    .unreq          TMP1
++    .unreq          TMP2
++
++.purgem idct_helper
++
++
++/*****************************************************************************/
++
++/*
++ * jsimd_ycc_extrgb_convert_neon
++ * jsimd_ycc_extbgr_convert_neon
++ * jsimd_ycc_extrgbx_convert_neon
++ * jsimd_ycc_extbgrx_convert_neon
++ * jsimd_ycc_extxbgr_convert_neon
++ * jsimd_ycc_extxrgb_convert_neon
++ *
++ * Colorspace conversion YCbCr -> RGB
++ */
++
++
++.macro do_load size
++    .if \size == 8
++        ld1  {v4.8b}, [U], 8
++        ld1  {v5.8b}, [V], 8
++        ld1  {v0.8b}, [Y], 8
++        prfm PLDL1KEEP, [U, #64]
++        prfm PLDL1KEEP, [V, #64]
++        prfm PLDL1KEEP, [Y, #64]
++    .elseif \size == 4
++        ld1  {v4.b}[0], [U], 1
++        ld1  {v4.b}[1], [U], 1
++        ld1  {v4.b}[2], [U], 1
++        ld1  {v4.b}[3], [U], 1
++        ld1  {v5.b}[0], [V], 1
++        ld1  {v5.b}[1], [V], 1
++        ld1  {v5.b}[2], [V], 1
++        ld1  {v5.b}[3], [V], 1
++        ld1  {v0.b}[0], [Y], 1
++        ld1  {v0.b}[1], [Y], 1
++        ld1  {v0.b}[2], [Y], 1
++        ld1  {v0.b}[3], [Y], 1
++    .elseif \size == 2
++        ld1  {v4.b}[4], [U], 1
++        ld1  {v4.b}[5], [U], 1
++        ld1  {v5.b}[4], [V], 1
++        ld1  {v5.b}[5], [V], 1
++        ld1  {v0.b}[4], [Y], 1
++        ld1  {v0.b}[5], [Y], 1
++    .elseif \size == 1
++        ld1  {v4.b}[6], [U], 1
++        ld1  {v5.b}[6], [V], 1
++        ld1  {v0.b}[6], [Y], 1
++    .else
++        .error unsupported macroblock size
++    .endif
++.endm
++
++.macro do_store bpp, size
++    .if \bpp == 24
++        .if \size == 8
++            st3  {v10.8b, v11.8b, v12.8b}, [RGB], 24
++        .elseif \size == 4
++            st3  {v10.b, v11.b, v12.b}[0], [RGB], 3
++            st3  {v10.b, v11.b, v12.b}[1], [RGB], 3
++            st3  {v10.b, v11.b, v12.b}[2], [RGB], 3
++            st3  {v10.b, v11.b, v12.b}[3], [RGB], 3
++        .elseif \size == 2
++            st3  {v10.b, v11.b, v12.b}[4], [RGB], 3
++            st3  {v10.b, v11.b, v12.b}[5], [RGB], 3
++        .elseif \size == 1
++            st3  {v10.b, v11.b, v12.b}[6], [RGB], 3
++        .else
++            .error unsupported macroblock size
++        .endif
++    .elseif \bpp == 32
++        .if \size == 8
++            st4  {v10.8b, v11.8b, v12.8b, v13.8b}, [RGB], 32
++        .elseif \size == 4
++            st4  {v10.b, v11.b, v12.b, v13.b}[0], [RGB], 4
++            st4  {v10.b, v11.b, v12.b, v13.b}[1], [RGB], 4
++            st4  {v10.b, v11.b, v12.b, v13.b}[2], [RGB], 4
++            st4  {v10.b, v11.b, v12.b, v13.b}[3], [RGB], 4
++        .elseif \size == 2
++            st4  {v10.b, v11.b, v12.b, v13.b}[4], [RGB], 4
++            st4  {v10.b, v11.b, v12.b, v13.b}[5], [RGB], 4
++        .elseif \size == 1
++            st4  {v10.b, v11.b, v12.b, v13.b}[6], [RGB], 4
++        .else
++            .error unsupported macroblock size
++        .endif
++    .elseif \bpp==16
++        .if \size == 8
++            st1  {v25.8h}, [RGB],16
++        .elseif \size == 4
++            st1  {v25.4h}, [RGB],8
++        .elseif \size == 2
++            st1  {v25.h}[4], [RGB],2
++            st1  {v25.h}[5], [RGB],2
++        .elseif \size == 1
++            st1  {v25.h}[6], [RGB],2
++        .else
++            .error unsupported macroblock size
++        .endif
++     .else
++        .error unsupported bpp
++    .endif
++.endm
++
++.macro generate_jsimd_ycc_rgb_convert_neon colorid, bpp, r_offs, rsize, g_offs, gsize, b_offs, bsize, defsize
++
++/*
++ * 2-stage pipelined YCbCr->RGB conversion
++ */
++
++.macro do_yuv_to_rgb_stage1
++    uaddw        v6.8h, v2.8h, v4.8b     /* q3 = u - 128 */
++    uaddw        v8.8h, v2.8h, v5.8b     /* q2 = v - 128 */
++    smull        v20.4s, v6.4h, v1.4h[1] /* multiply by -11277 */
++    smlal        v20.4s, v8.4h, v1.4h[2] /* multiply by -23401 */
++    smull2       v22.4s, v6.8h, v1.4h[1] /* multiply by -11277 */
++    smlal2       v22.4s, v8.8h, v1.4h[2] /* multiply by -23401 */
++    smull        v24.4s, v8.4h, v1.4h[0] /* multiply by 22971 */
++    smull2       v26.4s, v8.8h, v1.4h[0] /* multiply by 22971 */
++    smull        v28.4s, v6.4h, v1.4h[3] /* multiply by 29033 */
++    smull2       v30.4s, v6.8h, v1.4h[3] /* multiply by 29033 */
++.endm
++
++.macro do_yuv_to_rgb_stage2
++    rshrn        v20.4h, v20.4s, #15
++    rshrn2       v20.8h, v22.4s, #15
++    rshrn        v24.4h, v24.4s, #14
++    rshrn2       v24.8h, v26.4s, #14
++    rshrn        v28.4h, v28.4s, #14
++    rshrn2       v28.8h, v30.4s, #14
++    uaddw        v20.8h, v20.8h, v0.8b
++    uaddw        v24.8h, v24.8h, v0.8b
++    uaddw        v28.8h, v28.8h, v0.8b
++.if \bpp != 16
++    sqxtun       v1\g_offs\defsize, v20.8h
++    sqxtun       v1\r_offs\defsize, v24.8h
++    sqxtun       v1\b_offs\defsize, v28.8h
++.else
++    sqshlu       v21.8h, v20.8h, #8
++    sqshlu       v25.8h, v24.8h, #8
++    sqshlu       v29.8h, v28.8h, #8
++    sri          v25.8h, v21.8h, #5
++    sri          v25.8h, v29.8h, #11
++.endif
++
++.endm
++
++.macro do_yuv_to_rgb_stage2_store_load_stage1
++    rshrn        v20.4h, v20.4s, #15
++    rshrn        v24.4h, v24.4s, #14
++    rshrn        v28.4h, v28.4s, #14
++    ld1          {v4.8b}, [U], 8
++    rshrn2       v20.8h, v22.4s, #15
++    rshrn2       v24.8h, v26.4s, #14
++    rshrn2       v28.8h, v30.4s, #14
++    ld1          {v5.8b}, [V], 8
++    uaddw        v20.8h, v20.8h, v0.8b
++    uaddw        v24.8h, v24.8h, v0.8b
++    uaddw        v28.8h, v28.8h, v0.8b
++.if \bpp != 16 /**************** rgb24/rgb32 *********************************/
++    sqxtun       v1\g_offs\defsize, v20.8h
++    ld1          {v0.8b}, [Y], 8
++    sqxtun       v1\r_offs\defsize, v24.8h
++    prfm         PLDL1KEEP, [U, #64]
++    prfm         PLDL1KEEP, [V, #64]
++    prfm         PLDL1KEEP, [Y, #64]
++    sqxtun       v1\b_offs\defsize, v28.8h
++    uaddw        v6.8h, v2.8h, v4.8b     /* v6.16b = u - 128 */
++    uaddw        v8.8h, v2.8h, v5.8b     /* q2 = v - 128 */
++    smull        v20.4s, v6.4h, v1.4h[1] /* multiply by -11277 */
++    smlal        v20.4s, v8.4h, v1.4h[2] /* multiply by -23401 */
++    smull2       v22.4s, v6.8h, v1.4h[1] /* multiply by -11277 */
++    smlal2       v22.4s, v8.8h, v1.4h[2] /* multiply by -23401 */
++    smull        v24.4s, v8.4h, v1.4h[0] /* multiply by 22971 */
++    smull2       v26.4s, v8.8h, v1.4h[0] /* multiply by 22971 */
++.else /**************************** rgb565 ***********************************/
++    sqshlu       v21.8h, v20.8h, #8
++    sqshlu       v25.8h, v24.8h, #8
++    sqshlu       v29.8h, v28.8h, #8
++    uaddw        v6.8h, v2.8h, v4.8b     /* v6.16b = u - 128 */
++    uaddw        v8.8h, v2.8h, v5.8b     /* q2 = v - 128 */
++    ld1          {v0.8b}, [Y], 8
++    smull        v20.4s, v6.4h, v1.4h[1] /* multiply by -11277 */
++    smlal        v20.4s, v8.4h, v1.4h[2] /* multiply by -23401 */
++    smull2       v22.4s, v6.8h, v1.4h[1] /* multiply by -11277 */
++    smlal2       v22.4s, v8.8h, v1.4h[2] /* multiply by -23401 */
++    sri          v25.8h, v21.8h, #5
++    smull        v24.4s, v8.4h, v1.4h[0] /* multiply by 22971 */
++    smull2       v26.4s, v8.8h, v1.4h[0] /* multiply by 22971 */
++    prfm         PLDL1KEEP, [U, #64]
++    prfm         PLDL1KEEP, [V, #64]
++    prfm         PLDL1KEEP, [Y, #64]
++    sri          v25.8h, v29.8h, #11
++.endif
++    do_store     \bpp, 8
++    smull        v28.4s, v6.4h, v1.4h[3] /* multiply by 29033 */
++    smull2       v30.4s, v6.8h, v1.4h[3] /* multiply by 29033 */
++.endm
++
++.macro do_yuv_to_rgb
++    do_yuv_to_rgb_stage1
++    do_yuv_to_rgb_stage2
++.endm
++
++/* Apple gas crashes on adrl, work around that by using adr.
++ * But this requires a copy of these constants for each function.
++ */
++
++.balign 16
++jsimd_ycc_\colorid\()_neon_consts:
++    .short          0,      0,     0,      0
++    .short          22971, -11277, -23401, 29033
++    .short          -128,  -128,   -128,   -128
++    .short          -128,  -128,   -128,   -128
++
++asm_function jsimd_ycc_\colorid\()_convert_neon
++    OUTPUT_WIDTH    .req x0
++    INPUT_BUF       .req x1
++    INPUT_ROW       .req x2
++    OUTPUT_BUF      .req x3
++    NUM_ROWS        .req x4
++
++    INPUT_BUF0      .req x5
++    INPUT_BUF1      .req x6
++    INPUT_BUF2      .req INPUT_BUF
++
++    RGB             .req x7
++    Y               .req x8
++    U               .req x9
++    V               .req x10
++    N               .req x15
++
++    sub             sp, sp, 336
++    str             x15, [sp], 16
++    /* Load constants to d1, d2, d3 (v0.4h is just used for padding) */
++    adr             x15, jsimd_ycc_\colorid\()_neon_consts
++    /* Save NEON registers */
++    st1             {v0.8b - v3.8b}, [sp], 32
++    st1             {v4.8b - v7.8b}, [sp], 32
++    st1             {v8.8b - v11.8b}, [sp], 32
++    st1             {v12.8b - v15.8b}, [sp], 32
++    st1             {v16.8b - v19.8b}, [sp], 32
++    st1             {v20.8b - v23.8b}, [sp], 32
++    st1             {v24.8b - v27.8b}, [sp], 32
++    st1             {v28.8b - v31.8b}, [sp], 32
++    ld1             {v0.4h, v1.4h}, [x15], 16
++    ld1             {v2.8h}, [x15]
++
++    /* Save ARM registers and handle input arguments */
++    /* push            {x4, x5, x6, x7, x8, x9, x10, x30} */
++    stp             x4, x5, [sp], 16
++    stp             x6, x7, [sp], 16
++    stp             x8, x9, [sp], 16
++    stp             x10, x30, [sp], 16
++    ldr             INPUT_BUF0, [INPUT_BUF]
++    ldr             INPUT_BUF1, [INPUT_BUF, 8]
++    ldr             INPUT_BUF2, [INPUT_BUF, 16]
++    .unreq          INPUT_BUF
++
++    /* Initially set v10, v11.4h, v12.8b, d13 to 0xFF */
++    movi            v10.16b, #255
++    movi            v13.16b, #255
++
++    /* Outer loop over scanlines */
++    cmp             NUM_ROWS, #1
++    blt             9f
++0:
++    lsl             x16, INPUT_ROW, #3
++    ldr             Y, [INPUT_BUF0, x16]
++    ldr             U, [INPUT_BUF1, x16]
++    mov             N, OUTPUT_WIDTH
++    ldr             V, [INPUT_BUF2, x16]
++    add             INPUT_ROW, INPUT_ROW, #1
++    ldr             RGB, [OUTPUT_BUF], #8
++
++    /* Inner loop over pixels */
++    subs            N, N, #8
++    blt             3f
++    do_load         8
++    do_yuv_to_rgb_stage1
++    subs            N, N, #8
++    blt             2f
++1:
++    do_yuv_to_rgb_stage2_store_load_stage1
++    subs            N, N, #8
++    bge             1b
++2:
++    do_yuv_to_rgb_stage2
++    do_store        \bpp, 8
++    tst             N, #7
++    beq             8f
++3:
++    tst             N, #4
++    beq             3f
++    do_load         4
++3:
++    tst             N, #2
++    beq             4f
++    do_load         2
++4:
++    tst             N, #1
++    beq             5f
++    do_load         1
++5:
++    do_yuv_to_rgb
++    tst             N, #4
++    beq             6f
++    do_store        \bpp, 4
++6:
++    tst             N, #2
++    beq             7f
++    do_store        \bpp, 2
++7:
++    tst             N, #1
++    beq             8f
++    do_store        \bpp, 1
++8:
++    subs            NUM_ROWS, NUM_ROWS, #1
++    bgt             0b
++9:
++    /* Restore all registers and return */
++    sub             sp, sp, #336
++    ldr             x15, [sp], 16
++    ld1             {v0.8b - v3.8b}, [sp], 32
++    ld1             {v4.8b - v7.8b}, [sp], 32
++    ld1             {v8.8b - v11.8b}, [sp], 32
++    ld1             {v12.8b - v15.8b}, [sp], 32
++    ld1             {v16.8b - v19.8b}, [sp], 32
++    ld1             {v20.8b - v23.8b}, [sp], 32
++    ld1             {v24.8b - v27.8b}, [sp], 32
++    ld1             {v28.8b - v31.8b}, [sp], 32
++    /* pop             {r4, r5, r6, r7, r8, r9, r10, pc} */
++    ldp             x4, x5, [sp], 16
++    ldp             x6, x7, [sp], 16
++    ldp             x8, x9, [sp], 16
++    ldp             x10, x30, [sp], 16
++    br              x30
++    .unreq          OUTPUT_WIDTH
++    .unreq          INPUT_ROW
++    .unreq          OUTPUT_BUF
++    .unreq          NUM_ROWS
++    .unreq          INPUT_BUF0
++    .unreq          INPUT_BUF1
++    .unreq          INPUT_BUF2
++    .unreq          RGB
++    .unreq          Y
++    .unreq          U
++    .unreq          V
++    .unreq          N
++
++.purgem do_yuv_to_rgb
++.purgem do_yuv_to_rgb_stage1
++.purgem do_yuv_to_rgb_stage2
++.purgem do_yuv_to_rgb_stage2_store_load_stage1
++.endm
++
++/*--------------------------------- id ----- bpp R  rsize  G  gsize  B  bsize  defsize   */
++generate_jsimd_ycc_rgb_convert_neon extrgb,  24, 0, .4h,   1, .4h,   2, .4h,   .8b
++generate_jsimd_ycc_rgb_convert_neon extbgr,  24, 2, .4h,   1, .4h,   0, .4h,   .8b
++generate_jsimd_ycc_rgb_convert_neon extrgbx, 32, 0, .4h,   1, .4h,   2, .4h,   .8b
++generate_jsimd_ycc_rgb_convert_neon extbgrx, 32, 2, .4h,   1, .4h,   0, .4h,   .8b
++generate_jsimd_ycc_rgb_convert_neon extxbgr, 32, 3, .4h,   2, .4h,   1, .4h,   .8b
++generate_jsimd_ycc_rgb_convert_neon extxrgb, 32, 1, .4h,   2, .4h,   3, .4h,   .8b
++generate_jsimd_ycc_rgb_convert_neon rgb565,  16, 0, .4h,   0, .4h,   0, .4h,   .8b
++.purgem do_load
++.purgem do_store
index c112c1e..e20b0d9 100644 (file)
         }],
         [ 'target_arch=="arm64"', {
           'sources': [
-            'jsimd_none.c',
+            'simd/jsimd_arm64.c',
+            'simd/jsimd_arm64_neon.S',
           ],
         }],
         [ 'target_arch=="mipsel"', {
             ],
           },
         }],
-        [ 'OS=="mac"', {
+        [ 'OS=="mac" or OS=="ios"', {
           'dependencies': [
             '../yasm/yasm.gyp:yasm#host',
           ],
             ],
           },
         }],
-        [ 'OS=="linux" or OS=="freebsd" or (OS=="android" and target_arch!="arm")', {
+        [ 'OS=="linux" or OS=="freebsd" or (OS=="android" and (target_arch=="ia32" or target_arch=="x64"))', {
           'conditions': [
             [ 'use_system_yasm==0', {
               'dependencies': [
           'rule_name': 'assemble',
           'extension': 'asm',
           'conditions': [
-            [ 'target_arch!="arm"', {
+            [ 'target_arch=="ia32" or target_arch=="x64"', {
               'inputs': [ '<(yasm_path)', ],
               'outputs': [
                 '<(shared_generated_dir)/<(RULE_INPUT_ROOT).<(object_suffix)',
diff --git a/src/third_party/libjpeg_turbo/simd/jsimd_arm64.c b/src/third_party/libjpeg_turbo/simd/jsimd_arm64.c
new file mode 100644 (file)
index 0000000..65724cb
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * jsimd_arm64.c
+ *
+ * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright 2009-2011, 2013-2014 D. R. Commander
+ *
+ * Based on the x86 SIMD extension for IJG JPEG library,
+ * Copyright (C) 1999-2006, MIYASAKA Masaru.
+ * For conditions of distribution and use, see copyright notice in jsimdext.inc
+ *
+ * This file contains the interface between the "normal" portions
+ * of the library and the SIMD implementations when running on a
+ * 64-bit ARM architecture.
+ */
+
+#define JPEG_INTERNALS
+#include "../jinclude.h"
+#include "../jpeglib.h"
+#include "../jsimd.h"
+#include "../jdct.h"
+#include "../jsimddct.h"
+#include "jsimd.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+static unsigned int simd_support = ~0;
+
+/*
+ * Check what SIMD accelerations are supported.
+ *
+ * FIXME: This code is racy under a multi-threaded environment.
+ */
+
+/* 
+ * ARMv8 architectures support NEON extensions by default.
+ * It is no longer optional as it was with ARMv7.
+ */ 
+
+
+LOCAL(void)
+init_simd (void)
+{
+  char *env = NULL;
+
+  if (simd_support != ~0U)
+    return;
+
+  simd_support = 0;
+
+  simd_support |= JSIMD_ARM_NEON;
+
+  /* Force different settings through environment variables */
+  env = getenv("JSIMD_FORCENEON");
+  if ((env != NULL) && (strcmp(env, "1") == 0))
+    simd_support &= JSIMD_ARM_NEON;
+  env = getenv("JSIMD_FORCENONE");
+  if ((env != NULL) && (strcmp(env, "1") == 0))
+    simd_support = 0;
+}
+
+GLOBAL(int)
+jsimd_can_rgb_ycc (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_rgb_gray (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_ycc_rgb (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+  if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4))
+    return 0;
+
+  if (simd_support & JSIMD_ARM_NEON)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_ycc_rgb565 (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+
+  if (simd_support & JSIMD_ARM_NEON)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_rgb_ycc_convert (j_compress_ptr cinfo,
+                       JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+                       JDIMENSION output_row, int num_rows)
+{
+}
+
+GLOBAL(void)
+jsimd_rgb_gray_convert (j_compress_ptr cinfo,
+                        JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+                        JDIMENSION output_row, int num_rows)
+{
+}
+
+GLOBAL(void)
+jsimd_ycc_rgb_convert (j_decompress_ptr cinfo,
+                       JSAMPIMAGE input_buf, JDIMENSION input_row,
+                       JSAMPARRAY output_buf, int num_rows)
+{
+  void (*neonfct)(JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
+
+  switch(cinfo->out_color_space) {
+    case JCS_EXT_RGB:
+      neonfct=jsimd_ycc_extrgb_convert_neon;
+      break;
+    case JCS_EXT_RGBX:
+    case JCS_EXT_RGBA:
+      neonfct=jsimd_ycc_extrgbx_convert_neon;
+      break;
+    case JCS_EXT_BGR:
+      neonfct=jsimd_ycc_extbgr_convert_neon;
+      break;
+    case JCS_EXT_BGRX:
+    case JCS_EXT_BGRA:
+      neonfct=jsimd_ycc_extbgrx_convert_neon;
+      break;
+    case JCS_EXT_XBGR:
+    case JCS_EXT_ABGR:
+      neonfct=jsimd_ycc_extxbgr_convert_neon;
+      break;
+    case JCS_EXT_XRGB:
+    case JCS_EXT_ARGB:
+      neonfct=jsimd_ycc_extxrgb_convert_neon;
+      break;
+    default:
+      neonfct=jsimd_ycc_extrgb_convert_neon;
+      break;
+  }
+
+  if (simd_support & JSIMD_ARM_NEON)
+    neonfct(cinfo->output_width, input_buf, input_row, output_buf, num_rows);
+}
+
+GLOBAL(void)
+jsimd_ycc_rgb565_convert (j_decompress_ptr cinfo,
+                          JSAMPIMAGE input_buf, JDIMENSION input_row,
+                          JSAMPARRAY output_buf, int num_rows)
+{
+  if (simd_support & JSIMD_ARM_NEON)
+    jsimd_ycc_rgb565_convert_neon(cinfo->output_width, input_buf, input_row,
+                                  output_buf, num_rows);
+}
+
+GLOBAL(int)
+jsimd_can_h2v2_downsample (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_h2v1_downsample (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+                       JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+}
+
+GLOBAL(void)
+jsimd_h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+                       JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+}
+
+GLOBAL(int)
+jsimd_can_h2v2_upsample (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_h2v1_upsample (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_h2v2_upsample (j_decompress_ptr cinfo,
+                     jpeg_component_info * compptr,
+                     JSAMPARRAY input_data,
+                     JSAMPARRAY * output_data_ptr)
+{
+}
+
+GLOBAL(void)
+jsimd_h2v1_upsample (j_decompress_ptr cinfo,
+                     jpeg_component_info * compptr,
+                     JSAMPARRAY input_data,
+                     JSAMPARRAY * output_data_ptr)
+{
+}
+
+GLOBAL(int)
+jsimd_can_h2v2_fancy_upsample (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_h2v1_fancy_upsample (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_h2v2_fancy_upsample (j_decompress_ptr cinfo,
+                           jpeg_component_info * compptr,
+                           JSAMPARRAY input_data,
+                           JSAMPARRAY * output_data_ptr)
+{
+}
+
+GLOBAL(void)
+jsimd_h2v1_fancy_upsample (j_decompress_ptr cinfo,
+                           jpeg_component_info * compptr,
+                           JSAMPARRAY input_data,
+                           JSAMPARRAY * output_data_ptr)
+{
+}
+
+GLOBAL(int)
+jsimd_can_h2v2_merged_upsample (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_h2v1_merged_upsample (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_h2v2_merged_upsample (j_decompress_ptr cinfo,
+                            JSAMPIMAGE input_buf,
+                            JDIMENSION in_row_group_ctr,
+                            JSAMPARRAY output_buf)
+{
+}
+
+GLOBAL(void)
+jsimd_h2v1_merged_upsample (j_decompress_ptr cinfo,
+                            JSAMPIMAGE input_buf,
+                            JDIMENSION in_row_group_ctr,
+                            JSAMPARRAY output_buf)
+{
+}
+
+GLOBAL(int)
+jsimd_can_convsamp (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_convsamp_float (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_convsamp (JSAMPARRAY sample_data, JDIMENSION start_col,
+                DCTELEM * workspace)
+{
+}
+
+GLOBAL(void)
+jsimd_convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col,
+                      FAST_FLOAT * workspace)
+{
+}
+
+GLOBAL(int)
+jsimd_can_fdct_islow (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_fdct_ifast (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_fdct_float (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_fdct_islow (DCTELEM * data)
+{
+}
+
+GLOBAL(void)
+jsimd_fdct_ifast (DCTELEM * data)
+{
+}
+
+GLOBAL(void)
+jsimd_fdct_float (FAST_FLOAT * data)
+{
+}
+
+GLOBAL(int)
+jsimd_can_quantize (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_quantize_float (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_quantize (JCOEFPTR coef_block, DCTELEM * divisors,
+                DCTELEM * workspace)
+{
+}
+
+GLOBAL(void)
+jsimd_quantize_float (JCOEFPTR coef_block, FAST_FLOAT * divisors,
+                      FAST_FLOAT * workspace)
+{
+}
+
+GLOBAL(int)
+jsimd_can_idct_2x2 (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (sizeof(JCOEF) != 2)
+    return 0;
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+  if (sizeof(ISLOW_MULT_TYPE) != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ARM_NEON)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_idct_4x4 (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (sizeof(JCOEF) != 2)
+    return 0;
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+  if (sizeof(ISLOW_MULT_TYPE) != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ARM_NEON)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+                JCOEFPTR coef_block, JSAMPARRAY output_buf,
+                JDIMENSION output_col)
+{
+  if (simd_support & JSIMD_ARM_NEON)
+    jsimd_idct_2x2_neon(compptr->dct_table, coef_block, output_buf,
+                        output_col);
+}
+
+GLOBAL(void)
+jsimd_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+                JCOEFPTR coef_block, JSAMPARRAY output_buf,
+                JDIMENSION output_col)
+{
+  if (simd_support & JSIMD_ARM_NEON)
+    jsimd_idct_4x4_neon(compptr->dct_table, coef_block, output_buf,
+                        output_col);
+}
+
+GLOBAL(int)
+jsimd_can_idct_islow (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (sizeof(JCOEF) != 2)
+    return 0;
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+  if (sizeof(ISLOW_MULT_TYPE) != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ARM_NEON)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_idct_ifast (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (sizeof(JCOEF) != 2)
+    return 0;
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+  if (sizeof(IFAST_MULT_TYPE) != 2)
+    return 0;
+  if (IFAST_SCALE_BITS != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ARM_NEON)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_idct_float (void)
+{
+  init_simd();
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
+                  JDIMENSION output_col)
+{
+  if (simd_support & JSIMD_ARM_NEON)
+    jsimd_idct_islow_neon(compptr->dct_table, coef_block, output_buf,
+                          output_col);
+}
+
+GLOBAL(void)
+jsimd_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
+                  JDIMENSION output_col)
+{
+  if (simd_support & JSIMD_ARM_NEON)
+    jsimd_idct_ifast_neon(compptr->dct_table, coef_block, output_buf,
+                          output_col);
+}
+
+GLOBAL(void)
+jsimd_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
+                  JDIMENSION output_col)
+{
+}
diff --git a/src/third_party/libjpeg_turbo/simd/jsimd_arm64_neon.S b/src/third_party/libjpeg_turbo/simd/jsimd_arm64_neon.S
new file mode 100644 (file)
index 0000000..f488b0f
--- /dev/null
@@ -0,0 +1,1861 @@
+/*
+ * ARMv8 NEON optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Author: Siarhei Siamashka <siarhei.siamashka@nokia.com>
+ * Copyright (C) 2013-2014, Linaro Limited
+ * Author: Ragesh Radhakrishnan <ragesh.r@linaro.org>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
+#endif
+
+.text
+.arch armv8-a+fp+simd
+
+
+#define RESPECT_STRICT_ALIGNMENT 1
+
+
+/*****************************************************************************/
+
+/* Supplementary macro for setting function attributes */
+.macro asm_function fname
+#ifdef __APPLE__
+    .globl _\fname
+_\fname:
+#else
+    .global \fname
+#ifdef __ELF__
+    .hidden \fname
+    .type \fname, %function
+#endif
+\fname:
+#endif
+.endm
+
+/* Transpose elements of single 128 bit registers */
+.macro transpose_single x0,x1,xi,xilen,literal
+    ins  \xi\xilen[0],  \x0\xilen[0]
+    ins  \x1\xilen[0],  \x0\xilen[1]
+    trn1 \x0\literal,   \x0\literal, \x1\literal
+    trn2 \x1\literal,   \xi\literal, \x1\literal
+.endm
+
+/* Transpose elements of 2 differnet registers */
+.macro transpose x0,x1,xi,xilen,literal
+    mov  \xi\xilen,     \x0\xilen
+    trn1 \x0\literal,   \x0\literal, \x1\literal
+    trn2 \x1\literal,   \xi\literal, \x1\literal
+.endm
+
+/* Transpose a block of 4x4 coefficients in four 64-bit registers */
+.macro transpose_4x4_32 x0,x0len x1,x1len x2,x2len x3,x3len,xi,xilen
+    mov  \xi\xilen, \x0\xilen
+    trn1 \x0\x0len, \x0\x0len, \x2\x2len
+    trn2 \x2\x2len, \xi\x0len, \x2\x2len
+    mov  \xi\xilen, \x1\xilen
+    trn1 \x1\x1len, \x1\x1len, \x3\x3len
+    trn2 \x3\x3len, \xi\x1len, \x3\x3len
+.endm
+
+.macro transpose_4x4_16 x0,x0len x1,x1len, x2,x2len, x3,x3len,xi,xilen
+    mov  \xi\xilen, \x0\xilen
+    trn1 \x0\x0len, \x0\x0len, \x1\x1len
+    trn2 \x1\x2len, \xi\x0len, \x1\x2len
+    mov  \xi\xilen, \x2\xilen
+    trn1 \x2\x2len, \x2\x2len, \x3\x3len
+    trn2 \x3\x2len, \xi\x1len, \x3\x3len
+.endm
+
+.macro transpose_4x4 x0, x1, x2, x3,x5
+    transpose_4x4_16 \x0,.4h, \x1,.4h, \x2,.4h,\x3,.4h,\x5,.16b
+    transpose_4x4_32 \x0,.2s, \x1,.2s, \x2,.2s,\x3,.2s,\x5,.16b
+.endm
+
+
+#define CENTERJSAMPLE 128
+
+/*****************************************************************************/
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ *
+ * GLOBAL(void)
+ * jsimd_idct_islow_neon (void * dct_table, JCOEFPTR coef_block,
+ *                        JSAMPARRAY output_buf, JDIMENSION output_col)
+ */
+
+#define FIX_0_298631336  (2446)
+#define FIX_0_390180644  (3196)
+#define FIX_0_541196100  (4433)
+#define FIX_0_765366865  (6270)
+#define FIX_0_899976223  (7373)
+#define FIX_1_175875602  (9633)
+#define FIX_1_501321110  (12299)
+#define FIX_1_847759065  (15137)
+#define FIX_1_961570560  (16069)
+#define FIX_2_053119869  (16819)
+#define FIX_2_562915447  (20995)
+#define FIX_3_072711026  (25172)
+
+#define FIX_1_175875602_MINUS_1_961570560 (FIX_1_175875602 - FIX_1_961570560)
+#define FIX_1_175875602_MINUS_0_390180644 (FIX_1_175875602 - FIX_0_390180644)
+#define FIX_0_541196100_MINUS_1_847759065 (FIX_0_541196100 - FIX_1_847759065)
+#define FIX_3_072711026_MINUS_2_562915447 (FIX_3_072711026 - FIX_2_562915447)
+#define FIX_0_298631336_MINUS_0_899976223 (FIX_0_298631336 - FIX_0_899976223)
+#define FIX_1_501321110_MINUS_0_899976223 (FIX_1_501321110 - FIX_0_899976223)
+#define FIX_2_053119869_MINUS_2_562915447 (FIX_2_053119869 - FIX_2_562915447)
+#define FIX_0_541196100_PLUS_0_765366865  (FIX_0_541196100 + FIX_0_765366865)
+
+/*
+ * Reference SIMD-friendly 1-D ISLOW iDCT C implementation.
+ * Uses some ideas from the comments in 'simd/jiss2int-64.asm'
+ */
+#define REF_1D_IDCT(xrow0, xrow1, xrow2, xrow3, xrow4, xrow5, xrow6, xrow7)   \
+{                                                                             \
+    DCTELEM row0, row1, row2, row3, row4, row5, row6, row7;                   \
+    INT32   q1, q2, q3, q4, q5, q6, q7;                                       \
+    INT32   tmp11_plus_tmp2, tmp11_minus_tmp2;                                \
+                                                                              \
+    /* 1-D iDCT input data */                                                 \
+    row0 = xrow0;                                                             \
+    row1 = xrow1;                                                             \
+    row2 = xrow2;                                                             \
+    row3 = xrow3;                                                             \
+    row4 = xrow4;                                                             \
+    row5 = xrow5;                                                             \
+    row6 = xrow6;                                                             \
+    row7 = xrow7;                                                             \
+                                                                              \
+    q5 = row7 + row3;                                                         \
+    q4 = row5 + row1;                                                         \
+    q6 = MULTIPLY(q5, FIX_1_175875602_MINUS_1_961570560) +                    \
+         MULTIPLY(q4, FIX_1_175875602);                                       \
+    q7 = MULTIPLY(q5, FIX_1_175875602) +                                      \
+         MULTIPLY(q4, FIX_1_175875602_MINUS_0_390180644);                     \
+    q2 = MULTIPLY(row2, FIX_0_541196100) +                                    \
+         MULTIPLY(row6, FIX_0_541196100_MINUS_1_847759065);                   \
+    q4 = q6;                                                                  \
+    q3 = ((INT32) row0 - (INT32) row4) << 13;                                 \
+    q6 += MULTIPLY(row5, -FIX_2_562915447) +                                  \
+          MULTIPLY(row3, FIX_3_072711026_MINUS_2_562915447);                  \
+    /* now we can use q1 (reloadable constants have been used up) */          \
+    q1 = q3 + q2;                                                             \
+    q4 += MULTIPLY(row7, FIX_0_298631336_MINUS_0_899976223) +                 \
+          MULTIPLY(row1, -FIX_0_899976223);                                   \
+    q5 = q7;                                                                  \
+    q1 = q1 + q6;                                                             \
+    q7 += MULTIPLY(row7, -FIX_0_899976223) +                                  \
+          MULTIPLY(row1, FIX_1_501321110_MINUS_0_899976223);                  \
+                                                                              \
+    /* (tmp11 + tmp2) has been calculated (out_row1 before descale) */        \
+    tmp11_plus_tmp2 = q1;                                                     \
+    row1 = 0;                                                                 \
+                                                                              \
+    q1 = q1 - q6;                                                             \
+    q5 += MULTIPLY(row5, FIX_2_053119869_MINUS_2_562915447) +                 \
+          MULTIPLY(row3, -FIX_2_562915447);                                   \
+    q1 = q1 - q6;                                                             \
+    q6 = MULTIPLY(row2, FIX_0_541196100_PLUS_0_765366865) +                   \
+         MULTIPLY(row6, FIX_0_541196100);                                     \
+    q3 = q3 - q2;                                                             \
+                                                                              \
+    /* (tmp11 - tmp2) has been calculated (out_row6 before descale) */        \
+    tmp11_minus_tmp2 = q1;                                                    \
+                                                                              \
+    q1 = ((INT32) row0 + (INT32) row4) << 13;                                 \
+    q2 = q1 + q6;                                                             \
+    q1 = q1 - q6;                                                             \
+                                                                              \
+    /* pick up the results */                                                 \
+    tmp0  = q4;                                                               \
+    tmp1  = q5;                                                               \
+    tmp2  = (tmp11_plus_tmp2 - tmp11_minus_tmp2) / 2;                         \
+    tmp3  = q7;                                                               \
+    tmp10 = q2;                                                               \
+    tmp11 = (tmp11_plus_tmp2 + tmp11_minus_tmp2) / 2;                         \
+    tmp12 = q3;                                                               \
+    tmp13 = q1;                                                               \
+}
+
+#define XFIX_0_899976223                    v0.4h[0]
+#define XFIX_0_541196100                    v0.4h[1]
+#define XFIX_2_562915447                    v0.4h[2]
+#define XFIX_0_298631336_MINUS_0_899976223  v0.4h[3]
+#define XFIX_1_501321110_MINUS_0_899976223  v1.4h[0]
+#define XFIX_2_053119869_MINUS_2_562915447  v1.4h[1]
+#define XFIX_0_541196100_PLUS_0_765366865   v1.4h[2]
+#define XFIX_1_175875602                    v1.4h[3]
+#define XFIX_1_175875602_MINUS_0_390180644  v2.4h[0]
+#define XFIX_0_541196100_MINUS_1_847759065  v2.4h[1]
+#define XFIX_3_072711026_MINUS_2_562915447  v2.4h[2]
+#define XFIX_1_175875602_MINUS_1_961570560  v2.4h[3]
+
+.balign 16
+jsimd_idct_islow_neon_consts:
+    .short FIX_0_899976223                    /* d0[0] */
+    .short FIX_0_541196100                    /* d0[1] */
+    .short FIX_2_562915447                    /* d0[2] */
+    .short FIX_0_298631336_MINUS_0_899976223  /* d0[3] */
+    .short FIX_1_501321110_MINUS_0_899976223  /* d1[0] */
+    .short FIX_2_053119869_MINUS_2_562915447  /* d1[1] */
+    .short FIX_0_541196100_PLUS_0_765366865   /* d1[2] */
+    .short FIX_1_175875602                    /* d1[3] */
+    /* reloadable constants */
+    .short FIX_1_175875602_MINUS_0_390180644  /* d2[0] */
+    .short FIX_0_541196100_MINUS_1_847759065  /* d2[1] */
+    .short FIX_3_072711026_MINUS_2_562915447  /* d2[2] */
+    .short FIX_1_175875602_MINUS_1_961570560  /* d2[3] */
+
+asm_function jsimd_idct_islow_neon
+
+    DCT_TABLE       .req x0
+    COEF_BLOCK      .req x1
+    OUTPUT_BUF      .req x2
+    OUTPUT_COL      .req x3
+    TMP1            .req x0
+    TMP2            .req x1
+    TMP3            .req x2
+    TMP4            .req x15
+
+    ROW0L           .req v16
+    ROW0R           .req v17
+    ROW1L           .req v18
+    ROW1R           .req v19
+    ROW2L           .req v20
+    ROW2R           .req v21
+    ROW3L           .req v22
+    ROW3R           .req v23
+    ROW4L           .req v24
+    ROW4R           .req v25
+    ROW5L           .req v26
+    ROW5R           .req v27
+    ROW6L           .req v28
+    ROW6R           .req v29
+    ROW7L           .req v30
+    ROW7R           .req v31
+    /* Save all NEON registers and x15 (32 NEON registers * 8 bytes + 16) */
+    sub             sp, sp, 272
+    str             x15, [sp], 16
+    adr             x15, jsimd_idct_islow_neon_consts
+    st1             {v0.8b - v3.8b}, [sp], 32
+    st1             {v4.8b - v7.8b}, [sp], 32
+    st1             {v8.8b - v11.8b}, [sp], 32
+    st1             {v12.8b - v15.8b}, [sp], 32
+    st1             {v16.8b - v19.8b}, [sp], 32
+    st1             {v20.8b - v23.8b}, [sp], 32
+    st1             {v24.8b - v27.8b}, [sp], 32
+    st1             {v28.8b - v31.8b}, [sp], 32
+    ld1             {v16.4h, v17.4h, v18.4h, v19.4h}, [COEF_BLOCK], 32
+    ld1             {v0.4h, v1.4h, v2.4h, v3.4h}, [DCT_TABLE], 32
+    ld1             {v20.4h, v21.4h, v22.4h, v23.4h}, [COEF_BLOCK], 32
+    mul             v16.4h, v16.4h, v0.4h
+    mul             v17.4h, v17.4h, v1.4h
+    ins             v16.2d[1], v17.2d[0]  /* 128 bit q8 */
+    ld1             {v4.4h, v5.4h, v6.4h, v7.4h}, [DCT_TABLE], 32
+    mul             v18.4h, v18.4h, v2.4h
+    mul             v19.4h, v19.4h, v3.4h
+    ins             v18.2d[1], v19.2d[0]  /* 128 bit q9 */
+    ld1             {v24.4h, v25.4h, v26.4h, v27.4h}, [COEF_BLOCK], 32
+    mul             v20.4h, v20.4h, v4.4h
+    mul             v21.4h, v21.4h, v5.4h
+    ins             v20.2d[1], v21.2d[0]  /* 128 bit q10 */
+    ld1             {v0.4h, v1.4h, v2.4h, v3.4h}, [DCT_TABLE], 32
+    mul             v22.4h, v22.4h, v6.4h
+    mul             v23.4h, v23.4h, v7.4h
+    ins             v22.2d[1], v23.2d[0]  /* 128 bit q11 */
+    ld1             {v28.4h, v29.4h, v30.4h, v31.4h}, [COEF_BLOCK]
+    mul             v24.4h, v24.4h, v0.4h
+    mul             v25.4h, v25.4h, v1.4h
+    ins             v24.2d[1], v25.2d[0]  /* 128 bit q12 */
+    ld1             {v4.4h, v5.4h, v6.4h, v7.4h}, [DCT_TABLE], 32
+    mul             v28.4h, v28.4h, v4.4h
+    mul             v29.4h, v29.4h, v5.4h
+    ins             v28.2d[1], v29.2d[0]  /* 128 bit q14 */
+    mul             v26.4h, v26.4h, v2.4h
+    mul             v27.4h, v27.4h, v3.4h
+    ins             v26.2d[1], v27.2d[0]  /* 128 bit q13 */
+    ld1             {v0.4h, v1.4h, v2.4h, v3.4h}, [x15]  /* load constants */
+    add             x15, x15, #16
+    mul             v30.4h, v30.4h, v6.4h
+    mul             v31.4h, v31.4h, v7.4h
+    ins             v30.2d[1], v31.2d[0]  /* 128 bit q15 */
+    /* Go to the bottom of the stack */
+    sub             sp, sp, 352
+    stp             x4, x5, [sp], 16
+    st1             {v8.4h - v11.4h}, [sp], 32  /* save NEON registers */
+    st1             {v12.4h - v15.4h}, [sp], 32
+    /* 1-D IDCT, pass 1, left 4x8 half */
+    add             v4.4h,    ROW7L.4h, ROW3L.4h
+    add             v5.4h,    ROW5L.4h, ROW1L.4h
+    smull           v12.4s,   v4.4h,    XFIX_1_175875602_MINUS_1_961570560
+    smlal           v12.4s,   v5.4h,    XFIX_1_175875602
+    smull           v14.4s,   v4.4h,    XFIX_1_175875602
+    /* Check for the zero coefficients in the right 4x8 half */
+    smlal           v14.4s,   v5.4h,    XFIX_1_175875602_MINUS_0_390180644
+    ssubl           v6.4s,    ROW0L.4h, ROW4L.4h
+      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 1 * 8))]
+    smull           v4.4s,    ROW2L.4h, XFIX_0_541196100
+    smlal           v4.4s,    ROW6L.4h, XFIX_0_541196100_MINUS_1_847759065
+      orr           x0,       x4,       x5
+    mov             v8.16b,   v12.16b
+    smlsl           v12.4s,   ROW5L.4h, XFIX_2_562915447
+      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 2 * 8))]
+    smlal           v12.4s,   ROW3L.4h, XFIX_3_072711026_MINUS_2_562915447
+    shl             v6.4s,    v6.4s,    #13
+      orr           x0,       x0,       x4
+    smlsl           v8.4s,    ROW1L.4h, XFIX_0_899976223
+      orr           x0,       x0 ,      x5
+    add             v2.4s,    v6.4s,    v4.4s
+      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 3 * 8))]
+    mov             v10.16b,  v14.16b
+    add             v2.4s,    v2.4s,    v12.4s
+      orr           x0,       x0,       x4
+    smlsl           v14.4s,   ROW7L.4h, XFIX_0_899976223
+      orr           x0,       x0,       x5
+    smlal           v14.4s,   ROW1L.4h, XFIX_1_501321110_MINUS_0_899976223
+    rshrn           ROW1L.4h, v2.4s,    #11
+      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 4 * 8))]
+    sub             v2.4s,    v2.4s,    v12.4s
+    smlal           v10.4s,   ROW5L.4h, XFIX_2_053119869_MINUS_2_562915447
+      orr           x0,       x0,       x4
+    smlsl           v10.4s,   ROW3L.4h, XFIX_2_562915447
+      orr           x0,       x0,       x5
+    sub             v2.4s,    v2.4s,    v12.4s
+    smull           v12.4s,   ROW2L.4h, XFIX_0_541196100_PLUS_0_765366865
+      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 5 * 8))]
+    smlal           v12.4s,   ROW6L.4h, XFIX_0_541196100
+    sub             v6.4s,    v6.4s,    v4.4s
+      orr           x0,       x0,       x4
+    rshrn           ROW6L.4h, v2.4s,    #11
+      orr           x0,       x0,       x5
+    add             v2.4s,    v6.4s,    v10.4s
+      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 6 * 8))]
+    sub             v6.4s,    v6.4s,    v10.4s
+    saddl           v10.4s,   ROW0L.4h, ROW4L.4h
+      orr           x0,       x0,       x4
+    rshrn           ROW2L.4h, v2.4s,    #11
+      orr           x0,       x0,       x5
+    rshrn           ROW5L.4h, v6.4s,    #11
+      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 7 * 8))]
+    shl             v10.4s,   v10.4s,   #13
+    smlal           v8.4s,    ROW7L.4h, XFIX_0_298631336_MINUS_0_899976223
+      orr           x0,       x0,       x4
+    add             v4.4s,    v10.4s,   v12.4s
+      orr           x0,       x0,       x5
+    cmp             x0, #0 /* orrs instruction removed */
+    sub             v2.4s,    v10.4s,   v12.4s
+    add             v12.4s,   v4.4s,    v14.4s
+      ldp           w4,       w5,       [COEF_BLOCK, #(-96 + 2 * (4 + 0 * 8))]
+    sub             v4.4s,    v4.4s,    v14.4s
+    add             v10.4s,   v2.4s,    v8.4s
+      orr           x0,       x4,       x5
+    sub             v6.4s,    v2.4s,    v8.4s
+      /* pop             {x4, x5} */
+      sub           sp, sp, 80
+      ldp           x4, x5, [sp], 16
+    rshrn           ROW7L.4h, v4.4s,    #11
+    rshrn           ROW3L.4h, v10.4s,   #11
+    rshrn           ROW0L.4h, v12.4s,   #11
+    rshrn           ROW4L.4h, v6.4s,    #11
+
+      beq             3f /* Go to do some special handling for the sparse right 4x8 half */
+
+    /* 1-D IDCT, pass 1, right 4x8 half */
+    ld1             {v2.4h},  [x15]    /* reload constants */
+    add             v10.4h,   ROW7R.4h, ROW3R.4h
+    add             v8.4h,    ROW5R.4h, ROW1R.4h
+    /* Transpose ROW6L <-> ROW7L   (v3 available free register) */
+    transpose       ROW6L, ROW7L, v3, .16b, .4h
+    smull           v12.4s,   v10.4h,   XFIX_1_175875602_MINUS_1_961570560
+    smlal           v12.4s,   v8.4h,    XFIX_1_175875602
+    /* Transpose ROW2L <-> ROW3L   (v3 available free register) */
+    transpose       ROW2L, ROW3L, v3, .16b, .4h
+    smull           v14.4s,   v10.4h,   XFIX_1_175875602
+    smlal           v14.4s,   v8.4h,    XFIX_1_175875602_MINUS_0_390180644
+    /* Transpose ROW0L <-> ROW1L   (v3 available free register) */
+    transpose       ROW0L, ROW1L, v3, .16b, .4h
+    ssubl           v6.4s,    ROW0R.4h, ROW4R.4h
+    smull           v4.4s,    ROW2R.4h, XFIX_0_541196100
+    smlal           v4.4s,    ROW6R.4h, XFIX_0_541196100_MINUS_1_847759065
+    /* Transpose ROW4L <-> ROW5L   (v3 available free register) */
+    transpose       ROW4L, ROW5L, v3, .16b, .4h
+    mov             v8.16b,   v12.16b
+    smlsl           v12.4s,   ROW5R.4h, XFIX_2_562915447
+    smlal           v12.4s,   ROW3R.4h, XFIX_3_072711026_MINUS_2_562915447
+    /* Transpose ROW1L <-> ROW3L   (v3 available free register) */
+    transpose       ROW1L, ROW3L, v3, .16b, .2s
+    shl             v6.4s,    v6.4s,    #13
+    smlsl           v8.4s,    ROW1R.4h, XFIX_0_899976223
+    /* Transpose ROW4L <-> ROW6L   (v3 available free register) */
+    transpose       ROW4L, ROW6L, v3, .16b, .2s
+    add             v2.4s,    v6.4s,    v4.4s
+    mov             v10.16b,  v14.16b
+    add             v2.4s,    v2.4s,    v12.4s
+    /* Transpose ROW0L <-> ROW2L   (v3 available free register) */
+    transpose       ROW0L, ROW2L, v3, .16b, .2s
+    smlsl           v14.4s,   ROW7R.4h, XFIX_0_899976223
+    smlal           v14.4s,   ROW1R.4h, XFIX_1_501321110_MINUS_0_899976223
+    rshrn           ROW1R.4h, v2.4s,    #11
+    /* Transpose ROW5L <-> ROW7L   (v3 available free register) */
+    transpose       ROW5L, ROW7L, v3, .16b, .2s
+    sub             v2.4s,    v2.4s,    v12.4s
+    smlal           v10.4s,   ROW5R.4h, XFIX_2_053119869_MINUS_2_562915447
+    smlsl           v10.4s,   ROW3R.4h, XFIX_2_562915447
+    sub             v2.4s,    v2.4s,    v12.4s
+    smull           v12.4s,   ROW2R.4h, XFIX_0_541196100_PLUS_0_765366865
+    smlal           v12.4s,   ROW6R.4h, XFIX_0_541196100
+    sub             v6.4s,    v6.4s,    v4.4s
+    rshrn           ROW6R.4h, v2.4s,    #11
+    add             v2.4s,    v6.4s,    v10.4s
+    sub             v6.4s,    v6.4s,    v10.4s
+    saddl           v10.4s,   ROW0R.4h, ROW4R.4h
+    rshrn           ROW2R.4h, v2.4s,    #11
+    rshrn           ROW5R.4h, v6.4s,    #11
+    shl             v10.4s,   v10.4s,   #13
+    smlal           v8.4s,    ROW7R.4h, XFIX_0_298631336_MINUS_0_899976223
+    add             v4.4s,    v10.4s,   v12.4s
+    sub             v2.4s,    v10.4s,   v12.4s
+    add             v12.4s,   v4.4s,    v14.4s
+    sub             v4.4s,    v4.4s,    v14.4s
+    add             v10.4s,   v2.4s,    v8.4s
+    sub             v6.4s,    v2.4s,    v8.4s
+    rshrn           ROW7R.4h, v4.4s,    #11
+    rshrn           ROW3R.4h, v10.4s,   #11
+    rshrn           ROW0R.4h, v12.4s,   #11
+    rshrn           ROW4R.4h, v6.4s,    #11
+    /* Transpose right 4x8 half */
+    transpose       ROW6R, ROW7R, v3, .16b, .4h
+    transpose       ROW2R, ROW3R, v3, .16b, .4h
+    transpose       ROW0R, ROW1R, v3, .16b, .4h
+    transpose       ROW4R, ROW5R, v3, .16b, .4h
+    transpose       ROW1R, ROW3R, v3, .16b, .2s
+    transpose       ROW4R, ROW6R, v3, .16b, .2s
+    transpose       ROW0R, ROW2R, v3, .16b, .2s
+    transpose       ROW5R, ROW7R, v3, .16b, .2s
+
+1:  /* 1-D IDCT, pass 2 (normal variant), left 4x8 half */
+    ld1             {v2.4h},  [x15]    /* reload constants */
+    smull           v12.4S,   ROW1R.4h, XFIX_1_175875602 /* ROW5L.4h <-> ROW1R.4h */
+    smlal           v12.4s,   ROW1L.4h, XFIX_1_175875602
+    smlal           v12.4s,   ROW3R.4h, XFIX_1_175875602_MINUS_1_961570560 /* ROW7L.4h <-> ROW3R.4h */
+    smlal           v12.4s,   ROW3L.4h, XFIX_1_175875602_MINUS_1_961570560
+    smull           v14.4s,   ROW3R.4h, XFIX_1_175875602 /* ROW7L.4h <-> ROW3R.4h */
+    smlal           v14.4s,   ROW3L.4h, XFIX_1_175875602
+    smlal           v14.4s,   ROW1R.4h, XFIX_1_175875602_MINUS_0_390180644 /* ROW5L.4h <-> ROW1R.4h */
+    smlal           v14.4s,   ROW1L.4h, XFIX_1_175875602_MINUS_0_390180644
+    ssubl           v6.4s,    ROW0L.4h, ROW0R.4h /* ROW4L.4h <-> ROW0R.4h */
+    smull           v4.4s,    ROW2L.4h, XFIX_0_541196100
+    smlal           v4.4s,    ROW2R.4h, XFIX_0_541196100_MINUS_1_847759065 /* ROW6L.4h <-> ROW2R.4h */
+    mov             v8.16b,   v12.16b
+    smlsl           v12.4s,   ROW1R.4h, XFIX_2_562915447 /* ROW5L.4h <-> ROW1R.4h */
+    smlal           v12.4s,   ROW3L.4h, XFIX_3_072711026_MINUS_2_562915447
+    shl             v6.4s,    v6.4s,    #13
+    smlsl           v8.4s,    ROW1L.4h, XFIX_0_899976223
+    add             v2.4s,    v6.4s,    v4.4s
+    mov             v10.16b,  v14.16b
+    add             v2.4s,    v2.4s,    v12.4s
+    smlsl           v14.4s,   ROW3R.4h, XFIX_0_899976223 /* ROW7L.4h <-> ROW3R.4h */
+    smlal           v14.4s,   ROW1L.4h, XFIX_1_501321110_MINUS_0_899976223
+    shrn            ROW1L.4h, v2.4s,    #16
+    sub             v2.4s,    v2.4s,    v12.4s
+    smlal           v10.4s,   ROW1R.4h, XFIX_2_053119869_MINUS_2_562915447 /* ROW5L.4h <-> ROW1R.4h */
+    smlsl           v10.4s,   ROW3L.4h, XFIX_2_562915447
+    sub             v2.4s,    v2.4s,    v12.4s
+    smull           v12.4s,   ROW2L.4h, XFIX_0_541196100_PLUS_0_765366865
+    smlal           v12.4s,   ROW2R.4h, XFIX_0_541196100 /* ROW6L.4h <-> ROW2R.4h */
+    sub             v6.4s,    v6.4s,    v4.4s
+    shrn            ROW2R.4h, v2.4s,    #16 /* ROW6L.4h <-> ROW2R.4h */
+    add             v2.4s,    v6.4s,    v10.4s
+    sub             v6.4s,    v6.4s,    v10.4s
+    saddl           v10.4s,   ROW0L.4h, ROW0R.4h /* ROW4L.4h <-> ROW0R.4h */
+    shrn            ROW2L.4h, v2.4s,    #16
+    shrn            ROW1R.4h, v6.4s,    #16 /* ROW5L.4h <-> ROW1R.4h */
+    shl             v10.4s,   v10.4s,   #13
+    smlal           v8.4s,    ROW3R.4h, XFIX_0_298631336_MINUS_0_899976223 /* ROW7L.4h <-> ROW3R.4h */
+    add             v4.4s,    v10.4s,   v12.4s
+    sub             v2.4s,    v10.4s,   v12.4s
+    add             v12.4s,   v4.4s,    v14.4s
+    sub             v4.4s,    v4.4s,    v14.4s
+    add             v10.4s,   v2.4s,    v8.4s
+    sub             v6.4s,    v2.4s,    v8.4s
+    shrn            ROW3R.4h, v4.4s,    #16 /* ROW7L.4h <-> ROW3R.4h */
+    shrn            ROW3L.4h, v10.4s,   #16
+    shrn            ROW0L.4h, v12.4s,   #16
+    shrn            ROW0R.4h, v6.4s,    #16 /* ROW4L.4h <-> ROW0R.4h */
+    /* 1-D IDCT, pass 2, right 4x8 half */
+    ld1             {v2.4h},  [x15]    /* reload constants */
+    smull           v12.4s,   ROW5R.4h, XFIX_1_175875602
+    smlal           v12.4s,   ROW5L.4h, XFIX_1_175875602 /* ROW5L.4h <-> ROW1R.4h */
+    smlal           v12.4s,   ROW7R.4h, XFIX_1_175875602_MINUS_1_961570560
+    smlal           v12.4s,   ROW7L.4h, XFIX_1_175875602_MINUS_1_961570560 /* ROW7L.4h <-> ROW3R.4h */
+    smull           v14.4s,   ROW7R.4h, XFIX_1_175875602
+    smlal           v14.4s,   ROW7L.4h, XFIX_1_175875602 /* ROW7L.4h <-> ROW3R.4h */
+    smlal           v14.4s,   ROW5R.4h, XFIX_1_175875602_MINUS_0_390180644
+    smlal           v14.4s,   ROW5L.4h, XFIX_1_175875602_MINUS_0_390180644 /* ROW5L.4h <-> ROW1R.4h */
+    ssubl           v6.4s,    ROW4L.4h, ROW4R.4h /* ROW4L.4h <-> ROW0R.4h */
+    smull           v4.4s,    ROW6L.4h, XFIX_0_541196100 /* ROW6L.4h <-> ROW2R.4h */
+    smlal           v4.4s,    ROW6R.4h, XFIX_0_541196100_MINUS_1_847759065
+    mov             v8.16b,   v12.16b
+    smlsl           v12.4s,   ROW5R.4h, XFIX_2_562915447
+    smlal           v12.4s,   ROW7L.4h, XFIX_3_072711026_MINUS_2_562915447 /* ROW7L.4h <-> ROW3R.4h */
+    shl             v6.4s,    v6.4s,    #13
+    smlsl           v8.4s,    ROW5L.4h, XFIX_0_899976223 /* ROW5L.4h <-> ROW1R.4h */
+    add             v2.4s,    v6.4s,    v4.4s
+    mov             v10.16b,  v14.16b
+    add             v2.4s,    v2.4s,    v12.4s
+    smlsl           v14.4s,   ROW7R.4h, XFIX_0_899976223
+    smlal           v14.4s,   ROW5L.4h, XFIX_1_501321110_MINUS_0_899976223 /* ROW5L.4h <-> ROW1R.4h */
+    shrn            ROW5L.4h, v2.4s,    #16 /* ROW5L.4h <-> ROW1R.4h */
+    sub             v2.4s,    v2.4s,    v12.4s
+    smlal           v10.4s,   ROW5R.4h, XFIX_2_053119869_MINUS_2_562915447
+    smlsl           v10.4s,   ROW7L.4h, XFIX_2_562915447 /* ROW7L.4h <-> ROW3R.4h */
+    sub             v2.4s,    v2.4s,    v12.4s
+    smull           v12.4s,   ROW6L.4h, XFIX_0_541196100_PLUS_0_765366865 /* ROW6L.4h <-> ROW2R.4h */
+    smlal           v12.4s,   ROW6R.4h, XFIX_0_541196100
+    sub             v6.4s,    v6.4s,    v4.4s
+    shrn            ROW6R.4h, v2.4s,    #16
+    add             v2.4s,    v6.4s,    v10.4s
+    sub             v6.4s,    v6.4s,    v10.4s
+    saddl           v10.4s,   ROW4L.4h, ROW4R.4h /* ROW4L.4h <-> ROW0R.4h */
+    shrn            ROW6L.4h, v2.4s,    #16 /* ROW6L.4h <-> ROW2R.4h */
+    shrn            ROW5R.4h, v6.4s,    #16
+    shl             v10.4s,   v10.4s,   #13
+    smlal           v8.4s,    ROW7R.4h, XFIX_0_298631336_MINUS_0_899976223
+    add             v4.4s,    v10.4s,   v12.4s
+    sub             v2.4s,    v10.4s,   v12.4s
+    add             v12.4s,   v4.4s,    v14.4s
+    sub             v4.4s,    v4.4s,    v14.4s
+    add             v10.4s,   v2.4s,    v8.4s
+    sub             v6.4s,    v2.4s,    v8.4s
+    shrn            ROW7R.4h, v4.4s,    #16
+    shrn            ROW7L.4h, v10.4s,   #16 /* ROW7L.4h <-> ROW3R.4h */
+    shrn            ROW4L.4h, v12.4s,   #16 /* ROW4L.4h <-> ROW0R.4h */
+    shrn            ROW4R.4h, v6.4s,    #16
+
+2:  /* Descale to 8-bit and range limit */
+    ins             v16.2d[1], v17.2d[0]
+    ins             v18.2d[1], v19.2d[0]
+    ins             v20.2d[1], v21.2d[0]
+    ins             v22.2d[1], v23.2d[0]
+    sqrshrn         v16.8b,   v16.8h,   #2
+    sqrshrn2        v16.16b,  v18.8h,   #2
+    sqrshrn         v18.8b,   v20.8h,   #2
+    sqrshrn2        v18.16b,  v22.8h,   #2
+
+    /* vpop            {v8.4h - d15.4h} */ /* restore NEON registers */
+    ld1             {v8.4h - v11.4h}, [sp], 32
+    ld1             {v12.4h - v15.4h}, [sp], 32
+    ins             v24.2d[1], v25.2d[0]
+
+    sqrshrn         v20.8b,   v24.8h,   #2
+      /* Transpose the final 8-bit samples and do signed->unsigned conversion */
+    /* trn1            v16.8h,    v16.8h,  v18.8h */
+    transpose       v16, v18, v3, .16b, .8h
+    ins             v26.2d[1], v27.2d[0]
+    ins             v28.2d[1], v29.2d[0]
+    ins             v30.2d[1], v31.2d[0]
+    sqrshrn2        v20.16b,  v26.8h,   #2
+    sqrshrn         v22.8b,   v28.8h,   #2
+    movi            v0.16b,   #(CENTERJSAMPLE)
+    sqrshrn2        v22.16b,  v30.8h,   #2
+    transpose_single v16, v17, v3, .2d, .8b
+    transpose_single v18, v19, v3, .2d, .8b
+    add             v16.8b,   v16.8b,   v0.8b
+    add             v17.8b,   v17.8b,   v0.8b
+    add             v18.8b,   v18.8b,   v0.8b
+    add             v19.8b,   v19.8b,   v0.8b
+    transpose       v20, v22, v3, .16b, .8h
+    /* Store results to the output buffer */
+    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
+    add             TMP1,     TMP1,     OUTPUT_COL
+    add             TMP2,     TMP2,     OUTPUT_COL
+    st1             {v16.8b}, [TMP1]
+    transpose_single v20, v21, v3, .2d, .8b
+    st1             {v17.8b}, [TMP2]
+    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
+    add             TMP1,     TMP1,     OUTPUT_COL
+    add             TMP2,     TMP2,     OUTPUT_COL
+    st1             {v18.8b}, [TMP1]
+    add             v20.8b,   v20.8b,   v0.8b
+    add             v21.8b,   v21.8b,   v0.8b
+    st1             {v19.8b}, [TMP2]
+    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
+    ldp             TMP3,     TMP4,     [OUTPUT_BUF]
+    add             TMP1,     TMP1,     OUTPUT_COL
+    add             TMP2,     TMP2,     OUTPUT_COL
+    add             TMP3,     TMP3,     OUTPUT_COL
+    add             TMP4,     TMP4,     OUTPUT_COL
+    transpose_single v22, v23, v3, .2d, .8b
+    st1             {v20.8b}, [TMP1]
+    add             v22.8b,   v22.8b,   v0.8b
+    add             v23.8b,   v23.8b,   v0.8b
+    st1             {v21.8b}, [TMP2]
+    st1             {v22.8b}, [TMP3]
+    st1             {v23.8b}, [TMP4]
+    ldr             x15, [sp], 16
+    ld1             {v0.8b - v3.8b}, [sp], 32
+    ld1             {v4.8b - v7.8b}, [sp], 32
+    ld1             {v8.8b - v11.8b}, [sp], 32
+    ld1             {v12.8b - v15.8b}, [sp], 32
+    ld1             {v16.8b - v19.8b}, [sp], 32
+    ld1             {v20.8b - v23.8b}, [sp], 32
+    ld1             {v24.8b - v27.8b}, [sp], 32
+    ld1             {v28.8b - v31.8b}, [sp], 32
+    blr             x30
+
+3:  /* Left 4x8 half is done, right 4x8 half contains mostly zeros */
+
+    /* Transpose left 4x8 half */
+    transpose       ROW6L, ROW7L, v3, .16b, .4h
+    transpose       ROW2L, ROW3L, v3, .16b, .4h
+    transpose       ROW0L, ROW1L, v3, .16b, .4h
+    transpose       ROW4L, ROW5L, v3, .16b, .4h
+    shl             ROW0R.4h, ROW0R.4h, #2 /* PASS1_BITS */
+    transpose       ROW1L, ROW3L, v3, .16b, .2s
+    transpose       ROW4L, ROW6L, v3, .16b, .2s
+    transpose       ROW0L, ROW2L, v3, .16b, .2s
+    transpose       ROW5L, ROW7L, v3, .16b, .2s
+    cmp             x0, #0
+    beq             4f /* Right 4x8 half has all zeros, go to 'sparse' second pass */
+
+    /* Only row 0 is non-zero for the right 4x8 half  */
+    dup             ROW1R.4h, ROW0R.4h[1]
+    dup             ROW2R.4h, ROW0R.4h[2]
+    dup             ROW3R.4h, ROW0R.4h[3]
+    dup             ROW4R.4h, ROW0R.4h[0]
+    dup             ROW5R.4h, ROW0R.4h[1]
+    dup             ROW6R.4h, ROW0R.4h[2]
+    dup             ROW7R.4h, ROW0R.4h[3]
+    dup             ROW0R.4h, ROW0R.4h[0]
+    b               1b /* Go to 'normal' second pass */
+
+4:  /* 1-D IDCT, pass 2 (sparse variant with zero rows 4-7), left 4x8 half */
+    ld1             {v2.4h},  [x15]    /* reload constants */
+    smull           v12.4s,   ROW1L.4h, XFIX_1_175875602
+    smlal           v12.4s,   ROW3L.4h, XFIX_1_175875602_MINUS_1_961570560
+    smull           v14.4s,   ROW3L.4h, XFIX_1_175875602
+    smlal           v14.4s,   ROW1L.4h, XFIX_1_175875602_MINUS_0_390180644
+    smull           v4.4s,    ROW2L.4h, XFIX_0_541196100
+    sshll           v6.4s,    ROW0L.4h, #13
+    mov             v8.16b,   v12.16b
+    smlal           v12.4s,   ROW3L.4h, XFIX_3_072711026_MINUS_2_562915447
+    smlsl           v8.4s,    ROW1L.4h, XFIX_0_899976223
+    add             v2.4s,    v6.4s,    v4.4s
+    mov             v10.16b,  v14.16b
+    smlal           v14.4s,   ROW1L.4h, XFIX_1_501321110_MINUS_0_899976223
+    add             v2.4s,    v2.4s,    v12.4s
+    add             v12.4s,   v12.4s,   v12.4s
+    smlsl           v10.4s,   ROW3L.4h, XFIX_2_562915447
+    shrn            ROW1L.4h, v2.4s,    #16
+    sub             v2.4s,    v2.4s,    v12.4s
+    smull           v12.4s,   ROW2L.4h, XFIX_0_541196100_PLUS_0_765366865
+    sub             v6.4s,    v6.4s,    v4.4s
+    shrn            ROW2R.4h, v2.4s,    #16 /* ROW6L.4h <-> ROW2R.4h */
+    add             v2.4s,    v6.4s,    v10.4s
+    sub             v6.4s,    v6.4s,    v10.4s
+    sshll           v10.4s,   ROW0L.4h, #13
+    shrn            ROW2L.4h, v2.4s,    #16
+    shrn            ROW1R.4h, v6.4s,    #16 /* ROW5L.4h <-> ROW1R.4h */
+    add             v4.4s,    v10.4s,   v12.4s
+    sub             v2.4s,    v10.4s,   v12.4s
+    add             v12.4s,   v4.4s,    v14.4s
+    sub             v4.4s,    v4.4s,    v14.4s
+    add             v10.4s,   v2.4s,    v8.4s
+    sub             v6.4s,    v2.4s,    v8.4s
+    shrn            ROW3R.4h, v4.4s,    #16 /* ROW7L.4h <-> ROW3R.4h */
+    shrn            ROW3L.4h, v10.4s,   #16
+    shrn            ROW0L.4h, v12.4s,   #16
+    shrn            ROW0R.4h, v6.4s,    #16 /* ROW4L.4h <-> ROW0R.4h */
+    /* 1-D IDCT, pass 2 (sparse variant with zero rows 4-7), right 4x8 half */
+    ld1             {v2.4h},  [x15]    /* reload constants */
+    smull           v12.4s,   ROW5L.4h, XFIX_1_175875602
+    smlal           v12.4s,   ROW7L.4h, XFIX_1_175875602_MINUS_1_961570560
+    smull           v14.4s,   ROW7L.4h, XFIX_1_175875602
+    smlal           v14.4s,   ROW5L.4h, XFIX_1_175875602_MINUS_0_390180644
+    smull           v4.4s,    ROW6L.4h, XFIX_0_541196100
+    sshll           v6.4s,    ROW4L.4h, #13
+    mov             v8.16b,   v12.16b
+    smlal           v12.4s,   ROW7L.4h, XFIX_3_072711026_MINUS_2_562915447
+    smlsl           v8.4s,    ROW5L.4h, XFIX_0_899976223
+    add             v2.4s,    v6.4s,    v4.4s
+    mov             v10.16b,  v14.16b
+    smlal           v14.4s,   ROW5L.4h, XFIX_1_501321110_MINUS_0_899976223
+    add             v2.4s,    v2.4s,    v12.4s
+    add             v12.4s,   v12.4s,   v12.4s
+    smlsl           v10.4s,   ROW7L.4h, XFIX_2_562915447
+    shrn            ROW5L.4h, v2.4s,    #16 /* ROW5L.4h <-> ROW1R.4h */
+    sub             v2.4s,    v2.4s,    v12.4s
+    smull           v12.4s,   ROW6L.4h, XFIX_0_541196100_PLUS_0_765366865
+    sub             v6.4s,    v6.4s,    v4.4s
+    shrn            ROW6R.4h, v2.4s,    #16
+    add             v2.4s,    v6.4s,    v10.4s
+    sub             v6.4s,    v6.4s,    v10.4s
+    sshll           v10.4s,   ROW4L.4h, #13
+    shrn            ROW6L.4h, v2.4s,    #16 /* ROW6L.4h <-> ROW2R.4h */
+    shrn            ROW5R.4h, v6.4s,    #16
+    add             v4.4s,    v10.4s,   v12.4s
+    sub             v2.4s,    v10.4s,   v12.4s
+    add             v12.4s,   v4.4s,    v14.4s
+    sub             v4.4s,    v4.4s,    v14.4s
+    add             v10.4s,   v2.4s,    v8.4s
+    sub             v6.4s,    v2.4s,    v8.4s
+    shrn            ROW7R.4h, v4.4s,    #16
+    shrn            ROW7L.4h, v10.4s,   #16 /* ROW7L.4h <-> ROW3R.4h */
+    shrn            ROW4L.4h, v12.4s,   #16 /* ROW4L.4h <-> ROW0R.4h */
+    shrn            ROW4R.4h, v6.4s,    #16
+    b               2b /* Go to epilogue */
+
+    .unreq          DCT_TABLE
+    .unreq          COEF_BLOCK
+    .unreq          OUTPUT_BUF
+    .unreq          OUTPUT_COL
+    .unreq          TMP1
+    .unreq          TMP2
+    .unreq          TMP3
+    .unreq          TMP4
+
+    .unreq          ROW0L
+    .unreq          ROW0R
+    .unreq          ROW1L
+    .unreq          ROW1R
+    .unreq          ROW2L
+    .unreq          ROW2R
+    .unreq          ROW3L
+    .unreq          ROW3R
+    .unreq          ROW4L
+    .unreq          ROW4R
+    .unreq          ROW5L
+    .unreq          ROW5R
+    .unreq          ROW6L
+    .unreq          ROW6R
+    .unreq          ROW7L
+    .unreq          ROW7R
+
+
+/*****************************************************************************/
+
+/*
+ * jsimd_idct_ifast_neon
+ *
+ * This function contains a fast, not so accurate integer implementation of
+ * the inverse DCT (Discrete Cosine Transform). It uses the same calculations
+ * and produces exactly the same output as IJG's original 'jpeg_idct_ifast'
+ * function from jidctfst.c
+ *
+ * Normally 1-D AAN DCT needs 5 multiplications and 29 additions.
+ * But in ARM NEON case some extra additions are required because VQDMULH
+ * instruction can't handle the constants larger than 1. So the expressions
+ * like "x * 1.082392200" have to be converted to "x * 0.082392200 + x",
+ * which introduces an extra addition. Overall, there are 6 extra additions
+ * per 1-D IDCT pass, totalling to 5 VQDMULH and 35 VADD/VSUB instructions.
+ */
+
+#define XFIX_1_082392200 v0.4h[0]
+#define XFIX_1_414213562 v0.4h[1]
+#define XFIX_1_847759065 v0.4h[2]
+#define XFIX_2_613125930 v0.4h[3]
+
+.balign 16
+jsimd_idct_ifast_neon_consts:
+    .short (277 * 128 - 256 * 128) /* XFIX_1_082392200 */
+    .short (362 * 128 - 256 * 128) /* XFIX_1_414213562 */
+    .short (473 * 128 - 256 * 128) /* XFIX_1_847759065 */
+    .short (669 * 128 - 512 * 128) /* XFIX_2_613125930 */
+
+asm_function jsimd_idct_ifast_neon
+
+    DCT_TABLE       .req x0
+    COEF_BLOCK      .req x1
+    OUTPUT_BUF      .req x2
+    OUTPUT_COL      .req x3
+    TMP1            .req x0
+    TMP2            .req x1
+    TMP3            .req x2
+    TMP4            .req x22
+    TMP5            .req x23
+
+    /* Load and dequantize coefficients into NEON registers
+     * with the following allocation:
+     *       0 1 2 3 | 4 5 6 7
+     *      ---------+--------
+     *   0 | d16     | d17     ( v8.8h  )
+     *   1 | d18     | d19     ( v9.8h  )
+     *   2 | d20     | d21     ( v10.8h )
+     *   3 | d22     | d23     ( v11.8h )
+     *   4 | d24     | d25     ( v12.8h )
+     *   5 | d26     | d27     ( v13.8h )
+     *   6 | d28     | d29     ( v14.8h )
+     *   7 | d30     | d31     ( v15.8h )
+     */
+    /* Save NEON registers used in fast IDCT */
+    sub             sp, sp, #176
+    stp             x22, x23, [sp], 16
+    adr             x23, jsimd_idct_ifast_neon_consts
+    st1             {v0.8b - v3.8b}, [sp], 32
+    st1             {v4.8b - v7.8b}, [sp], 32
+    st1             {v8.8b - v11.8b}, [sp], 32
+    st1             {v12.8b - v15.8b}, [sp], 32
+    st1             {v16.8b - v19.8b}, [sp], 32
+    ld1             {v8.8h, v9.8h}, [COEF_BLOCK], 32
+    ld1             {v0.8h, v1.8h}, [DCT_TABLE], 32
+    ld1             {v10.8h, v11.8h}, [COEF_BLOCK], 32
+    mul             v8.8h,  v8.8h,  v0.8h
+    ld1             {v2.8h, v3.8h}, [DCT_TABLE], 32
+    mul             v9.8h,  v9.8h,  v1.8h
+    ld1             {v12.8h, v13.8h}, [COEF_BLOCK], 32
+    mul             v10.8h, v10.8h, v2.8h
+    ld1             {v0.8h, v1.8h}, [DCT_TABLE], 32
+    mul             v11.8h, v11.8h, v3.8h
+    ld1             {v14.8h, v15.8h}, [COEF_BLOCK], 32
+    mul             v12.8h, v12.8h, v0.8h
+    ld1             {v2.8h, v3.8h}, [DCT_TABLE], 32
+    mul             v14.8h, v14.8h, v2.8h
+    mul             v13.8h, v13.8h, v1.8h
+    ld1             {v0.4h}, [x23]      /* load constants */
+    mul             v15.8h, v15.8h, v3.8h
+
+    /* 1-D IDCT, pass 1 */
+    sub             v2.8h,    v10.8h,   v14.8h
+    add             v14.8h,   v10.8h,   v14.8h
+    sub             v1.8h,    v11.8h,   v13.8h
+    add             v13.8h,   v11.8h,   v13.8h
+    sub             v5.8h,    v9.8h,    v15.8h
+    add             v15.8h,   v9.8h,    v15.8h
+    sqdmulh         v4.8h,    v2.8h,    XFIX_1_414213562
+    sqdmulh         v6.8h,    v1.8h,    XFIX_2_613125930
+    add             v3.8h,    v1.8h,    v1.8h
+    sub             v1.8h,    v5.8h,    v1.8h
+    add             v10.8h,   v2.8h,    v4.8h
+    sqdmulh         v4.8h,    v1.8h,    XFIX_1_847759065
+    sub             v2.8h,    v15.8h,   v13.8h
+    add             v3.8h,    v3.8h,    v6.8h
+    sqdmulh         v6.8h,    v2.8h,    XFIX_1_414213562
+    add             v1.8h,    v1.8h,    v4.8h
+    sqdmulh         v4.8h,    v5.8h,    XFIX_1_082392200
+    sub             v10.8h,   v10.8h,   v14.8h
+    add             v2.8h,    v2.8h,    v6.8h
+    sub             v6.8h,    v8.8h,    v12.8h
+    add             v12.8h,   v8.8h,    v12.8h
+    add             v9.8h,    v5.8h,    v4.8h
+    add             v5.8h,    v6.8h,    v10.8h
+    sub             v10.8h,   v6.8h,    v10.8h
+    add             v6.8h,    v15.8h,   v13.8h
+    add             v8.8h,    v12.8h,   v14.8h
+    sub             v3.8h,    v6.8h,    v3.8h
+    sub             v12.8h,   v12.8h,   v14.8h
+    sub             v3.8h,    v3.8h,    v1.8h
+    sub             v1.8h,    v9.8h,    v1.8h
+    add             v2.8h,    v3.8h,    v2.8h
+    sub             v15.8h,   v8.8h,    v6.8h
+    add             v1.8h,    v1.8h,    v2.8h
+    add             v8.8h,    v8.8h,    v6.8h
+    add             v14.8h,   v5.8h,    v3.8h
+    sub             v9.8h,    v5.8h,    v3.8h
+    sub             v13.8h,   v10.8h,   v2.8h
+    add             v10.8h,   v10.8h,   v2.8h
+    /* Transpose  q8-q9 */
+    mov             v18.16b,  v8.16b
+    trn1            v8.8h,    v8.8h,    v9.8h
+    trn2            v9.8h,    v18.8h,   v9.8h
+    sub             v11.8h,   v12.8h,   v1.8h
+    /* Transpose  q14-q15 */
+    mov             v18.16b,  v14.16b
+    trn1            v14.8h,   v14.8h,   v15.8h
+    trn2            v15.8h,   v18.8h,   v15.8h
+    add             v12.8h,   v12.8h,   v1.8h
+    /* Transpose  q10-q11 */
+    mov             v18.16b,  v10.16b
+    trn1            v10.8h,   v10.8h,   v11.8h
+    trn2            v11.8h,   v18.8h,   v11.8h
+    /* Transpose  q12-q13 */
+    mov             v18.16b,  v12.16b
+    trn1            v12.8h,   v12.8h,   v13.8h
+    trn2            v13.8h,   v18.8h,   v13.8h
+    /* Transpose  q9-q11 */
+    mov             v18.16b,  v9.16b
+    trn1            v9.4s,    v9.4s,    v11.4s
+    trn2            v11.4s,   v18.4s,   v11.4s
+    /* Transpose  q12-q14 */
+    mov             v18.16b,  v12.16b
+    trn1            v12.4s,   v12.4s,   v14.4s
+    trn2            v14.4s,   v18.4s,   v14.4s
+    /* Transpose  q8-q10 */
+    mov             v18.16b,  v8.16b
+    trn1            v8.4s,    v8.4s,    v10.4s
+    trn2            v10.4s,   v18.4s,   v10.4s
+    /* Transpose  q13-q15 */
+    mov             v18.16b,  v13.16b
+    trn1            v13.4s,   v13.4s,   v15.4s
+    trn2            v15.4s,   v18.4s,   v15.4s
+    /* vswp            v14.4h,   v10-MSB.4h */
+    umov            x22, v14.d[0]
+    ins             v14.2d[0], v10.2d[1]
+    ins             v10.2d[1], x22
+    /* vswp            v13.4h,   v9MSB.4h */
+
+    umov            x22, v13.d[0]
+    ins             v13.2d[0], v9.2d[1]
+    ins             v9.2d[1], x22
+    /* 1-D IDCT, pass 2 */
+    sub             v2.8h,    v10.8h,   v14.8h
+    /* vswp            v15.4h,   v11MSB.4h */
+    umov            x22, v15.d[0]
+    ins             v15.2d[0], v11.2d[1]
+    ins             v11.2d[1], x22
+    add             v14.8h,   v10.8h,   v14.8h
+    /* vswp            v12.4h,   v8-MSB.4h */
+    umov            x22, v12.d[0]
+    ins             v12.2d[0], v8.2d[1]
+    ins             v8.2d[1], x22
+    sub             v1.8h,    v11.8h,   v13.8h
+    add             v13.8h,   v11.8h,   v13.8h
+    sub             v5.8h,    v9.8h,    v15.8h
+    add             v15.8h,   v9.8h,    v15.8h
+    sqdmulh         v4.8h,    v2.8h,    XFIX_1_414213562
+    sqdmulh         v6.8h,    v1.8h,    XFIX_2_613125930
+    add             v3.8h,    v1.8h,    v1.8h
+    sub             v1.8h,    v5.8h,    v1.8h
+    add             v10.8h,   v2.8h,    v4.8h
+    sqdmulh         v4.8h,    v1.8h,    XFIX_1_847759065
+    sub             v2.8h,    v15.8h,   v13.8h
+    add             v3.8h,    v3.8h,    v6.8h
+    sqdmulh         v6.8h,    v2.8h,    XFIX_1_414213562
+    add             v1.8h,    v1.8h,    v4.8h
+    sqdmulh         v4.8h,    v5.8h,    XFIX_1_082392200
+    sub             v10.8h,   v10.8h,   v14.8h
+    add             v2.8h,    v2.8h,    v6.8h
+    sub             v6.8h,    v8.8h,    v12.8h
+    add             v12.8h,   v8.8h,    v12.8h
+    add             v9.8h,    v5.8h,    v4.8h
+    add             v5.8h,    v6.8h,    v10.8h
+    sub             v10.8h,   v6.8h,    v10.8h
+    add             v6.8h,    v15.8h,   v13.8h
+    add             v8.8h,    v12.8h,   v14.8h
+    sub             v3.8h,    v6.8h,    v3.8h
+    sub             v12.8h,   v12.8h,   v14.8h
+    sub             v3.8h,    v3.8h,    v1.8h
+    sub             v1.8h,    v9.8h,    v1.8h
+    add             v2.8h,    v3.8h,    v2.8h
+    sub             v15.8h,   v8.8h,    v6.8h
+    add             v1.8h,    v1.8h,    v2.8h
+    add             v8.8h,    v8.8h,    v6.8h
+    add             v14.8h,   v5.8h,    v3.8h
+    sub             v9.8h,    v5.8h,    v3.8h
+    sub             v13.8h,   v10.8h,   v2.8h
+    add             v10.8h,   v10.8h,   v2.8h
+    sub             v11.8h,   v12.8h,   v1.8h
+    add             v12.8h,   v12.8h,   v1.8h
+    /* Descale to 8-bit and range limit */
+    movi            v0.16b,   #0x80
+    sqshrn          v8.8b,    v8.8h,    #5
+    sqshrn2         v8.16b,   v9.8h,    #5
+    sqshrn          v9.8b,    v10.8h,   #5
+    sqshrn2         v9.16b,   v11.8h,   #5
+    sqshrn          v10.8b,   v12.8h,   #5
+    sqshrn2         v10.16b,  v13.8h,   #5
+    sqshrn          v11.8b,   v14.8h,   #5
+    sqshrn2         v11.16b,  v15.8h,   #5
+    add             v8.16b,   v8.16b,   v0.16b
+    add             v9.16b,   v9.16b,   v0.16b
+    add             v10.16b,  v10.16b,  v0.16b
+    add             v11.16b,  v11.16b,  v0.16b
+    /* Transpose the final 8-bit samples */
+    /* Transpose  q8-q9 */
+    mov             v18.16b,  v8.16b
+    trn1            v8.8h,    v8.8h,    v9.8h
+    trn2            v9.8h,    v18.8h,   v9.8h
+    /* Transpose  q10-q11 */
+    mov             v18.16b,  v10.16b
+    trn1            v10.8h,   v10.8h,   v11.8h
+    trn2            v11.8h,   v18.8h,   v11.8h
+    /* Transpose  q8-q10 */
+    mov             v18.16b,  v8.16b
+    trn1            v8.4s,    v8.4s,    v10.4s
+    trn2            v10.4s,   v18.4s,   v10.4s
+    /* Transpose  q9-q11 */
+    mov             v18.16b,  v9.16b
+    trn1            v9.4s,    v9.4s,    v11.4s
+    trn2            v11.4s,   v18.4s,   v11.4s
+    /* make copy */
+    ins             v17.2d[0], v8.2d[1]
+    /* Transpose  d16-d17-msb */
+    mov             v18.16b,  v8.16b
+    trn1            v8.8b,    v8.8b,    v17.8b
+    trn2            v17.8b,   v18.8b,   v17.8b
+    /* make copy */
+    ins             v19.2d[0], v9.2d[1]
+    mov             v18.16b,  v9.16b
+    trn1            v9.8b,    v9.8b,    v19.8b
+    trn2            v19.8b,   v18.8b,   v19.8b
+    /* Store results to the output buffer */
+    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
+    add             TMP1,     TMP1,     OUTPUT_COL
+    add             TMP2,     TMP2,     OUTPUT_COL
+    st1             {v8.8b},  [TMP1]
+    st1             {v17.8b}, [TMP2]
+    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
+    add             TMP1,     TMP1,     OUTPUT_COL
+    add             TMP2,     TMP2,     OUTPUT_COL
+    st1             {v9.8b},  [TMP1]
+    /* make copy */
+    ins             v7.2d[0], v10.2d[1]
+    mov             v18.16b,  v10.16b
+    trn1            v10.8b,   v10.8b,   v7.8b
+    trn2            v7.8b,    v18.8b,   v7.8b
+    st1             {v19.8b}, [TMP2]
+    ldp             TMP1,     TMP2,     [OUTPUT_BUF], 16
+    ldp             TMP4,     TMP5,     [OUTPUT_BUF], 16
+    add             TMP1,     TMP1,     OUTPUT_COL
+    add             TMP2,     TMP2,     OUTPUT_COL
+    add             TMP4,     TMP4,     OUTPUT_COL
+    add             TMP5,     TMP5,     OUTPUT_COL
+    st1             {v10.8b}, [TMP1]
+    /* make copy */
+    ins             v16.2d[0], v11.2d[1]
+    mov             v18.16b,  v11.16b
+    trn1            v11.8b,   v11.8b,   v16.8b
+    trn2            v16.8b,   v18.8b,   v16.8b
+    st1             {v7.8b},  [TMP2]
+    st1             {v11.8b}, [TMP4]
+    st1             {v16.8b}, [TMP5]
+    sub             sp, sp, #176
+    ldp             x22, x23, [sp], 16
+    ld1             {v0.8b - v3.8b}, [sp], 32
+    ld1             {v4.8b - v7.8b}, [sp], 32
+    ld1             {v8.8b - v11.8b}, [sp], 32
+    ld1             {v12.8b - v15.8b}, [sp], 32
+    ld1             {v16.8b - v19.8b}, [sp], 32
+    blr             x30
+
+    .unreq          DCT_TABLE
+    .unreq          COEF_BLOCK
+    .unreq          OUTPUT_BUF
+    .unreq          OUTPUT_COL
+    .unreq          TMP1
+    .unreq          TMP2
+    .unreq          TMP3
+    .unreq          TMP4
+
+
+/*****************************************************************************/
+
+/*
+ * jsimd_idct_4x4_neon
+ *
+ * This function contains inverse-DCT code for getting reduced-size
+ * 4x4 pixels output from an 8x8 DCT block. It uses the same  calculations
+ * and produces exactly the same output as IJG's original 'jpeg_idct_4x4'
+ * function from jpeg-6b (jidctred.c).
+ *
+ * NOTE: jpeg-8 has an improved implementation of 4x4 inverse-DCT, which
+ *       requires much less arithmetic operations and hence should be faster.
+ *       The primary purpose of this particular NEON optimized function is
+ *       bit exact compatibility with jpeg-6b.
+ *
+ * TODO: a bit better instructions scheduling can be achieved by expanding
+ *       idct_helper/transpose_4x4 macros and reordering instructions,
+ *       but readability will suffer somewhat.
+ */
+
+#define CONST_BITS  13
+
+#define FIX_0_211164243  (1730)  /* FIX(0.211164243) */
+#define FIX_0_509795579  (4176)  /* FIX(0.509795579) */
+#define FIX_0_601344887  (4926)  /* FIX(0.601344887) */
+#define FIX_0_720959822  (5906)  /* FIX(0.720959822) */
+#define FIX_0_765366865  (6270)  /* FIX(0.765366865) */
+#define FIX_0_850430095  (6967)  /* FIX(0.850430095) */
+#define FIX_0_899976223  (7373)  /* FIX(0.899976223) */
+#define FIX_1_061594337  (8697)  /* FIX(1.061594337) */
+#define FIX_1_272758580  (10426) /* FIX(1.272758580) */
+#define FIX_1_451774981  (11893) /* FIX(1.451774981) */
+#define FIX_1_847759065  (15137) /* FIX(1.847759065) */
+#define FIX_2_172734803  (17799) /* FIX(2.172734803) */
+#define FIX_2_562915447  (20995) /* FIX(2.562915447) */
+#define FIX_3_624509785  (29692) /* FIX(3.624509785) */
+
+.balign 16
+jsimd_idct_4x4_neon_consts:
+    .short     FIX_1_847759065     /* v0.4h[0] */
+    .short     -FIX_0_765366865    /* v0.4h[1] */
+    .short     -FIX_0_211164243    /* v0.4h[2] */
+    .short     FIX_1_451774981     /* v0.4h[3] */
+    .short     -FIX_2_172734803    /* d1[0] */
+    .short     FIX_1_061594337     /* d1[1] */
+    .short     -FIX_0_509795579    /* d1[2] */
+    .short     -FIX_0_601344887    /* d1[3] */
+    .short     FIX_0_899976223     /* v2.4h[0] */
+    .short     FIX_2_562915447     /* v2.4h[1] */
+    .short     1 << (CONST_BITS+1) /* v2.4h[2] */
+    .short     0                   /* v2.4h[3] */
+
+.macro idct_helper x4, x6, x8, x10, x12, x14, x16, shift, y26, y27, y28, y29
+    smull           v28.4s, \x4,    v2.4h[2]
+    smlal           v28.4s, \x8,    v0.4h[0]
+    smlal           v28.4s, \x14,   v0.4h[1]
+
+    smull           v26.4s, \x16,   v1.4h[2]
+    smlal           v26.4s, \x12,   v1.4h[3]
+    smlal           v26.4s, \x10,   v2.4h[0]
+    smlal           v26.4s, \x6,    v2.4h[1]
+
+    smull           v30.4s, \x4,    v2.4h[2]
+    smlsl           v30.4s, \x8,    v0.4h[0]
+    smlsl           v30.4s, \x14,   v0.4h[1]
+
+    smull           v24.4s, \x16,   v0.4h[2]
+    smlal           v24.4s, \x12,   v0.4h[3]
+    smlal           v24.4s, \x10,   v1.4h[0]
+    smlal           v24.4s, \x6,    v1.4h[1]
+
+    add             v20.4s, v28.4s, v26.4s
+    sub             v28.4s, v28.4s, v26.4s
+
+.if \shift > 16
+    srshr           v20.4s, v20.4s, #\shift
+    srshr           v28.4s, v28.4s, #\shift
+    xtn             \y26,   v20.4s
+    xtn             \y29,   v28.4s
+.else
+    rshrn           \y26,   v20.4s, #\shift
+    rshrn           \y29,   v28.4s, #\shift
+.endif
+
+    add             v20.4s, v30.4s, v24.4s
+    sub             v30.4s, v30.4s, v24.4s
+
+.if \shift > 16
+    srshr           v20.4s, v20.4s, #\shift
+    srshr           v30.4s, v30.4s, #\shift
+    xtn             \y27,   v20.4s
+    xtn             \y28,   v30.4s
+.else
+    rshrn           \y27,   v20.4s, #\shift
+    rshrn           \y28,   v30.4s, #\shift
+.endif
+
+.endm
+
+asm_function jsimd_idct_4x4_neon
+
+    DCT_TABLE       .req x0
+    COEF_BLOCK      .req x1
+    OUTPUT_BUF      .req x2
+    OUTPUT_COL      .req x3
+    TMP1            .req x0
+    TMP2            .req x1
+    TMP3            .req x2
+    TMP4            .req x15
+
+    /* Save all used NEON registers */
+    sub             sp, sp, 272
+    str             x15, [sp], 16
+    /* Load constants (v3.4h is just used for padding) */
+    adr             TMP4, jsimd_idct_4x4_neon_consts
+    st1             {v0.8b - v3.8b}, [sp], 32
+    st1             {v4.8b - v7.8b}, [sp], 32
+    st1             {v8.8b - v11.8b}, [sp], 32
+    st1             {v12.8b - v15.8b}, [sp], 32
+    st1             {v16.8b - v19.8b}, [sp], 32
+    st1             {v20.8b - v23.8b}, [sp], 32
+    st1             {v24.8b - v27.8b}, [sp], 32
+    st1             {v28.8b - v31.8b}, [sp], 32
+    ld1             {v0.4h, v1.4h, v2.4h, v3.4h}, [TMP4]
+
+    /* Load all COEF_BLOCK into NEON registers with the following allocation:
+     *       0 1 2 3 | 4 5 6 7
+     *      ---------+--------
+     *   0 | v4.4h   | v5.4h
+     *   1 | v6.4h   | v7.4h
+     *   2 | v8.4h   | v9.4h
+     *   3 | v10.4h  | v11.4h
+     *   4 | -       | -
+     *   5 | v12.4h  | v13.4h
+     *   6 | v14.4h  | v15.4h
+     *   7 | v16.4h  | v17.4h
+     */
+    ld1             {v4.4h, v5.4h, v6.4h, v7.4h}, [COEF_BLOCK], 32
+    ld1             {v8.4h, v9.4h, v10.4h, v11.4h}, [COEF_BLOCK], 32
+    add             COEF_BLOCK, COEF_BLOCK, #16
+    ld1             {v12.4h, v13.4h, v14.4h, v15.4h}, [COEF_BLOCK], 32
+    ld1             {v16.4h, v17.4h}, [COEF_BLOCK], 16
+    /* dequantize */
+    ld1             {v18.4h, v19.4h, v20.4h, v21.4h}, [DCT_TABLE], 32
+    mul             v4.4h, v4.4h, v18.4h
+    mul             v5.4h, v5.4h, v19.4h
+    ins             v4.2d[1], v5.2d[0]    /* 128 bit q4 */
+    ld1             {v22.4h, v23.4h, v24.4h, v25.4h}, [DCT_TABLE], 32
+    mul             v6.4h, v6.4h, v20.4h
+    mul             v7.4h, v7.4h, v21.4h
+    ins             v6.2d[1], v7.2d[0]    /* 128 bit q6 */
+    mul             v8.4h, v8.4h, v22.4h
+    mul             v9.4h, v9.4h, v23.4h
+    ins             v8.2d[1], v9.2d[0]    /* 128 bit q8 */
+    add             DCT_TABLE, DCT_TABLE, #16
+    ld1             {v26.4h, v27.4h, v28.4h, v29.4h}, [DCT_TABLE], 32
+    mul             v10.4h, v10.4h, v24.4h
+    mul             v11.4h, v11.4h, v25.4h
+    ins             v10.2d[1], v11.2d[0]  /* 128 bit q10 */
+    mul             v12.4h, v12.4h, v26.4h
+    mul             v13.4h, v13.4h, v27.4h
+    ins             v12.2d[1], v13.2d[0]  /* 128 bit q12 */
+    ld1             {v30.4h, v31.4h}, [DCT_TABLE], 16
+    mul             v14.4h, v14.4h, v28.4h
+    mul             v15.4h, v15.4h, v29.4h
+    ins             v14.2d[1], v15.2d[0]  /* 128 bit q14 */
+    mul             v16.4h, v16.4h, v30.4h
+    mul             v17.4h, v17.4h, v31.4h
+    ins             v16.2d[1], v17.2d[0]  /* 128 bit q16 */
+
+    /* Pass 1 */
+    idct_helper     v4.4h, v6.4h, v8.4h, v10.4h, v12.4h, v14.4h, v16.4h, 12, v4.4h, v6.4h, v8.4h, v10.4h
+    transpose_4x4   v4, v6, v8, v10, v3
+    ins             v10.2d[1], v11.2d[0]
+    idct_helper     v5.4h, v7.4h, v9.4h, v11.4h, v13.4h, v15.4h, v17.4h, 12, v5.4h, v7.4h, v9.4h, v11.4h
+    transpose_4x4   v5, v7, v9, v11, v3
+    ins             v10.2d[1], v11.2d[0]
+    /* Pass 2 */
+    idct_helper     v4.4h, v6.4h, v8.4h, v10.4h, v7.4h, v9.4h, v11.4h, 19, v26.4h, v27.4h, v28.4h, v29.4h
+    transpose_4x4   v26, v27, v28, v29, v3
+
+    /* Range limit */
+    movi            v30.8h, #0x80
+    ins             v26.2d[1], v27.2d[0]
+    ins             v28.2d[1], v29.2d[0]
+    add             v26.8h, v26.8h, v30.8h
+    add             v28.8h, v28.8h, v30.8h
+    sqxtun          v26.8b, v26.8h
+    sqxtun          v27.8b, v28.8h
+
+    /* Store results to the output buffer */
+    ldp             TMP1, TMP2, [OUTPUT_BUF], 16
+    ldp             TMP3, TMP4, [OUTPUT_BUF]
+    add             TMP1, TMP1, OUTPUT_COL
+    add             TMP2, TMP2, OUTPUT_COL
+    add             TMP3, TMP3, OUTPUT_COL
+    add             TMP4, TMP4, OUTPUT_COL
+
+#if defined(__ARMEL__) && !RESPECT_STRICT_ALIGNMENT
+    /* We can use much less instructions on little endian systems if the
+     * OS kernel is not configured to trap unaligned memory accesses
+     */
+    st1             {v26.s}[0], [TMP1], 4
+    st1             {v27.s}[0], [TMP3], 4
+    st1             {v26.s}[1], [TMP2], 4
+    st1             {v27.s}[1], [TMP4], 4
+#else
+    st1             {v26.b}[0], [TMP1], 1
+    st1             {v27.b}[0], [TMP3], 1
+    st1             {v26.b}[1], [TMP1], 1
+    st1             {v27.b}[1], [TMP3], 1
+    st1             {v26.b}[2], [TMP1], 1
+    st1             {v27.b}[2], [TMP3], 1
+    st1             {v26.b}[3], [TMP1], 1
+    st1             {v27.b}[3], [TMP3], 1
+
+    st1             {v26.b}[4], [TMP2], 1
+    st1             {v27.b}[4], [TMP4], 1
+    st1             {v26.b}[5], [TMP2], 1
+    st1             {v27.b}[5], [TMP4], 1
+    st1             {v26.b}[6], [TMP2], 1
+    st1             {v27.b}[6], [TMP4], 1
+    st1             {v26.b}[7], [TMP2], 1
+    st1             {v27.b}[7], [TMP4], 1
+#endif
+
+    /* vpop            {v8.4h - v15.4h}    ;not available */
+    sub             sp, sp, #272
+    ldr             x15, [sp], 16
+    ld1             {v0.8b - v3.8b}, [sp], 32
+    ld1             {v4.8b - v7.8b}, [sp], 32
+    ld1             {v8.8b - v11.8b}, [sp], 32
+    ld1             {v12.8b - v15.8b}, [sp], 32
+    ld1             {v16.8b - v19.8b}, [sp], 32
+    ld1             {v20.8b - v23.8b}, [sp], 32
+    ld1             {v24.8b - v27.8b}, [sp], 32
+    ld1             {v28.8b - v31.8b}, [sp], 32
+    blr             x30
+
+    .unreq          DCT_TABLE
+    .unreq          COEF_BLOCK
+    .unreq          OUTPUT_BUF
+    .unreq          OUTPUT_COL
+    .unreq          TMP1
+    .unreq          TMP2
+    .unreq          TMP3
+    .unreq          TMP4
+
+.purgem idct_helper
+
+
+/*****************************************************************************/
+
+/*
+ * jsimd_idct_2x2_neon
+ *
+ * This function contains inverse-DCT code for getting reduced-size
+ * 2x2 pixels output from an 8x8 DCT block. It uses the same  calculations
+ * and produces exactly the same output as IJG's original 'jpeg_idct_2x2'
+ * function from jpeg-6b (jidctred.c).
+ *
+ * NOTE: jpeg-8 has an improved implementation of 2x2 inverse-DCT, which
+ *       requires much less arithmetic operations and hence should be faster.
+ *       The primary purpose of this particular NEON optimized function is
+ *       bit exact compatibility with jpeg-6b.
+ */
+
+.balign 8
+jsimd_idct_2x2_neon_consts:
+    .short     -FIX_0_720959822    /* v14[0] */
+    .short     FIX_0_850430095     /* v14[1] */
+    .short     -FIX_1_272758580    /* v14[2] */
+    .short     FIX_3_624509785     /* v14[3] */
+
+.macro idct_helper x4, x6, x10, x12, x16, shift, y26, y27
+    sshll      v15.4s, \x4,    #15
+    smull      v26.4s, \x6,    v14.4h[3]
+    smlal      v26.4s, \x10,   v14.4h[2]
+    smlal      v26.4s, \x12,   v14.4h[1]
+    smlal      v26.4s, \x16,   v14.4h[0]
+
+    add        v20.4s, v15.4s, v26.4s
+    sub        v15.4s, v15.4s, v26.4s
+
+.if \shift > 16
+    srshr      v20.4s, v20.4s, #\shift
+    srshr      v15.4s, v15.4s, #\shift
+    xtn        \y26,   v20.4s
+    xtn        \y27,   v15.4s
+.else
+    rshrn      \y26,   v20.4s, #\shift
+    rshrn      \y27,   v15.4s, #\shift
+.endif
+
+.endm
+
+asm_function jsimd_idct_2x2_neon
+
+    DCT_TABLE       .req x0
+    COEF_BLOCK      .req x1
+    OUTPUT_BUF      .req x2
+    OUTPUT_COL      .req x3
+    TMP1            .req x0
+    TMP2            .req x15
+
+    /* vpush           {v8.4h - v15.4h}            ; not available */
+    sub             sp, sp, 208
+    str             x15, [sp], 16
+
+    /* Load constants */
+    adr             TMP2, jsimd_idct_2x2_neon_consts
+    st1             {v4.8b - v7.8b}, [sp], 32
+    st1             {v8.8b - v11.8b}, [sp], 32
+    st1             {v12.8b - v15.8b}, [sp], 32
+    st1             {v16.8b - v19.8b}, [sp], 32
+    st1             {v21.8b - v22.8b}, [sp], 16
+    st1             {v24.8b - v27.8b}, [sp], 32
+    st1             {v30.8b - v31.8b}, [sp], 16
+    ld1             {v14.4h}, [TMP2]
+
+    /* Load all COEF_BLOCK into NEON registers with the following allocation:
+     *       0 1 2 3 | 4 5 6 7
+     *      ---------+--------
+     *   0 | v4.4h   | v5.4h
+     *   1 | v6.4h   | v7.4h
+     *   2 | -       | -
+     *   3 | v10.4h  | v11.4h
+     *   4 | -       | -
+     *   5 | v12.4h  | v13.4h
+     *   6 | -       | -
+     *   7 | v16.4h  | v17.4h
+     */
+    ld1             {v4.4h, v5.4h, v6.4h, v7.4h}, [COEF_BLOCK], 32
+    add             COEF_BLOCK, COEF_BLOCK, #16
+    ld1             {v10.4h, v11.4h}, [COEF_BLOCK], 16
+    add             COEF_BLOCK, COEF_BLOCK, #16
+    ld1             {v12.4h, v13.4h}, [COEF_BLOCK], 16
+    add             COEF_BLOCK, COEF_BLOCK, #16
+    ld1             {v16.4h, v17.4h}, [COEF_BLOCK], 16
+    /* Dequantize */
+    ld1             {v18.4h, v19.4h, v20.4h, v21.4h}, [DCT_TABLE], 32
+    mul             v4.4h, v4.4h, v18.4h
+    mul             v5.4h, v5.4h, v19.4h
+    ins             v4.2d[1], v5.2d[0]
+    mul             v6.4h, v6.4h, v20.4h
+    mul             v7.4h, v7.4h, v21.4h
+    ins             v6.2d[1], v7.2d[0]
+    add             DCT_TABLE, DCT_TABLE, #16
+    ld1             {v24.4h, v25.4h}, [DCT_TABLE], 16
+    mul             v10.4h, v10.4h, v24.4h
+    mul             v11.4h, v11.4h, v25.4h
+    ins             v10.2d[1], v11.2d[0]
+    add             DCT_TABLE, DCT_TABLE, #16
+    ld1             {v26.4h, v27.4h}, [DCT_TABLE], 16
+    mul             v12.4h, v12.4h, v26.4h
+    mul             v13.4h, v13.4h, v27.4h
+    ins             v12.2d[1], v13.2d[0]
+    add             DCT_TABLE, DCT_TABLE, #16
+    ld1             {v30.4h, v31.4h}, [DCT_TABLE], 16
+    mul             v16.4h, v16.4h, v30.4h
+    mul             v17.4h, v17.4h, v31.4h
+    ins             v16.2d[1], v17.2d[0]
+
+    /* Pass 1 */
+#if 0
+    idct_helper     v4.4h, v6.4h, v10.4h, v12.4h, v16.4h, 13, v4.4h, v6.4h
+    transpose_4x4   v4.4h, v6.4h, v8.4h,  v10.4h
+    idct_helper     v5.4h, v7.4h, v11.4h, v13.4h, v17.4h, 13, v5.4h, v7.4h
+    transpose_4x4   v5.4h, v7.4h, v9.4h,  v11.4h
+#else
+    smull           v26.4s, v6.4h,  v14.4h[3]
+    smlal           v26.4s, v10.4h, v14.4h[2]
+    smlal           v26.4s, v12.4h, v14.4h[1]
+    smlal           v26.4s, v16.4h, v14.4h[0]
+    smull           v24.4s, v7.4h,  v14.4h[3]
+    smlal           v24.4s, v11.4h, v14.4h[2]
+    smlal           v24.4s, v13.4h, v14.4h[1]
+    smlal           v24.4s, v17.4h, v14.4h[0]
+    sshll           v15.4s, v4.4h,  #15
+    sshll           v30.4s, v5.4h,  #15
+    add             v20.4s, v15.4s, v26.4s
+    sub             v15.4s, v15.4s, v26.4s
+    rshrn           v4.4h,  v20.4s, #13
+    rshrn           v6.4h,  v15.4s, #13
+    add             v20.4s, v30.4s, v24.4s
+    sub             v15.4s, v30.4s, v24.4s
+    rshrn           v5.4h,  v20.4s, #13
+    rshrn           v7.4h,  v15.4s, #13
+    ins             v4.2d[1], v5.2d[0]
+    ins             v6.2d[1], v7.2d[0]
+    transpose       v4, v6, v3, .16b, .8h
+    transpose       v6, v10, v3, .16b, .4s
+    ins             v11.2d[0], v10.2d[1]
+    ins             v7.2d[0], v6.2d[1]
+#endif
+
+    /* Pass 2 */
+    idct_helper     v4.4h, v6.4h, v10.4h, v7.4h, v11.4h, 20, v26.4h, v27.4h
+
+    /* Range limit */
+    movi            v30.8h, #0x80
+    ins             v26.2d[1], v27.2d[0]
+    add             v26.8h, v26.8h, v30.8h
+    sqxtun          v30.8b, v26.8h
+    ins             v26.2d[0], v30.2d[0]
+    sqxtun          v27.8b, v26.8h
+
+    /* Store results to the output buffer */
+    ldp             TMP1, TMP2, [OUTPUT_BUF]
+    add             TMP1, TMP1, OUTPUT_COL
+    add             TMP2, TMP2, OUTPUT_COL
+
+    st1             {v26.b}[0], [TMP1], 1
+    st1             {v27.b}[4], [TMP1], 1
+    st1             {v26.b}[1], [TMP2], 1
+    st1             {v27.b}[5], [TMP2], 1
+
+    sub             sp, sp, #208
+    ldr             x15, [sp], 16
+    ld1             {v4.8b - v7.8b}, [sp], 32
+    ld1             {v8.8b - v11.8b}, [sp], 32
+    ld1             {v12.8b - v15.8b}, [sp], 32
+    ld1             {v16.8b - v19.8b}, [sp], 32
+    ld1             {v21.8b - v22.8b}, [sp], 16
+    ld1             {v24.8b - v27.8b}, [sp], 32
+    ld1             {v30.8b - v31.8b}, [sp], 16
+    blr             x30
+
+    .unreq          DCT_TABLE
+    .unreq          COEF_BLOCK
+    .unreq          OUTPUT_BUF
+    .unreq          OUTPUT_COL
+    .unreq          TMP1
+    .unreq          TMP2
+
+.purgem idct_helper
+
+
+/*****************************************************************************/
+
+/*
+ * jsimd_ycc_extrgb_convert_neon
+ * jsimd_ycc_extbgr_convert_neon
+ * jsimd_ycc_extrgbx_convert_neon
+ * jsimd_ycc_extbgrx_convert_neon
+ * jsimd_ycc_extxbgr_convert_neon
+ * jsimd_ycc_extxrgb_convert_neon
+ *
+ * Colorspace conversion YCbCr -> RGB
+ */
+
+
+.macro do_load size
+    .if \size == 8
+        ld1  {v4.8b}, [U], 8
+        ld1  {v5.8b}, [V], 8
+        ld1  {v0.8b}, [Y], 8
+        prfm PLDL1KEEP, [U, #64]
+        prfm PLDL1KEEP, [V, #64]
+        prfm PLDL1KEEP, [Y, #64]
+    .elseif \size == 4
+        ld1  {v4.b}[0], [U], 1
+        ld1  {v4.b}[1], [U], 1
+        ld1  {v4.b}[2], [U], 1
+        ld1  {v4.b}[3], [U], 1
+        ld1  {v5.b}[0], [V], 1
+        ld1  {v5.b}[1], [V], 1
+        ld1  {v5.b}[2], [V], 1
+        ld1  {v5.b}[3], [V], 1
+        ld1  {v0.b}[0], [Y], 1
+        ld1  {v0.b}[1], [Y], 1
+        ld1  {v0.b}[2], [Y], 1
+        ld1  {v0.b}[3], [Y], 1
+    .elseif \size == 2
+        ld1  {v4.b}[4], [U], 1
+        ld1  {v4.b}[5], [U], 1
+        ld1  {v5.b}[4], [V], 1
+        ld1  {v5.b}[5], [V], 1
+        ld1  {v0.b}[4], [Y], 1
+        ld1  {v0.b}[5], [Y], 1
+    .elseif \size == 1
+        ld1  {v4.b}[6], [U], 1
+        ld1  {v5.b}[6], [V], 1
+        ld1  {v0.b}[6], [Y], 1
+    .else
+        .error unsupported macroblock size
+    .endif
+.endm
+
+.macro do_store bpp, size
+    .if \bpp == 24
+        .if \size == 8
+            st3  {v10.8b, v11.8b, v12.8b}, [RGB], 24
+        .elseif \size == 4
+            st3  {v10.b, v11.b, v12.b}[0], [RGB], 3
+            st3  {v10.b, v11.b, v12.b}[1], [RGB], 3
+            st3  {v10.b, v11.b, v12.b}[2], [RGB], 3
+            st3  {v10.b, v11.b, v12.b}[3], [RGB], 3
+        .elseif \size == 2
+            st3  {v10.b, v11.b, v12.b}[4], [RGB], 3
+            st3  {v10.b, v11.b, v12.b}[5], [RGB], 3
+        .elseif \size == 1
+            st3  {v10.b, v11.b, v12.b}[6], [RGB], 3
+        .else
+            .error unsupported macroblock size
+        .endif
+    .elseif \bpp == 32
+        .if \size == 8
+            st4  {v10.8b, v11.8b, v12.8b, v13.8b}, [RGB], 32
+        .elseif \size == 4
+            st4  {v10.b, v11.b, v12.b, v13.b}[0], [RGB], 4
+            st4  {v10.b, v11.b, v12.b, v13.b}[1], [RGB], 4
+            st4  {v10.b, v11.b, v12.b, v13.b}[2], [RGB], 4
+            st4  {v10.b, v11.b, v12.b, v13.b}[3], [RGB], 4
+        .elseif \size == 2
+            st4  {v10.b, v11.b, v12.b, v13.b}[4], [RGB], 4
+            st4  {v10.b, v11.b, v12.b, v13.b}[5], [RGB], 4
+        .elseif \size == 1
+            st4  {v10.b, v11.b, v12.b, v13.b}[6], [RGB], 4
+        .else
+            .error unsupported macroblock size
+        .endif
+    .elseif \bpp==16
+        .if \size == 8
+            st1  {v25.8h}, [RGB],16
+        .elseif \size == 4
+            st1  {v25.4h}, [RGB],8
+        .elseif \size == 2
+            st1  {v25.h}[4], [RGB],2
+            st1  {v25.h}[5], [RGB],2
+        .elseif \size == 1
+            st1  {v25.h}[6], [RGB],2
+        .else
+            .error unsupported macroblock size
+        .endif
+     .else
+        .error unsupported bpp
+    .endif
+.endm
+
+.macro generate_jsimd_ycc_rgb_convert_neon colorid, bpp, r_offs, rsize, g_offs, gsize, b_offs, bsize, defsize
+
+/*
+ * 2-stage pipelined YCbCr->RGB conversion
+ */
+
+.macro do_yuv_to_rgb_stage1
+    uaddw        v6.8h, v2.8h, v4.8b     /* q3 = u - 128 */
+    uaddw        v8.8h, v2.8h, v5.8b     /* q2 = v - 128 */
+    smull        v20.4s, v6.4h, v1.4h[1] /* multiply by -11277 */
+    smlal        v20.4s, v8.4h, v1.4h[2] /* multiply by -23401 */
+    smull2       v22.4s, v6.8h, v1.4h[1] /* multiply by -11277 */
+    smlal2       v22.4s, v8.8h, v1.4h[2] /* multiply by -23401 */
+    smull        v24.4s, v8.4h, v1.4h[0] /* multiply by 22971 */
+    smull2       v26.4s, v8.8h, v1.4h[0] /* multiply by 22971 */
+    smull        v28.4s, v6.4h, v1.4h[3] /* multiply by 29033 */
+    smull2       v30.4s, v6.8h, v1.4h[3] /* multiply by 29033 */
+.endm
+
+.macro do_yuv_to_rgb_stage2
+    rshrn        v20.4h, v20.4s, #15
+    rshrn2       v20.8h, v22.4s, #15
+    rshrn        v24.4h, v24.4s, #14
+    rshrn2       v24.8h, v26.4s, #14
+    rshrn        v28.4h, v28.4s, #14
+    rshrn2       v28.8h, v30.4s, #14
+    uaddw        v20.8h, v20.8h, v0.8b
+    uaddw        v24.8h, v24.8h, v0.8b
+    uaddw        v28.8h, v28.8h, v0.8b
+.if \bpp != 16
+    sqxtun       v1\g_offs\defsize, v20.8h
+    sqxtun       v1\r_offs\defsize, v24.8h
+    sqxtun       v1\b_offs\defsize, v28.8h
+.else
+    sqshlu       v21.8h, v20.8h, #8
+    sqshlu       v25.8h, v24.8h, #8
+    sqshlu       v29.8h, v28.8h, #8
+    sri          v25.8h, v21.8h, #5
+    sri          v25.8h, v29.8h, #11
+.endif
+
+.endm
+
+.macro do_yuv_to_rgb_stage2_store_load_stage1
+    rshrn        v20.4h, v20.4s, #15
+    rshrn        v24.4h, v24.4s, #14
+    rshrn        v28.4h, v28.4s, #14
+    ld1          {v4.8b}, [U], 8
+    rshrn2       v20.8h, v22.4s, #15
+    rshrn2       v24.8h, v26.4s, #14
+    rshrn2       v28.8h, v30.4s, #14
+    ld1          {v5.8b}, [V], 8
+    uaddw        v20.8h, v20.8h, v0.8b
+    uaddw        v24.8h, v24.8h, v0.8b
+    uaddw        v28.8h, v28.8h, v0.8b
+.if \bpp != 16 /**************** rgb24/rgb32 *********************************/
+    sqxtun       v1\g_offs\defsize, v20.8h
+    ld1          {v0.8b}, [Y], 8
+    sqxtun       v1\r_offs\defsize, v24.8h
+    prfm         PLDL1KEEP, [U, #64]
+    prfm         PLDL1KEEP, [V, #64]
+    prfm         PLDL1KEEP, [Y, #64]
+    sqxtun       v1\b_offs\defsize, v28.8h
+    uaddw        v6.8h, v2.8h, v4.8b     /* v6.16b = u - 128 */
+    uaddw        v8.8h, v2.8h, v5.8b     /* q2 = v - 128 */
+    smull        v20.4s, v6.4h, v1.4h[1] /* multiply by -11277 */
+    smlal        v20.4s, v8.4h, v1.4h[2] /* multiply by -23401 */
+    smull2       v22.4s, v6.8h, v1.4h[1] /* multiply by -11277 */
+    smlal2       v22.4s, v8.8h, v1.4h[2] /* multiply by -23401 */
+    smull        v24.4s, v8.4h, v1.4h[0] /* multiply by 22971 */
+    smull2       v26.4s, v8.8h, v1.4h[0] /* multiply by 22971 */
+.else /**************************** rgb565 ***********************************/
+    sqshlu       v21.8h, v20.8h, #8
+    sqshlu       v25.8h, v24.8h, #8
+    sqshlu       v29.8h, v28.8h, #8
+    uaddw        v6.8h, v2.8h, v4.8b     /* v6.16b = u - 128 */
+    uaddw        v8.8h, v2.8h, v5.8b     /* q2 = v - 128 */
+    ld1          {v0.8b}, [Y], 8
+    smull        v20.4s, v6.4h, v1.4h[1] /* multiply by -11277 */
+    smlal        v20.4s, v8.4h, v1.4h[2] /* multiply by -23401 */
+    smull2       v22.4s, v6.8h, v1.4h[1] /* multiply by -11277 */
+    smlal2       v22.4s, v8.8h, v1.4h[2] /* multiply by -23401 */
+    sri          v25.8h, v21.8h, #5
+    smull        v24.4s, v8.4h, v1.4h[0] /* multiply by 22971 */
+    smull2       v26.4s, v8.8h, v1.4h[0] /* multiply by 22971 */
+    prfm         PLDL1KEEP, [U, #64]
+    prfm         PLDL1KEEP, [V, #64]
+    prfm         PLDL1KEEP, [Y, #64]
+    sri          v25.8h, v29.8h, #11
+.endif
+    do_store     \bpp, 8
+    smull        v28.4s, v6.4h, v1.4h[3] /* multiply by 29033 */
+    smull2       v30.4s, v6.8h, v1.4h[3] /* multiply by 29033 */
+.endm
+
+.macro do_yuv_to_rgb
+    do_yuv_to_rgb_stage1
+    do_yuv_to_rgb_stage2
+.endm
+
+/* Apple gas crashes on adrl, work around that by using adr.
+ * But this requires a copy of these constants for each function.
+ */
+
+.balign 16
+jsimd_ycc_\colorid\()_neon_consts:
+    .short          0,      0,     0,      0
+    .short          22971, -11277, -23401, 29033
+    .short          -128,  -128,   -128,   -128
+    .short          -128,  -128,   -128,   -128
+
+asm_function jsimd_ycc_\colorid\()_convert_neon
+    OUTPUT_WIDTH    .req x0
+    INPUT_BUF       .req x1
+    INPUT_ROW       .req x2
+    OUTPUT_BUF      .req x3
+    NUM_ROWS        .req x4
+
+    INPUT_BUF0      .req x5
+    INPUT_BUF1      .req x6
+    INPUT_BUF2      .req INPUT_BUF
+
+    RGB             .req x7
+    Y               .req x8
+    U               .req x9
+    V               .req x10
+    N               .req x15
+
+    sub             sp, sp, 336
+    str             x15, [sp], 16
+    /* Load constants to d1, d2, d3 (v0.4h is just used for padding) */
+    adr             x15, jsimd_ycc_\colorid\()_neon_consts
+    /* Save NEON registers */
+    st1             {v0.8b - v3.8b}, [sp], 32
+    st1             {v4.8b - v7.8b}, [sp], 32
+    st1             {v8.8b - v11.8b}, [sp], 32
+    st1             {v12.8b - v15.8b}, [sp], 32
+    st1             {v16.8b - v19.8b}, [sp], 32
+    st1             {v20.8b - v23.8b}, [sp], 32
+    st1             {v24.8b - v27.8b}, [sp], 32
+    st1             {v28.8b - v31.8b}, [sp], 32
+    ld1             {v0.4h, v1.4h}, [x15], 16
+    ld1             {v2.8h}, [x15]
+
+    /* Save ARM registers and handle input arguments */
+    /* push            {x4, x5, x6, x7, x8, x9, x10, x30} */
+    stp             x4, x5, [sp], 16
+    stp             x6, x7, [sp], 16
+    stp             x8, x9, [sp], 16
+    stp             x10, x30, [sp], 16
+    ldr             INPUT_BUF0, [INPUT_BUF]
+    ldr             INPUT_BUF1, [INPUT_BUF, 8]
+    ldr             INPUT_BUF2, [INPUT_BUF, 16]
+    .unreq          INPUT_BUF
+
+    /* Initially set v10, v11.4h, v12.8b, d13 to 0xFF */
+    movi            v10.16b, #255
+    movi            v13.16b, #255
+
+    /* Outer loop over scanlines */
+    cmp             NUM_ROWS, #1
+    blt             9f
+0:
+    lsl             x16, INPUT_ROW, #3
+    ldr             Y, [INPUT_BUF0, x16]
+    ldr             U, [INPUT_BUF1, x16]
+    mov             N, OUTPUT_WIDTH
+    ldr             V, [INPUT_BUF2, x16]
+    add             INPUT_ROW, INPUT_ROW, #1
+    ldr             RGB, [OUTPUT_BUF], #8
+
+    /* Inner loop over pixels */
+    subs            N, N, #8
+    blt             3f
+    do_load         8
+    do_yuv_to_rgb_stage1
+    subs            N, N, #8
+    blt             2f
+1:
+    do_yuv_to_rgb_stage2_store_load_stage1
+    subs            N, N, #8
+    bge             1b
+2:
+    do_yuv_to_rgb_stage2
+    do_store        \bpp, 8
+    tst             N, #7
+    beq             8f
+3:
+    tst             N, #4
+    beq             3f
+    do_load         4
+3:
+    tst             N, #2
+    beq             4f
+    do_load         2
+4:
+    tst             N, #1
+    beq             5f
+    do_load         1
+5:
+    do_yuv_to_rgb
+    tst             N, #4
+    beq             6f
+    do_store        \bpp, 4
+6:
+    tst             N, #2
+    beq             7f
+    do_store        \bpp, 2
+7:
+    tst             N, #1
+    beq             8f
+    do_store        \bpp, 1
+8:
+    subs            NUM_ROWS, NUM_ROWS, #1
+    bgt             0b
+9:
+    /* Restore all registers and return */
+    sub             sp, sp, #336
+    ldr             x15, [sp], 16
+    ld1             {v0.8b - v3.8b}, [sp], 32
+    ld1             {v4.8b - v7.8b}, [sp], 32
+    ld1             {v8.8b - v11.8b}, [sp], 32
+    ld1             {v12.8b - v15.8b}, [sp], 32
+    ld1             {v16.8b - v19.8b}, [sp], 32
+    ld1             {v20.8b - v23.8b}, [sp], 32
+    ld1             {v24.8b - v27.8b}, [sp], 32
+    ld1             {v28.8b - v31.8b}, [sp], 32
+    /* pop             {r4, r5, r6, r7, r8, r9, r10, pc} */
+    ldp             x4, x5, [sp], 16
+    ldp             x6, x7, [sp], 16
+    ldp             x8, x9, [sp], 16
+    ldp             x10, x30, [sp], 16
+    br              x30
+    .unreq          OUTPUT_WIDTH
+    .unreq          INPUT_ROW
+    .unreq          OUTPUT_BUF
+    .unreq          NUM_ROWS
+    .unreq          INPUT_BUF0
+    .unreq          INPUT_BUF1
+    .unreq          INPUT_BUF2
+    .unreq          RGB
+    .unreq          Y
+    .unreq          U
+    .unreq          V
+    .unreq          N
+
+.purgem do_yuv_to_rgb
+.purgem do_yuv_to_rgb_stage1
+.purgem do_yuv_to_rgb_stage2
+.purgem do_yuv_to_rgb_stage2_store_load_stage1
+.endm
+
+/*--------------------------------- id ----- bpp R  rsize  G  gsize  B  bsize  defsize   */
+generate_jsimd_ycc_rgb_convert_neon extrgb,  24, 0, .4h,   1, .4h,   2, .4h,   .8b
+generate_jsimd_ycc_rgb_convert_neon extbgr,  24, 2, .4h,   1, .4h,   0, .4h,   .8b
+generate_jsimd_ycc_rgb_convert_neon extrgbx, 32, 0, .4h,   1, .4h,   2, .4h,   .8b
+generate_jsimd_ycc_rgb_convert_neon extbgrx, 32, 2, .4h,   1, .4h,   0, .4h,   .8b
+generate_jsimd_ycc_rgb_convert_neon extxbgr, 32, 3, .4h,   2, .4h,   1, .4h,   .8b
+generate_jsimd_ycc_rgb_convert_neon extxrgb, 32, 1, .4h,   2, .4h,   3, .4h,   .8b
+generate_jsimd_ycc_rgb_convert_neon rgb565,  16, 0, .4h,   0, .4h,   0, .4h,   .8b
+.purgem do_load
+.purgem do_store
index ac6c860..44c61fd 100644 (file)
 /* Supplementary macro for setting function attributes */
 .macro asm_function fname
 #ifdef __APPLE__
-    .func _\fname
     .globl _\fname
 _\fname:
 #else
-    .func \fname
     .global \fname
 #ifdef __ELF__
     .hidden \fname
@@ -670,7 +668,6 @@ asm_function jsimd_idct_islow_neon
     .unreq          ROW6R
     .unreq          ROW7L
     .unreq          ROW7R
-.endfunc
 
 
 /*****************************************************************************/
@@ -895,7 +892,6 @@ asm_function jsimd_idct_ifast_neon
     .unreq          TMP2
     .unreq          TMP3
     .unreq          TMP4
-.endfunc
 
 
 /*****************************************************************************/
@@ -1108,7 +1104,6 @@ asm_function jsimd_idct_4x4_neon
     .unreq          TMP2
     .unreq          TMP3
     .unreq          TMP4
-.endfunc
 
 .purgem idct_helper
 
@@ -1263,7 +1258,6 @@ asm_function jsimd_idct_2x2_neon
     .unreq          OUTPUT_COL
     .unreq          TMP1
     .unreq          TMP2
-.endfunc
 
 .purgem idct_helper
 
@@ -1547,7 +1541,6 @@ asm_function jsimd_ycc_\colorid\()_convert_neon
     .unreq          U
     .unreq          V
     .unreq          N
-.endfunc
 
 .purgem do_yuv_to_rgb
 .purgem do_yuv_to_rgb_stage1
@@ -1858,7 +1851,6 @@ asm_function jsimd_\colorid\()_ycc_convert_neon
     .unreq          U
     .unreq          V
     .unreq          N
-.endfunc
 
 .purgem do_rgb_to_yuv
 .purgem do_rgb_to_yuv_stage1
@@ -1940,7 +1932,6 @@ asm_function jsimd_convsamp_neon
     .unreq          TMP2
     .unreq          TMP3
     .unreq          TMP4
-.endfunc
 
 
 /*****************************************************************************/
@@ -2064,7 +2055,6 @@ asm_function jsimd_fdct_ifast_neon
 
     .unreq          DATA
     .unreq          TMP
-.endfunc
 
 
 /*****************************************************************************/
@@ -2166,7 +2156,6 @@ asm_function jsimd_quantize_neon
     .unreq          CORRECTION
     .unreq          SHIFT
     .unreq          LOOP_COUNT
-.endfunc
 
 
 /*****************************************************************************/
@@ -2401,7 +2390,6 @@ asm_function jsimd_h2v1_fancy_upsample_neon
     .unreq          WIDTH
     .unreq          TMP
 
-.endfunc
 
 .purgem upsample16
 .purgem upsample32
index b379656..c65e008 100644 (file)
@@ -34,7 +34,7 @@ void vp9_set_mb_mi(VP9_COMMON *cm, int width, int height) {
 
   cm->mi_cols = aligned_width >> MI_SIZE_LOG2;
   cm->mi_rows = aligned_height >> MI_SIZE_LOG2;
-  cm->mi_stride = cm->mi_cols + MI_BLOCK_SIZE;
+  cm->mi_stride = calc_mi_size(cm->mi_cols);
 
   cm->mb_cols = (cm->mi_cols + 1) >> 1;
   cm->mb_rows = (cm->mi_rows + 1) >> 1;
@@ -60,16 +60,18 @@ static int alloc_mi(VP9_COMMON *cm, int mi_size) {
 
   for (i = 0; i < 2; ++i) {
     cm->mip_array[i] =
-        (MODE_INFO *)vpx_calloc(mi_size, sizeof(*cm->mip));
+        (MODE_INFO *)vpx_calloc(mi_size, sizeof(MODE_INFO));
     if (cm->mip_array[i] == NULL)
       return 1;
 
     cm->mi_grid_base_array[i] =
-        (MODE_INFO **)vpx_calloc(mi_size, sizeof(*cm->mi_grid_base));
+        (MODE_INFO **)vpx_calloc(mi_size, sizeof(MODE_INFO*));
     if (cm->mi_grid_base_array[i] == NULL)
       return 1;
   }
 
+  cm->mi_alloc_size = mi_size;
+
   // Init the index.
   cm->mi_idx = 0;
   cm->prev_mi_idx = 1;
@@ -131,7 +133,8 @@ int vp9_alloc_context_buffers(VP9_COMMON *cm, int width, int height) {
   vp9_free_context_buffers(cm);
 
   vp9_set_mb_mi(cm, width, height);
-  if (alloc_mi(cm, cm->mi_stride * (cm->mi_rows + MI_BLOCK_SIZE))) goto fail;
+  if (alloc_mi(cm, cm->mi_stride * calc_mi_size(cm->mi_rows)))
+    goto fail;
 
   cm->last_frame_seg_map = (uint8_t *)vpx_calloc(cm->mi_rows * cm->mi_cols, 1);
   if (!cm->last_frame_seg_map) goto fail;
index 97b267c..5a43a8b 100644 (file)
@@ -137,6 +137,7 @@ typedef struct VP9Common {
 
   int mi_idx;
   int prev_mi_idx;
+  int mi_alloc_size;
   MODE_INFO *mip_array[2];
   MODE_INFO **mi_grid_base_array[2];
 
@@ -271,6 +272,11 @@ static INLINE void set_skip_context(MACROBLOCKD *xd, int mi_row, int mi_col) {
   }
 }
 
+static INLINE int calc_mi_size(int len) {
+  // len is in mi units.
+  return len + MI_BLOCK_SIZE;
+}
+
 static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
                                   int mi_row, int bh,
                                   int mi_col, int bw,
index 28c674a..debe22d 100644 (file)
@@ -627,12 +627,16 @@ static void resize_context_buffers(VP9_COMMON *cm, int width, int height) {
                        "Width and height beyond allowed size.");
 #endif
   if (cm->width != width || cm->height != height) {
+    const int aligned_width = ALIGN_POWER_OF_TWO(width, MI_SIZE_LOG2);
+    const int aligned_height = ALIGN_POWER_OF_TWO(height, MI_SIZE_LOG2);
+
     // Change in frame size (assumption: color format does not change).
     if (cm->width == 0 || cm->height == 0 ||
-        width * height > cm->width * cm->height) {
+        aligned_width > cm->width ||
+        aligned_width * aligned_height > cm->width * cm->height) {
       if (vp9_alloc_context_buffers(cm, width, height))
         vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
-                           "Failed to allocate frame buffers");
+                           "Failed to allocate context buffers");
     } else {
       vp9_set_mb_mi(cm, width, height);
     }
index 841b465..f9996c7 100644 (file)
@@ -423,11 +423,13 @@ static void write_modes_sb(VP9_COMP *cpi,
   const int bs = (1 << bsl) / 4;
   PARTITION_TYPE partition;
   BLOCK_SIZE subsize;
-  MODE_INFO *m = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col];
+  const MODE_INFO *m = NULL;
 
   if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols)
     return;
 
+  m = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col];
+
   partition = partition_lookup[bsl][m->mbmi.sb_type];
   write_partition(cm, xd, bs, mi_row, mi_col, partition, bsize, w);
   subsize = get_subsize(bsize, partition);
index 1868e65..8cdd1d9 100644 (file)
@@ -41,14 +41,9 @@ SkCanvas::SaveLayerStrategy SkBBoxHierarchyRecord::willSaveLayer(const SkRect* b
          (NULL != paint->getColorFilter()));
     SkRect drawBounds;
     if (paintAffectsTransparentBlack) {
-        if (bounds) {
-            drawBounds = *bounds;
-            this->getTotalMatrix().mapRect(&drawBounds);
-        } else {
-            SkIRect deviceBounds;
-            this->getClipDeviceBounds(&deviceBounds);
-            drawBounds.set(deviceBounds);
-        }
+        SkIRect deviceBounds;
+        this->getClipDeviceBounds(&deviceBounds);
+        drawBounds.set(deviceBounds);
     }
     fStateTree->appendSaveLayer(this->writeStream().bytesWritten());
     SkCanvas::SaveLayerStrategy strategy = this->INHERITED::willSaveLayer(bounds, paint, flags);
index 5e0ac7e..4290bb8 100644 (file)
@@ -32,6 +32,7 @@ struct SkGlyph {
     void*       fDistanceField;
     uint8_t     fMaskFormat;
     int8_t      fRsbDelta, fLsbDelta;  // used by auto-kerning
+    int8_t      fForceBW;
 
     void init(uint32_t id) {
         fID             = id;
@@ -39,6 +40,7 @@ struct SkGlyph {
         fPath           = NULL;
         fDistanceField  = NULL;
         fMaskFormat     = MASK_FORMAT_UNKNOWN;
+        fForceBW        = 0;
     }
 
     /**
index b138c32..1e4ae79 100644 (file)
@@ -424,7 +424,8 @@ void SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2,
     bool    degenerateBC = SkPath::IsLineDegenerate(pt1, pt2);
     bool    degenerateCD = SkPath::IsLineDegenerate(pt2, pt3);
 
-    if (degenerateAB + degenerateBC + degenerateCD >= 2) {
+    if (degenerateAB + degenerateBC + degenerateCD >= 2
+            || (degenerateAB && SkPath::IsLineDegenerate(fPrevPt, pt2))) {
         this->lineTo(pt3);
         return;
     }
index e4dd62a..467fab3 100644 (file)
@@ -57,6 +57,21 @@ SkOpSegment* SkOpContour::nonVerticalSegment(int* start, int* end) {
     return NULL;
 }
 
+// if one is very large the smaller may have collapsed to nothing
+static void bump_out_close_span(double* startTPtr, double* endTPtr) {
+    double startT = *startTPtr;
+    double endT = *endTPtr;
+    if (approximately_negative(endT - startT)) {
+        if (endT <= 1 - FLT_EPSILON) {
+            *endTPtr += FLT_EPSILON;
+            SkASSERT(*endTPtr <= 1);
+        } else {
+            *startTPtr -= FLT_EPSILON;
+            SkASSERT(*startTPtr >= 0);
+        }
+    }
+}
+
 // first pass, add missing T values
 // second pass, determine winding values of overlaps
 void SkOpContour::addCoincidentPoints() {
@@ -82,15 +97,7 @@ void SkOpContour::addCoincidentPoints() {
         if ((cancelers = startSwapped = startT > endT)) {
             SkTSwap(startT, endT);
         }
-        if (startT == endT) { // if one is very large the smaller may have collapsed to nothing
-            if (endT <= 1 - FLT_EPSILON) {
-                endT += FLT_EPSILON;
-                SkASSERT(endT <= 1);
-            } else {
-                startT -= FLT_EPSILON;
-                SkASSERT(startT >= 0);
-            }
-        }
+        bump_out_close_span(&startT, &endT);
         SkASSERT(!approximately_negative(endT - startT));
         double oStartT = coincidence.fTs[1][0];
         double oEndT = coincidence.fTs[1][1];
@@ -98,6 +105,7 @@ void SkOpContour::addCoincidentPoints() {
             SkTSwap(oStartT, oEndT);
             cancelers ^= true;
         }
+        bump_out_close_span(&oStartT, &oEndT);
         SkASSERT(!approximately_negative(oEndT - oStartT));
         const SkPoint& startPt = coincidence.fPts[0][startSwapped];
         if (cancelers) {
@@ -559,15 +567,7 @@ void SkOpContour::calcCommonCoincidentWinding(const SkCoincidence& coincidence)
         SkTSwap<double>(startT, endT);
         SkTSwap<const SkPoint*>(startPt, endPt);
     }
-    if (startT == endT) { // if span is very large, the smaller may have collapsed to nothing
-        if (endT <= 1 - FLT_EPSILON) {
-            endT += FLT_EPSILON;
-            SkASSERT(endT <= 1);
-        } else {
-            startT -= FLT_EPSILON;
-            SkASSERT(startT >= 0);
-        }
-    }
+    bump_out_close_span(&startT, &endT);
     SkASSERT(!approximately_negative(endT - startT));
     double oStartT = coincidence.fTs[1][0];
     double oEndT = coincidence.fTs[1][1];
@@ -575,6 +575,7 @@ void SkOpContour::calcCommonCoincidentWinding(const SkCoincidence& coincidence)
         SkTSwap<double>(oStartT, oEndT);
         cancelers ^= true;
     }
+    bump_out_close_span(&oStartT, &oEndT);
     SkASSERT(!approximately_negative(oEndT - oStartT));
     if (cancelers) {
         thisOne.addTCancel(*startPt, *endPt, &other);
index 747cd9d..336ac11 100644 (file)
@@ -1293,7 +1293,8 @@ void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
     double testT = test->fT;
     SkOpSpan* oTest = &other->fTs[oIndex];
     const SkPoint* oTestPt = &oTest->fPt;
-    SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
+    // paths with extreme data will fail this test and eject out of pathops altogether later on
+    // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
     do {
         SkASSERT(test->fT < 1);
         SkASSERT(oTest->fT < 1);
@@ -1476,6 +1477,9 @@ bool SkOpSegment::calcAngles() {
     const SkOpSpan* span = &fTs[0];
     if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther->multipleEnds()) {
         index = findStartSpan(0);  // curve start intersects
+        if (fTs[index].fT == 0) {
+            return false;
+        }
         SkASSERT(index > 0);
         if (activePrior >= 0) {
             addStartSpan(index);
index f27497b..33ef0d5 100644 (file)
@@ -398,11 +398,11 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
     glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
 }
 
-void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
-    glyph->fWidth = 0;
-
-    this->generateAdvance(glyph);
-
+HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
+                                           DWRITE_RENDERING_MODE renderingMode,
+                                           DWRITE_TEXTURE_TYPE textureType,
+                                           RECT* bbox)
+{
     //Measure raster size.
     fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
     fXform.dy = SkFixedToFloat(glyph->getSubYFixed());
@@ -426,25 +426,70 @@ void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
     run.glyphOffsets = &offset;
 
     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
-    HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis(
-             &run,
-             1.0f, // pixelsPerDip,
-             &fXform,
-             fRenderingMode,
-             fMeasuringMode,
-             0.0f, // baselineOriginX,
-             0.0f, // baselineOriginY,
-             &glyphRunAnalysis),
-         "Could not create glyph run analysis.");
-
-    RECT bbox;
-    HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox),
-         "Could not get texture bounds.");
+    HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
+            &run,
+            1.0f, // pixelsPerDip,
+            &fXform,
+            renderingMode,
+            fMeasuringMode,
+            0.0f, // baselineOriginX,
+            0.0f, // baselineOriginY,
+            &glyphRunAnalysis),
+        "Could not create glyph run analysis.");
+
+    HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
+        "Could not get texture bounds.");
+
+    return S_OK;
+}
 
+/** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
+ *  { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
+ *  for small, but not quite zero, sized glyphs.
+ *  Only set as non-empty if the returned bounds are non-empty.
+ */
+static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
+    if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
+        return false;
+    }
     glyph->fWidth = SkToU16(bbox.right - bbox.left);
     glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
     glyph->fLeft = SkToS16(bbox.left);
     glyph->fTop = SkToS16(bbox.top);
+    return true;
+}
+
+void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
+    glyph->fWidth = 0;
+    glyph->fHeight = 0;
+    glyph->fLeft = 0;
+    glyph->fTop = 0;
+
+    this->generateAdvance(glyph);
+
+    RECT bbox;
+    HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
+         "Requested bounding box could not be determined.");
+
+    if (glyph_check_and_set_bounds(glyph, bbox)) {
+        return;
+    }
+
+    // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
+    // glyphs of the specified texture type. When this happens, try with the
+    // alternate texture type.
+    if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
+        HRVM(this->getBoundingBox(glyph,
+                                  DWRITE_RENDERING_MODE_ALIASED,
+                                  DWRITE_TEXTURE_ALIASED_1x1,
+                                  &bbox),
+             "Fallback bounding box could not be determined.");
+        if (glyph_check_and_set_bounds(glyph, bbox)) {
+            glyph->fForceBW = 1;
+        }
+    }
+    // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
+    // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
 }
 
 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* metrics) {
@@ -602,9 +647,12 @@ static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
     }
 }
 
-const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
+const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph,
+                                           DWRITE_RENDERING_MODE renderingMode,
+                                           DWRITE_TEXTURE_TYPE textureType)
+{
     int sizeNeeded = glyph.fWidth * glyph.fHeight;
-    if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) {
+    if (DWRITE_RENDERING_MODE_ALIASED != renderingMode) {
         sizeNeeded *= 3;
     }
     if (sizeNeeded > fBits.count()) {
@@ -639,7 +687,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
     HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run,
                                           1.0f, // pixelsPerDip,
                                           &fXform,
-                                          fRenderingMode,
+                                          renderingMode,
                                           fMeasuringMode,
                                           0.0f, // baselineOriginX,
                                           0.0f, // baselineOriginY,
@@ -653,7 +701,7 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
     bbox.top = glyph.fTop;
     bbox.right = glyph.fLeft + glyph.fWidth;
     bbox.bottom = glyph.fTop + glyph.fHeight;
-    HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType,
+    HRNM(glyphRunAnalysis->CreateAlphaTexture(textureType,
                                               &bbox,
                                               fBits.begin(),
                                               sizeNeeded),
@@ -663,7 +711,13 @@ const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) {
 
 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
     //Create the mask.
-    const void* bits = this->drawDWMask(glyph);
+    DWRITE_RENDERING_MODE renderingMode = fRenderingMode;
+    DWRITE_TEXTURE_TYPE textureType = fTextureType;
+    if (glyph.fForceBW) {
+        renderingMode = DWRITE_RENDERING_MODE_ALIASED;
+        textureType = DWRITE_TEXTURE_ALIASED_1x1;
+    }
+    const void* bits = this->drawDWMask(glyph, renderingMode, textureType);
     if (!bits) {
         sk_bzero(glyph.fImage, glyph.computeImageSize());
         return;
@@ -671,7 +725,7 @@ void SkScalerContext_DW::generateImage(const SkGlyph& glyph) {
 
     //Copy the mask into the glyph.
     const uint8_t* src = (const uint8_t*)bits;
-    if (DWRITE_RENDERING_MODE_ALIASED == fRenderingMode) {
+    if (DWRITE_RENDERING_MODE_ALIASED == renderingMode) {
         bilevel_to_bw(src, glyph);
         const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format;
     } else if (!isLCD(fRec)) {
index e8eff0d..0bd79e7 100644 (file)
@@ -33,7 +33,14 @@ protected:
     virtual void generateFontMetrics(SkPaint::FontMetrics*) SK_OVERRIDE;
 
 private:
-    const void* drawDWMask(const SkGlyph& glyph);
+    const void* drawDWMask(const SkGlyph& glyph,
+                           DWRITE_RENDERING_MODE renderingMode,
+                           DWRITE_TEXTURE_TYPE textureType);
+
+    HRESULT getBoundingBox(SkGlyph* glyph,
+                           DWRITE_RENDERING_MODE renderingMode,
+                           DWRITE_TEXTURE_TYPE textureType,
+                           RECT* bbox);
 
     SkTDArray<uint8_t> fBits;
     /** The total matrix without the text height scale. */
index 4ee9f5d..9f6144b 100644 (file)
@@ -408,6 +408,54 @@ DEF_TEST(ImageFilterDrawTiled, reporter) {
     }
 }
 
+static void drawSaveLayerPicture(int width, int height, int tileSize, SkBBHFactory* factory, SkBitmap* result) {
+
+    SkMatrix matrix;
+    matrix.setTranslate(SkIntToScalar(50), 0);
+
+    SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
+    SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf.get()));
+    SkAutoTUnref<SkImageFilter> imageFilter(SkMatrixImageFilter::Create(matrix, SkPaint::kNone_FilterLevel, cfif.get()));
+
+    SkPaint paint;
+    paint.setImageFilter(imageFilter.get());
+    SkPictureRecorder recorder;
+    SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
+    SkCanvas* recordingCanvas = recorder.beginRecording(width, height, factory, 0);
+    recordingCanvas->translate(-55, 0);
+    recordingCanvas->saveLayer(&bounds, &paint);
+    recordingCanvas->restore();
+    SkAutoTUnref<SkPicture> picture1(recorder.endRecording());
+
+    result->allocN32Pixels(width, height);
+    SkCanvas canvas(*result);
+    canvas.clear(0);
+    canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
+    canvas.drawPicture(picture1.get());
+}
+
+DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
+    // Check that matrix filter when drawn tiled with BBH exactly
+    // matches the same thing drawn without BBH.
+    // Tests pass by not asserting.
+
+    const int width = 200, height = 200;
+    const int tileSize = 100;
+    SkBitmap result1, result2;
+    SkRTreeFactory factory;
+
+    drawSaveLayerPicture(width, height, tileSize, &factory, &result1);
+    drawSaveLayerPicture(width, height, tileSize, NULL, &result2);
+
+    for (int y = 0; y < height; y++) {
+        int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
+        REPORTER_ASSERT(reporter, !diffs);
+        if (diffs) {
+            break;
+        }
+    }
+}
+
 static void drawBlurredRect(SkCanvas* canvas) {
     SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
     SkPaint filterPaint;
index 2c67449..866b5b2 100644 (file)
@@ -3771,7 +3771,52 @@ static void bufferOverflow(skiatest::Reporter* reporter, const char* filename) {
     testPathFailOp(reporter, path, pathB, kUnion_PathOp, filename);
 }
 
+// m 100,0 60,170 -160,-110 200,0 -170,11000000000 z
+static void fuzz433(skiatest::Reporter* reporter, const char* filename) {
+    SkPath path1, path2;
+    path1.moveTo(100,0);
+    path1.lineTo(60,170);
+    path1.lineTo(-160,-110);
+    path1.lineTo(200,0);
+    path1.lineTo(-170,11000000000.0f);
+    path1.close();
+
+    path2.moveTo(100 + 20,0 + 20);
+    path2.lineTo(60 + 20,170 + 20);
+    path2.lineTo(-160 + 20,-110 + 20);
+    path2.lineTo(200 + 20,0 + 20);
+    path2.lineTo(-170 + 20,11000000000.0f + 20);
+    path2.close();
+
+    testPathFailOp(reporter, path1, path2, kIntersect_PathOp, filename);
+}
+
+static void fuzz433b(skiatest::Reporter* reporter, const char* filename) {
+    SkPath path1, path2;
+    path1.setFillType(SkPath::kEvenOdd_FillType);
+    path1.moveTo(140, 40);
+    path1.lineTo(200, 210);
+    path1.lineTo(40, 100);
+    path1.lineTo(240, 100);
+    path1.lineTo(70, 1.1e+10f);
+    path1.lineTo(140, 40);
+    path1.close();
+
+    path1.setFillType(SkPath::kWinding_FillType);
+    path2.moveTo(190, 60);
+    path2.lineTo(250, 230);
+    path2.lineTo(90, 120);
+    path2.lineTo(290, 120);
+    path2.lineTo(120, 1.1e+10f);
+    path2.lineTo(190, 60);
+    path2.close();
+
+    testPathFailOp(reporter, path1, path2, kUnion_PathOp, filename);
+}
+
 static struct TestDesc failTests[] = {
+    TEST(fuzz433b),
+    TEST(fuzz433),
     TEST(bufferOverflow),
 };
 
index 3941ad6..0de64b0 100644 (file)
@@ -64,6 +64,32 @@ static void test_path_crbug364224() {
     canvas->drawPath(path, paint);
 }
 
+/**
+ * In debug mode, this path was causing an assertion to fail in
+ * SkPathStroker::preJoinTo() and, in Release, the use of an unitialized value.
+ */
+static void make_path_crbugskia2820(SkPath* path, skiatest::Reporter* reporter) {
+    SkPoint orig, p1, p2, p3;
+    orig = SkPoint::Make(1.f, 1.f);
+    p1 = SkPoint::Make(1.f - SK_ScalarNearlyZero, 1.f);
+    p2 = SkPoint::Make(1.f, 1.f + SK_ScalarNearlyZero);
+    p3 = SkPoint::Make(2.f, 2.f);
+
+    path->reset();
+    path->moveTo(orig);
+    path->cubicTo(p1, p2, p3);
+    path->close();
+}
+
+static void test_path_crbugskia2820(skiatest::Reporter* reporter) {//GrContext* context) {
+    SkPath path;
+    make_path_crbugskia2820(&path, reporter);
+
+    SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
+    stroke.setStrokeStyle(2 * SK_Scalar1);
+    stroke.applyToPath(&path, path);
+}
+
 static void make_path0(SkPath* path) {
     // from  *  https://code.google.com/p/skia/issues/detail?id=1706
 
@@ -3553,4 +3579,5 @@ DEF_TEST(Paths, reporter) {
     PathTest_Private::TestPathTo(reporter);
     PathRefTest_Private::TestPathRef(reporter);
     test_dump(reporter);
+    test_path_crbugskia2820(reporter);
 }
index fa9a549..d9a5016 100644 (file)
@@ -10818,6 +10818,14 @@ Therefore, the affected-histogram name has to have at least one dot in it.
   </summary>
 </histogram>
 
+<histogram name="Media.AudioRendererAudioGlitches" enum="AudioGlitchResult">
+  <owner>henrika@chromium.org</owner>
+  <summary>
+    Captures if render-side audio glitches are detected or not. Sampled when a
+    low-latency output audio stream is destructed.
+  </summary>
+</histogram>
+
 <histogram name="Media.AudioRendererEvents" enum="AudioRendererEvents">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>Captures statistics for various AudioRendererImpl events.</summary>
@@ -37298,6 +37306,11 @@ Therefore, the affected-histogram name has to have at least one dot in it.
   <int value="8" label="k1920"/>
 </enum>
 
+<enum name="AudioGlitchResult" type="int">
+  <int value="0" label="No audio glitches"/>
+  <int value="1" label="Audio glitches"/>
+</enum>
+
 <enum name="AudioInputSilenceReport" type="int">
   <int value="0" label="No measurement"/>
   <int value="1" label="Only audio"/>
@@ -40818,6 +40831,9 @@ Therefore, the affected-histogram name has to have at least one dot in it.
   <int value="880" label="EASYUNLOCKPRIVATE_CLEARPERMITACCESS"/>
   <int value="881" label="EASYUNLOCKPRIVATE_SETREMOTEDEVICES"/>
   <int value="882" label="EASYUNLOCKPRIVATE_GETREMOTEDEVICES"/>
+  <int value="883" label="FILESYSTEMPROVIDER_GETALL"/>
+  <int value="884"
+      label="EASYUNLOCKPRIVATE_CONNECTTOBLUETOOTHSERVICEINSECURELY"/>
 </enum>
 
 <enum name="ExtensionInstallCause" type="int">
@@ -47559,6 +47575,7 @@ To add a new entry, add it with any value and run test to compute valid value.
   <int value="1" label="Add new user from title bar menu"/>
   <int value="2" label="Add new user from settings dialog"/>
   <int value="3" label="Add new user from the User Manager"/>
+  <int value="4" label="Auto-created after deleting last user"/>
 </enum>
 
 <enum name="ProfileAndroidAccountManagementMenu" type="int">
@@ -48750,6 +48767,7 @@ To add a new entry, add it with any value and run test to compute valid value.
   <int value="8" label="SERVICE_UTILITY_SEMANTIC_CAPS_REQUEST"/>
   <int value="9" label="SERVICE_UTILITY_SEMANTIC_CAPS_SUCCEEDED"/>
   <int value="10" label="SERVICE_UTILITY_SEMANTIC_CAPS_FAILED"/>
+  <int value="11" label="SERVICE_UTILITY_FAILED_TO_START"/>
 </enum>
 
 <enum name="ServiceWorkerDatabaseStatus" type="int">
@@ -51465,6 +51483,7 @@ To add a new entry, add it with any value and run test to compute valid value.
   <suffix name="SSL" label="Bypass due to SSL"/>
   <suffix name="LocalBypassRules"
       label="Bypass due to client-side bypass rules"/>
+  <suffix name="ManagedProxyConfig" label="Bypass due to a managed config"/>
   <suffix name="Current" label="Bypass due to explicit instruction"/>
   <suffix name="ShortAll" label="Short bypass"/>
   <suffix name="ShortTriggeringRequest"
index 7d9d8a6..af8f87b 100644 (file)
@@ -24,6 +24,8 @@ public class VSyncMonitor {
     private static final long NANOSECONDS_PER_MILLISECOND = 1000000;
     private static final long NANOSECONDS_PER_MICROSECOND = 1000;
 
+    private boolean mInsideVSync = false;
+
     /**
      * VSync listener class
      */
@@ -150,16 +152,32 @@ public class VSyncMonitor {
         mGoodStartingPointNano = goodStartingPointNano;
     }
 
+    /**
+     * @return true if onVSync handler is executing. If onVSync handler
+     * introduces invalidations, View#invalidate() should be called. If
+     * View#postInvalidateOnAnimation is called instead, the corresponding onDraw
+     * will be delayed by one frame. The embedder of VSyncMonitor should check
+     * this value if it wants to post an invalidation.
+     */
+    public boolean isInsideVSync() {
+        return mInsideVSync;
+    }
+
     private long getCurrentNanoTime() {
         return System.nanoTime();
     }
 
     private void onVSyncCallback(long frameTimeNanos, long currentTimeNanos) {
         assert mHaveRequestInFlight;
+        mInsideVSync = true;
         mHaveRequestInFlight = false;
         mLastVSyncCpuTimeNano = currentTimeNanos;
-        if (mListener != null) {
-            mListener.onVSync(this, frameTimeNanos / NANOSECONDS_PER_MICROSECOND);
+        try {
+            if (mListener != null) {
+                mListener.onVSync(this, frameTimeNanos / NANOSECONDS_PER_MICROSECOND);
+            }
+        } finally {
+            mInsideVSync = false;
         }
     }
 
index 05186eb..180b493 100644 (file)
@@ -8,13 +8,14 @@ import android.annotation.TargetApi;
 import android.app.Activity;
 import android.content.ClipData;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Build;
-import android.os.Environment;
 import android.provider.MediaStore;
 import android.text.TextUtils;
+import android.util.Log;
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.ContentUriUtils;
@@ -22,6 +23,7 @@ import org.chromium.base.JNINamespace;
 import org.chromium.ui.R;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -32,6 +34,7 @@ import java.util.List;
  */
 @JNINamespace("ui")
 class SelectFileDialog implements WindowAndroid.IntentCallback{
+    private static final String TAG = "SelectFileDialog";
     private static final String IMAGE_TYPE = "image/";
     private static final String VIDEO_TYPE = "video/";
     private static final String AUDIO_TYPE = "audio/";
@@ -40,6 +43,8 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
     private static final String ALL_AUDIO_TYPES = AUDIO_TYPE + "*";
     private static final String ANY_TYPES = "*/*";
     private static final String CAPTURE_IMAGE_DIRECTORY = "browser-photos";
+    // Keep this variable in sync with the value defined in file_paths.xml.
+    private static final String IMAGE_FILE_PATH = "images";
 
     private final long mNativeSelectFileDialog;
     private List<String> mFileTypes;
@@ -66,8 +71,23 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
 
         Intent chooser = new Intent(Intent.ACTION_CHOOSER);
         Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
-        mCameraOutputUri = Uri.fromFile(getFileForImageCapture());
+        camera.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
+                Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        Context context = window.getApplicationContext();
+        try {
+            mCameraOutputUri = ContentUriUtils.getContentUriFromFile(
+                    context, getFileForImageCapture(context));
+        } catch (IOException e) {
+            Log.e(TAG, "Cannot retrieve content uri from file", e);
+        }
+        if (mCameraOutputUri == null) {
+            onFileNotSelected();
+            return;
+        }
+
         camera.putExtra(MediaStore.EXTRA_OUTPUT, mCameraOutputUri);
+        camera.setClipData(
+                ClipData.newUri(context.getContentResolver(), IMAGE_FILE_PATH, mCameraOutputUri));
         Intent camcorder = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
         Intent soundRecorder = new Intent(
                 MediaStore.Audio.Media.RECORD_SOUND_ACTION);
@@ -125,18 +145,16 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
     }
 
     /**
-     * Get a file for the image capture in the CAPTURE_IMAGE_DIRECTORY directory.
+     * Get a file for the image capture in the IMAGE_FILE_PATH directory.
+     * @param context The application context.
      */
-    private File getFileForImageCapture() {
-        File externalDataDir = Environment.getExternalStoragePublicDirectory(
-                Environment.DIRECTORY_DCIM);
-        File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
-                File.separator + CAPTURE_IMAGE_DIRECTORY);
-        if (!cameraDataDir.exists() && !cameraDataDir.mkdirs()) {
-            cameraDataDir = externalDataDir;
+    private File getFileForImageCapture(Context context) throws IOException {
+        final File path = new File(context.getFilesDir(), IMAGE_FILE_PATH);
+        if (!path.exists() && !path.mkdir()) {
+            throw new IOException("Folder cannot be created.");
         }
-        File photoFile = new File(cameraDataDir.getAbsolutePath() +
-                File.separator + System.currentTimeMillis() + ".jpg");
+        File photoFile = File.createTempFile(
+                String.valueOf(System.currentTimeMillis()), ".jpg", path);
         return photoFile;
     }
 
@@ -160,7 +178,8 @@ class SelectFileDialog implements WindowAndroid.IntentCallback{
         if (results == null) {
             // If we have a successful return but no data, then assume this is the camera returning
             // the photo that we requested.
-            nativeOnFileSelected(mNativeSelectFileDialog, mCameraOutputUri.getPath(), "");
+            nativeOnFileSelected(mNativeSelectFileDialog, mCameraOutputUri.toString(),
+                    mCameraOutputUri.getLastPathSegment());
 
             // Broadcast to the media scanner that there's a new photo on the device so it will
             // show up right away in the gallery (rather than waiting until the next time the media
index 424b566..6d3f3a6 100644 (file)
@@ -57,6 +57,14 @@ public class WindowAndroid {
     };
 
     /**
+     * @return true if onVSync handler is executing.
+     * @see org.chromium.ui.VSyncMonitor#isInsideVSync().
+     */
+    public boolean isInsideVSync() {
+        return mVSyncMonitor.isInsideVSync();
+    }
+
+    /**
      * @param context The application context.
      */
     @SuppressLint("UseSparseArrays")
index 55c4d04..8c7df57 100644 (file)
@@ -311,6 +311,11 @@ std::string GetCanonicalLocale(const std::string& locale) {
   return base::i18n::GetCanonicalLocale(locale.c_str());
 }
 
+std::string GetLanguage(const std::string& locale) {
+  const std::string::size_type hyphen_pos = locale.find('-');
+  return std::string(locale, 0, hyphen_pos);
+}
+
 bool CheckAndResolveLocale(const std::string& locale,
                            std::string* resolved_locale) {
 #if defined(OS_MACOSX)
@@ -397,7 +402,7 @@ bool CheckAndResolveLocale(const std::string& locale,
 #endif
 }
 
-std::string GetApplicationLocale(const std::string& pref_locale) {
+std::string GetApplicationLocaleInternal(const std::string& pref_locale) {
 #if defined(OS_MACOSX)
 
   // Use any override (Cocoa for the browser), otherwise use the preference
@@ -411,12 +416,6 @@ std::string GetApplicationLocale(const std::string& pref_locale) {
   if (app_locale.empty())
     app_locale = "en-US";
 
-  // Windows/Linux call SetICUDefaultLocale after determining the actual locale
-  // with CheckAndResolveLocal to make ICU APIs work in that locale.
-  // Mac doesn't use a locale directory tree of resources (it uses Mac style
-  // resources), so mirror the Windows/Linux behavior of calling
-  // SetICUDefaultLocale.
-  base::i18n::SetICUDefaultLocale(app_locale);
   return app_locale;
 
 #else
@@ -478,7 +477,6 @@ std::string GetApplicationLocale(const std::string& pref_locale) {
   std::vector<std::string>::const_iterator i = candidates.begin();
   for (; i != candidates.end(); ++i) {
     if (CheckAndResolveLocale(*i, &resolved_locale)) {
-      base::i18n::SetICUDefaultLocale(resolved_locale);
       return resolved_locale;
     }
   }
@@ -486,7 +484,6 @@ std::string GetApplicationLocale(const std::string& pref_locale) {
   // Fallback on en-US.
   const std::string fallback_locale("en-US");
   if (IsLocaleAvailable(fallback_locale)) {
-    base::i18n::SetICUDefaultLocale(fallback_locale);
     return fallback_locale;
   }
 
@@ -495,6 +492,18 @@ std::string GetApplicationLocale(const std::string& pref_locale) {
 #endif
 }
 
+std::string GetApplicationLocale(const std::string& pref_locale,
+                                 bool set_icu_locale) {
+  const std::string locale = GetApplicationLocaleInternal(pref_locale);
+  if (set_icu_locale && !locale.empty())
+    base::i18n::SetICUDefaultLocale(locale);
+  return locale;
+}
+
+std::string GetApplicationLocale(const std::string& pref_locale) {
+  return GetApplicationLocale(pref_locale, true /* set_icu_locale */);
+}
+
 bool IsLocaleNameTranslated(const char* locale,
                             const std::string& display_locale) {
   base::string16 display_name =
index a71240c..e4ea9ee 100644 (file)
@@ -24,6 +24,9 @@ namespace l10n_util {
 // std::string as an argument.
 UI_BASE_EXPORT std::string GetCanonicalLocale(const std::string& locale);
 
+// Takes normalized locale as |locale|. Returns language part (before '-').
+UI_BASE_EXPORT std::string GetLanguage(const std::string& locale);
+
 // This method translates a generic locale name to one of the locally defined
 // ones. This method returns true if it succeeds.
 UI_BASE_EXPORT bool CheckAndResolveLocale(const std::string& locale,
@@ -37,7 +40,13 @@ UI_BASE_EXPORT bool CheckAndResolveLocale(const std::string& locale,
 // command line (--lang), second we try the value in the prefs file (passed in
 // as |pref_locale|), finally, we fall back on the system locale. We only return
 // a value if there's a corresponding resource DLL for the locale.  Otherwise,
-// we fall back to en-us.
+// we fall back to en-us. |set_icu_locale| determines whether the resulting
+// locale is set as the default ICU locale before returning it.
+UI_BASE_EXPORT std::string GetApplicationLocale(const std::string& pref_locale,
+                                                bool set_icu_locale);
+
+// Convenience version of GetApplicationLocale() that sets the resulting locale
+// as the default ICU locale before returning it.
 UI_BASE_EXPORT std::string GetApplicationLocale(const std::string& pref_locale);
 
 // Returns true if a display name for |locale| is available in the locale
index 9e2ae4d..972dd26 100644 (file)
@@ -141,12 +141,15 @@ TEST_F(L10nUtilTest, GetAppLocale) {
     base::i18n::SetICUDefaultLocale("en-US");
     env->SetVar("LANGUAGE", "xx:fr_CA");
     EXPECT_EQ("fr", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("fr", icu::Locale::getDefault().getLanguage());
 
     env->SetVar("LANGUAGE", "xx:yy:en_gb.utf-8@quot");
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     env->SetVar("LANGUAGE", "xx:zh-hk");
     EXPECT_EQ("zh-TW", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("zh", icu::Locale::getDefault().getLanguage());
 
     // We emulate gettext's behavior here, which ignores LANG/LC_MESSAGES/LC_ALL
     // when LANGUAGE is specified. If no language specified in LANGUAGE is
@@ -155,9 +158,11 @@ TEST_F(L10nUtilTest, GetAppLocale) {
     base::i18n::SetICUDefaultLocale("fr-FR");
     env->SetVar("LANGUAGE", "xx:yy");
     EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     env->SetVar("LANGUAGE", "/fr:zh_CN");
     EXPECT_EQ("zh-CN", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("zh", icu::Locale::getDefault().getLanguage());
 
     // Test prioritization of the different environment variables.
     env->SetVar("LANGUAGE", "fr");
@@ -165,35 +170,46 @@ TEST_F(L10nUtilTest, GetAppLocale) {
     env->SetVar("LC_MESSAGES", "he");
     env->SetVar("LANG", "nb");
     EXPECT_EQ("fr", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("fr", icu::Locale::getDefault().getLanguage());
     env->UnSetVar("LANGUAGE");
     EXPECT_EQ("es", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("es", icu::Locale::getDefault().getLanguage());
     env->UnSetVar("LC_ALL");
     EXPECT_EQ("he", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("he", icu::Locale::getDefault().getLanguage());
     env->UnSetVar("LC_MESSAGES");
     EXPECT_EQ("nb", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("nb", icu::Locale::getDefault().getLanguage());
     env->UnSetVar("LANG");
 
     SetDefaultLocaleForTest("ca", env.get());
     EXPECT_EQ("ca", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("ca", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("ca-ES", env.get());
     EXPECT_EQ("ca", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("ca", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("ca@valencia", env.get());
     EXPECT_EQ("ca@valencia", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("ca", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("ca_ES@valencia", env.get());
     EXPECT_EQ("ca@valencia", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("ca", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("ca_ES.UTF8@valencia", env.get());
     EXPECT_EQ("ca@valencia", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("ca", icu::Locale::getDefault().getLanguage());
   }
 
   SetDefaultLocaleForTest("en-US", env.get());
   EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(std::string()));
+  EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
   SetDefaultLocaleForTest("xx", env.get());
   EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(std::string()));
+  EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
   if (!kPlatformHasDefaultLocale) {
     // ChromeOS & embedded use only browser prefs in GetApplicationLocale(),
@@ -201,88 +217,148 @@ TEST_F(L10nUtilTest, GetAppLocale) {
     // the default locale from the OS or environment.
     SetDefaultLocaleForTest("en-GB", env.get());
     EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(""));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("en-US", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-GB"));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("en-US", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-AU"));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("en-US", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-NZ"));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("en-US", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-CA"));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("en-US", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-ZA"));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
   } else {
     // Most platforms have an OS-provided locale. This locale is preferred.
     SetDefaultLocaleForTest("en-GB", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("fr-CA", env.get());
     EXPECT_EQ("fr", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("fr", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("es-MX", env.get());
     EXPECT_EQ("es-419", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("es", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("es-AR", env.get());
     EXPECT_EQ("es-419", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("es", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("es-ES", env.get());
     EXPECT_EQ("es", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("es", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("es", env.get());
     EXPECT_EQ("es", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("es", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("zh-HK", env.get());
     EXPECT_EQ("zh-TW", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("zh", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("zh-MO", env.get());
     EXPECT_EQ("zh-TW", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("zh", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("zh-SG", env.get());
     EXPECT_EQ("zh-CN", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("zh", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("en-CA", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("en-AU", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("en-NZ", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
 
     SetDefaultLocaleForTest("en-ZA", env.get());
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string()));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
   }
 
+  SetDefaultLocaleForTest("en-US", env.get());
+
   if (kSupportsLocalePreference) {
     // On windows, the user can override the locale in preferences.
     base::i18n::SetICUDefaultLocale("en-US");
     EXPECT_EQ("fr", l10n_util::GetApplicationLocale("fr"));
+    EXPECT_STREQ("fr", icu::Locale::getDefault().getLanguage());
     EXPECT_EQ("fr", l10n_util::GetApplicationLocale("fr-CA"));
+    EXPECT_STREQ("fr", icu::Locale::getDefault().getLanguage());
 
     base::i18n::SetICUDefaultLocale("en-US");
     // Aliases iw, no, tl to he, nb, fil.
     EXPECT_EQ("he", l10n_util::GetApplicationLocale("iw"));
+    EXPECT_STREQ("he", icu::Locale::getDefault().getLanguage());
     EXPECT_EQ("nb", l10n_util::GetApplicationLocale("no"));
+    EXPECT_STREQ("nb", icu::Locale::getDefault().getLanguage());
     EXPECT_EQ("fil", l10n_util::GetApplicationLocale("tl"));
+    EXPECT_STREQ("fil", icu::Locale::getDefault().getLanguage());
     // es-419 and es-XX (where XX is not Spain) should be
     // mapped to es-419 (Latin American Spanish).
     EXPECT_EQ("es-419", l10n_util::GetApplicationLocale("es-419"));
+    EXPECT_STREQ("es", icu::Locale::getDefault().getLanguage());
     EXPECT_EQ("es", l10n_util::GetApplicationLocale("es-ES"));
+    EXPECT_STREQ("es", icu::Locale::getDefault().getLanguage());
     EXPECT_EQ("es-419", l10n_util::GetApplicationLocale("es-AR"));
+    EXPECT_STREQ("es", icu::Locale::getDefault().getLanguage());
 
     base::i18n::SetICUDefaultLocale("es-AR");
     EXPECT_EQ("es", l10n_util::GetApplicationLocale("es"));
+    EXPECT_STREQ("es", icu::Locale::getDefault().getLanguage());
 
     base::i18n::SetICUDefaultLocale("zh-HK");
     EXPECT_EQ("zh-CN", l10n_util::GetApplicationLocale("zh-CN"));
+    EXPECT_STREQ("zh", icu::Locale::getDefault().getLanguage());
 
     base::i18n::SetICUDefaultLocale("he");
     EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("en"));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
+
+    base::i18n::SetICUDefaultLocale("he");
+    EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("en", false));
+    EXPECT_STREQ("he", icu::Locale::getDefault().getLanguage());
+
+    base::i18n::SetICUDefaultLocale("de");
+    EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("xx", false));
+    EXPECT_STREQ("de", icu::Locale::getDefault().getLanguage());
+
+    base::i18n::SetICUDefaultLocale("de");
+    EXPECT_EQ("fr", l10n_util::GetApplicationLocale("fr", false));
+    EXPECT_STREQ("de", icu::Locale::getDefault().getLanguage());
+
+    base::i18n::SetICUDefaultLocale("de");
+    EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("en", false));
+    EXPECT_STREQ("de", icu::Locale::getDefault().getLanguage());
+
+    base::i18n::SetICUDefaultLocale("de");
+    EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("en-US", true));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
+  } else {
+    base::i18n::SetICUDefaultLocale("de");
+    EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(std::string(), false));
+    EXPECT_STREQ("de", icu::Locale::getDefault().getLanguage());
+
+    base::i18n::SetICUDefaultLocale("de");
+    EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(std::string(), true));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
   }
 
 #if defined(OS_WIN)
@@ -290,13 +366,17 @@ TEST_F(L10nUtilTest, GetAppLocale) {
   if (base::win::GetVersion() < base::win::VERSION_VISTA) {
     base::i18n::SetICUDefaultLocale("am");
     EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(""));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
     base::i18n::SetICUDefaultLocale("en-GB");
     EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("am"));
+    EXPECT_STREQ("en", icu::Locale::getDefault().getLanguage());
   } else {
     base::i18n::SetICUDefaultLocale("am");
     EXPECT_EQ("am", l10n_util::GetApplicationLocale(""));
+    EXPECT_STREQ("am", icu::Locale::getDefault().getLanguage());
     base::i18n::SetICUDefaultLocale("en-GB");
     EXPECT_EQ("am", l10n_util::GetApplicationLocale("am"));
+    EXPECT_STREQ("am", icu::Locale::getDefault().getLanguage());
   }
 #endif  // defined(OS_WIN)
 
index aa97a56..46cb977 100644 (file)
@@ -378,7 +378,7 @@ void Layer::SetLayerFilters() {
   }
   if (alpha_shape_) {
     filters.Append(cc::FilterOperation::CreateAlphaThresholdFilter(
-            *alpha_shape_, 1.f, 0.f));
+            *alpha_shape_, 0.f, 0.f));
   }
 
   cc_layer_->SetFilters(filters);
index 9cb80c4..97d15df 100644 (file)
@@ -839,6 +839,21 @@ TEST_F(LayerWithNullDelegateTest, SetBoundsSchedulesPaint) {
   WaitForDraw();
 }
 
+void ExpectRgba(int x, int y, SkColor expected_color, SkColor actual_color) {
+  EXPECT_EQ(expected_color, actual_color)
+      << "Pixel error at x=" << x << " y=" << y << "; "
+      << "actual RGBA=("
+      << SkColorGetR(actual_color) << ","
+      << SkColorGetG(actual_color) << ","
+      << SkColorGetB(actual_color) << ","
+      << SkColorGetA(actual_color) << "); "
+      << "expected RGBA=("
+      << SkColorGetR(expected_color) << ","
+      << SkColorGetG(expected_color) << ","
+      << SkColorGetB(expected_color) << ","
+      << SkColorGetA(expected_color) << ")";
+}
+
 // Checks that pixels are actually drawn to the screen with a read back.
 TEST_F(LayerWithRealCompositorTest, DrawPixels) {
   gfx::Size viewport_size = GetCompositor()->size();
@@ -869,18 +884,86 @@ TEST_F(LayerWithRealCompositorTest, DrawPixels) {
     for (int y = 0; y < viewport_size.height(); y++) {
       SkColor actual_color = bitmap.getColor(x, y);
       SkColor expected_color = y < blue_height ? SK_ColorBLUE : SK_ColorRED;
-      EXPECT_EQ(expected_color, actual_color)
-          << "Pixel error at x=" << x << " y=" << y << "; "
-          << "actual RGBA=("
-          << SkColorGetR(actual_color) << ","
-          << SkColorGetG(actual_color) << ","
-          << SkColorGetB(actual_color) << ","
-          << SkColorGetA(actual_color) << "); "
-          << "expected RGBA=("
-          << SkColorGetR(expected_color) << ","
-          << SkColorGetG(expected_color) << ","
-          << SkColorGetB(expected_color) << ","
-          << SkColorGetA(expected_color) << ")";
+      ExpectRgba(x, y, expected_color, actual_color);
+    }
+  }
+}
+
+// Checks that drawing a layer with transparent pixels is blended correctly
+// with the lower layer.
+TEST_F(LayerWithRealCompositorTest, DrawAlphaBlendedPixels) {
+  gfx::Size viewport_size = GetCompositor()->size();
+
+  int test_size = 200;
+  EXPECT_GE(viewport_size.width(), test_size);
+  EXPECT_GE(viewport_size.height(), test_size);
+
+  // Blue with a wee bit of transparency.
+  SkColor blue_with_alpha = SkColorSetARGBInline(40, 10, 20, 200);
+  SkColor blend_color = SkColorSetARGBInline(255, 216, 3, 32);
+
+  scoped_ptr<Layer> background_layer(
+      CreateColorLayer(SK_ColorRED, gfx::Rect(viewport_size)));
+  scoped_ptr<Layer> foreground_layer(
+      CreateColorLayer(blue_with_alpha, gfx::Rect(viewport_size)));
+
+  // This must be set to false for layers with alpha to be blended correctly.
+  foreground_layer->SetFillsBoundsOpaquely(false);
+
+  background_layer->Add(foreground_layer.get());
+  DrawTree(background_layer.get());
+
+  SkBitmap bitmap;
+  ASSERT_TRUE(ReadPixels(&bitmap, gfx::Rect(viewport_size)));
+  ASSERT_FALSE(bitmap.empty());
+
+  SkAutoLockPixels lock(bitmap);
+  for (int x = 0; x < test_size; x++) {
+    for (int y = 0; y < test_size; y++) {
+      SkColor actual_color = bitmap.getColor(x, y);
+      ExpectRgba(x, y, blend_color, actual_color);
+    }
+  }
+}
+
+// Checks that using the AlphaShape filter applied to a layer with
+// transparency, alpha-blends properly with the layer below.
+TEST_F(LayerWithRealCompositorTest, DrawAlphaThresholdFilterPixels) {
+  gfx::Size viewport_size = GetCompositor()->size();
+
+  int test_size = 200;
+  EXPECT_GE(viewport_size.width(), test_size);
+  EXPECT_GE(viewport_size.height(), test_size);
+
+  int blue_height = 10;
+  SkColor blue_with_alpha = SkColorSetARGBInline(40, 0, 0, 255);
+  SkColor blend_color = SkColorSetARGBInline(255, 215, 0, 40);
+
+  scoped_ptr<Layer> background_layer(
+      CreateColorLayer(SK_ColorRED, gfx::Rect(viewport_size)));
+  scoped_ptr<Layer> foreground_layer(
+      CreateColorLayer(blue_with_alpha, gfx::Rect(viewport_size)));
+
+  // Add a shape to restrict the visible part of the layer.
+  SkRegion shape;
+  shape.setRect(0, 0, viewport_size.width(), blue_height);
+  foreground_layer->SetAlphaShape(make_scoped_ptr(new SkRegion(shape)));
+
+  foreground_layer->SetFillsBoundsOpaquely(false);
+
+  background_layer->Add(foreground_layer.get());
+  DrawTree(background_layer.get());
+
+  SkBitmap bitmap;
+  ASSERT_TRUE(ReadPixels(&bitmap, gfx::Rect(viewport_size)));
+  ASSERT_FALSE(bitmap.empty());
+
+  SkAutoLockPixels lock(bitmap);
+  for (int x = 0; x < test_size; x++) {
+    for (int y = 0; y < test_size; y++) {
+      SkColor actual_color = bitmap.getColor(x, y);
+      ExpectRgba(x, y, actual_color,
+                 y < blue_height ? blend_color : SK_ColorRED);
     }
   }
 }
index e80fb4c..0dce3e3 100644 (file)
@@ -26,7 +26,7 @@ div.audio-player {
   color: #3d3d3d;
   cursor: default;
   flex: 1 1 auto;
-  font-family: Open Sans, Droid Sans Fallback, sans-serif;
+  font-family: Noto Sans UI, sans-serif;
   font-size: 10pt;
   position: relative;
 }
index bc9500b..b4700f4 100644 (file)
@@ -10,7 +10,7 @@
   cursor: default;
   display: flex;
   flex-direction: column;
-  font-family: Open Sans, Droid Sans Fallback, sans-serif;
+  font-family: Noto Sans UI, sans-serif;
   font-size: 10pt;
   justify-content: flex-start;
   left: 0;
index f34644e..0cc294e 100644 (file)
@@ -157,24 +157,12 @@ a:focus {
   line-height: 45px;
 }
 
-.dialog-navigation-list-header #profile-badge {
-  display: inline-block;
-  height: 29px;  /* Size of a profile image. */
-  margin: 8px;
-  vertical-align: top;
-  width: 29px;  /* Size of a profile image. */
-}
-
 .dialog-navigation-list-header #app-name {
   color: #303030;
   font-size: 130%;
   margin: 0 15px;
 }
 
-.dialog-navigation-list-header #profile-badge:not([hidden]) + #app-name {
-  margin: 0;
-}
-
 .dialog-navigation-list-contents {
   display: flex;
   flex: 1 1 auto;
index c2452c1..d3dd5e7 100644 (file)
@@ -480,7 +480,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52;
         this.onShowGearMenu_.bind(this));
     chrome.fileBrowserPrivate.onDesktopChanged.addListener(function() {
       this.updateVisitDesktopMenus_();
-      this.ui_.updateProfileBadge();
     }.bind(this));
     chrome.fileBrowserPrivate.onProfileAdded.addListener(
         this.updateVisitDesktopMenus_.bind(this));
index 6f11bfc..ed378b6 100644 (file)
@@ -137,7 +137,6 @@ var FileManagerUI = function(element, dialogType) {
   Object.seal(this);
 
   // Initialize the header.
-  this.updateProfileBadge();
   this.element_.querySelector('#app-name').innerText =
       chrome.runtime.getManifest().name;
 
@@ -237,39 +236,6 @@ FileManagerUI.prototype.initAdditionalUI = function() {
 };
 
 /**
- * Updates visibility and image of the profile badge.
- */
-FileManagerUI.prototype.updateProfileBadge = function() {
-  if (this.dialogType_ !== DialogType.FULL_PAGE)
-    return;
-
-  chrome.fileBrowserPrivate.getProfiles(function(profiles,
-                                                 currentId,
-                                                 displayedId) {
-    var profileImage;
-    if (currentId !== displayedId) {
-      for (var i = 0; i < profiles.length; i++) {
-        if (profiles[i].profileId === currentId) {
-          profileImage = profiles[i].profileImage;
-          break;
-        }
-      }
-    }
-    var profileBadge = this.element_.querySelector('#profile-badge');
-    if (profileImage) {
-      profileBadge.style.background =
-          '-webkit-image-set(' +
-          'url(' + profileImage.scale1xUrl + ') 1x,' +
-          'url(' + profileImage.scale2xUrl + ') 2x) no-repeat center';
-      profileBadge.hidden = false;
-    } else {
-      profileBadge.style.background = '';
-      profileBadge.hidden = true;
-    }
-  }.bind(this));
-};
-
-/**
  * Handles click event on the search button.
  * @param {Event} event Click event.
  * @private
index b02fd33..d6a881b 100644 (file)
     <div class="dialog-container">
       <div class="dialog-navigation-list">
         <div class="dialog-navigation-list-header">
-          <span id="profile-badge" hidden></span><span id="app-name"></span>
+          <span id="app-name"></span>
         </div>
         <div class="dialog-navigation-list-contents">
           <tree id="directory-tree" tabindex="15"></tree>
index 0888d84..77021d2 100644 (file)
@@ -4,7 +4,7 @@
 
 body {
   -webkit-user-select: none;
-  font-family: Open Sans, Droid Sans Fallback, sans-serif;
+  font-family: Noto Sans UI, sans-serif;
   font-size: 84%;
   margin: 0;
 }
index 508bc2e..a2480ad 100644 (file)
@@ -870,6 +870,7 @@ Gallery.prototype.updateSelectionAndState_ = function() {
     }
   } else {
     document.title = '';
+    this.filenameEdit_.disabled = true;
     this.filenameEdit_.value = '';
     this.shareButton_.hidden = true;
   }
index 64deea8..38b51ba 100644 (file)
@@ -5,7 +5,7 @@
 body {
   -webkit-user-select: none;
   background: black;
-  font-family: Noto Sans UI,Droid Sans Fallback,sans-serif;
+  font-family: Noto Sans UI,sans-serif;
   font-size: 84%;
   margin: 0;
   overflow: hidden;
index 920204b..ca0c8ad 100644 (file)
@@ -70,6 +70,27 @@ FontList FontList::DeriveWithStyle(int font_style) const {
   return Derive(0, font_style);
 }
 
+gfx::FontList FontList::DeriveWithHeightUpperBound(int height) const {
+  gfx::FontList font_list(*this);
+  for (int font_size = font_list.GetFontSize(); font_size > 1; --font_size) {
+    const int internal_leading =
+        font_list.GetBaseline() - font_list.GetCapHeight();
+    // Some platforms don't support getting the cap height, and simply return
+    // the entire font ascent from GetCapHeight().  Centering the ascent makes
+    // the font look too low, so if GetCapHeight() returns the ascent, center
+    // the entire font height instead.
+    const int space =
+        height - ((internal_leading != 0) ?
+                  font_list.GetCapHeight() : font_list.GetHeight());
+    const int y_offset = space / 2 - internal_leading;
+    const int space_at_bottom = height - (y_offset + font_list.GetHeight());
+    if ((y_offset >= 0) && (space_at_bottom >= 0))
+      break;
+    font_list = font_list.DeriveWithSizeDelta(-1);
+  }
+  return font_list;
+}
+
 int FontList::GetHeight() const {
   return impl_->GetHeight();
 }
index 1ba8ad1..bc3afc2 100644 (file)
@@ -83,6 +83,31 @@ class GFX_EXPORT FontList {
   // values: Font::BOLD, Font::ITALIC and Font::UNDERLINE.
   FontList DeriveWithStyle(int font_style) const;
 
+  // Shrinks the font size until the font list fits within |height| while
+  // having its cap height vertically centered. Returns a new FontList with
+  // the correct height.
+  //
+  // The expected layout:
+  //   +--------+-----------------------------------------------+------------+
+  //   |        | y offset                                      | space      |
+  //   |        +--------+-------------------+------------------+ above      |
+  //   |        |        |                   | internal leading | cap height |
+  //   | box    | font   | ascent (baseline) +------------------+------------+
+  //   | height | height |                   | cap height                    |
+  //   |        |        |-------------------+------------------+------------+
+  //   |        |        | descent (height - baseline)          | space      |
+  //   |        +--------+--------------------------------------+ below      |
+  //   |        | space at bottom                               | cap height |
+  //   +--------+-----------------------------------------------+------------+
+  // Goal:
+  //     center of box height == center of cap height
+  //     (i.e. space above cap height == space below cap height)
+  // Restrictions:
+  //     y offset >= 0
+  //     space at bottom >= 0
+  //     (i.e. Entire font must be visible inside the box.)
+  gfx::FontList DeriveWithHeightUpperBound(int height) const;
+
   // Returns the height of this font list, which is max(ascent) + max(descent)
   // for all the fonts in the font list.
   int GetHeight() const;
index fc5f839..6dcbb85 100644 (file)
@@ -286,4 +286,27 @@ TEST(FontListTest, Fonts_GetHeight_GetBaseline) {
             font_list_mix.GetBaseline());
 }
 
+TEST(FontListTest, Fonts_DeriveWithHeightUpperBound) {
+  std::vector<Font> fonts;
+
+  fonts.push_back(gfx::Font("Arial", 18));
+  fonts.push_back(gfx::Font("Sans serif", 18));
+  fonts.push_back(gfx::Font("Symbol", 18));
+  FontList font_list = FontList(fonts);
+
+  // A smaller upper bound should derive a font list with a smaller height.
+  const int height_1 = font_list.GetHeight() - 5;
+  FontList derived_1 = font_list.DeriveWithHeightUpperBound(height_1);
+  EXPECT_LE(derived_1.GetHeight(), height_1);
+  EXPECT_LT(derived_1.GetHeight(), font_list.GetHeight());
+  EXPECT_LT(derived_1.GetFontSize(), font_list.GetFontSize());
+
+  // A larger upper bound should not change the height of the font list.
+  const int height_2 = font_list.GetHeight() + 5;
+  FontList derived_2 = font_list.DeriveWithHeightUpperBound(height_2);
+  EXPECT_LE(derived_2.GetHeight(), height_2);
+  EXPECT_EQ(font_list.GetHeight(), derived_2.GetHeight());
+  EXPECT_EQ(font_list.GetFontSize(), derived_2.GetFontSize());
+}
+
 }  // namespace gfx
index a198358..4f9fbc9 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "ui/gfx/font_render_params.h"
 
+#include <fontconfig/fontconfig.h>
+
 #include "base/command_line.h"
 #include "base/containers/mru_cache.h"
 #include "base/hash.h"
@@ -17,8 +19,6 @@
 #include "ui/gfx/linux_font_delegate.h"
 #include "ui/gfx/switches.h"
 
-#include <fontconfig/fontconfig.h>
-
 namespace gfx {
 
 namespace {
index 403b836..c408740 100644 (file)
@@ -130,16 +130,6 @@ PlatformFontPango::PlatformFontPango(const std::string& font_name,
                   query.style, gfx::GetFontRenderParams(query, NULL));
 }
 
-double PlatformFontPango::underline_position() const {
-  const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
-  return underline_position_pixels_;
-}
-
-double PlatformFontPango::underline_thickness() const {
-  const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
-  return underline_thickness_pixels_;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // PlatformFontPango, PlatformFont implementation:
 
@@ -283,8 +273,6 @@ void PlatformFontPango::InitFromDetails(
 
   pango_metrics_inited_ = false;
   average_width_pixels_ = 0.0f;
-  underline_position_pixels_ = 0.0f;
-  underline_thickness_pixels_ = 0.0f;
 }
 
 void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
@@ -298,8 +286,6 @@ void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
   cap_height_pixels_ = other->cap_height_pixels_;
   pango_metrics_inited_ = other->pango_metrics_inited_;
   average_width_pixels_ = other->average_width_pixels_;
-  underline_position_pixels_ = other->underline_position_pixels_;
-  underline_thickness_pixels_ = other->underline_thickness_pixels_;
 }
 
 void PlatformFontPango::PaintSetup(SkPaint* paint) const {
@@ -318,19 +304,6 @@ void PlatformFontPango::InitPangoMetrics() {
     ScopedPangoFontDescription pango_desc(GetNativeFont());
     PangoFontMetrics* pango_metrics = GetPangoFontMetrics(pango_desc.get());
 
-    underline_position_pixels_ =
-        pango_font_metrics_get_underline_position(pango_metrics) /
-        PANGO_SCALE;
-
-    // TODO(davemoore): Come up with a better solution.
-    // This is a hack, but without doing this the underlines
-    // we get end up fuzzy. So we align to the midpoint of a pixel.
-    underline_position_pixels_ /= 2;
-
-    underline_thickness_pixels_ =
-        pango_font_metrics_get_underline_thickness(pango_metrics) /
-        PANGO_SCALE;
-
     // First get the Pango-based width (converting from Pango units to pixels).
     const double pango_width_pixels =
         pango_font_metrics_get_approximate_char_width(pango_metrics) /
index 3a49438..a636db2 100644 (file)
@@ -40,13 +40,6 @@ class GFX_EXPORT PlatformFontPango : public PlatformFont {
   static void SetDefaultFontDescription(const std::string& font_description);
 #endif
 
-  // Position as an offset from the height of the drawn text, used to draw
-  // an underline. This is a negative number, so the underline would be
-  // drawn at y + height + underline_position.
-  double underline_position() const;
-  // The thickness to draw the underline.
-  double underline_thickness() const;
-
   // Overridden from PlatformFont:
   virtual Font DeriveFont(int size_delta, int style) const OVERRIDE;
   virtual int GetHeight() const OVERRIDE;
@@ -82,7 +75,7 @@ class GFX_EXPORT PlatformFontPango : public PlatformFont {
   // Initializes this object as a copy of another PlatformFontPango.
   void InitFromPlatformFont(const PlatformFontPango* other);
 
-  // Potentially slow call to get pango metrics (average width, underline info).
+  // Potentially slow call to get pango metrics (average width).
   void InitPangoMetrics();
 
   // Setup a Skia context to use the current typeface.
@@ -114,8 +107,6 @@ class GFX_EXPORT PlatformFontPango : public PlatformFont {
   // to compute them.
   bool pango_metrics_inited_;
   double average_width_pixels_;
-  double underline_position_pixels_;
-  double underline_thickness_pixels_;
 
   // The default font, used for the default constructor.
   static Font* default_font_;
index 86a5242..07cbfb9 100644 (file)
@@ -55,11 +55,20 @@ void SetPangoUnderlineMetrics(PangoFontDescription *desc,
   // Pango returns the position "above the baseline". Change its sign to convert
   // it to a vertical offset from the baseline.
   int position = -pango_font_metrics_get_underline_position(metrics);
-  pango_quantize_line_geometry(&thickness, &position);
+
   // Note: pango_quantize_line_geometry() guarantees pixel boundaries, so
   //       PANGO_PIXELS() is safe to use.
-  renderer->SetUnderlineMetrics(PANGO_PIXELS(thickness),
-                                PANGO_PIXELS(position));
+  pango_quantize_line_geometry(&thickness, &position);
+  int thickness_pixels = PANGO_PIXELS(thickness);
+  int position_pixels = PANGO_PIXELS(position);
+
+  // Ugly hack: make sure that underlines don't get clipped. See
+  // http://crbug.com/393117.
+  int descent_pixels = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
+  position_pixels = std::min(position_pixels,
+                             descent_pixels - thickness_pixels);
+
+  renderer->SetUnderlineMetrics(thickness_pixels, position_pixels);
 }
 
 }  // namespace
index 36f635f..ae4f81a 100644 (file)
@@ -32,7 +32,7 @@ ScopedJavaSurface::ScopedJavaSurface(
       is_protected_(false) {
   JNIEnv* env = base::android::AttachCurrentThread();
   RegisterNativesIfNeeded(env);
-  DCHECK(env->IsInstanceOf(surface.obj(), g_Surface_clazz));
+  DCHECK(env->IsInstanceOf(surface.obj(), Surface_clazz(env)));
   j_surface_.Reset(surface);
 }
 
index f74ff7a..029a5a4 100644 (file)
@@ -305,6 +305,8 @@ void KeyboardController::NotifyKeyboardBoundsChanging(
     } else {
       ResetWindowInsets();
     }
+  } else {
+    current_keyboard_bounds_ = gfx::Rect();
   }
 }
 
index d7faf0f..9946060 100644 (file)
@@ -56,7 +56,10 @@ void KeyboardLayoutManager::SetChildBounds(aura::Window* child,
     // case the show keyboard request is called before the height is set.
     controller_->ShowKeyboard(false);
   } else {
-    controller_->NotifyKeyboardBoundsChanging(requested_bounds);
+    // We need to send out this notification only if keyboard is visible since
+    // keyboard window is resized even if keyboard is hidden.
+    if (controller_->keyboard_visible())
+      controller_->NotifyKeyboardBoundsChanging(requested_bounds);
   }
 }
 
index 01a3b7a..089dc5e 100644 (file)
@@ -171,7 +171,8 @@ html[dir=rtl] .main-pane {
   display: none;
 }
 
-.pod[auth-type='offlinePassword'].focused .password-entry-container {
+.pod[auth-type='offlinePassword'].focused .password-entry-container,
+.pod[auth-type='forceOfflinePassword'].focused .password-entry-container {
   display: flex;
   flex: auto;
 }
@@ -226,6 +227,11 @@ html[dir=rtl] .main-pane {
   flex: none;
 }
 
+.custom-icon.faded {
+  -webkit-transition: opacity 200ms ease-in-out,
+                      visibility 200ms ease-in-out;
+}
+
 .custom-icon-container {
   display: flex;
   flex: none;
index bebb45e..6828093 100644 (file)
@@ -85,10 +85,11 @@ cr.define('login', function() {
    * @const
    */
   var UserPodTabOrder = {
-    POD_INPUT: 1,     // Password input fields (and whole pods themselves).
-    HEADER_BAR: 2,    // Buttons on the header bar (Shutdown, Add User).
-    ACTION_BOX: 3,    // Action box buttons.
-    PAD_MENU_ITEM: 4  // User pad menu items (Remove this user).
+    POD_INPUT: 1,        // Password input fields (and whole pods themselves).
+    POD_CUSTOM_ICON: 2,  // Pod custom icon next to passwrod input field.
+    HEADER_BAR: 3,       // Buttons on the header bar (Shutdown, Add User).
+    ACTION_BOX: 4,       // Action box buttons.
+    PAD_MENU_ITEM: 5     // User pad menu items (Remove this user).
   };
 
   /**
@@ -103,6 +104,7 @@ cr.define('login', function() {
     NUMERIC_PIN: 2,
     USER_CLICK: 3,
     EXPAND_THEN_USER_CLICK: 4,
+    FORCE_OFFLINE_PASSWORD: 5
   };
 
   /**
@@ -114,6 +116,7 @@ cr.define('login', function() {
     2: 'numericPin',
     3: 'userClick',
     4: 'expandThenUserClick',
+    5: 'forceOfflinePassword'
   };
 
   // Focus and tab order are organized as follows:
@@ -121,9 +124,12 @@ cr.define('login', function() {
   // (1) all user pods have tab index 1 so they are traversed first;
   // (2) when a user pod is activated, its tab index is set to -1 and its
   // main input field gets focus and tab index 1;
-  // (3) buttons on the header bar have tab index 2 so they follow user pods;
-  // (4) Action box buttons have tab index 3 and follow header bar buttons;
-  // (5) lastly, focus jumps to the Status Area and back to user pods.
+  // (3) if user pod custom icon is interactive, it has tab index 2 so it
+  // follows the input.
+  // (4) buttons on the header bar have tab index 3 so they follow the custom
+  // icon, or user pod if custom icon is not interactive;
+  // (5) Action box buttons have tab index 4 and follow header bar buttons;
+  // (6) lastly, focus jumps to the Status Area and back to user pods.
   //
   // 'Focus' event is handled by a capture handler for the whole document
   // and in some cases 'mousedown' event handlers are used instead of 'click'
@@ -252,6 +258,23 @@ cr.define('login', function() {
      */
     animationResourceSize_: 0,
 
+    /**
+     * When {@code fadeOut} is called, the element gets hidden using fadeout
+     * animation. This is reference to the listener for transition end added to
+     * the icon element while it's fading out.
+     * @type {?function(Event)}
+     * @private
+     */
+    hideTransitionListener_: null,
+
+    /**
+     * Callback for click and 'Enter' key events that gets set if the icon is
+     * interactive.
+     * @type {?function()}
+     * @private
+     */
+    actionHandler_: null,
+
     /** @override */
     decorate: function() {
       this.iconElement.addEventListener('mouseover',
@@ -260,6 +283,16 @@ cr.define('login', function() {
                                          this.hideTooltip_.bind(this, false));
       this.iconElement.addEventListener('mousedown',
                                          this.hideTooltip_.bind(this, false));
+      this.iconElement.addEventListener('click',
+                                        this.handleClick_.bind(this));
+      this.iconElement.addEventListener('keydown',
+                                        this.handleKeyDown_.bind(this));
+
+      // When the icon is focused using mouse, there should be no outline shown.
+      // Preventing default mousedown event accomplishes this.
+      this.iconElement.addEventListener('mousedown', function(e) {
+        e.preventDefault();
+      });
     },
 
     /**
@@ -298,16 +331,24 @@ cr.define('login', function() {
      * Shows the icon.
      */
     show: function() {
+      this.resetHideTransitionState_();
       this.hidden = false;
     },
 
     /**
-     * Hides the icon.  Makes sure the tooltip is hidden and animation reset.
+     * Hides the icon using a fade-out animation.
      */
-    hide: function() {
+    fadeOut: function() {
+      // The icon is already being hidden.
+      if (this.iconElement.classList.contains('faded'))
+        return;
+
       this.hideTooltip_(true);
-      this.setAnimation(null);
-      this.hidden = true;
+      this.iconElement.classList.add('faded');
+      this.hideTransitionListener_ = this.hide_.bind(this);
+      this.iconElement.addEventListener('webkitTransitionEnd',
+                                        this.hideTransitionListener_);
+      ensureTransitionEndEvent(this.iconElement, 200);
     },
 
     /**
@@ -403,6 +444,80 @@ cr.define('login', function() {
     },
 
     /**
+     * Sets up icon tabIndex attribute and handler for click and 'Enter' key
+     * down events.
+     * @param {?function()} callback If icon should be interactive, the
+     *     function to get called on click and 'Enter' key down events. Should
+     *     be null to make the icon  non interactive.
+     */
+    setInteractive: function(callback) {
+      // Update tabIndex property if needed.
+      if (!!this.actionHandler_ != !!callback) {
+        if (callback) {
+          this.iconElement.setAttribute('tabIndex',
+                                         UserPodTabOrder.POD_CUSTOM_ICON);
+        } else {
+          this.iconElement.removeAttribute('tabIndex');
+        }
+      }
+
+      // Set the new action handler.
+      this.actionHandler_ = callback;
+    },
+
+    /**
+     * Hides the icon. Makes sure the tooltip is hidden and animation reset.
+     * @private
+     */
+    hide_: function() {
+      this.hideTooltip_(true);
+      this.hidden = true;
+      this.setAnimation(null);
+      this.setInteractive(null);
+      this.resetHideTransitionState_();
+    },
+
+    /**
+     * Ensures the icon's transition state potentially set by a call to
+     * {@code fadeOut} is cleared.
+     * @private
+     */
+    resetHideTransitionState_: function() {
+      if (this.hideTransitionListener_) {
+        this.iconElement.removeEventListener('webkitTransitionEnd',
+                                             this.hideTransitionListener_);
+        this.hideTransitionListener_ = null;
+      }
+      this.iconElement.classList.toggle('faded', false);
+    },
+
+    /**
+     * Handles click event on the icon element. No-op if
+     * {@code this.actionHandler_} is not set.
+     * @param {Event} e The click event.
+     * @private
+     */
+    handleClick_: function(e) {
+      if (!this.actionHandler_)
+        return;
+      this.actionHandler_();
+      stopEventPropagation(e);
+    },
+
+    /**
+     * Handles key down event on the icon element. Only 'Enter' key is handled.
+     * No-op if {@code this.actionHandler_} is not set.
+     * @param {Event} e The key down event.
+     * @private
+     */
+    handleKeyDown_: function(e) {
+      if (!this.actionHandler_ || e.keyIdentifier != 'Enter')
+        return;
+      this.actionHandler_(e);
+      stopEventPropagation(e);
+    },
+
+    /**
      * Called when mouse enters the icon. It sets timeout for showing the
      * tooltip.
      * @private
@@ -415,7 +530,7 @@ cr.define('login', function() {
     },
 
     /**
-     * Shows the current tooltip, if one is set.
+     * Shows the current tooltip if one is set.
      * @private
      */
     showTooltip_: function() {
@@ -973,7 +1088,8 @@ cr.define('login', function() {
      * @type {bool}
      */
     get isAuthTypePassword() {
-      return this.authType_ == AUTH_TYPE.OFFLINE_PASSWORD;
+      return this.authType_ == AUTH_TYPE.OFFLINE_PASSWORD ||
+             this.authType_ == AUTH_TYPE.FORCE_OFFLINE_PASSWORD;
     },
 
     /**
@@ -2199,6 +2315,12 @@ cr.define('login', function() {
       pod.customIconElement.setSize(icon.size || {width: 0, height: 0});
       pod.customIconElement.setAnimation(icon.animation || null);
       pod.customIconElement.setOpacity(icon.opacity || 100);
+      if (icon.hardlockOnClick) {
+        pod.customIconElement.setInteractive(
+            this.hardlockUserPod_.bind(this, username));
+      } else {
+        pod.customIconElement.setInteractive(null);
+      }
       pod.customIconElement.show();
       // This has to be called after |show| in case the tooltip should be shown
       // immediatelly.
@@ -2207,6 +2329,17 @@ cr.define('login', function() {
     },
 
     /**
+     * Hard-locks user pod for the user. If user pod is hard-locked, it can be
+     * only unlocked using password, and the authentication type cannot be
+     * changed.
+     * @param {!string} username The user's username.
+     * @private
+     */
+    hardlockUserPod_: function(username) {
+      chrome.send('hardlockPod', [username]);
+    },
+
+    /**
      * Hides the custom icon in the user pod added by showUserPodCustomIcon().
      * @param {string} username Username of pod to remove button
      */
@@ -2218,7 +2351,7 @@ cr.define('login', function() {
         return;
       }
 
-      pod.customIconElement.hide();
+      pod.customIconElement.fadeOut();
     },
 
     /**
diff --git a/src/ui/resources/default_100_percent/common/close_3_mask.png b/src/ui/resources/default_100_percent/common/close_3_mask.png
new file mode 100644 (file)
index 0000000..a4a41db
Binary files /dev/null and b/src/ui/resources/default_100_percent/common/close_3_mask.png differ
index f176d2e..2b9fd72 100644 (file)
Binary files a/src/ui/resources/default_100_percent/common/easy_unlock_unlocked.png and b/src/ui/resources/default_100_percent/common/easy_unlock_unlocked.png differ
diff --git a/src/ui/resources/default_100_percent/common/ntp_default_favicon.png b/src/ui/resources/default_100_percent/common/ntp_default_favicon.png
new file mode 100644 (file)
index 0000000..0d72b80
Binary files /dev/null and b/src/ui/resources/default_100_percent/common/ntp_default_favicon.png differ
diff --git a/src/ui/resources/default_200_percent/common/close_3_mask.png b/src/ui/resources/default_200_percent/common/close_3_mask.png
new file mode 100644 (file)
index 0000000..60ed8d8
Binary files /dev/null and b/src/ui/resources/default_200_percent/common/close_3_mask.png differ
index 67ee996..d285d49 100644 (file)
Binary files a/src/ui/resources/default_200_percent/common/easy_unlock_unlocked.png and b/src/ui/resources/default_200_percent/common/easy_unlock_unlocked.png differ
diff --git a/src/ui/resources/default_200_percent/common/ntp_default_favicon.png b/src/ui/resources/default_200_percent/common/ntp_default_favicon.png
new file mode 100644 (file)
index 0000000..bfd116b
Binary files /dev/null and b/src/ui/resources/default_200_percent/common/ntp_default_favicon.png differ
index f627817..b71eb90 100644 (file)
       <structure type="chrome_scaled_image" name="IDR_CLOSE_2_H" file="close_2_hover.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_2_MASK" file="close_2_mask.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_2_P" file="close_2_pressed.png" />
+      <structure type="chrome_scaled_image" name="IDR_CLOSE_3_MASK" file="common/close_3_mask.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_DIALOG" file="close_dialog.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_DIALOG_H" file="close_dialog_hover.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_DIALOG_P" file="close_dialog_pressed.png" />
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SETTINGS_PRESSED" file="common/notification_settings_pressed.png"/>
       </if>
       <if expr="not is_android and not is_ios">
+        <structure type="chrome_scaled_image" name="IDR_NTP_DEFAULT_FAVICON" file="common/ntp_default_favicon.png" />
+      </if>
+      <if expr="not is_android and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_HOVER" file="cros/action_box_button_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_NORMAL" file="cros/action_box_button_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_OOBE_ACTION_BOX_BUTTON_PRESSED" file="cros/action_box_button_pressed.png" />
index 51a6c24..8d8eb3b 100644 (file)
@@ -2,7 +2,7 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="ja">
 <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">MotoyaG04Gothic,Noto Sans UI,IPAPGothic,ui-sans, 13px</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans CJK Japanese,ui-sans, 13px</translation>
 <if expr="is_win">
   <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,Meiryo,'MS PGothic',sans-serif</translation>
   <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,Meiryo,'MS PGothic',sans-serif</translation>
@@ -14,9 +14,6 @@
   <translation id="IDS_WEB_FONT_FAMILY">VL PGothic,Sazanami Gothic,Kochi Gothic,sans-serif</translation>
 </if>
 <if expr="chromeos and _google_chrome">
-  <translation id="IDS_WEB_FONT_FAMILY">MotoyaG04Gothic, Noto Sans UI, sans-serif</translation>
-</if>
-<if expr="chromeos and not _google_chrome">
-  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, IPAPGothic, sans-serif</translation>
+  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans CJK Japanese, sans-serif</translation>
 </if>
 </translationbundle>
index f8da373..bd3c2f1 100644 (file)
@@ -2,7 +2,7 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="ko">
 <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,NanumGothic,ui-sans, 13px</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans CJK Korean,ui-sans, 13px</translation>
 <if expr="is_win">
   <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Malgun Gothic',Gulim,sans-serif</translation>
   <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Malgun Gothic',Gulim,sans-serif</translation>
@@ -14,6 +14,6 @@
   <translation id="IDS_WEB_FONT_FAMILY">NanumGothic,UnDotum,Baekmuk Gulim,sans-serif</translation>
 </if>
 <if expr="chromeos">
-  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, NanumGothic, sans-serif</translation>
+  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans CJK Korean, sans-serif</translation>
 </if>
 </translationbundle>
index e9c4026..aa89acd 100644 (file)
@@ -2,7 +2,7 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-CN">
 <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,MYingHeiGB18030,MYingHeiB5HK,ui-sans, 13px</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans CJK Simplified Chinese,ui-sans, 13px</translation>
 <if expr="is_win">
   <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Microsoft Yahei',Simsun,sans-serif</translation>
   <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Microsoft Yahei',Simsun,sans-serif</translation>
 <if expr="is_macosx or is_ios">
   <translation id="IDS_WEB_FONT_FAMILY">Helvetica,STHeiti,sans-serif</translation>
 </if>
-<if expr="chromeos and _google_chrome">
-  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, MYingHeiGB18030, MYingHeiB5HK, sans-serif</translation>
-</if>
-<if expr="chromeos and not _google_chrome">
-  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Droid Sans Fallback, sans-serif</translation>
+<if expr="chromeos">
+  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans CJK Simplified Chinese, sans-serif</translation>
 </if>
 </translationbundle>
index 05c69e3..8d0311c 100644 (file)
@@ -2,7 +2,7 @@
 <!DOCTYPE translationbundle>
 <translationbundle lang="zh-TW">
 <translation id="IDS_MINIMUM_UI_FONT_SIZE">10</translation>
-<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,MYingHeiB5HK,MYingHeiGB18030,ui-sans, 13px</translation>
+<translation id="IDS_UI_FONT_FAMILY_CROS">Noto Sans UI,Noto Sans CJK Traditional Chinese,ui-sans, 13px</translation>
 <if expr="is_win">
   <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Microsoft Jhenghei',PMingLiu,sans-serif</translation>
   <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Microsoft Jhenghei',PMingLiu,sans-serif</translation>
@@ -11,9 +11,6 @@
   <translation id="IDS_WEB_FONT_FAMILY">Helvetica,Heiti TC,sans-serif</translation>
 </if>
 <if expr="chromeos and _google_chrome">
-  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, MYingHeiB5HK, MYingHeiGB18030, sans-serif</translation>
-</if>
-<if expr="chromeos and not _google_chrome">
-  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Droid Sans Fallback, sans-serif</translation>
+  <translation id="IDS_WEB_FONT_FAMILY">Noto Sans UI, Noto Sans CJK Traditional Chinese, sans-serif</translation>
 </if>
 </translationbundle>
index 03b422a..9092bab 100644 (file)
@@ -7,11 +7,9 @@
 #include <algorithm>
 
 #include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
 #include "grit/ui_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/views/painter.h"
@@ -21,31 +19,6 @@ namespace views {
 
 namespace internal {
 
-// A helper that combines each border image-set painter with arrows and metrics.
-struct BorderImages {
-  BorderImages(const int border_image_ids[],
-               const int arrow_image_ids[],
-               int border_interior_thickness,
-               int arrow_interior_thickness,
-               int corner_radius);
-
-  scoped_ptr<Painter> border_painter;
-  gfx::ImageSkia left_arrow;
-  gfx::ImageSkia top_arrow;
-  gfx::ImageSkia right_arrow;
-  gfx::ImageSkia bottom_arrow;
-
-  // The thickness of border and arrow images and their interior areas.
-  // Thickness is the width of left/right and the height of top/bottom images.
-  // The interior is measured without including stroke or shadow pixels.
-  int border_thickness;
-  int border_interior_thickness;
-  int arrow_thickness;
-  int arrow_interior_thickness;
-  // The corner radius of the bubble's rounded-rect interior area.
-  int corner_radius;
-};
-
 BorderImages::BorderImages(const int border_image_ids[],
                            const int arrow_image_ids[],
                            int border_interior_thickness,
@@ -68,13 +41,12 @@ BorderImages::BorderImages(const int border_image_ids[],
   }
 }
 
+BorderImages::~BorderImages() {}
+
 }  // namespace internal
 
 namespace {
 
-// The border and arrow stroke size used in image assets, in pixels.
-const int kStroke = 1;
-
 // Bubble border and arrow image resource ids. They don't use the IMAGE_GRID
 // macro because there is no center image.
 const int kNoShadowImages[] = {
@@ -150,6 +122,8 @@ BorderImages* GetBorderImages(BubbleBorder::Shadow shadow) {
 
 }  // namespace
 
+const int BubbleBorder::kStroke = 1;
+
 BubbleBorder::BubbleBorder(Arrow arrow, Shadow shadow, SkColor color)
     : arrow_(arrow),
       arrow_offset_(0),
@@ -278,7 +252,7 @@ gfx::Size BubbleBorder::GetSizeForContentsSize(
       std::max(images_->arrow_thickness + images_->border_interior_thickness,
                images_->border_thickness);
   // Only take arrow image sizes into account when the bubble tip is shown.
-  if (arrow_paint_type_ == PAINT_TRANSPARENT || !has_arrow(arrow_))
+  if (arrow_paint_type_ == PAINT_NONE || !has_arrow(arrow_))
     size.SetToMax(gfx::Size(min, min));
   else if (is_arrow_on_horizontal(arrow_))
     size.SetToMax(gfx::Size(min_with_arrow_width, min_with_arrow_thickness));
@@ -360,6 +334,10 @@ void BubbleBorder::DrawArrow(gfx::Canvas* canvas,
   canvas->DrawPath(path, paint);
 }
 
+internal::BorderImages* BubbleBorder::GetImagesForTest() const {
+  return images_;
+}
+
 void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
   if (border_->shadow() == BubbleBorder::NO_SHADOW_OPAQUE_BORDER)
     canvas->DrawColor(border_->background_color());
index 15f0f85..8ce546a 100644 (file)
@@ -7,19 +7,47 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/image/image_skia.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 
 namespace gfx {
-class ImageSkia;
 class Rect;
 }
 
 namespace views {
+class Painter;
 
 namespace internal {
-struct BorderImages;
-}
+
+// A helper that combines each border image-set painter with arrows and metrics.
+struct BorderImages {
+  BorderImages(const int border_image_ids[],
+               const int arrow_image_ids[],
+               int border_interior_thickness,
+               int arrow_interior_thickness,
+               int corner_radius);
+  virtual ~BorderImages();
+
+  scoped_ptr<Painter> border_painter;
+  gfx::ImageSkia left_arrow;
+  gfx::ImageSkia top_arrow;
+  gfx::ImageSkia right_arrow;
+  gfx::ImageSkia bottom_arrow;
+
+  // The thickness of border and arrow images and their interior areas.
+  // Thickness is the width of left/right and the height of top/bottom images.
+  // The interior is measured without including stroke or shadow pixels.
+  int border_thickness;
+  int border_interior_thickness;
+  int arrow_thickness;
+  int arrow_interior_thickness;
+  // The corner radius of the bubble's rounded-rect interior area.
+  int corner_radius;
+};
+
+}  // namespace internal
 
 // Renders a border, with optional arrow, and a custom dropshadow.
 // This can be used to produce floating "bubble" objects with rounded corners.
@@ -173,11 +201,19 @@ class VIEWS_EXPORT BubbleBorder : public Border {
   virtual gfx::Size GetMinimumSize() const OVERRIDE;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetSizeForContentsSizeTest);
+  FRIEND_TEST_ALL_PREFIXES(BubbleBorderTest, GetBoundsOriginTest);
+
+  // The border and arrow stroke size used in image assets, in pixels.
+  static const int kStroke;
+
   gfx::Size GetSizeForContentsSize(const gfx::Size& contents_size) const;
   gfx::ImageSkia* GetArrowImage() const;
   gfx::Rect GetArrowRect(const gfx::Rect& bounds) const;
   void DrawArrow(gfx::Canvas* canvas, const gfx::Rect& arrow_bounds) const;
 
+  internal::BorderImages* GetImagesForTest() const;
+
   Arrow arrow_;
   int arrow_offset_;
   ArrowPaintType arrow_paint_type_;
index b8838f6..404902c 100644 (file)
@@ -4,11 +4,13 @@
 
 #include "ui/views/bubble/bubble_border.h"
 
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/stringprintf.h"
 #include "ui/views/test/views_test_base.h"
 
 namespace views {
 
-typedef ViewsTestBase BubbleBorderTest;
+typedef views::ViewsTestBase BubbleBorderTest;
 
 TEST_F(BubbleBorderTest, GetMirroredArrow) {
   // Horizontal mirroring.
@@ -202,39 +204,212 @@ TEST_F(BubbleBorderTest, IsArrowAtCenter) {
   EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::FLOAT));
 }
 
-TEST_F(BubbleBorderTest, TestMinimalSize) {
-  gfx::Rect anchor = gfx::Rect(100, 100, 20, 20);
-  gfx::Size contents = gfx::Size(10, 10);
-  BubbleBorder b1(BubbleBorder::RIGHT_TOP, BubbleBorder::NO_SHADOW, 0);
-
-  // The height should be much bigger then the requested size + border and
-  // padding since it needs to be able to include the tip bitmap.
-  gfx::Rect visible_tip_1 = b1.GetBounds(anchor, contents);
-  EXPECT_GE(visible_tip_1.height(), 30);
-  EXPECT_LE(visible_tip_1.width(), 30);
-
-  // With the tip being invisible the height should now be much smaller.
-  b1.set_paint_arrow(BubbleBorder::PAINT_TRANSPARENT);
-  gfx::Rect invisible_tip_1 = b1.GetBounds(anchor, contents);
-  EXPECT_LE(invisible_tip_1.height(), 30);
-  EXPECT_LE(invisible_tip_1.width(), 30);
-
-  // When the orientation of the tip changes, the above mentioned tests need to
-  // be reverse for width and height.
-  BubbleBorder b2(BubbleBorder::TOP_RIGHT, BubbleBorder::NO_SHADOW, 0);
-
-  // The width should be much bigger then the requested size + border and
-  // padding since it needs to be able to include the tip bitmap.
-  gfx::Rect visible_tip_2 = b2.GetBounds(anchor, contents);
-  EXPECT_GE(visible_tip_2.width(), 30);
-  EXPECT_LE(visible_tip_2.height(), 30);
-
-  // With the tip being invisible the width should now be much smaller.
-  b2.set_paint_arrow(BubbleBorder::PAINT_TRANSPARENT);
-  gfx::Rect invisible_tip_2 = b2.GetBounds(anchor, contents);
-  EXPECT_LE(invisible_tip_2.width(), 30);
-  EXPECT_LE(invisible_tip_2.height(), 30);
+TEST_F(BubbleBorderTest, GetSizeForContentsSizeTest) {
+  views::BubbleBorder border(BubbleBorder::NONE,
+                             BubbleBorder::NO_SHADOW,
+                             SK_ColorWHITE);
+
+  const views::internal::BorderImages* kImages = border.GetImagesForTest();
+
+  // kSmallSize is smaller than the minimum allowable size and does not
+  // contribute to the resulting size.
+  const gfx::Size kSmallSize = gfx::Size(1, 2);
+  // kMediumSize is larger than the minimum allowable size and contributes to
+  // the resulting size.
+  const gfx::Size kMediumSize = gfx::Size(50, 60);
+
+  const gfx::Size kSmallHorizArrow(
+      2 * kImages->border_thickness + kImages->top_arrow.width(),
+      kImages->border_thickness + kImages->arrow_thickness +
+          kImages->border_interior_thickness);
+
+  const gfx::Size kSmallVertArrow(kSmallHorizArrow.height(),
+                                  kSmallHorizArrow.width());
+
+  const gfx::Size kSmallNoArrow(2 * kImages->border_thickness,
+                                2 * kImages->border_thickness);
+
+  const gfx::Size kMediumHorizArrow(
+      kMediumSize.width() + 2 * border.GetBorderThickness(),
+      kMediumSize.height() + border.GetBorderThickness() +
+          kImages->arrow_thickness);
+
+  const gfx::Size kMediumVertArrow(
+      kMediumSize.width() + border.GetBorderThickness() +
+          kImages->arrow_thickness,
+      kMediumSize.height() + 2 * border.GetBorderThickness());
+
+  const gfx::Size kMediumNoArrow(
+      kMediumSize.width() + 2 * border.GetBorderThickness(),
+      kMediumSize.height() + 2 * border.GetBorderThickness());
+
+  struct TestCase {
+    BubbleBorder::Arrow arrow;
+    gfx::Size content;
+    gfx::Size expected_with_arrow;
+    gfx::Size expected_without_arrow;
+  };
+
+  TestCase cases[] = {
+    // Content size: kSmallSize
+    { BubbleBorder::TOP_LEFT, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
+    { BubbleBorder::TOP_CENTER, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
+    { BubbleBorder::TOP_RIGHT, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
+    { BubbleBorder::BOTTOM_LEFT, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
+    { BubbleBorder::BOTTOM_CENTER, kSmallSize, kSmallHorizArrow,
+      kSmallNoArrow },
+    { BubbleBorder::BOTTOM_RIGHT, kSmallSize, kSmallHorizArrow, kSmallNoArrow },
+    { BubbleBorder::LEFT_TOP, kSmallSize, kSmallVertArrow, kSmallNoArrow },
+    { BubbleBorder::LEFT_CENTER, kSmallSize, kSmallVertArrow, kSmallNoArrow },
+    { BubbleBorder::LEFT_BOTTOM, kSmallSize, kSmallVertArrow, kSmallNoArrow },
+    { BubbleBorder::RIGHT_TOP, kSmallSize, kSmallVertArrow, kSmallNoArrow },
+    { BubbleBorder::RIGHT_CENTER, kSmallSize, kSmallVertArrow, kSmallNoArrow },
+    { BubbleBorder::RIGHT_BOTTOM, kSmallSize, kSmallVertArrow, kSmallNoArrow },
+    { BubbleBorder::NONE, kSmallSize, kSmallNoArrow, kSmallNoArrow },
+    { BubbleBorder::FLOAT, kSmallSize, kSmallNoArrow, kSmallNoArrow },
+
+    // Content size: kMediumSize
+    { BubbleBorder::TOP_LEFT, kMediumSize, kMediumHorizArrow, kMediumNoArrow },
+    { BubbleBorder::TOP_CENTER, kMediumSize, kMediumHorizArrow,
+      kMediumNoArrow },
+    { BubbleBorder::TOP_RIGHT, kMediumSize, kMediumHorizArrow, kMediumNoArrow },
+    { BubbleBorder::BOTTOM_LEFT, kMediumSize, kMediumHorizArrow,
+      kMediumNoArrow },
+    { BubbleBorder::BOTTOM_CENTER, kMediumSize, kMediumHorizArrow,
+      kMediumNoArrow },
+    { BubbleBorder::BOTTOM_RIGHT, kMediumSize, kMediumHorizArrow,
+      kMediumNoArrow },
+    { BubbleBorder::LEFT_TOP, kMediumSize, kMediumVertArrow, kMediumNoArrow },
+    { BubbleBorder::LEFT_CENTER, kMediumSize, kMediumVertArrow,
+      kMediumNoArrow },
+    { BubbleBorder::LEFT_BOTTOM, kMediumSize, kMediumVertArrow,
+      kMediumNoArrow },
+    { BubbleBorder::RIGHT_TOP, kMediumSize, kMediumVertArrow, kMediumNoArrow },
+    { BubbleBorder::RIGHT_CENTER, kMediumSize, kMediumVertArrow,
+      kMediumNoArrow },
+    { BubbleBorder::RIGHT_BOTTOM, kMediumSize, kMediumVertArrow,
+      kMediumNoArrow },
+    { BubbleBorder::NONE, kMediumSize, kMediumNoArrow, kMediumNoArrow },
+    { BubbleBorder::FLOAT, kMediumSize, kMediumNoArrow, kMediumNoArrow }
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    SCOPED_TRACE(base::StringPrintf("i=%d arrow=%d",
+        static_cast<int>(i), cases[i].arrow));
+
+    border.set_arrow(cases[i].arrow);
+
+    border.set_paint_arrow(BubbleBorder::PAINT_NORMAL);
+    EXPECT_EQ(cases[i].expected_with_arrow,
+              border.GetSizeForContentsSize(cases[i].content));
+
+    border.set_paint_arrow(BubbleBorder::PAINT_TRANSPARENT);
+    EXPECT_EQ(cases[i].expected_with_arrow,
+              border.GetSizeForContentsSize(cases[i].content));
+
+    border.set_paint_arrow(BubbleBorder::PAINT_NONE);
+    EXPECT_EQ(cases[i].expected_without_arrow,
+              border.GetSizeForContentsSize(cases[i].content));
+  }
 }
 
+TEST_F(BubbleBorderTest, GetBoundsOriginTest) {
+  views::BubbleBorder border(BubbleBorder::TOP_LEFT,
+                             BubbleBorder::NO_SHADOW,
+                             SK_ColorWHITE);
+
+  const gfx::Rect kAnchor(100, 100, 20, 30);
+  const gfx::Size kContentSize(50, 60);
+
+  const views::internal::BorderImages* kImages = border.GetImagesForTest();
+
+  border.set_arrow(BubbleBorder::TOP_LEFT);
+  const gfx::Size kTotalSizeWithHorizArrow =
+      border.GetSizeForContentsSize(kContentSize);
+
+  border.set_arrow(BubbleBorder::RIGHT_BOTTOM);
+  const gfx::Size kTotalSizeWithVertArrow =
+      border.GetSizeForContentsSize(kContentSize);
+
+  border.set_arrow(BubbleBorder::NONE);
+  const gfx::Size kTotalSizeWithNoArrow =
+      border.GetSizeForContentsSize(kContentSize);
+
+  const int kBorderThickness = border.GetBorderThickness();
+
+  const int kArrowOffsetForHorizCenter = kTotalSizeWithHorizArrow.width() / 2;
+  const int kArrowOffsetForVertCenter = kTotalSizeWithVertArrow.height() / 2;
+  const int kArrowOffsetForNotCenter =
+      kImages->border_thickness + (kImages->top_arrow.width() / 2);
+
+  const int kArrowSize =
+      kImages->arrow_interior_thickness + BubbleBorder::kStroke -
+          kImages->arrow_thickness;
+
+  const int kTopHorizArrowY = kAnchor.y() + kAnchor.height() + kArrowSize;
+  const int kBottomHorizArrowY =
+      kAnchor.y() - kArrowSize - kTotalSizeWithHorizArrow.height();
+
+  const int kLeftVertArrowX = kAnchor.x() + kAnchor.width() + kArrowSize;
+  const int kRightVertArrowX =
+      kAnchor.x() - kArrowSize - kTotalSizeWithVertArrow.width();
+
+  struct TestCase {
+    BubbleBorder::Arrow arrow;
+    BubbleBorder::BubbleAlignment alignment;
+    int expected_x;
+    int expected_y;
+  };
+
+  TestCase cases[] = {
+    // Horizontal arrow tests.
+    { BubbleBorder::TOP_LEFT, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
+      kAnchor.CenterPoint().x() - kArrowOffsetForNotCenter, kTopHorizArrowY },
+    { BubbleBorder::TOP_LEFT, BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE,
+      kAnchor.x() + BubbleBorder::kStroke - kBorderThickness, kTopHorizArrowY },
+    { BubbleBorder::TOP_CENTER, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
+      kAnchor.CenterPoint().x() - kArrowOffsetForHorizCenter, kTopHorizArrowY },
+    { BubbleBorder::BOTTOM_RIGHT, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
+      kAnchor.CenterPoint().x() + kArrowOffsetForNotCenter -
+          kTotalSizeWithHorizArrow.width(), kBottomHorizArrowY },
+    { BubbleBorder::BOTTOM_RIGHT, BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE,
+      kAnchor.x() + kAnchor.width() - kTotalSizeWithHorizArrow.width() +
+          kBorderThickness - BubbleBorder::kStroke, kBottomHorizArrowY },
+
+    // Vertical arrow tests.
+    { BubbleBorder::LEFT_TOP, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
+      kLeftVertArrowX, kAnchor.CenterPoint().y() - kArrowOffsetForNotCenter },
+    { BubbleBorder::LEFT_TOP, BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE,
+      kLeftVertArrowX, kAnchor.y() + BubbleBorder::kStroke - kBorderThickness },
+    { BubbleBorder::LEFT_CENTER, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
+      kLeftVertArrowX, kAnchor.CenterPoint().y() - kArrowOffsetForVertCenter },
+    { BubbleBorder::RIGHT_BOTTOM, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
+      kRightVertArrowX, kAnchor.CenterPoint().y() + kArrowOffsetForNotCenter -
+          kTotalSizeWithVertArrow.height() },
+    { BubbleBorder::RIGHT_BOTTOM, BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE,
+      kRightVertArrowX, kAnchor.y() + kAnchor.height() -
+          kTotalSizeWithVertArrow.height() + kBorderThickness -
+          BubbleBorder::kStroke },
+
+    // No arrow tests.
+    { BubbleBorder::NONE, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
+      kAnchor.x() + (kAnchor.width() - kTotalSizeWithNoArrow.width()) / 2,
+      kAnchor.y() + kAnchor.height() },
+    { BubbleBorder::FLOAT, BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR,
+      kAnchor.x() + (kAnchor.width() - kTotalSizeWithNoArrow.width()) / 2,
+      kAnchor.y() + (kAnchor.height() - kTotalSizeWithNoArrow.height()) / 2 },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    SCOPED_TRACE(base::StringPrintf("i=%d arrow=%d alignment=%d",
+        static_cast<int>(i), cases[i].arrow, cases[i].alignment));
+    border.set_arrow(cases[i].arrow);
+    border.set_alignment(cases[i].alignment);
+
+    gfx::Point origin = border.GetBounds(kAnchor, kContentSize).origin();
+    EXPECT_EQ(cases[i].expected_x, origin.x());
+    EXPECT_EQ(cases[i].expected_y, origin.y());
+  }
+}
 
 }  // namespace views
index 090ab4f..aad1ba7 100644 (file)
@@ -58,7 +58,6 @@ class MouseMoveDetectorHost : public MouseWatcherHost {
   virtual bool Contains(const gfx::Point& screen_point,
                         MouseEventType type) OVERRIDE;
  private:
-
   DISALLOW_COPY_AND_ASSIGN(MouseMoveDetectorHost);
 };
 
@@ -380,6 +379,7 @@ void TrayBubbleView::SetWidth(int width) {
 void TrayBubbleView::SetArrowPaintType(
     views::BubbleBorder::ArrowPaintType paint_type) {
   bubble_border_->set_paint_arrow(paint_type);
+  UpdateBubble();
 }
 
 gfx::Insets TrayBubbleView::GetBorderInsets() const {
index 45f1a86..4f6c7d4 100644 (file)
@@ -280,7 +280,28 @@ gfx::Rect DesktopWindowTreeHostWin::GetWorkAreaBoundsInScreen() const {
 
 void DesktopWindowTreeHostWin::SetShape(gfx::NativeRegion native_region) {
   if (native_region) {
-    message_handler_->SetRegion(gfx::CreateHRGNFromSkRegion(*native_region));
+    // TODO(wez): This would be a lot simpler if we were passed an SkPath.
+    // See crbug.com/410593.
+    gfx::NativeRegion shape = native_region;
+    SkRegion device_region;
+    if (gfx::IsInHighDPIMode()) {
+      shape = &device_region;
+      const float& scale = gfx::GetDPIScale();
+      std::vector<SkIRect> rects;
+      for (SkRegion::Iterator it(*native_region); !it.done(); it.next()) {
+        const SkIRect& rect = it.rect();
+        SkRect scaled_rect =
+            SkRect::MakeLTRB(rect.left() * scale, rect.top() * scale,
+                             rect.right() * scale, rect.bottom() * scale);
+        SkIRect rounded_scaled_rect;
+        scaled_rect.roundOut(&rounded_scaled_rect);
+        rects.push_back(rounded_scaled_rect);
+      }
+      if (!rects.empty())
+        device_region.setRects(&rects[0], rects.size());
+    }
+
+    message_handler_->SetRegion(gfx::CreateHRGNFromSkRegion(*shape));
   } else {
     message_handler_->SetRegion(NULL);
   }
index 9be53e0..92f3f7f 100644 (file)
@@ -193,8 +193,10 @@ Address CodeRange::AllocateRawMemory(const size_t requested_size,
                                      const size_t commit_size,
                                      size_t* allocated) {
   DCHECK(commit_size <= requested_size);
-  DCHECK(current_allocation_block_index_ < allocation_list_.length());
-  if (requested_size > allocation_list_[current_allocation_block_index_].size) {
+  DCHECK(allocation_list_.length() == 0 ||
+         current_allocation_block_index_ < allocation_list_.length());
+  if (allocation_list_.length() == 0 ||
+      requested_size > allocation_list_[current_allocation_block_index_].size) {
     // Find an allocation block large enough.
     if (!GetNextAllocationBlock(requested_size)) return NULL;
   }
@@ -218,7 +220,7 @@ Address CodeRange::AllocateRawMemory(const size_t requested_size,
   allocation_list_[current_allocation_block_index_].size -= *allocated;
   if (*allocated == current.size) {
     // This block is used up, get the next one.
-    if (!GetNextAllocationBlock(0)) return NULL;
+    GetNextAllocationBlock(0);
   }
   return current.start;
 }
index fcbd299..4411fa1 100644 (file)
@@ -1535,17 +1535,8 @@ HInstruction* HForceRepresentation::New(Zone* zone, HValue* context,
        HValue* value, Representation representation) {
   if (FLAG_fold_constants && value->IsConstant()) {
     HConstant* c = HConstant::cast(value);
-    if (c->HasNumberValue()) {
-      double double_res = c->DoubleValue();
-      if (representation.IsDouble()) {
-        return HConstant::New(zone, context, double_res);
-
-      } else if (representation.CanContainDouble(double_res)) {
-        return HConstant::New(zone, context,
-                              static_cast<int32_t>(double_res),
-                              representation);
-      }
-    }
+    c = c->CopyToRepresentation(representation, zone);
+    if (c != NULL) return c;
   }
   return new(zone) HForceRepresentation(value, representation);
 }
index ca9adec..ceb73fa 100644 (file)
@@ -9205,6 +9205,12 @@ HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver,
 
   Push(graph()->GetConstantMinus1());
   if (IsFastDoubleElementsKind(kind) || IsFastSmiElementsKind(kind)) {
+    // Make sure that we can actually compare numbers correctly below, see
+    // https://code.google.com/p/chromium/issues/detail?id=407946 for details.
+    search_element = AddUncasted<HForceRepresentation>(
+        search_element, IsFastSmiElementsKind(kind) ? Representation::Smi()
+                                                    : Representation::Double());
+
     LoopBuilder loop(this, context(), direction);
     {
       HValue* index = loop.BeginBody(initial, terminating, token);
@@ -9212,12 +9218,8 @@ HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver,
           elements, index, static_cast<HValue*>(NULL),
           kind, ALLOW_RETURN_HOLE);
       IfBuilder if_issame(this);
-      if (IsFastDoubleElementsKind(kind)) {
-        if_issame.If<HCompareNumericAndBranch>(
-            element, search_element, Token::EQ_STRICT);
-      } else {
-        if_issame.If<HCompareObjectEqAndBranch>(element, search_element);
-      }
+      if_issame.If<HCompareNumericAndBranch>(element, search_element,
+                                             Token::EQ_STRICT);
       if_issame.Then();
       {
         Drop(1);
index eaa596f..efb27b3 100644 (file)
 namespace v8 {
 namespace internal {
 
-inline bool Representation::CanContainDouble(double value) {
-  if (IsDouble() || is_more_general_than(Representation::Double())) {
-    return true;
-  }
-  if (IsInt32Double(value)) {
-    if (IsInteger32()) return true;
-    if (IsSmi()) return Smi::IsValid(static_cast<int32_t>(value));
-  }
-  return false;
-}
-
-
 Representation Representation::FromType(Type* type) {
   DisallowHeapAllocation no_allocation;
   if (type->Is(Type::None())) return Representation::None();
index 36a817c..6a75ae7 100644 (file)
@@ -131,8 +131,6 @@ class Representation {
     return other.is_more_general_than(*this) || other.Equals(*this);
   }
 
-  bool CanContainDouble(double value);
-
   Representation generalize(Representation other) {
     if (other.fits_into(*this)) return *this;
     if (other.is_more_general_than(*this)) return other;
index cbb4044..afcd7b8 100644 (file)
@@ -35,7 +35,7 @@
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     28
 #define BUILD_NUMBER      71
-#define PATCH_LEVEL 5
+#define PATCH_LEVEL 9
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
 #define IS_CANDIDATE_VERSION 0
index 0062094..3c59610 100644 (file)
@@ -203,6 +203,28 @@ static void VerifyMemoryChunk(Isolate* isolate,
 }
 
 
+TEST(Regress3540) {
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->InitializeLoggingAndCounters();
+  Heap* heap = isolate->heap();
+  CHECK(heap->ConfigureHeapDefault());
+  MemoryAllocator* memory_allocator = new MemoryAllocator(isolate);
+  CHECK(
+      memory_allocator->SetUp(heap->MaxReserved(), heap->MaxExecutableSize()));
+  TestMemoryAllocatorScope test_allocator_scope(isolate, memory_allocator);
+  CodeRange* code_range = new CodeRange(isolate);
+  const size_t code_range_size = 4 * MB;
+  if (!code_range->SetUp(code_range_size)) return;
+  size_t allocated_size;
+  Address result;
+  for (int i = 0; i < 5; i++) {
+    result = code_range->AllocateRawMemory(
+        code_range_size - MB, code_range_size - MB, &allocated_size);
+    CHECK((result != NULL) == (i == 0));
+  }
+}
+
+
 static unsigned int Pseudorandom() {
   static uint32_t lo = 2345;
   lo = 18273 * (lo & 0xFFFFF) + (lo >> 16);
diff --git a/src/v8/test/mjsunit/regress/regress-crbug-407946.js b/src/v8/test/mjsunit/regress/regress-crbug-407946.js
new file mode 100644 (file)
index 0000000..d5687cc
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function f(n) { return [0].indexOf((n - n) + 0); }
+
+assertEquals(0, f(.1));
+assertEquals(0, f(.1));
+%OptimizeFunctionOnNextCall(f);
+assertEquals(0, f(.1));
diff --git a/src/v8/test/mjsunit/regress/regress-force-constant-representation.js b/src/v8/test/mjsunit/regress/regress-force-constant-representation.js
new file mode 100644 (file)
index 0000000..4ec2a6a
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+// Test push double as tagged.
+var a = [{}];
+function f(a) {
+  a.push(Infinity);
+}
+
+f(a);
+f(a);
+f(a);
+%OptimizeFunctionOnNextCall(f);
+f(a);
+assertEquals([{}, Infinity, Infinity, Infinity, Infinity], a);
index c14d5c1..7b6d3a3 100644 (file)
@@ -50,6 +50,9 @@
 ['simulator', {
   'function-apply-aliased': [SKIP],
 }],  # 'simulator'
+['arch == arm and simulator_run == True', {
+  'dfg-int-overflow-in-loop': [SKIP],
+}],  # 'arch == arm and simulator_run == True'
 ['arch == arm64 and simulator_run == True', {
   'dfg-int-overflow-in-loop': [SKIP],
 }],  # 'arch == arm64 and simulator_run == True'
index 6e9f554..0592024 100755 (executable)
@@ -28,6 +28,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
+from collections import OrderedDict
 import itertools
 import multiprocessing
 import optparse
@@ -52,6 +53,31 @@ from testrunner.objects import context
 ARCH_GUESS = utils.DefaultArch()
 DEFAULT_TESTS = ["mjsunit", "fuzz-natives", "base-unittests",
                  "cctest", "compiler-unittests", "message", "preparser"]
+
+# Map of test name synonyms to lists of test suites. Should be ordered by
+# expected runtimes (suites with slow test cases first). These groups are
+# invoked in seperate steps on the bots.
+TEST_MAP = {
+  "default": [
+    "mjsunit",
+    "fuzz-natives",
+    "cctest",
+    "message",
+    "preparser",
+  ],
+  "optimize_for_size": [
+    "mjsunit",
+    "cctest",
+    "webkit",
+  ],
+  "unittests": [
+    "compiler-unittests",
+    "heap-unittests",
+    "base-unittests",
+    "libplatform-unittests",
+  ],
+}
+
 TIMEOUT_DEFAULT = 60
 TIMEOUT_SCALEFACTOR = {"debug"   : 4,
                        "release" : 1 }
@@ -377,14 +403,23 @@ def Main():
 
   suite_paths = utils.GetSuitePaths(join(workspace, "test"))
 
+  # Expand arguments with grouped tests. The args should reflect the list of
+  # suites as otherwise filters would break.
+  def ExpandTestGroups(name):
+    if name in TEST_MAP:
+      return [suite for suite in TEST_MAP[arg]]
+    else:
+      return [name]
+  args = reduce(lambda x, y: x + y,
+         [ExpandTestGroups(arg) for arg in args],
+         [])
+
   if len(args) == 0:
     suite_paths = [ s for s in DEFAULT_TESTS if s in suite_paths ]
   else:
-    args_suites = set()
+    args_suites = OrderedDict() # Used as set
     for arg in args:
-      suite = arg.split(os.path.sep)[0]
-      if not suite in args_suites:
-        args_suites.add(suite)
+      args_suites[arg.split(os.path.sep)[0]] = True
     suite_paths = [ s for s in args_suites if s in suite_paths ]
 
   suites = []
index 3785d38..e4ca1d8 100644 (file)
@@ -110,6 +110,13 @@ bool ContextProviderInProcess::BindToCurrentThread() {
 
 void ContextProviderInProcess::InitializeCapabilities() {
   capabilities_.gpu = context3d_->GetImplementation()->capabilities();
+
+  size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit();
+  capabilities_.max_transfer_buffer_usage_bytes =
+      mapped_memory_limit ==
+              WebGraphicsContext3DInProcessCommandBufferImpl::kNoLimit
+          ? std::numeric_limits<size_t>::max()
+          : mapped_memory_limit;
 }
 
 cc::ContextProvider::Capabilities
index afd843a..2dc7dc8 100644 (file)
@@ -118,6 +118,10 @@ WebGraphicsContext3DInProcessCommandBufferImpl::
     ~WebGraphicsContext3DInProcessCommandBufferImpl() {
 }
 
+size_t WebGraphicsContext3DInProcessCommandBufferImpl::GetMappedMemoryLimit() {
+  return context_->GetMappedMemoryLimit();
+}
+
 bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() {
   if (initialized_)
     return true;
@@ -135,15 +139,17 @@ bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() {
     // will need to be lost either when the first context requesting the
     // discrete GPU is created, or the last one is destroyed.
     gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
-    context_.reset(GLInProcessContext::Create(NULL, /* service */
-                                              NULL, /* surface */
-                                              is_offscreen_,
-                                              window_,
-                                              gfx::Size(1, 1),
-                                              NULL, /* share_context */
-                                              share_resources_,
-                                              attribs_,
-                                              gpu_preference));
+    context_.reset(GLInProcessContext::Create(
+        NULL, /* service */
+        NULL, /* surface */
+        is_offscreen_,
+        window_,
+        gfx::Size(1, 1),
+        NULL, /* share_context */
+        share_resources_,
+        attribs_,
+        gpu_preference,
+        ::gpu::GLInProcessContextSharedMemoryLimits()));
   }
 
   if (context_) {
index 54d7f17..0248dff 100644 (file)
@@ -36,6 +36,10 @@ namespace gpu {
 class WEBKIT_GPU_EXPORT WebGraphicsContext3DInProcessCommandBufferImpl
     : public WebGraphicsContext3DImpl {
  public:
+  enum MappedMemoryReclaimLimit {
+    kNoLimit = 0,
+  };
+
   static scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
       CreateViewContext(
           const blink::WebGraphicsContext3D::Attributes& attributes,
@@ -54,6 +58,8 @@ class WEBKIT_GPU_EXPORT WebGraphicsContext3DInProcessCommandBufferImpl
 
   virtual ~WebGraphicsContext3DInProcessCommandBufferImpl();
 
+  size_t GetMappedMemoryLimit();
+
   //----------------------------------------------------------------------
   // WebGraphicsContext3D methods
   virtual bool makeContextCurrent();
index 64b0d15..03685f6 100644 (file)
 # Edit these when rolling DEPS.xwalk.
 # -----------------------------------
 
-chromium_crosswalk_rev = '04ba13a65546e6e6309e560b9a2491b904ed57a8'
-blink_crosswalk_rev = '92e5d6adee53362b3f5aaec11bcb0526d5f0715d'
-v8_crosswalk_rev = '9b7376c845d7ba58715f4ffd9a80fd670b021360'
-ozone_wayland_rev = 'd301e5c546a7dea0de8fde5b07a2a57afd02103b'
+chromium_crosswalk_rev = '5ee6f9bf16ecbb3d56b195063b9b55d42effb67b'
+blink_crosswalk_rev = 'bc7b6c17bc9634579c6df664d04fdf38a1edd56a'
+v8_crosswalk_rev = '452135ceb9d31a6bc30fb39bf743623e0f553afa'
+ozone_wayland_rev = '9595d59e35e37675587523590e21397addf78446'
 
 crosswalk_git = 'https://github.com/crosswalk-project'
 ozone_wayland_git = 'https://github.com/01org'
index 0b05496..90600cd 100644 (file)
@@ -1,4 +1,4 @@
-MAJOR=9
+MAJOR=10
 MINOR=38
-BUILD=207
+BUILD=208
 PATCH=0
index 117427e..1d06038 100644 (file)
@@ -13,6 +13,7 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.View;
 
 import org.xwalk.app.runtime.extension.XWalkRuntimeExtensionManager;
@@ -25,6 +26,8 @@ public abstract class XWalkRuntimeActivityBase extends Activity {
 
     private static final String DEFAULT_LIBRARY_APK_URL = null;
 
+    private static final String TAG = "XWalkRuntimeActivityBase";
+
     private XWalkRuntimeView mRuntimeView;
 
     private boolean mShownNotFoundDialog = false;
@@ -140,9 +143,9 @@ public abstract class XWalkRuntimeActivityBase extends Activity {
             } else {
                 XWalkPreferences.setValue(XWalkPreferences.ANIMATABLE_XWALK_VIEW, false);
             }
-            mRuntimeView = new XWalkRuntimeView(this, this, null);
             mShownNotFoundDialog = false;
             if (mLibraryNotFoundDialog != null) mLibraryNotFoundDialog.cancel();
+            mRuntimeView = new XWalkRuntimeView(this, this, null);
             if (mRemoteDebugging) {
                 XWalkPreferences.setValue(XWalkPreferences.REMOTE_DEBUGGING, true);
             } else {
@@ -171,7 +174,7 @@ public abstract class XWalkRuntimeActivityBase extends Activity {
             handleException(e.getCause());
             return;
         }
-        throw new RuntimeException(e);
+        Log.e(TAG, Log.getStackTraceString(e));
     }
 
     private void showRuntimeLibraryExceptionDialog(String title, String message) {
index b276a3d..7b661e9 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-# Copyright (c) 2013 Intel Corporation. All rights reserved.
+# Copyright (c) 2013,2014 Intel Corporation. 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 @@ import re
 import shutil
 import stat
 import sys
+import tempfile
 
 # get xwalk absolute path so we can run this script from any location
 xwalk_dir = os.path.dirname(os.path.abspath(__file__))
@@ -25,6 +26,7 @@ from handle_xml import AddElementAttributeAndText
 from handle_xml import EditElementAttribute
 from handle_xml import EditElementValueByNodeName
 from handle_permissions import HandlePermissions
+from util import CleanDir, CreateAndCopyDir
 from xml.dom import minidom
 
 TEMPLATE_DIR_NAME = 'template'
@@ -115,25 +117,24 @@ def Prepare(app_info, compressor):
   """Copy the Android template project to a new app project
      named app_info.app_name
   """
-  # create new app_dir in xwalk_dir
+  # create new app_dir in temp dir
   app_name = app_info.android_name
-  app_dir = os.path.join(xwalk_dir, app_name)
+  app_dir = os.path.join(tempfile.gettempdir(), app_name)
   app_package = app_info.package
   app_root = app_info.app_root
   template_app_dir = os.path.join(xwalk_dir, TEMPLATE_DIR_NAME)
 
   # 1) copy template project to app_dir
-  if os.path.exists(app_dir):
-    shutil.rmtree(app_dir)
+  CleanDir(app_dir)
   shutil.copytree(template_app_dir, app_dir)
 
   # 2) replace app_dir 'src' dir with template 'src' dir
-  shutil.rmtree(os.path.join(app_dir, 'src'))
+  CleanDir(os.path.join(app_dir, 'src'))
   template_src_root = os.path.join(template_app_dir, 'src', 'org', 'xwalk',
                                    'app', 'template')
 
   # 3) Create directory tree from app package (org.xyz.foo -> src/org/xyz/foo)
-  #    and copy AppTemplateActivity.java to <app_name>Activity.java 
+  #    and copy AppTemplateActivity.java to <app_name>Activity.java
   template_activity_file = os.path.join(template_src_root,
                                         'AppTemplateActivity.java')
   if not os.path.isfile(template_activity_file):
@@ -151,8 +152,7 @@ def Prepare(app_info, compressor):
   # 4) Copy all HTML source from app_root to app_dir
   if app_root:
     app_assets_dir = os.path.join(app_dir, 'assets', 'www')
-    if os.path.isdir(app_assets_dir):
-      shutil.rmtree(app_assets_dir)
+    CleanDir(app_assets_dir)
     shutil.copytree(app_root, app_assets_dir)
     if compressor:
       CompressSourceFiles(app_assets_dir, compressor)
@@ -168,7 +168,8 @@ def EncodingUnicodeValue(value):
 
 
 def CustomizeStringXML(name, description):
-  strings_path = os.path.join(xwalk_dir, name, 'res', 'values', 'strings.xml')
+  strings_path = os.path.join(tempfile.gettempdir(), name, 'res', 'values',
+                              'strings.xml')
   if not os.path.isfile(strings_path):
     print ('Please make sure strings_xml'
            ' exists under template folder.')
@@ -185,7 +186,8 @@ def CustomizeStringXML(name, description):
 
 
 def CustomizeThemeXML(name, fullscreen, manifest):
-  theme_path = os.path.join(xwalk_dir, name, 'res', 'values-v14', 'theme.xml')
+  theme_path = os.path.join(tempfile.gettempdir(), name, 'res', 'values-v14',
+                            'theme.xml')
   if not os.path.isfile(theme_path):
     print('Error: theme.xml is missing in the build tool.')
     sys.exit(6)
@@ -211,6 +213,7 @@ def CustomizeXML(app_info, description, icon_dict, manifest, permissions):
   orientation = app_info.orientation
   package = app_info.package
   app_name = app_info.app_name
+  app_dir = os.path.join(tempfile.gettempdir(), name)
   # Chinese character with unicode get from 'manifest.json' will cause
   # 'UnicodeEncodeError' when finally wrote to 'AndroidManifest.xml'.
   app_name = EncodingUnicodeValue(app_name)
@@ -219,7 +222,7 @@ def CustomizeXML(app_info, description, icon_dict, manifest, permissions):
   # append a space before '@' or '?' to fix that.
   if app_name.startswith('@') or app_name.startswith('?'):
     app_name = ' ' + app_name
-  manifest_path = os.path.join(xwalk_dir, name, 'AndroidManifest.xml')
+  manifest_path = os.path.join(app_dir, 'AndroidManifest.xml')
   if not os.path.isfile(manifest_path):
     print ('Please make sure AndroidManifest.xml'
            ' exists under template folder.')
@@ -251,7 +254,7 @@ def CustomizeXML(app_info, description, icon_dict, manifest, permissions):
     EditElementAttribute(xmldoc, 'application', 'android:icon',
                          '@drawable/%s' % icon_name)
 
-  file_handle = open(os.path.join(xwalk_dir, name, 'AndroidManifest.xml'), 'w')
+  file_handle = open(os.path.join(app_dir, 'AndroidManifest.xml'), 'w')
   xmldoc.writexml(file_handle, encoding='utf-8')
   file_handle.close()
 
@@ -282,12 +285,12 @@ def SetVariable(file_path, string_line, variable, value):
 def CustomizeJava(app_info, app_url, app_local_path, keep_screen_on):
   name = app_info.android_name
   package = app_info.package
-  app_pkg_dir = os.path.join(xwalk_dir, name, 'src',
-                             package.replace('.', os.path.sep))
+  app_dir = os.path.join(tempfile.gettempdir(), name)
+  app_pkg_dir = os.path.join(app_dir, 'src', package.replace('.', os.path.sep))
   dest_activity = os.path.join(app_pkg_dir, name + 'Activity.java')
   ReplaceString(dest_activity, 'org.xwalk.app.template', package)
   ReplaceString(dest_activity, 'AppTemplate', name)
-  manifest_file = os.path.join(xwalk_dir, name, 'assets/www', 'manifest.json')
+  manifest_file = os.path.join(app_dir, 'assets', 'www', 'manifest.json')
   if os.path.isfile(manifest_file):
     ReplaceString(
         dest_activity,
@@ -299,8 +302,7 @@ def CustomizeJava(app_info, app_url, app_local_path, keep_screen_on):
         ReplaceString(dest_activity, 'file:///android_asset/www/index.html',
                       app_url)
     elif app_local_path:
-      if os.path.isfile(os.path.join(xwalk_dir, name, 'assets/www',
-                                     app_local_path)):
+      if os.path.isfile(os.path.join(app_dir, 'assets', 'www', app_local_path)):
         ReplaceString(dest_activity, 'file:///android_asset/www/index.html',
                       'app://' + package + '/' + app_local_path)
       else:
@@ -368,12 +370,12 @@ def CustomizeExtensions(app_info, extensions):
   if not extensions:
     return
   name = app_info.android_name
-  apk_path = os.path.join(xwalk_dir, name)
-  apk_assets_path = os.path.join(apk_path, 'assets')
+  app_dir = os.path.join(tempfile.gettempdir(), name)
+  apk_assets_path = os.path.join(app_dir, 'assets')
   extensions_string = 'xwalk-extensions'
 
   # Set up the target directories and files.
-  dest_jar_path = os.path.join(apk_path, extensions_string)
+  dest_jar_path = os.path.join(app_dir, extensions_string)
   os.mkdir(dest_jar_path)
   dest_js_path = os.path.join(apk_assets_path, extensions_string)
   os.mkdir(dest_js_path)
@@ -420,7 +422,7 @@ def CustomizeExtensions(app_info, extensions):
       json_output['jsapi'] = js_path_prefix + json_output['jsapi']
       extension_json_list.append(json_output)
       # Merge the permissions of extensions into AndroidManifest.xml.
-      manifest_path = os.path.join(xwalk_dir, name, 'AndroidManifest.xml')
+      manifest_path = os.path.join(app_dir, 'AndroidManifest.xml')
       xmldoc = minidom.parse(manifest_path)
       if ('permissions' in json_output):
         # Get used permission list to avoid repetition as "--permissions"
@@ -453,13 +455,15 @@ def CustomizeExtensions(app_info, extensions):
 def GenerateCommandLineFile(app_info, xwalk_command_line):
   if xwalk_command_line == '':
     return
-  assets_path = os.path.join(xwalk_dir, app_info.android_name, 'assets')
+  assets_path = os.path.join(tempfile.gettempdir(), app_info.android_name,
+                             'assets')
   file_path = os.path.join(assets_path, 'xwalk-command-line')
   command_line_file = open(file_path, 'w')
   command_line_file.write('xwalk ' + xwalk_command_line)
 
 
 def CustomizeIconByDict(name, app_root, icon_dict):
+  app_dir = os.path.join(tempfile.gettempdir(), name)
   icon_name = None
   drawable_dict = {'ldpi': [1, 37], 'mdpi': [37, 72], 'hdpi': [72, 96],
                    'xhdpi': [96, 120], 'xxhdpi': [120, 144],
@@ -477,7 +481,7 @@ def CustomizeIconByDict(name, app_root, icon_dict):
     for kd, vd in drawable_dict.items():
       for item in icon_list:
         if item[0] >= vd[0] and item[0] < vd[1]:
-          drawable_path = os.path.join(xwalk_dir, name, 'res', 'drawable-' + kd)
+          drawable_path = os.path.join(app_dir, 'res', 'drawable-' + kd)
           if not os.path.exists(drawable_path):
             os.makedirs(drawable_path)
           icon = os.path.join(app_root, item[1])
@@ -496,7 +500,7 @@ def CustomizeIconByDict(name, app_root, icon_dict):
 
 def CustomizeIconByOption(name, icon):
   if os.path.isfile(icon):
-    drawable_path = os.path.join(xwalk_dir, name, 'res', 'drawable')
+    drawable_path = os.path.join(tempfile.gettempdir(), name, 'res', 'drawable')
     if not os.path.exists(drawable_path):
       os.makedirs(drawable_path)
     icon_file = os.path.basename(icon)
@@ -505,7 +509,7 @@ def CustomizeIconByOption(name, icon):
     icon_name = os.path.splitext(icon_file)[0]
     return icon_name
   else:
-    print('Error: "%s" does not exist.')
+    print('Error: "%s" does not exist.' % icon)
     sys.exit(6)
 
 
@@ -588,6 +592,8 @@ def main():
           'Crosswalk is powered by Chromium and supports Chromium command line.'
           'For example, '
           '--xwalk-command-line=\'--chromium-command-1 --xwalk-command-2\'')
+  info = ('Create an Android project directory at this location. ')
+  parser.add_option('--project-dir', help=info)
   parser.add_option('--xwalk-command-line', default='', help=info)
   info = ('Minify and obfuscate javascript and css.'
           '--compressor: compress javascript and css.'
@@ -625,9 +631,18 @@ def main():
                  options.permissions, options.app_url, options.app_local_path,
                  options.keep_screen_on, options.extensions, None,
                  options.xwalk_command_line, options.compressor)
+
+    # build project is now in /tmp/<name>. Copy to project_dir
+    if options.project_dir:
+      src_dir = os.path.join(tempfile.gettempdir(), app_info.android_name)
+      dest_dir = os.path.join(options.project_dir, app_info.android_name)
+      CreateAndCopyDir(src_dir, dest_dir, True)
+
   except SystemExit as ec:
     print('Exiting with error code: %d' % ec.code)
     return ec.code
+  finally:
+    CleanDir(os.path.join(tempfile.gettempdir(), app_info.android_name))
   return 0
 
 
index 719d02f..c85d0fd 100755 (executable)
@@ -7,8 +7,7 @@
 import os
 import shutil
 import sys
-
-xwalk_dir = os.path.dirname(os.path.abspath(__file__))
+import tempfile
 
 def CopyToPathWithName(root, name, final_path, rename):
   if name == '':
@@ -30,7 +29,8 @@ def CopyToPathWithName(root, name, final_path, rename):
 
 
 def CopyDrawables(image_dict, orientation, sanitized_name, name, app_root):
-  drawable = os.path.join(xwalk_dir, sanitized_name, 'res', 'drawable')
+  drawable = os.path.join(tempfile.gettempdir(), sanitized_name, 'res',
+                          'drawable')
   if orientation == 'landscape':
     drawable = drawable + '-land'
   elif orientation == 'portrait':
@@ -114,7 +114,7 @@ def CustomizeBackground(background_color,
                         orientation,
                         sanitized_name,
                         app_root):
-  background_path = os.path.join(xwalk_dir, sanitized_name, 'res',
+  background_path = os.path.join(tempfile.gettempdir(), sanitized_name, 'res',
                                  'drawable', 'launchscreen_bg.xml')
   if not os.path.isfile(background_path):
     print('Error: launchscreen_bg.xml is missing in the build tool.')
index 65a6409..19d14e0 100755 (executable)
@@ -12,6 +12,7 @@ import re
 import shutil
 import subprocess
 import sys
+import tempfile
 
 # get xwalk absolute path so we can run this script from any location
 xwalk_dir = os.path.dirname(os.path.abspath(__file__))
@@ -22,7 +23,8 @@ from customize import VerifyPackageName, CustomizeAll, \
                       ParseParameterForCompressor
 from extension_manager import GetExtensionList, GetExtensionStatus
 from handle_permissions import permission_mapping_table
-from util import AllArchitectures, CleanDir, GetVersion, RunCommand
+from util import AllArchitectures, CleanDir, GetVersion, RunCommand, \
+                 CreateAndCopyDir
 from manifest_json_parser import HandlePermissionList
 from manifest_json_parser import ManifestJsonParser
 
@@ -107,7 +109,7 @@ def ParseManifest(options):
 
 
 def ParseXPK(options, out_dir):
-  cmd = ['python', os.path.join (xwalk_dir, 'parse_xpk.py'),
+  cmd = ['python', os.path.join(xwalk_dir, 'parse_xpk.py'),
          '--file=%s' % os.path.expanduser(options.xpk),
          '--out=%s' % out_dir]
   RunCommand(cmd)
@@ -218,7 +220,7 @@ def Customize(options, app_info, manifest):
   extension_binary_path_list = GetExtensionBinaryPathList()
   if len(extension_binary_path_list) > 0:
     if options.extensions is None:
-      options.extensions = "" 
+      options.extensions = ""
     else:
       options.extensions += os.pathsep
 
@@ -235,6 +237,7 @@ def Customize(options, app_info, manifest):
 
 
 def Execution(options, name):
+  app_dir = os.path.join(tempfile.gettempdir(), name)
   android_path = Which('android')
   if android_path is None:
     print('The "android" binary could not be found. Check your Android SDK '
@@ -278,27 +281,24 @@ def Execution(options, name):
 
   # Update android project for app and xwalk_core_library.
   update_project_cmd = [android_path, 'update', 'project',
-                        '--path', os.path.join (xwalk_dir, name),
+                        '--path', app_dir,
                         '--target', target_string,
                         '--name', name]
   if options.mode == 'embedded':
     RunCommand([android_path, 'update', 'lib-project',
-                '--path', os.path.join(xwalk_dir, name, 'xwalk_core_library'),
+                '--path', os.path.join(app_dir, 'xwalk_core_library'),
                 '--target', target_string])
     update_project_cmd.extend(['-l', 'xwalk_core_library'])
-  else:
-    # Shared mode doesn't need xwalk_runtime_java.jar.
-    os.remove(os.path.join(xwalk_dir, name, 'libs', 'xwalk_runtime_java.jar'))
 
   RunCommand(update_project_cmd)
 
   # Check whether external extensions are included.
   extensions_string = 'xwalk-extensions'
-  extensions_dir = os.path.join(xwalk_dir, name, extensions_string)
+  extensions_dir = os.path.join(app_dir, extensions_string)
   external_extension_jars = FindExtensionJars(extensions_dir)
   for external_extension_jar in external_extension_jars:
     shutil.copyfile(external_extension_jar,
-                    os.path.join(xwalk_dir, name, 'libs',
+                    os.path.join(app_dir, 'libs',
                                  os.path.basename(external_extension_jar)))
 
   if options.mode == 'embedded':
@@ -310,13 +310,12 @@ def Execution(options, name):
     if not arch:
       print ('Invalid CPU arch: %s.' % arch)
       sys.exit(10)
-    library_lib_path = os.path.join(xwalk_dir, name, 'xwalk_core_library',
-                                    'libs')
+    library_lib_path = os.path.join(app_dir, 'xwalk_core_library', 'libs')
     for dir_name in os.listdir(library_lib_path):
       lib_dir = os.path.join(library_lib_path, dir_name)
       if ContainsNativeLibrary(lib_dir):
         shutil.rmtree(lib_dir)
-    native_lib_path = os.path.join(xwalk_dir, name, 'native_libs', arch)
+    native_lib_path = os.path.join(app_dir, 'native_libs', arch)
     if ContainsNativeLibrary(native_lib_path):
       shutil.copytree(native_lib_path, os.path.join(library_lib_path, arch))
     else:
@@ -324,8 +323,11 @@ def Execution(options, name):
             'embedded APK.' % arch)
       sys.exit(10)
 
-  ant_cmd = [ant_path, 'release', '-f',
-             os.path.join(xwalk_dir, name, 'build.xml')]
+  if options.project_only:
+    return
+
+  # Build the APK
+  ant_cmd = [ant_path, 'release', '-f', os.path.join(app_dir, 'build.xml')]
   if not options.verbose:
     ant_cmd.extend(['-quiet'])
   ant_cmd.extend(['-Dkey.store=%s' % os.path.abspath(key_store)])
@@ -340,7 +342,7 @@ def Execution(options, name):
           % (' '.join(ant_cmd), ant_result))
     sys.exit(ant_result)
 
-  src_file = os.path.join(xwalk_dir, name, 'bin', '%s-release.apk' % name)
+  src_file = os.path.join(app_dir, 'bin', '%s-release.apk' % name)
   package_name = name
   if options.app_version:
     package_name += ('_' + options.app_version)
@@ -392,19 +394,25 @@ def PrintPackageInfo(options, name, packaged_archs):
 def MakeApk(options, app_info, manifest):
   Customize(options, app_info, manifest)
   name = app_info.android_name
+  app_dir = os.path.join(tempfile.gettempdir(), name)
   packaged_archs = []
   if options.mode == 'shared':
+    # For shared mode, it's not necessary to use the whole xwalk core library,
+    # use xwalk_core_library_java_app_part.jar from it is enough.
+    java_app_part_jar = os.path.join(xwalk_dir, 'xwalk_core_library', 'libs',
+                                     'xwalk_core_library_java_app_part.jar')
+    shutil.copy(java_app_part_jar, os.path.join(app_dir, 'libs'))
     Execution(options, name)
   elif options.mode == 'embedded':
     # Copy xwalk_core_library into app folder and move the native libraries
     # out.
     # When making apk for specified CPU arch, will only include the
     # corresponding native library by copying it back into xwalk_core_library.
-    target_library_path = os.path.join(xwalk_dir, name, 'xwalk_core_library')
+    target_library_path = os.path.join(app_dir, 'xwalk_core_library')
     shutil.copytree(os.path.join(xwalk_dir, 'xwalk_core_library'),
                     target_library_path)
     library_lib_path = os.path.join(target_library_path, 'libs')
-    native_lib_path = os.path.join(xwalk_dir, name, 'native_libs')
+    native_lib_path = os.path.join(app_dir, 'native_libs')
     os.makedirs(native_lib_path)
     available_archs = []
     for dir_name in os.listdir(library_lib_path):
@@ -435,7 +443,25 @@ def MakeApk(options, app_info, manifest):
         print('No packages created, aborting')
         sys.exit(13)
 
-  PrintPackageInfo(options, name, packaged_archs)
+  # if project_dir, save build directory
+  if options.project_dir:
+    save_dir = os.path.join(options.project_dir, name)
+    if CreateAndCopyDir(app_dir, save_dir, True):
+      print ('\nA project directory was created successfully in %s' %
+             save_dir)
+      print ('To generate an APK manually, go to %s and run the '
+             'following command:' % save_dir)
+      print ('  ant release -f build.xml')
+      print ('For more information, see\n'
+             ' http://developer.android.com/tools/building/'
+             'building-cmdline.html')
+    else:
+      print ('Error: Unable to create a project directory during the build. '
+             'Please check the directory passed in --project-dir, '
+             'available disk space, and write permission.')
+
+  if not options.project_only:
+    PrintPackageInfo(options, name, packaged_archs)
 
 def main(argv):
   parser = optparse.OptionParser()
@@ -480,6 +506,7 @@ def main(argv):
           'For example, --app-local-path=/relative/path/of/entry/file')
   group.add_option('--app-local-path', help=info)
   parser.add_option_group(group)
+  # Mandatory options group
   group = optparse.OptionGroup(parser, 'Mandatory arguments',
       'They are used for describing the APK information through '
       'command line options.')
@@ -489,6 +516,7 @@ def main(argv):
           '--package=com.example.YourPackage')
   group.add_option('--package', help=info)
   parser.add_option_group(group)
+  # Optional options group (alphabetical)
   group = optparse.OptionGroup(parser, 'Optional arguments',
       'They are used for various settings for applications through '
       'command line options.')
@@ -502,11 +530,6 @@ def main(argv):
           'be made by adding a prefix based on architecture to the version '
           'code base. For example, --app-versionCodeBase=24')
   group.add_option('--app-versionCodeBase', type='int', help=info)
-  info = ('Use command lines.'
-          'Crosswalk is powered by Chromium and supports Chromium command line.'
-          'For example, '
-          '--xwalk-command-line=\'--chromium-command-1 --xwalk-command-2\'')
-  group.add_option('--xwalk-command-line', default='', help=info)
   info = ('The description of the application. For example, '
           '--description=YourApplicationDescription')
   group.add_option('--description', help=info)
@@ -538,9 +561,22 @@ def main(argv):
   info = ('The list of permissions to be used by web application. For example, '
           '--permissions=geolocation:webgl')
   group.add_option('--permissions', help=info)
-  info = ('Packaging tool will move the output APKS to the target directory')
+  info = ('Create an Android project directory with Crosswalk at this location.'
+          ' (See project-only option below)')
+  group.add_option('--project-dir', help=info)
+  info = ('Must be used with project-dir option. Create an Android project '
+          'directory with Crosswalk but do not build the APK package')
+  group.add_option('--project-only', action='store_true', default=False,
+                   dest='project_only', help=info)
+  info = ('Packaging tool will move the output APKs to the target directory')
   group.add_option('--target-dir', default=os.getcwd(), help=info)
+  info = ('Use command lines.'
+          'Crosswalk is powered by Chromium and supports Chromium command line.'
+          'For example, '
+          '--xwalk-command-line=\'--chromium-command-1 --xwalk-command-2\'')
+  group.add_option('--xwalk-command-line', default='', help=info)
   parser.add_option_group(group)
+  # Keystore options group
   group = optparse.OptionGroup(parser, 'Keystore Options',
       'The keystore is a signature from web developer, it\'s used when '
       'developer wants to distribute the applications.')
@@ -578,7 +614,8 @@ def main(argv):
   xpk_temp_dir = ''
   if options.xpk:
     xpk_name = os.path.splitext(os.path.basename(options.xpk))[0]
-    xpk_temp_dir = os.path.join(xwalk_dir, xpk_name + '_xpk')
+    xpk_temp_dir = os.path.join(tempfile.gettempdir(), xpk_name + '_xpk')
+    CleanDir(xpk_temp_dir)
     ParseXPK(options, xpk_temp_dir)
 
   if options.app_root and not options.manifest:
@@ -645,13 +682,23 @@ def main(argv):
     if not os.path.isdir(target_dir):
       os.makedirs(target_dir)
 
+  if options.project_dir:
+    if options.project_dir == tempfile.gettempdir():
+      print('\nmake_apk.py error: Option --project-dir can not be '
+            'the system temporary\ndirectory.')
+      sys.exit(8)
+  if options.project_only and not options.project_dir:
+    print('\nmake_apk.py error: Option --project-only must be used '
+          'with --project-dir')
+    sys.exit(8)
+
   try:
     MakeApk(options, app_info, manifest)
   except SystemExit as ec:
-    CleanDir(app_info.android_name)
-    CleanDir('out')
-    CleanDir(xpk_temp_dir)
     return ec.code
+  finally:
+    CleanDir(os.path.join(tempfile.gettempdir(), app_info.android_name))
+    CleanDir(xpk_temp_dir)
   return 0
 
 
index 2cc9b22..261a241 100755 (executable)
@@ -133,6 +133,7 @@ class TestMakeApk(unittest.TestCase):
     if options.mode == 'embedded':
       native_library_dir = os.path.join('xwalk_core_library', 'libs')
       native_library_temp_dir = 'temp'
+      Clean('temp', '0') # May be left over from aborted tests
       shutil.copytree(native_library_dir, native_library_temp_dir)
       for root, _, files in os.walk(native_library_dir):
         if 'libxwalkcore.so' in files:
@@ -232,7 +233,8 @@ class TestMakeApk(unittest.TestCase):
     cmd = ['python', 'make_apk.py', '--name=Example',
            '--package=org.xwalk.example', '--app-version=1.0.0',
            '--description=a sample application',
-           '--app-url=http://www.intel.com', self._mode]
+           '--app-url=http://www.intel.com',
+           '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     manifest = 'Example/AndroidManifest.xml'
@@ -248,7 +250,9 @@ class TestMakeApk(unittest.TestCase):
            '--package=org.xwalk.example', '--app-version=1.0.0',
            '--description=a sample application',
            '--app-versionCode=3',
-           '--app-url=http://www.intel.com', self._mode]
+           '--app-url=http://www.intel.com',
+           '--project-dir=.',
+           self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     manifest = 'Example/AndroidManifest.xml'
@@ -274,7 +278,9 @@ class TestMakeApk(unittest.TestCase):
            '--description=a sample application',
            '--app-versionCodeBase=3',
            arch,
-           '--app-url=http://www.intel.com', self._mode]
+           '--app-url=http://www.intel.com',
+           '--project-dir=.',
+           self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     manifest = 'Example/AndroidManifest.xml'
@@ -298,7 +304,9 @@ class TestMakeApk(unittest.TestCase):
            '--description=a sample application',
            '--app-versionCodeBase=30000000',
            arch,
-           '--app-url=http://www.intel.com', self._mode]
+           '--app-url=http://www.intel.com',
+           '--project-dir=.',
+           self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     manifest = 'Example/AndroidManifest.xml'
@@ -307,7 +315,9 @@ class TestMakeApk(unittest.TestCase):
   def testPermissions(self):
     cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--permissions=geolocation',
-           '--app-url=http://www.intel.com', self._mode]
+           '--app-url=http://www.intel.com',
+           '--project-dir=.',
+           self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     manifest = 'Example/AndroidManifest.xml'
@@ -439,7 +449,7 @@ class TestMakeApk(unittest.TestCase):
     icon = os.path.join('test_data', 'manifest', 'icons', 'icon_96.png')
     cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--app-url=http://www.intel.com',
-           '--icon=%s' % icon, self._mode]
+           '--icon=%s' % icon, '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     manifest = 'Example/AndroidManifest.xml'
@@ -452,7 +462,7 @@ class TestMakeApk(unittest.TestCase):
     manifest_path = os.path.join('test_data', 'manifest', 'manifest_icon.json')
     cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--app-url=http://www.intel.com',
-           '--manifest=%s' % manifest_path, self._mode]
+           '--manifest=%s' % manifest_path, '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     manifest = 'Example/AndroidManifest.xml'
@@ -464,7 +474,7 @@ class TestMakeApk(unittest.TestCase):
   def testFullscreen(self):
     cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--app-url=http://www.intel.com',
-           '-f', self._mode]
+           '-f', '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     theme = 'Example/res/values-v14/theme.xml'
@@ -479,7 +489,7 @@ class TestMakeApk(unittest.TestCase):
   def testEnableRemoteDebugging(self):
     cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--app-url=http://www.intel.com',
-           '--enable-remote-debugging', self._mode]
+           '--enable-remote-debugging', '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     activity = 'Example/src/org/xwalk/example/ExampleActivity.java'
@@ -492,7 +502,9 @@ class TestMakeApk(unittest.TestCase):
     manifest_path = os.path.join('test_data', 'manifest', 'manifest.json')
     cmd = ['python', 'make_apk.py', '--enable-remote-debugging',
            '--package=org.xwalk.example',
-           '--manifest=%s' % manifest_path, self._mode]
+           '--manifest=%s' % manifest_path,
+           '--project-dir=.',
+           self._mode]
     RunCommand(cmd)
     activity = 'Example/src/org/xwalk/example/ExampleActivity.java'
     with open(activity, 'r') as content_file:
@@ -533,7 +545,8 @@ class TestMakeApk(unittest.TestCase):
            '--package=org.xwalk.example', '--app-url=http://www.intel.com',
            '--keystore-path=%s' % keystore_path, '--keystore-alias=xwalk-test',
            '--keystore-passcode=xwalk-test',
-           '--keystore-alias-passcode=xwalk-test', self._mode]
+           '--keystore-alias-passcode=xwalk-test',
+           '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.assertTrue(os.path.isdir('Example'))
     self.checkApks('Example', '1.0.0', keystore_path)
@@ -549,7 +562,8 @@ class TestMakeApk(unittest.TestCase):
            '--keystore-path=%s' % keystore_path_with_space,
            '--keystore-alias=xwalk test',
            '--keystore-passcode=xwalk-test',
-           '--keystore-alias-passcode=xwalk test', self._mode]
+           '--keystore-alias-passcode=xwalk test',
+           '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.assertTrue(os.path.isdir('Example'))
     self.checkApks('Example', '1.0.0', keystore_path_with_space)
@@ -558,7 +572,7 @@ class TestMakeApk(unittest.TestCase):
   def testManifest(self):
     manifest_path = os.path.join('test_data', 'manifest', 'manifest.json')
     cmd = ['python', 'make_apk.py', '--package=org.xwalk.example',
-           '--manifest=%s' % manifest_path, self._mode]
+           '--manifest=%s' % manifest_path, '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     manifest = 'Example/AndroidManifest.xml'
@@ -588,7 +602,7 @@ class TestMakeApk(unittest.TestCase):
     manifest_path = os.path.join('test_data', 'manifest',
                                  'manifest_app_launch_local_path.json')
     cmd = ['python', 'make_apk.py', '--package=org.xwalk.example',
-           '--manifest=%s' % manifest_path, self._mode]
+           '--manifest=%s' % manifest_path, '--project-dir=.', self._mode]
     out = RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     self.assertTrue(out.find('no app launch path') == -1)
@@ -683,7 +697,7 @@ class TestMakeApk(unittest.TestCase):
     extension_path = 'test_data/extensions/myextension'
     cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--app-url=http://www.intel.com',
-           '--extensions=%s' % extension_path, self._mode]
+           '--extensions=%s' % extension_path, '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     self.assertTrue(os.path.exists('Example'))
@@ -718,7 +732,8 @@ class TestMakeApk(unittest.TestCase):
     cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--app-root=%s' % test_entry_root,
            '--app-local-path=contactextension.html',
-           '--extensions=%s' % extension_path, self._mode]
+           '--extensions=%s' % extension_path,
+           '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     self.assertTrue(os.path.exists('Example'))
@@ -733,7 +748,7 @@ class TestMakeApk(unittest.TestCase):
   def testXPK(self):
     xpk_file = os.path.join('test_data', 'xpk', 'example.xpk')
     cmd = ['python', 'make_apk.py', '--package=org.xwalk.example',
-           '--xpk=%s' % xpk_file, self._mode]
+           '--xpk=%s' % xpk_file, '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     self.assertTrue(os.path.exists('Example'))
@@ -742,7 +757,7 @@ class TestMakeApk(unittest.TestCase):
   def testXPKWithError(self):
     xpk_file = os.path.join('test_data', 'xpk', 'error.xpk')
     cmd = ['python', 'make_apk.py', '--package=org.xwalk.example',
-           '--xpk=%s' % xpk_file, self._mode]
+           '--xpk=%s' % xpk_file, '--project-dir=.', self._mode]
     out = RunCommand(cmd)
     error_msg = 'XPK doesn\'t contain manifest file'
     self.assertTrue(out.find(error_msg) != -1)
@@ -751,7 +766,7 @@ class TestMakeApk(unittest.TestCase):
   def testOrientation(self):
     cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--app-url=http://www.intel.com',
-           '--orientation=landscape', self._mode]
+           '--orientation=landscape', '--project-dir=.', self._mode]
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     manifest = 'Example/AndroidManifest.xml'
@@ -814,7 +829,7 @@ class TestMakeApk(unittest.TestCase):
   def testVerbose(self):
     cmd = ['python', 'make_apk.py', '--name=Example', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--app-url=http://www.intel.com',
-           '--verbose', self._mode]
+           '--verbose', '--project-dir=.', self._mode]
     result = RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     self.assertTrue(result.find('aapt') != -1)
@@ -845,7 +860,8 @@ class TestMakeApk(unittest.TestCase):
            '--name=Example',
            '--orientation=landscape',
            '--package=org.xwalk.example',
-           '--permissions=geolocation']
+           '--permissions=geolocation',
+           '--project-dir=.']
     RunCommand(cmd)
     self.addCleanup(Clean, 'Example', '1.0.0')
     activity = 'Example/src/org/xwalk/example/ExampleActivity.java'
@@ -899,7 +915,8 @@ class TestMakeApk(unittest.TestCase):
            '--app-version=1.0.0',
            '--name=Example',
            '--package=org.xwalk.example',
-           '--verbose']
+           '--verbose',
+           '--project-dir=.']
     RunCommand(cmd)
     manifest = 'Example/AndroidManifest.xml'
     if not os.path.exists(manifest):
@@ -933,7 +950,7 @@ class TestMakeApk(unittest.TestCase):
     Clean('Example', '1.0.0')
     manifest_path = os.path.join('test_data', 'launchScreen', 'manifest.json')
     cmd = ['python', 'make_apk.py', '--package=org.xwalk.example',
-           '--manifest=%s' % manifest_path, self._mode]
+           '--manifest=%s' % manifest_path, '--project-dir=.', self._mode]
     RunCommand(cmd)
     # Check theme.xml.
     theme_path = os.path.join('Example', 'res', 'values-v14', 'theme.xml')
@@ -1015,7 +1032,8 @@ class TestMakeApk(unittest.TestCase):
            '--name=%s' % name,
            '--package=org.xwalk.example',
            '--compressor',
-           '--app-root=%s' % app_root]
+           '--app-root=%s' % app_root,
+           '--project-dir=.']
     RunCommand(cmd)
     CompareSizeForCompressor('all', css_file, 'css', name, fun)
     CompareSizeForCompressor('all', js_file, 'js', name, fun)
@@ -1024,7 +1042,8 @@ class TestMakeApk(unittest.TestCase):
            '--name=%s' % name,
            '--package=org.xwalk.example',
            '--app-root=%s' % app_root,
-           '--compressor']
+           '--compressor',
+           '--project-dir=.']
     RunCommand(cmd)
     CompareSizeForCompressor('all', css_file, 'css', name, fun)
     CompareSizeForCompressor('all', js_file, 'js', name, fun)
@@ -1033,7 +1052,8 @@ class TestMakeApk(unittest.TestCase):
            '--name=%s' % name,
            '--package=org.xwalk.example',
            '--compressor=js',
-           '--app-root=%s' % app_root]
+           '--app-root=%s' % app_root,
+           '--project-dir=.']
     RunCommand(cmd)
     CompareSizeForCompressor('js', js_file, 'js', name, fun)
 
@@ -1041,14 +1061,16 @@ class TestMakeApk(unittest.TestCase):
            '--name=%s' % name,
            '--package=org.xwalk.example',
            '--compressor=css',
-           '--app-root=%s' % app_root]
+           '--app-root=%s' % app_root,
+           '--project-dir=.']
     RunCommand(cmd)
     CompareSizeForCompressor('css', css_file, 'css', name, fun)
 
     cmd = ['python', 'customize.py',
            '--name=%s' % name,
            '--package=org.xwalk.example',
-           '--app-root=%s' % app_root]
+           '--app-root=%s' % app_root,
+           '--project-dir=.']
     RunCommand(cmd)
     CompareSizeForCompressor(None, css_file, 'css', name, fun)
     CompareSizeForCompressor(None, js_file, 'js', name, fun)
@@ -1057,7 +1079,8 @@ class TestMakeApk(unittest.TestCase):
            '--name=%s' % name,
            '--package=org.xwalk.example',
            '--app-root=%s' % app_root,
-           '--compressor=other']
+           '--compressor=other',
+           '--project-dir=.']
     RunCommand(cmd)
     CompareSizeForCompressor(None, css_file, 'css', name, fun)
     CompareSizeForCompressor(None, js_file, 'js', name, fun)
@@ -1078,14 +1101,15 @@ class TestMakeApk(unittest.TestCase):
     xml_path = 'Example/AndroidManifest.xml'
     piece_content = 'android:label="%s"' % '你好'
     cmd = ['python', 'make_apk.py', '--name=你好', '--app-version=1.0.0',
-           '--package=org.xwalk.example', '--app-url=http://www.intel.com']
+           '--package=org.xwalk.example', '--app-url=http://www.intel.com',
+           '--project-dir=.']
     RunCommand(cmd)
     self.VerifyResultInXMLFile(xml_path, piece_content)
 
     manifest_path = os.path.join('test_data', 'manifest', 'invalidchars',
                                  'manifest_with_chinese_name.json')
     cmd = ['python', 'make_apk.py', '--package=org.xwalk.example',
-           '--manifest=%s' % manifest_path]
+           '--manifest=%s' % manifest_path, '--project-dir=.']
     RunCommand(cmd)
     self.VerifyResultInXMLFile(xml_path, piece_content)
 
@@ -1095,14 +1119,14 @@ class TestMakeApk(unittest.TestCase):
     piece_content = '<string name="description">%s</string>' % '你好'
     cmd = ['python', 'make_apk.py', '--name=hello', '--app-version=1.0.0',
            '--package=org.xwalk.example', '--app-url=http://www.intel.com',
-           '--description=你好']
+           '--description=你好', '--project-dir=.']
     RunCommand(cmd)
     self.VerifyResultInXMLFile(xml_path, piece_content)
 
     manifest_path = os.path.join('test_data', 'manifest',
                                  'manifest_description_dbcs.json')
     cmd = ['python', 'make_apk.py', '--package=org.xwalk.example',
-           '--manifest=%s' % manifest_path]
+           '--manifest=%s' % manifest_path, '--project-dir=.']
     RunCommand(cmd)
     piece_content = '"description">%s</string>' % '你好 a sample description'
     self.VerifyResultInXMLFile(xml_path, piece_content)
index ed90122..99c0aa3 100644 (file)
@@ -49,3 +49,23 @@ def GetVersion(path):
   version_str += ('.').join(version_nums)
   file_handle.close()
   return version_str
+
+
+def CreateAndCopyDir(src_dir, dest_dir, delete_if_exists=False):
+  if not os.path.isdir(src_dir):
+    return False
+  # create path, except last directory (handled by copytree)
+  pre_dest_dir = os.path.dirname(dest_dir)
+  if not os.path.isdir(pre_dest_dir):
+    try:
+      os.makedirs(pre_dest_dir)  # throws exception on error
+    except OSError:
+      return False
+  if os.path.exists(dest_dir):
+    if delete_if_exists:
+      shutil.rmtree(dest_dir)
+    else:
+      return False
+  shutil.copytree(src_dir, dest_dir)
+  return True
+
index 737aa60..e43785e 100644 (file)
@@ -48,7 +48,7 @@ GURL GetDefaultWidgetEntryPage(
     scoped_refptr<xwalk::application::ApplicationData> data) {
   base::ThreadRestrictions::SetIOAllowed(true);
   base::FileEnumerator iter(
-      data->Path(), true,
+      data->path(), true,
       base::FileEnumerator::FILES,
       FILE_PATH_LITERAL("index.*"));
   size_t priority = arraysize(kDefaultWidgetEntryPage);
@@ -104,23 +104,26 @@ Application::~Application() {
 
 template<>
 GURL Application::GetStartURL<Manifest::TYPE_WIDGET>() {
-  GURL url = GetAbsoluteURLFromKey(widget_keys::kLaunchLocalPathKey);
-  if (!url.is_valid()) {
-    LOG(WARNING) << "Failed to find start URL from the 'config.xml'"
-                 << "trying to find default entry page.";
-    url = GetDefaultWidgetEntryPage(data_);
-  }
-
-  if (url.is_valid()) {
 #if defined(OS_TIZEN)
-    if (data_->IsHostedApp() && !url.SchemeIsHTTPOrHTTPS()) {
-      LOG(ERROR) << "Hosted apps are only supported with"
-                    "http:// or https:// scheme.";
-      return GURL();
-    }
+  if (data_->IsHostedApp()) {
+    std::string source;
+    data_->GetManifest()->GetString(widget_keys::kLaunchLocalPathKey, &source);
+    GURL url = GURL(source);
+
+    if (url.is_valid() && url.SchemeIsHTTPOrHTTPS())
+      return url;
+  }
 #endif
+
+  GURL url = GetAbsoluteURLFromKey(widget_keys::kLaunchLocalPathKey);
+  if (url.is_valid())
+    return url;
+
+  LOG(WARNING) << "Failed to find start URL from the 'config.xml'"
+               << "trying to find default entry page.";
+  url = GetDefaultWidgetEntryPage(data_);
+  if (url.is_valid())
     return url;
-  }
 
   LOG(WARNING) << "Failed to find a valid start URL in the manifest.";
   return GURL();
@@ -128,6 +131,13 @@ GURL Application::GetStartURL<Manifest::TYPE_WIDGET>() {
 
 template<>
 GURL Application::GetStartURL<Manifest::TYPE_MANIFEST>() {
+  if (data_->IsHostedApp()) {
+    std::string source;
+    data_->GetManifest()->GetString(keys::kStartURLKey, &source);
+    // Not trying to get a relative path for the "fake" application.
+    return GURL(source);
+  }
+
   GURL url = GetAbsoluteURLFromKey(keys::kStartURLKey);
   if (url.is_valid())
     return url;
@@ -234,10 +244,7 @@ GURL Application::GetAbsoluteURLFromKey(const std::string& key) {
   if (!manifest->GetString(key, &source) || source.empty())
     return GURL();
 
-  std::size_t found = source.find("://");
-  if (found == std::string::npos)
-    return data_->GetResourceURL(source);
-  return GURL(source);
+  return data_->GetResourceURL(source);
 }
 
 void Application::Terminate() {
index dcce8d4..6d28119 100644 (file)
@@ -245,7 +245,7 @@ ApplicationProtocolHandler::MaybeCreateJob(
   base::FilePath directory_path;
   std::string content_security_policy;
   if (application) {
-    directory_path = application->Path();
+    directory_path = application->path();
 
     const char* csp_key = GetCSPKey(application->manifest_type());
     const CSPInfo* csp_info = static_cast<CSPInfo*>(
index 6037e49..effe141 100644 (file)
@@ -227,10 +227,10 @@ void ApplicationService::OnApplicationTerminated(
 
   if (app_data->source_type() == ApplicationData::TEMP_DIRECTORY) {
       LOG(INFO) << "Deleting the app temporary directory "
-                << app_data->Path().AsUTF8Unsafe();
+                << app_data->path().AsUTF8Unsafe();
       content::BrowserThread::PostTask(content::BrowserThread::FILE,
           FROM_HERE, base::Bind(base::IgnoreResult(&base::DeleteFile),
-                                app_data->Path(), true /*recursive*/));
+                                app_data->path(), true /*recursive*/));
       // FIXME: So far we simply clean up all the app persistent data,
       // further we need to add an appropriate logic to handle it.
       content::BrowserContext::GarbageCollectStoragePartitions(
index fd41d65..a7e0587 100644 (file)
@@ -35,6 +35,25 @@ namespace widget_keys = application_widget_keys;
 
 namespace application {
 
+blink::WebScreenOrientationLockType GetDefaultOrientation(
+    const base::WeakPtr<Application>& app) {
+  TizenSettingInfo* info = static_cast<TizenSettingInfo*>(
+    app->data()->GetManifestData(widget_keys::kTizenSettingKey));
+  if (!info)
+    return blink::WebScreenOrientationLockDefault;
+  switch (info->screen_orientation()) {
+    case TizenSettingInfo::PORTRAIT:
+      return blink::WebScreenOrientationLockPortrait;
+    case TizenSettingInfo::LANDSCAPE:
+      return blink::WebScreenOrientationLockLandscape;
+    case TizenSettingInfo::AUTO:
+      return blink::WebScreenOrientationLockAny;
+    default:
+      NOTREACHED();
+      return blink::WebScreenOrientationLockDefault;
+  }
+}
+
 class ScreenOrientationProviderTizen :
     public content::ScreenOrientationProvider {
  public:
@@ -64,7 +83,7 @@ class ScreenOrientationProviderTizen :
   }
 
   virtual void UnlockOrientation() OVERRIDE {
-    LockOrientation(request_id_, blink::WebScreenOrientationLockDefault);
+    LockOrientation(request_id_, GetDefaultOrientation(app_));
   }
 
   virtual void OnOrientationChange() OVERRIDE {}
@@ -95,15 +114,18 @@ void ApplicationTizen::Hide() {
   std::set<Runtime*>::iterator it = runtimes_.begin();
   for (; it != runtimes_.end(); ++it) {
     if ((*it)->window())
-      (*it)->window()->Hide();
+      (*it)->window()->Minimize();
   }
 }
 
 bool ApplicationTizen::Launch(const LaunchParams& launch_params) {
   if (Application::Launch(launch_params)) {
     DCHECK(web_contents_);
-    web_contents_->GetScreenOrientationDispatcherHost()->
-        SetProvider(new ScreenOrientationProviderTizen(GetWeakPtr()));
+    content::ScreenOrientationProvider *provider =
+        new ScreenOrientationProviderTizen(GetWeakPtr());
+    web_contents_->GetScreenOrientationDispatcherHost()->SetProvider(provider);
+
+    provider->LockOrientation(0, GetDefaultOrientation(GetWeakPtr()));
     return true;
   }
   return false;
@@ -112,7 +134,7 @@ bool ApplicationTizen::Launch(const LaunchParams& launch_params) {
 base::FilePath ApplicationTizen::GetSplashScreenPath() {
   if (TizenSplashScreenInfo* ss_info = static_cast<TizenSplashScreenInfo*>(
       data()->GetManifestData(widget_keys::kTizenSplashScreenKey))) {
-    return data()->Path().Append(FILE_PATH_LITERAL(ss_info->src()));
+    return data()->path().Append(FILE_PATH_LITERAL(ss_info->src()));
   }
   return base::FilePath();
 }
index a3ad4a9..a94d68c 100644 (file)
@@ -148,6 +148,16 @@ GURL ApplicationData::GetResourceURL(const GURL& application_url,
   return ret_val;
 }
 
+GURL ApplicationData::GetResourceURL(const std::string& relative_path) const {
+  if (!base::PathExists(path_.Append(relative_path))) {
+    LOG(ERROR) << "The path does not exist in the application directory: "
+               << relative_path;
+    return GURL();
+  }
+
+  return GetResourceURL(URL(), relative_path);
+}
+
 bool ApplicationData::Init(const std::string& explicit_id,
                            base::string16* error) {
   DCHECK(error);
index f201ab2..3f0414b 100644 (file)
@@ -77,9 +77,7 @@ class ApplicationData : public base::RefCountedThreadSafe<ApplicationData> {
   // NOTE: Static so that it can be used from multiple threads.
   static GURL GetResourceURL(const GURL& application_url,
                              const std::string& relative_path);
-  GURL GetResourceURL(const std::string& relative_path) const {
-    return GetResourceURL(URL(), relative_path);
-  }
+  GURL GetResourceURL(const std::string& relative_path) const;
 
   // Returns the base application url for a given |application_id|.
   static GURL GetBaseURLFromApplicationId(const std::string& application_id);
@@ -94,9 +92,10 @@ class ApplicationData : public base::RefCountedThreadSafe<ApplicationData> {
   void SetManifestData(const std::string& key, ManifestData* data);
 
   // Accessors:
-
-  const base::FilePath& Path() const { return path_; }
-  void SetPath(const base::FilePath& path) { path_ = path; }
+  const base::FilePath& path() const { return path_; }
+#if defined(OS_TIZEN)  // FIXME : This method should be removed.
+  void set_path(const base::FilePath& path) { path_ = path; }
+#endif
   const GURL& URL() const { return application_url_; }
   SourceType source_type() const { return source_type_; }
   Manifest::Type manifest_type() const { return manifest_->type(); }
index 76c992f..12e1e3a 100644 (file)
@@ -121,6 +121,7 @@ const char kTizenMetaDataValueKey[] = "@value";
 const char kTizenSplashScreenKey[] = "widget.splash-screen";
 const char kTizenSplashScreenSrcKey[] = "@src";
 const char kContentNamespace[] = "widget.content.@namespace";
+const char kTizenScreenOrientationKey[] = "widget.setting.@screen-orientation";
 #endif
 
 }  // namespace application_widget_keys
index 1d92d23..b6800f7 100644 (file)
@@ -102,6 +102,7 @@ namespace application_widget_keys {
   extern const char kTizenSplashScreenKey[];
   extern const char kTizenSplashScreenSrcKey[];
   extern const char kContentNamespace[];
+  extern const char kTizenScreenOrientationKey[];
 #endif
 }  // namespace application_widget_keys
 
index 136e1a0..22e2957 100644 (file)
@@ -7,6 +7,7 @@
 #include <map>
 #include <utility>
 
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "xwalk/application/common/application_manifest_constants.h"
 
@@ -17,7 +18,8 @@ namespace keys = application_widget_keys;
 namespace application {
 
 TizenSettingInfo::TizenSettingInfo()
-    : hwkey_enabled_(true) {}
+    : hwkey_enabled_(true),
+      screen_orientation_(PORTRAIT) {}
 
 TizenSettingInfo::~TizenSettingInfo() {}
 
@@ -35,6 +37,15 @@ bool TizenSettingHandler::Parse(scoped_refptr<ApplicationData> application,
   manifest->GetString(keys::kTizenHardwareKey, &hwkey);
   app_info->set_hwkey_enabled(hwkey != "disable");
 
+  std::string screen_orientation;
+  manifest->GetString(keys::kTizenScreenOrientationKey, &screen_orientation);
+  if (base::strcasecmp("portrait", screen_orientation.c_str()) == 0)
+    app_info->set_screen_orientation(TizenSettingInfo::PORTRAIT);
+  else if (base::strcasecmp("landscape", screen_orientation.c_str()) == 0)
+    app_info->set_screen_orientation(TizenSettingInfo::LANDSCAPE);
+  else
+    app_info->set_screen_orientation(TizenSettingInfo::AUTO);
+
   application->SetManifestData(keys::kTizenSettingKey,
                                app_info.release());
   return true;
@@ -52,6 +63,17 @@ bool TizenSettingHandler::Validate(
                          " or not specified in configuration file.");
     return false;
   }
+
+  std::string screen_orientation;
+  manifest->GetString(keys::kTizenScreenOrientationKey, &screen_orientation);
+  if (!screen_orientation.empty() &&
+      base::strcasecmp("portrait", screen_orientation.c_str()) != 0 &&
+      base::strcasecmp("landscape", screen_orientation.c_str()) != 0 &&
+      base::strcasecmp("auto-rotation", screen_orientation.c_str()) != 0) {
+    *error = std::string("The screen-orientation must be 'portrait'/"
+                         "'landscape'/'auto-rotation' or not specified.");
+    return false;
+  }
   return true;
 }
 
index 9d5a62c..4602631 100644 (file)
@@ -20,11 +20,24 @@ class TizenSettingInfo : public ApplicationData::ManifestData {
   TizenSettingInfo();
   virtual ~TizenSettingInfo();
 
+  enum ScreenOrientation {
+    PORTRAIT,
+    LANDSCAPE,
+    AUTO
+  };
+
   void set_hwkey_enabled(bool enabled) { hwkey_enabled_ = enabled; }
   bool hwkey_enabled() const { return hwkey_enabled_; }
 
+  void set_screen_orientation(ScreenOrientation orientation) {
+    screen_orientation_ = orientation;
+  }
+
+  ScreenOrientation screen_orientation() const { return screen_orientation_; }
+
  private:
   bool hwkey_enabled_;
+  ScreenOrientation screen_orientation_;
 };
 
 class TizenSettingHandler : public ManifestHandler {
index 0c8abc5..9c1de58 100644 (file)
@@ -58,7 +58,7 @@ bool TizenSplashScreenHandler::Validate(
   splash_screen->GetAsDictionary(&ss_dict);
   std::string ss_src;
   ss_dict->GetString(keys::kTizenSplashScreenSrcKey, &ss_src);
-  base::FilePath path = application->Path().Append(FILE_PATH_LITERAL(ss_src));
+  base::FilePath path = application->path().Append(FILE_PATH_LITERAL(ss_src));
   if (!base::PathExists(path)) {
     *error = std::string("The splash screen image does not exist");
     return false;
index 9e7857e..d4bcd08 100644 (file)
@@ -15,6 +15,7 @@
 #include "third_party/re2/re2/re2.h"
 #include "xwalk/application/common/tizen/signature_data.h"
 #include "xwalk/application/common/tizen/signature_parser.h"
+#include "xwalk/application/common/tizen/signature_xmlsec_adaptor.h"
 
 namespace {
 
@@ -226,7 +227,6 @@ SignatureValidator::Status SignatureValidator::Check(
   SignatureFileSet::reverse_iterator iter = signature_set.rbegin();
   bool ret = false;
   for (; iter != signature_set.rend(); ++iter) {
-    LOG(INFO) << "Checking signature with id=" << iter->file_number();
     // Verify whether signature xml is a valid [XMLDSIG] document.
     if (!XMLSchemaValidate(*iter, widget_path)) {
       LOG(ERROR) << "Validating " << iter->file_name() << "schema failed.";
@@ -252,7 +252,8 @@ SignatureValidator::Status SignatureValidator::Check(
       return INVALID;
 
     // Perform reference validation and signature validation on signature
-    // TODO(XU): depends on root CA certificate installed on Tizen platform.
+    if (!SignatureXmlSecAdaptor::ValidateFile(*data.get(), widget_path))
+      return INVALID;
   }
   return VALID;
 }
diff --git a/src/xwalk/application/common/tizen/signature_xmlsec_adaptor.cc b/src/xwalk/application/common/tizen/signature_xmlsec_adaptor.cc
new file mode 100644 (file)
index 0000000..a589f4c
--- /dev/null
@@ -0,0 +1,349 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Copyright (C) 2002-2003 Aleksey Sanin.  All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "xwalk/application/common/tizen/signature_xmlsec_adaptor.h"
+
+#include <list>
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "net/cert/x509_certificate.h"
+#include "libxml/parser.h"
+#include "xmlsec/crypto.h"
+#include "xmlsec/io.h"
+#include "xmlsec/keysmngr.h"
+#include "xmlsec/xmlsec.h"
+#include "xmlsec/xmltree.h"
+#include "xmlsec/xmldsig.h"
+#ifndef XMLSEC_NO_XSLT
+#include "libxslt/xslt.h"
+#endif  // XMLSEC_NO_XSLT
+
+namespace {
+
+// TODO(XU): Once tizen platform provide certificate manager util APIs,
+// we should call API from system to query certificate's file path.
+class CertificateUtil {
+ public:
+  static const std::map<std::string, std::string>& certificate_path() {
+    return certificate_path_;
+  }
+
+ private:
+  static std::map<std::string, std::string> InitCertificatePath() {
+    std::map<std::string, std::string> root_certificates;
+    root_certificates["Tizen Partner-Manufacturer Distributor Root CA"] =
+        "tizen-distributor-root-ca-partner-manufacturer.pem";
+    root_certificates["SLP WebApp Temporary CA"] =
+        "tizen.root.preproduction.cert.pem";
+    root_certificates["Tizen Test Developer Root CA"] =
+        "tizen-developer-root-ca.pem";
+    root_certificates["Tizen Developers Root"] =
+        "tizen-developers-root.pem";
+    root_certificates["Tizen Partner Distributor Root CA"] =
+        "tizen-distributor-root-ca-partner.pem";
+    root_certificates["Tizen Partner-Operator Distributor Root CA"] =
+        "tizen-distributor-root-ca-partner-operator.pem";
+    root_certificates["Tizen Public Distributor Root CA"] =
+        "tizen-distributor-root-ca-public.pem";
+    root_certificates["Partner Class Developer Root"] =
+        "tizen-partner-class-developer-root.pem";
+    root_certificates["Partner Class Root Authority"] =
+        "tizen-partner-class-root-authority.pem";
+    root_certificates["Platform Class Developer Root"] =
+        "tizen-platform-class-developer-root.pem";
+    root_certificates["Platform Class Root Authority"] =
+        "tizen-platform-class-root-authority.pem";
+    root_certificates["Public Class Developer Root"] =
+        "tizen-public-class-developer-root.pem";
+    root_certificates["Public Class Root Authority"] =
+        "tizen-public-class-root-authority.pem";
+
+    return root_certificates;
+  }
+
+  static std::map<std::string, std::string> certificate_path_;
+};
+
+std::map<std::string, std::string>
+    CertificateUtil::certificate_path_ = InitCertificatePath();
+
+class XmlSecContext {
+ public:
+  static void GetExtractedPath(const xwalk::application::SignatureData& data);
+  static xmlSecKeysMngrPtr LoadTrustedCerts(
+      const xwalk::application::SignatureData& signature_data);
+  static int VerifyFile(
+      xmlSecKeysMngrPtr mngr, const xwalk::application::SignatureData& data);
+
+ private:
+  static int FileMatchCallback(const char* file_name);
+  static void* FileOpenCallback(const char* file_name);
+  static int FileReadCallback(void* context, char* buffer, int len);
+  static int FileCloseCallback(void* context);
+  static void ConvertToPemCert(std::string* cert);
+  static base::FilePath GetCertFromStore(const std::string& subject);
+
+  static std::string prefix_path_;
+  static std::pair<void*, bool> file_wrapper_;
+};
+
+std::string XmlSecContext::prefix_path_;
+std::pair<void*, bool> XmlSecContext::file_wrapper_;
+
+void XmlSecContext::GetExtractedPath(
+    const xwalk::application::SignatureData& data) {
+  XmlSecContext::prefix_path_ = data.GetExtractedWidgetPath().MaybeAsASCII();
+}
+
+int XmlSecContext::FileMatchCallback(const char* file_name) {
+  std::string path = XmlSecContext::prefix_path_ + std::string(file_name);
+  return xmlFileMatch(path.c_str());
+}
+
+void* XmlSecContext::FileOpenCallback(const char* file_name) {
+  std::string path = XmlSecContext::prefix_path_ + std::string(file_name);
+  XmlSecContext::file_wrapper_ =
+      std::make_pair(xmlFileOpen(path.c_str()), false);
+  return &(XmlSecContext::file_wrapper_);
+}
+
+int XmlSecContext::FileReadCallback(void* context, char* buffer, int len) {
+  std::pair<void*, bool>* file_wrapper =
+      static_cast<std::pair<void*, bool>*>(context);
+  DCHECK(file_wrapper);
+  if (file_wrapper->second)
+    return 0;
+
+  int output = xmlFileRead(file_wrapper->first, buffer, len);
+  if (output == 0) {
+    file_wrapper->second = true;
+    xmlFileClose(file_wrapper->first);
+  }
+  return output;
+}
+
+int XmlSecContext::FileCloseCallback(void* context) {
+  std::pair<void*, bool>* file_wrapper =
+      static_cast<std::pair<void*, bool>*>(context);
+  DCHECK(file_wrapper);
+  int output = 0;
+  if (!file_wrapper->second)
+    output = xmlFileClose(file_wrapper->first);
+
+  return output;
+}
+
+xmlSecKeysMngrPtr XmlSecContext::LoadTrustedCerts(
+    const xwalk::application::SignatureData& signature_data) {
+  xmlSecKeysMngrPtr mngr = xmlSecKeysMngrCreate();
+  if (!mngr) {
+    LOG(ERROR) << "Error: failed to create keys manager.";
+    return NULL;
+  }
+  if (xmlSecCryptoAppDefaultKeysMngrInit(mngr) < 0) {
+    LOG(ERROR) << "Error: failed to initialize keys manager.";
+    xmlSecKeysMngrDestroy(mngr);
+    return NULL;
+  }
+
+  std::list<std::string> certificate_list = signature_data.certificate_list();
+  std::string cert;
+  std::string issuer;
+  for (std::list<std::string>::iterator it = certificate_list.begin();
+      it != certificate_list.end(); ++it) {
+    cert = *it;
+    XmlSecContext::ConvertToPemCert(&cert);
+    net::CertificateList certs =
+        net::X509Certificate::CreateCertificateListFromBytes(
+            cert.data(), cert.length(), net::X509Certificate::FORMAT_AUTO);
+    issuer = certs[0]->issuer().GetDisplayName();
+
+    if (xmlSecCryptoAppKeysMngrCertLoadMemory(mngr,
+        reinterpret_cast<const unsigned char*>(cert.c_str()), cert.size(),
+        xmlSecKeyDataFormatCertPem, xmlSecKeyDataTypeTrusted) < 0) {
+      LOG(ERROR) << "Error: failed to load pem certificate.";
+      xmlSecKeysMngrDestroy(mngr);
+      return NULL;
+    }
+  }
+
+  const base::FilePath& root_cert_path =
+      XmlSecContext::GetCertFromStore(issuer);
+  if (!base::PathExists(root_cert_path)) {
+    LOG(ERROR) << "Failed to find root certificate.";
+    return NULL;
+  }
+
+  if (xmlSecCryptoAppKeysMngrCertLoad(mngr,
+      root_cert_path.MaybeAsASCII().c_str(), xmlSecKeyDataFormatPem,
+      xmlSecKeyDataTypeTrusted) < 0) {
+    LOG(ERROR) << "Error: failed to load root certificate";
+    xmlSecKeysMngrDestroy(mngr);
+    return NULL;
+  }
+
+  return mngr;
+}
+
+// Verifies XML signature in #xml_file
+// Returns 0 on success or a negative value if an error occurs.
+int XmlSecContext::VerifyFile(xmlSecKeysMngrPtr mngr,
+                              const xwalk::application::SignatureData& data) {
+  LOG(INFO) << "Verify " << data.signature_file_name();
+  xmlSecIOCleanupCallbacks();
+  XmlSecContext::GetExtractedPath(data);
+  xmlSecIORegisterCallbacks(
+      XmlSecContext::FileMatchCallback,
+      XmlSecContext::FileOpenCallback,
+      XmlSecContext::FileReadCallback,
+      XmlSecContext::FileCloseCallback);
+
+  xmlDocPtr doc = xmlParseFile(data.signature_file_name().c_str());
+  if (!doc) {
+    LOG(ERROR) << "Error: failed to parse " << data.signature_file_name();
+    return -1;
+  }
+
+  if (!xmlDocGetRootElement(doc)) {
+    LOG(ERROR) << "Error: unable to get root element.";
+    xmlFreeDoc(doc);
+    return -1;
+  }
+
+  xmlNodePtr node = xmlSecFindNode(
+      xmlDocGetRootElement(doc), xmlSecNodeSignature, xmlSecDSigNs);
+  if (!node) {
+    LOG(ERROR) << "Error: unable to find SecNodeSignature node.";
+    xmlFreeDoc(doc);
+    return -1;
+  }
+
+  xmlSecDSigCtxPtr dsig_ctx = xmlSecDSigCtxCreate(mngr);
+  if (!dsig_ctx) {
+    LOG(ERROR) << "Error: failed to create signature context.";
+    xmlFreeDoc(doc);
+    return -1;
+  }
+
+  if (xmlSecDSigCtxVerify(dsig_ctx, node) < 0) {
+    LOG(ERROR) << "Error: signature verify.";
+    xmlFreeDoc(doc);
+    xmlSecDSigCtxDestroy(dsig_ctx);
+    return -1;
+  }
+
+  int res = -1;
+  if (dsig_ctx->status != xmlSecDSigStatusSucceeded)
+    LOG(ERROR) << "Signature " << data.signature_file_name() <<" is INVALID";
+
+  LOG(INFO) << "Signature  "<< data.signature_file_name() << " is OK.";
+  res = 0;
+
+  xmlFreeDoc(doc);
+  xmlSecDSigCtxDestroy(dsig_ctx);
+  return res;
+}
+
+void XmlSecContext::ConvertToPemCert(std::string* cert) {
+  *cert = "-----BEGIN CERTIFICATE-----" + *cert;
+  *cert = *cert + "-----END CERTIFICATE-----";
+}
+
+base::FilePath XmlSecContext::GetCertFromStore(const std::string& subject) {
+  const char cert_prefix_path[] = "/usr/share/ca-certificates/tizen/";
+  std::map<std::string, std::string>::const_iterator iter =
+      CertificateUtil::certificate_path().find(subject);
+
+  if (iter == CertificateUtil::certificate_path().end()) {
+    LOG(ERROR) << "Failing to find root certificate.";
+    return base::FilePath("");
+  }
+  LOG(INFO) << "root cert path is " << cert_prefix_path + iter->second;
+  return base::FilePath(cert_prefix_path + iter->second);
+}
+
+}  // namespace
+
+namespace xwalk {
+namespace application {
+
+// static
+bool SignatureXmlSecAdaptor::ValidateFile(
+    const SignatureData& signature_data, const base::FilePath& widget_path) {
+  xmlInitParser();
+  xmlSubstituteEntitiesDefault(1);
+#ifndef XMLSEC_NO_XSLT
+  xsltSecurityPrefsPtr xslt_sec_prefs = xsltNewSecurityPrefs();
+  xsltSetSecurityPrefs(
+      xslt_sec_prefs, XSLT_SECPREF_READ_FILE, xsltSecurityForbid);
+  xsltSetSecurityPrefs(
+      xslt_sec_prefs, XSLT_SECPREF_WRITE_FILE, xsltSecurityForbid);
+  xsltSetSecurityPrefs(
+      xslt_sec_prefs, XSLT_SECPREF_CREATE_DIRECTORY, xsltSecurityForbid);
+  xsltSetSecurityPrefs(
+      xslt_sec_prefs, XSLT_SECPREF_READ_NETWORK, xsltSecurityForbid);
+  xsltSetSecurityPrefs(
+      xslt_sec_prefs, XSLT_SECPREF_WRITE_NETWORK, xsltSecurityForbid);
+  xsltSetDefaultSecurityPrefs(xslt_sec_prefs);
+#endif  // XMLSEC_NO_XSLT
+
+  if (xmlSecInit() < 0) {
+    LOG(ERROR) << "Error: xmlsec initialization failed.";
+    return false;
+  }
+
+  if (xmlSecCheckVersion() != 1) {
+    LOG(ERROR) << "Error: loaded xmlsec library version is not compatible.";
+    return false;
+  }
+
+#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
+  if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
+    LOG(ERROR) << "Error: unable to load default xmlsec-crypto library.";
+    return false;
+  }
+#endif  // XMLSEC_CRYPTO_DYNAMIC_LOADING
+
+  if (xmlSecCryptoAppInit(NULL) < 0) {
+    LOG(ERROR) << "Error: crypto initialization failed.";
+    return false;
+  }
+
+  if (xmlSecCryptoInit() < 0) {
+    LOG(ERROR) << "Error: xmlsec-crypto initialization failed.";
+    return false;
+  }
+
+  xmlSecKeysMngrPtr mngr = XmlSecContext::LoadTrustedCerts(signature_data);
+  if (!mngr)
+    return false;
+
+  if (XmlSecContext::VerifyFile(mngr, signature_data) < 0) {
+    xmlSecKeysMngrDestroy(mngr);
+    return false;
+  }
+
+  xmlSecKeysMngrDestroy(mngr);
+  xmlSecCryptoShutdown();
+  xmlSecCryptoAppShutdown();
+  xmlSecShutdown();
+
+#ifndef XMLSEC_NO_XSLT
+  xsltFreeSecurityPrefs(xslt_sec_prefs);
+  xsltCleanupGlobals();
+#endif  // XMLSEC_NO_XSLT
+  xmlCleanupParser();
+
+  return true;
+}
+
+}  // namespace application
+}  // namespace xwalk
diff --git a/src/xwalk/application/common/tizen/signature_xmlsec_adaptor.h b/src/xwalk/application/common/tizen/signature_xmlsec_adaptor.h
new file mode 100644 (file)
index 0000000..ace550e
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef XWALK_APPLICATION_COMMON_TIZEN_SIGNATURE_XMLSEC_ADAPTOR_H_
+#define XWALK_APPLICATION_COMMON_TIZEN_SIGNATURE_XMLSEC_ADAPTOR_H_
+
+#include "base/files/file_path.h"
+#include "xwalk/application/common/tizen/signature_data.h"
+
+namespace xwalk {
+namespace application {
+
+class SignatureXmlSecAdaptor {
+ public:
+  static bool ValidateFile(const SignatureData& signature_data,
+                           const base::FilePath& widget_path);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SignatureXmlSecAdaptor);
+};
+
+}  // namespace application
+}  // namespace xwalk
+
+#endif  // XWALK_APPLICATION_COMMON_TIZEN_SIGNATURE_XMLSEC_ADAPTOR_H_
index ca9e89d..b9d1036 100644 (file)
             '../../build/system.gyp:tizen',
             '../../tizen/xwalk_tizen.gypi:xwalk_tizen_lib',
             '../../../third_party/re2/re2.gyp:re2',
+            '../../../net/net.gyp:net',
           ],
+          'cflags': [
+            '<!@(pkg-config --cflags xmlsec1)',
+          ],
+          'link_settings': {
+            'libraries': [
+              '<!@(pkg-config --libs-only-l xmlsec1)',
+            ],
+          },
           'sources': [
             'manifest_handlers/navigation_handler.cc',
             'manifest_handlers/navigation_handler.h',
@@ -81,6 +90,8 @@
             'tizen/signature_parser.cc',
             'tizen/signature_validator.cc',
             'tizen/signature_validator.h',
+            'tizen/signature_xmlsec_adaptor.cc',
+            'tizen/signature_xmlsec_adaptor.h',
           ],
         }],
       ],
@@ -18,17 +18,17 @@ using xwalk::application::ApplicationService;
 using xwalk::application::Manifest;
 using xwalk::application::GetManifestPath;
 
-class ApplicationMultiAppTest : public ApplicationBrowserTest {
+class ApplicationTest : public ApplicationBrowserTest {
 };
 
-IN_PROC_BROWSER_TEST_F(ApplicationMultiAppTest, TestMultiApp) {
+IN_PROC_BROWSER_TEST_F(ApplicationTest, TestMultiApp) {
   ApplicationService* service = application_sevice();
   const size_t currently_running_count = service->active_applications().size();
   // Launch the first app.
   base::FilePath manifest_path =
       GetManifestPath(test_data_dir_.Append(FILE_PATH_LITERAL("dummy_app1")),
       Manifest::TYPE_MANIFEST);
-  Application* app1 = application_sevice()->LaunchFromManifestPath(
+  Application* app1 = service->LaunchFromManifestPath(
       manifest_path, Manifest::TYPE_MANIFEST);
   ASSERT_TRUE(app1);
   // Wait for app is fully loaded.
@@ -42,7 +42,7 @@ IN_PROC_BROWSER_TEST_F(ApplicationMultiAppTest, TestMultiApp) {
 
   // Verify that no new App instance was created, if one exists
   // with the same ID.
-  Application* failed_app1 = application_sevice()->LaunchFromManifestPath(
+  Application* failed_app1 = service->LaunchFromManifestPath(
       manifest_path, Manifest::TYPE_MANIFEST);
   ASSERT_FALSE(failed_app1);
 
@@ -77,3 +77,12 @@ IN_PROC_BROWSER_TEST_F(ApplicationMultiAppTest, TestMultiApp) {
   content::RunAllPendingInMessageLoop();
   EXPECT_EQ(service->active_applications().size(), currently_running_count);
 }
+
+IN_PROC_BROWSER_TEST_F(ApplicationTest, TestUnsafeStartURL) {
+  base::FilePath manifest_path = GetManifestPath(
+      test_data_dir_.Append(FILE_PATH_LITERAL("unsafe_start_URL")),
+      Manifest::TYPE_MANIFEST);
+  Application* app = application_sevice()->LaunchFromManifestPath(
+      manifest_path, Manifest::TYPE_MANIFEST);
+  EXPECT_EQ(NULL, app);
+}
diff --git a/src/xwalk/application/test/data/unsafe_start_URL/manifest.json b/src/xwalk/application/test/data/unsafe_start_URL/manifest.json
new file mode 100644 (file)
index 0000000..76c080b
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "name": "unsafe",
+  "start_url": "http://unsafe.com"
+}
index 4dff936..e5f9e90 100644 (file)
@@ -36,7 +36,7 @@ enum PkgmgrPluginBool {
 // Whole app directory size in KB
 int64 CountAppTotalSize(
     scoped_refptr<xwalk::application::ApplicationData> app_data) {
-  return base::ComputeDirectorySize(app_data->Path()) / 1024;
+  return base::ComputeDirectorySize(app_data->path()) / 1024;
 }
 
 // Data directory size in KB
@@ -44,10 +44,10 @@ int64 CountAppDataSize(
     scoped_refptr<xwalk::application::ApplicationData> app_data) {
   int64 size = 0;
 
-  base::FilePath private_path = app_data->Path().Append("private");
+  base::FilePath private_path = app_data->path().Append("private");
   size += base::ComputeDirectorySize(private_path);
 
-  base::FilePath tmp_path = app_data->Path().Append("tmp");
+  base::FilePath tmp_path = app_data->path().Append("tmp");
   size += base::ComputeDirectorySize(tmp_path);
 
   return size / 1024;
index 11ba840..3509ee2 100644 (file)
@@ -482,7 +482,7 @@ bool PackageInstaller::Install(const base::FilePath& path, std::string* id) {
       return false;
   }
 
-  app_data->SetPath(app_dir);
+  app_data->set_path(app_dir);
 
   if (!storage_->AddApplication(app_data)) {
     LOG(ERROR) << "Application with id " << app_data->ID()
@@ -578,7 +578,7 @@ bool PackageInstaller::Update(const std::string& app_id,
     return false;
   }
 
-  const base::FilePath& app_dir = old_app_data->Path();
+  const base::FilePath& app_dir = old_app_data->path();
   const base::FilePath tmp_dir(app_dir.value()
                                + FILE_PATH_LITERAL(".tmp"));
 
index 673cc59..b4b59bd 100755 (executable)
@@ -49,10 +49,7 @@ def PrepareFromXwalk(src_dir, target_dir):
     (os.path.join(source_code_dir, 'xwalk/app/android/app_template'),
      app_target_dir),
 
-    # Shared mode uses xwalk_app_runtime_java.jar only.
-    # Embedded mode needs both.
     (os.path.join(jar_src_dir, 'xwalk_app_runtime_java.jar'), jar_target_dir),
-    (os.path.join(jar_src_dir, 'xwalk_runtime_java.jar'), jar_target_dir),
 
     # XWalk Core Library
     (xwalk_core_library_dir, os.path.join(target_dir, 'xwalk_core_library')),
index 810a688..c3fb2b0 100755 (executable)
@@ -136,7 +136,8 @@ def CopyBinaries(out_dir):
     os.mkdir(libs_dir)
 
   libs_to_copy = [
-      'xwalk_core_library_java.jar',
+      'xwalk_core_library_java_app_part.jar',
+      'xwalk_core_library_java_library_part.jar',
   ]
 
   for lib in libs_to_copy:
index 2629faa..60f453a 100755 (executable)
@@ -31,15 +31,16 @@ def main():
      'R.txt'),
     (os.path.join(options.target, 'xwalk_core_library', 'AndroidManifest.xml'),
      'AndroidManifest.xml'),
-    (os.path.join(options.target, 'xwalk_core_library', 'libs',
-                  'xwalk_core_library_java.jar'),
+    (os.path.join(options.target, 'lib.java', 'xwalk_core_library_java.jar'),
      'classes.jar'),
   )
   # This is a list of files that will not be packaged: mostly a blacklist of
   # files within |dirs|.
   exclude_files = (
     os.path.join(options.target, 'xwalk_core_library', 'libs',
-                 'xwalk_core_library_java.jar'),
+                 'xwalk_core_library_java_app_part.jar'),
+    os.path.join(options.target, 'xwalk_core_library', 'libs',
+                 'xwalk_core_library_java_library_part.jar'),
   )
 
   aar_path = os.path.join(options.target, 'xwalk_core_library.aar')
index 7444d33..6b19c90 100644 (file)
@@ -16,7 +16,7 @@
 %endif
 
 Name:           crosswalk
-Version:        9.38.207.0
+Version:        10.38.208.0
 Release:        0
 Summary:        Chromium-based app runtime
 License:        (BSD-3-Clause and LGPL-2.1+)
@@ -74,6 +74,7 @@ BuildRequires:  pkgconfig(nspr)
 BuildRequires:  pkgconfig(nss)
 BuildRequires:  pkgconfig(sensor)
 BuildRequires:  pkgconfig(vconf)
+BuildRequires:  pkgconfig(xmlsec1)
 %if %{with x}
 BuildRequires:  pkgconfig(x11)
 BuildRequires:  pkgconfig(xcomposite)
@@ -102,6 +103,7 @@ BuildRequires:  pkgconfig(xkbcommon)
 %else
 BuildRequires:  pkgconfig(scim)
 %endif
+Requires:  ca-certificates-tizen
 
 %description
 Crosswalk is an app runtime based on Chromium. It is an open source project started by the Intel Open Source Technology Center (http://www.01.org).
index 1387183..883a448 100644 (file)
@@ -35,6 +35,7 @@ public class ReflectionHelper {
 
         Constructor<?> loadConstructor() {
             Class<?> clazz = loadClass(fullClassName);
+            if (clazz == null) return null;
             Class<?>[] params = new Class<?>[paramTypes.length];
             for (int i = 0; i < paramTypes.length; i++) {
                 Object type = paramTypes[i];
index 59e7430..238c43e 100644 (file)
@@ -125,34 +125,60 @@ class XWalkViewDelegate {
         ResourceExtractor.setMandatoryPaksToExtract(MANDATORY_PAKS);
         final int resourcesListResId = context.getResources().getIdentifier(
                 XWALK_RESOURCES_LIST_RES_NAME, "array", context.getPackageName());
-        if (resourcesListResId != 0) {
+        final AssetManager assets = context.getAssets();
+        if (!context.getPackageName().equals(context.getApplicationContext().getPackageName()) ||
+                resourcesListResId != 0) {
+            // For shared mode, assets are in library package.
+            // For embedding API usage, assets are in res/raw.
             ResourceExtractor.setResourceIntercepter(new ResourceIntercepter() {
 
                 @Override
                 public Set<String> getInterceptableResourceList() {
-                    try {
-                        Set<String> resourcesList = new HashSet<String>();
-                        String[] resources = context.getResources().getStringArray(resourcesListResId);
-                        for (String resource : resources) {
-                            resourcesList.add(resource);
+                    Set<String> resourcesList = new HashSet<String>();
+                    if (!context.getPackageName().equals(
+                            context.getApplicationContext().getPackageName())) {
+                        try {
+                            for (String resource : assets.list("")) {
+                                resourcesList.add(resource);
+                            }
+                        } catch (IOException e){}
+                    }
+                    if (resourcesListResId != 0) {
+                        try {
+                            String[] resources = context.getResources().getStringArray(resourcesListResId);
+                            for (String resource : resources) {
+                                resourcesList.add(resource);
+                            }
+                        } catch (NotFoundException e) {
+                            Log.w(TAG, "R.array." + XWALK_RESOURCES_LIST_RES_NAME + " can't be found.");
                         }
-                        return resourcesList;
-                    } catch (NotFoundException e) {
-                        Log.w(TAG, "R.array." + XWALK_RESOURCES_LIST_RES_NAME + " can't be found.");
                     }
-                    return null;
+                    return resourcesList;
                 }
 
                 @Override
                 public InputStream interceptLoadingForResource(String resource) {
-                    String resourceName = resource.split("\\.")[0];
-                    int resId = context.getResources().getIdentifier(
-                            resourceName, "raw", context.getPackageName());
-                    try {
-                        if (resId != 0) return context.getResources().openRawResource(resId);
-                    } catch (NotFoundException e) {
-                        Log.w(TAG, "R.raw." + resourceName + " can't be found.");
+                    if (!context.getPackageName().equals(
+                            context.getApplicationContext().getPackageName())) {
+                        try {
+                            InputStream fromAsset = context.getAssets().open(resource);
+                            if (fromAsset != null) return fromAsset;
+                        } catch (IOException e) {
+                            Log.w(TAG, resource + " can't be found in assets.");
+                        }
                     }
+
+                    if (resourcesListResId != 0) {
+                        String resourceName = resource.split("\\.")[0];
+                        int resId = context.getResources().getIdentifier(
+                                resourceName, "raw", context.getPackageName());
+                        try {
+                            if (resId != 0) return context.getResources().openRawResource(resId);
+                        } catch (NotFoundException e) {
+                            Log.w(TAG, "R.raw." + resourceName + " can't be found.");
+                        }
+                    }
+
                     return null;
                 }
             });
index fbc91f4..bd0def2 100644 (file)
@@ -698,7 +698,7 @@ public class XWalkViewInternal extends android.widget.FrameLayout {
     // TODO(yongsheng): make it static?
     @XWalkAPI
     public String getAPIVersion() {
-        return "2.1";
+        return "3.0";
     }
 
     /**
index 03775ae..6f7a05d 100644 (file)
@@ -343,6 +343,8 @@ public class PresentationExtension extends XWalkExtensionWithActivityStateListen
     }
 
     private void updatePresentationView(Display preferredDisplay) {
+        Activity activity = mActivity.get();
+        if (activity == null) return;
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 ||
                 preferredDisplay == null) {
             return;
@@ -367,7 +369,7 @@ public class PresentationExtension extends XWalkExtensionWithActivityStateListen
             ViewGroup parent = (ViewGroup)mPresentationContent.getContentView().getParent();
             if (parent != null) parent.removeView(mPresentationContent.getContentView());
 
-            mPresentationView = PresentationView.createInstance(mContext, preferredDisplay);
+            mPresentationView = PresentationView.createInstance(activity, preferredDisplay);
             mPresentationView.setContentView(mPresentationContent.getContentView());
             mPresentationView.setPresentationListener(new PresentationView.PresentationListener() {
                 @Override
index ff61f2e..f3c0b31 100644 (file)
@@ -98,7 +98,6 @@ XWalkBrowserMainParts::~XWalkBrowserMainParts() {
 void XWalkBrowserMainParts::PreMainMessageLoopStart() {
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   command_line->AppendSwitch(switches::kEnableViewport);
-  command_line->AppendSwitch(switches::kEnableViewportMeta);
 
   command_line->AppendSwitch(xswitches::kEnableOverlayScrollbars);
 
index d34d779..3026837 100644 (file)
@@ -106,6 +106,8 @@ void XWalkBrowserMainPartsAndroid::PreMainMessageLoopStart() {
   command_line->AppendSwitch(
       switches::kDisableOverlayFullscreenVideoSubtitle);
 
+  command_line->AppendSwitch(switches::kEnableViewportMeta);
+
   XWalkBrowserMainParts::PreMainMessageLoopStart();
 
   startup_url_ = GURL();
index b83e615..63e4ae6 100644 (file)
@@ -4,7 +4,7 @@
 
 {
   'variables': {
-    'core_library_empty_embedder_apk_name': 'XWalkCoreLibraryEmptyEmbedder',
+    'core_internal_empty_embedder_apk_name': 'XWalkCoreInternalEmptyEmbedder',
   },
   'targets': [
     {
       ],
     },
     {
-      'target_name': 'xwalk_core_library_empty_embedder_apk',
+      'target_name': 'xwalk_core_internal_empty_embedder_apk',
       'type': 'none',
       'dependencies': [
         'libxwalkcore',
         'xwalk_core_internal_java',
-        'xwalk_core_java',
       ],
       'variables': {
-        'apk_name': '<(core_library_empty_embedder_apk_name)',
-        'java_in_dir': 'runtime/android/core_library_empty',
+        'apk_name': '<(core_internal_empty_embedder_apk_name)',
+        'java_in_dir': 'runtime/android/core_internal_empty',
         'native_lib_target': 'libxwalkcore',
         'is_test_apk': 1,
         'additional_src_dirs': [
       },
     },
     {
-      'target_name': 'xwalk_core_library_java',
+      'target_name': 'xwalk_core_library_java_app_part',
       'type': 'none',
       'dependencies': [
-        'xwalk_core_internal_java',
         'xwalk_core_java',
-        'xwalk_core_library_empty_embedder_apk',
       ],
       'variables': {
         'classes_dir': '<(PRODUCT_DIR)/<(_target_name)/classes',
           'message': 'Creating <(_target_name) jar',
           'inputs': [
             'build/android/merge_jars.py',
+            '>@(input_jars_paths)',
+          ],
+          'outputs': [
+            '<(jar_final_path)',
+          ],
+          'action': [
+            'python', 'build/android/merge_jars.py',
+            '--classes-dir=<(classes_dir)',
+            '--jars=>(input_jars_paths)',
+            '--jar-path=<(jar_final_path)',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'xwalk_core_library_java_library_part',
+      'type': 'none',
+      'dependencies': [
+        'xwalk_core_internal_empty_embedder_apk',
+      ],
+      'variables': {
+        'classes_dir': '<(PRODUCT_DIR)/<(_target_name)/classes',
+        'jar_name': '<(_target_name).jar',
+        'jar_final_path': '<(PRODUCT_DIR)/lib.java/<(jar_name)',
+      },
+      'actions': [
+        {
+          'action_name': 'jars_<(_target_name)',
+          'message': 'Creating <(_target_name) jar',
+          'inputs': [
+            'build/android/merge_jars.py',
+            '>@(input_jars_paths)',
           ],
           'outputs': [
-            '<(PRODUCT_DIR)/pack_xwalk_core_library_java_intermediate/always_run',
+            '<(jar_final_path)',
+          ],
+          'action': [
+            'python', 'build/android/merge_jars.py',
+            '--classes-dir=<(classes_dir)',
+            '--jars=>(input_jars_paths)',
+            '--jar-path=<(jar_final_path)',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'xwalk_core_library_java',
+      'type': 'none',
+      'dependencies': [
+        'xwalk_core_library_java_app_part',
+        'xwalk_core_library_java_library_part',
+      ],
+      'variables': {
+        'classes_dir': '<(PRODUCT_DIR)/<(_target_name)/classes',
+        'jar_name': '<(_target_name).jar',
+        'jar_final_path': '<(PRODUCT_DIR)/lib.java/<(jar_name)',
+      },
+      'actions': [
+        {
+          'action_name': 'jars_<(_target_name)',
+          'message': 'Creating <(_target_name) jar',
+          'inputs': [
+            'build/android/merge_jars.py',
+            '>@(input_jars_paths)',
+          ],
+          'outputs': [
+            '<(jar_final_path)',
           ],
           'action': [
             'python', 'build/android/merge_jars.py',
       'type': 'none',
       'dependencies': [
         'xwalk_core_shell_apk',
-        'xwalk_core_library_java',
+        'xwalk_core_library_java_app_part',
+        'xwalk_core_library_java_library_part',
       ],
       'actions': [
         {
       'type': 'none',
       'dependencies': [
         'xwalk_core_library',
+        'xwalk_core_library_java',
       ],
       'actions': [
         {
index 293df9a..9d1723c 100644 (file)
@@ -90,7 +90,7 @@
       'sources': [
         'application/test/application_browsertest.cc',
         'application/test/application_browsertest.h',
-        'application/test/application_multi_app_test.cc',
+        'application/test/application_test.cc',
         'application/test/application_testapi.cc',
         'application/test/application_testapi.h',
         'application/test/application_testapi_test.cc',