diff --git a/DEPS b/DEPS index d545b321..f8f432e 100644 --- a/DEPS +++ b/DEPS
@@ -74,7 +74,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'e562f413ea3877842cbb8bc8711053ab06c9d9d9', + 'skia_revision': 'be4ffab4e208ec47b4298621b9c9e8456f31717e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -98,7 +98,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '93bb725b62f9779534c9444c1e1319fe8c28912e', + 'pdfium_revision': 'f8f22c7ac7f3d4b922f40f67e910114e55b187b0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -639,7 +639,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '05591bbeae6592fd924caec8e728a4ea86cbb8c9', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '4d5b68e7bde264a5d164d94465f3818971fa6153', # commit position 20628 + Var('webrtc_git') + '/src.git' + '@' + 'a1d0f2731001d26f50a977fab3f3419125f5cc43', # commit position 20628 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/ENG_REVIEW_OWNERS b/ENG_REVIEW_OWNERS index d848886..50b15b8 100644 --- a/ENG_REVIEW_OWNERS +++ b/ENG_REVIEW_OWNERS
@@ -4,7 +4,6 @@ ben@chromium.org brettw@chromium.org darin@chromium.org -dglazkov@chromium.org klobag@chromium.org jochen@chromium.org jam@chromium.org
diff --git a/WATCHLISTS b/WATCHLISTS index cccf96f3..f8fcfb37b 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -513,15 +513,6 @@ 'filepath': 'third_party/WebKit/LayoutTests/external/' \ '|third_party/WebKit/Tools/Scripts/webkitpy/w3c/' }, - 'blink_webcomponents': { - 'filepath': 'third_party/WebKit/Source/core/dom/.*Shadow' \ - '|third_party/WebKit/Source/core/dom/.*Slot' \ - '|third_party/WebKit/Source/core/dom/.*InsertionPoint' \ - '|third_party/WebKit/Source/core/dom/.*FlatTree' \ - '|third_party/WebKit/Source/core/html/custom/' \ - '|third_party/WebKit/Source/core/html/imports/' \ - '|third_party/WebKit/Source/bindings/core/v8/.*CustomElement' - }, 'blink_webp': { 'filepath': 'third_party/WebKit/Source/platform/image-decoders/webp' \ '|third_party/WebKit/Source/platform/image-encoders/skia/WEBP' @@ -1724,15 +1715,13 @@ 'blink_css': ['alexis.menard@intel.com', 'apavlov+blink@chromium.org', 'blink-reviews-css@chromium.org', - 'dglazkov+blink@chromium.org', 'rob.buis@samsung.com'], 'blink_css_flexbox': ['cbiesinger@chromium.org'], 'blink_css_fragmentation_tests': ['mstensho@chromium.org'], 'blink_css_grid_layout': ['jfernandez@igalia.com', 'rego@igalia.com', 'svillar@igalia.com'], - 'blink_custom_elements': ['dglazkov+blink@chromium.org', - 'dominicc+watchlist@chromium.org'], + 'blink_custom_elements': ['dominicc+watchlist@chromium.org'], 'blink_device_orientation': ['mlamouri+watch-blink@chromium.org', 'timvolodine@chromium.org'], 'blink_devtools': ['apavlov+blink@chromium.org', @@ -1742,12 +1731,10 @@ 'lushnikov+blink@chromium.org', 'pfeldman+blink@chromium.org'], 'blink_dom': ['blink-reviews-dom@chromium.org', - 'dglazkov+blink@chromium.org', 'eae+blinkwatch@chromium.org', 'rob.buis@samsung.com'], 'blink_dom_events': ['hayato@chromium.org'], 'blink_events': ['blink-reviews-events@chromium.org', - 'dglazkov+blink@chromium.org', 'dtapuska+blinkwatch@chromium.org', 'eae+blinkwatch@chromium.org'], 'blink_fetch': ['gavinp+loader@chromium.org', @@ -1764,8 +1751,7 @@ 'haraken@chromium.org', 'kouhei+heap@chromium.org', 'oilpan-reviews@chromium.org'], - 'blink_html': ['blink-reviews-html@chromium.org', - 'dglazkov+blink@chromium.org'], + 'blink_html': ['blink-reviews-html@chromium.org'], 'blink_htmlparser': ['kinuko+watch@chromium.org', 'loading-reviews+parser@chromium.org'], 'blink_indexed_db': ['cmumford@chromium.org', @@ -1818,8 +1804,7 @@ 'blink_preloadScanner': ['yoav@yoav.ws'], 'blink_prerender': ['gavinp+prerender@chromium.org', 'yoav@yoav.ws'], - 'blink_public_api': ['blink-reviews-api@chromium.org', - 'dglazkov+blink@chromium.org'], + 'blink_public_api': ['blink-reviews-api@chromium.org'], 'blink_quota': ['kinuko+fileapi@chromium.org', 'nhiroki@chromium.org', 'tzik@chromium.org'], @@ -1861,7 +1846,6 @@ 'blink_vibration': ['mlamouri+watch-blink@chromium.org'], 'blink_viewport_interaction': ['kenneth.christiansen@gmail.com'], 'blink_w3ctests': ['blink-reviews-w3ctests@chromium.org'], - 'blink_webcomponents': ['dglazkov+blink@chromium.org'], 'blink_webp': ['jzern@chromium.org', 'skal@google.com', 'urvang@chromium.org'],
diff --git a/ash/message_center/notifier_settings_view.h b/ash/message_center/notifier_settings_view.h index ccb9c3a..b69bafb 100644 --- a/ash/message_center/notifier_settings_view.h +++ b/ash/message_center/notifier_settings_view.h
@@ -97,9 +97,6 @@ // Overridden from views::ButtonListener: void ButtonPressed(views::Button* sender, const ui::Event& event) override; - // Callback for views::MenuModelAdapter. - void OnMenuClosed(); - views::ImageButton* title_arrow_; views::ImageView* quiet_mode_icon_; views::ToggleButton* quiet_mode_toggle_;
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index ddc51f54..bd1b553 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc
@@ -641,17 +641,14 @@ menu_model_ = std::make_unique<ShelfContextMenuModel>( std::vector<mojom::MenuItemPtr>(), nullptr, display_id); - menu_model_adapter_ = std::make_unique<views::MenuModelAdapter>( - menu_model_.get(), - base::Bind(&RootWindowController::OnMenuClosed, base::Unretained(this))); - // The wallpaper controller may not be set yet if the user clicked on the // status area before the initial animation completion. See crbug.com/222218 if (!wallpaper_widget_controller()) return; menu_runner_ = std::make_unique<views::MenuRunner>( - menu_model_adapter_->CreateMenu(), views::MenuRunner::CONTEXT_MENU); + menu_model_.get(), views::MenuRunner::CONTEXT_MENU, + base::Bind(&RootWindowController::OnMenuClosed, base::Unretained(this))); menu_runner_->RunMenuAt(wallpaper_widget_controller()->widget(), nullptr, gfx::Rect(location_in_screen, gfx::Size()), views::MENU_ANCHOR_TOPLEFT, source_type); @@ -1029,7 +1026,6 @@ void RootWindowController::OnMenuClosed() { menu_runner_.reset(); - menu_model_adapter_.reset(); menu_model_.reset(); shelf_->UpdateVisibilityState(); }
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h index 5b289ed..ffff227b 100644 --- a/ash/root_window_controller.h +++ b/ash/root_window_controller.h
@@ -36,7 +36,6 @@ } namespace views { -class MenuModelAdapter; class MenuRunner; class Widget; } @@ -283,7 +282,7 @@ // this. void ResetRootForNewWindowsIfNecessary(); - // Callback for MenuModelAdapter. + // Callback for MenuRunner. void OnMenuClosed(); std::unique_ptr<AshWindowTreeHost> ash_host_; @@ -304,7 +303,6 @@ // Manages the context menu. std::unique_ptr<ui::MenuModel> menu_model_; - std::unique_ptr<views::MenuModelAdapter> menu_model_adapter_; std::unique_ptr<views::MenuRunner> menu_runner_; std::unique_ptr<StackingController> stacking_controller_;
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index ea92f29c..0a4b5ae 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -1793,9 +1793,6 @@ ui::MenuSourceType source_type, views::InkDrop* ink_drop) { menu_model_ = std::move(menu_model); - menu_model_adapter_.reset(new views::MenuModelAdapter( - menu_model_.get(), - base::Bind(&ShelfView::OnMenuClosed, base::Unretained(this), ink_drop))); closing_event_time_ = base::TimeTicks(); int run_types = 0; @@ -1810,8 +1807,9 @@ run_types |= views::MenuRunner::SEND_GESTURE_EVENTS_TO_OWNER; } - launcher_menu_runner_.reset( - new views::MenuRunner(menu_model_adapter_->CreateMenu(), run_types)); + launcher_menu_runner_ = std::make_unique<views::MenuRunner>( + menu_model_.get(), run_types, + base::Bind(&ShelfView::OnMenuClosed, base::Unretained(this), ink_drop)); views::MenuAnchorPosition menu_alignment = views::MENU_ANCHOR_TOPLEFT; gfx::Rect anchor = gfx::Rect(click_point, gfx::Size()); @@ -1865,7 +1863,6 @@ ink_drop->AnimateToState(views::InkDropState::DEACTIVATED); launcher_menu_runner_.reset(); - menu_model_adapter_.reset(); menu_model_.reset(); // Auto-hide or alignment might have changed, but only for this shelf.
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h index 26d0f1b4..36ec275 100644 --- a/ash/shelf/shelf_view.h +++ b/ash/shelf/shelf_view.h
@@ -34,7 +34,6 @@ namespace views { class BoundsAnimator; -class MenuModelAdapter; class MenuRunner; } @@ -363,7 +362,7 @@ ui::MenuSourceType source_type, views::InkDrop* ink_drop); - // Callback for MenuModelAdapter. + // Callback for MenuRunner. void OnMenuClosed(views::InkDrop* ink_drop); // Overridden from views::BoundsAnimatorObserver: @@ -436,7 +435,6 @@ // Manages the context menu, and the list menu. std::unique_ptr<ui::MenuModel> menu_model_; - std::unique_ptr<views::MenuModelAdapter> menu_model_adapter_; std::unique_ptr<views::MenuRunner> launcher_menu_runner_; std::unique_ptr<ScopedRootWindowForNewWindows> scoped_root_window_for_new_windows_;
diff --git a/ash/system/bluetooth/tray_bluetooth.cc b/ash/system/bluetooth/tray_bluetooth.cc index dd6382a..eaebceb1 100644 --- a/ash/system/bluetooth/tray_bluetooth.cc +++ b/ash/system/bluetooth/tray_bluetooth.cc
@@ -201,6 +201,14 @@ } void Update() { + // Update immediately for initial device list and + // when bluetooth is disabled. + if (device_map_.size() == 0 || + !Shell::Get()->tray_bluetooth_helper()->GetBluetoothEnabled()) { + DoUpdate(); + return; + } + // Return here since an update is already queued. if (timer_.IsRunning()) return;
diff --git a/base/i18n/timezone.cc b/base/i18n/timezone.cc index 95e7aee3..8624e07e 100644 --- a/base/i18n/timezone.cc +++ b/base/i18n/timezone.cc
@@ -4,615 +4,31 @@ #include "base/i18n/timezone.h" -#include <stddef.h> -#include <string.h> +#include <memory> +#include <string> -#include <map> - -#include "base/macros.h" -#include "base/memory/singleton.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" +#include "third_party/icu/source/common/unicode/unistr.h" #include "third_party/icu/source/i18n/unicode/timezone.h" namespace base { -namespace { - -class TimezoneMap { - public: - static TimezoneMap* GetInstance() { - return Singleton<TimezoneMap>::get(); - } - - std::string CountryCodeForTimezone(const std::string& olson_code) { - std::map<const char*, const char*, CompareCStrings>::iterator iter = - map_.find(olson_code.c_str()); - if (iter != map_.end()) - return iter->second; - - return std::string(); - } - - private: - TimezoneMap() { - // These mappings are adapted from zone.tab, which is available at - // <http://www.ietf.org/timezones/data/zone.tab> and is a part of public - // domain. - struct OlsonCodeData { - const char* country_code; - const char* olson_code; - }; - static const OlsonCodeData olson_code_data[] = { - { "AD", "Europe/Andorra" }, - { "AE", "Asia/Dubai" }, - { "AF", "Asia/Kabul" }, - { "AG", "America/Antigua" }, - { "AI", "America/Anguilla" }, - { "AL", "Europe/Tirane" }, - { "AM", "Asia/Yerevan" }, - { "AO", "Africa/Luanda" }, - { "AQ", "Antarctica/McMurdo" }, - { "AQ", "Antarctica/Rothera" }, - { "AQ", "Antarctica/Palmer" }, - { "AQ", "Antarctica/Mawson" }, - { "AQ", "Antarctica/Davis" }, - { "AQ", "Antarctica/Casey" }, - { "AQ", "Antarctica/Vostok" }, - { "AQ", "Antarctica/DumontDUrville" }, - { "AQ", "Antarctica/Syowa" }, - { "AR", "America/Argentina/Buenos_Aires" }, - { "AR", "America/Argentina/Cordoba" }, - { "AR", "America/Argentina/Salta" }, - { "AR", "America/Argentina/Jujuy" }, - { "AR", "America/Argentina/Tucuman" }, - { "AR", "America/Argentina/Catamarca" }, - { "AR", "America/Argentina/La_Rioja" }, - { "AR", "America/Argentina/San_Juan" }, - { "AR", "America/Argentina/Mendoza" }, - { "AR", "America/Argentina/San_Luis" }, - { "AR", "America/Argentina/Rio_Gallegos" }, - { "AR", "America/Argentina/Ushuaia" }, - { "AS", "Pacific/Pago_Pago" }, - { "AT", "Europe/Vienna" }, - { "AU", "Australia/Lord_Howe" }, - { "AU", "Antarctica/Macquarie" }, - { "AU", "Australia/Hobart" }, - { "AU", "Australia/Currie" }, - { "AU", "Australia/Melbourne" }, - { "AU", "Australia/Sydney" }, - { "AU", "Australia/Broken_Hill" }, - { "AU", "Australia/Brisbane" }, - { "AU", "Australia/Lindeman" }, - { "AU", "Australia/Adelaide" }, - { "AU", "Australia/Darwin" }, - { "AU", "Australia/Perth" }, - { "AU", "Australia/Eucla" }, - { "AW", "America/Aruba" }, - { "AX", "Europe/Mariehamn" }, - { "AZ", "Asia/Baku" }, - { "BA", "Europe/Sarajevo" }, - { "BB", "America/Barbados" }, - { "BD", "Asia/Dhaka" }, - { "BE", "Europe/Brussels" }, - { "BF", "Africa/Ouagadougou" }, - { "BG", "Europe/Sofia" }, - { "BH", "Asia/Bahrain" }, - { "BI", "Africa/Bujumbura" }, - { "BJ", "Africa/Porto-Novo" }, - { "BL", "America/St_Barthelemy" }, - { "BM", "Atlantic/Bermuda" }, - { "BN", "Asia/Brunei" }, - { "BO", "America/La_Paz" }, - { "BQ", "America/Kralendijk" }, - { "BR", "America/Noronha" }, - { "BR", "America/Belem" }, - { "BR", "America/Fortaleza" }, - { "BR", "America/Recife" }, - { "BR", "America/Araguaina" }, - { "BR", "America/Maceio" }, - { "BR", "America/Bahia" }, - { "BR", "America/Sao_Paulo" }, - { "BR", "America/Campo_Grande" }, - { "BR", "America/Cuiaba" }, - { "BR", "America/Santarem" }, - { "BR", "America/Porto_Velho" }, - { "BR", "America/Boa_Vista" }, - { "BR", "America/Manaus" }, - { "BR", "America/Eirunepe" }, - { "BR", "America/Rio_Branco" }, - { "BS", "America/Nassau" }, - { "BT", "Asia/Thimphu" }, - { "BW", "Africa/Gaborone" }, - { "BY", "Europe/Minsk" }, - { "BZ", "America/Belize" }, - { "CA", "America/St_Johns" }, - { "CA", "America/Halifax" }, - { "CA", "America/Glace_Bay" }, - { "CA", "America/Moncton" }, - { "CA", "America/Goose_Bay" }, - { "CA", "America/Blanc-Sablon" }, - { "CA", "America/Toronto" }, - { "CA", "America/Nipigon" }, - { "CA", "America/Thunder_Bay" }, - { "CA", "America/Iqaluit" }, - { "CA", "America/Pangnirtung" }, - { "CA", "America/Resolute" }, - { "CA", "America/Atikokan" }, - { "CA", "America/Rankin_Inlet" }, - { "CA", "America/Winnipeg" }, - { "CA", "America/Rainy_River" }, - { "CA", "America/Regina" }, - { "CA", "America/Swift_Current" }, - { "CA", "America/Edmonton" }, - { "CA", "America/Cambridge_Bay" }, - { "CA", "America/Yellowknife" }, - { "CA", "America/Inuvik" }, - { "CA", "America/Creston" }, - { "CA", "America/Dawson_Creek" }, - { "CA", "America/Vancouver" }, - { "CA", "America/Whitehorse" }, - { "CA", "America/Dawson" }, - { "CC", "Indian/Cocos" }, - { "CD", "Africa/Kinshasa" }, - { "CD", "Africa/Lubumbashi" }, - { "CF", "Africa/Bangui" }, - { "CG", "Africa/Brazzaville" }, - { "CH", "Europe/Zurich" }, - { "CI", "Africa/Abidjan" }, - { "CK", "Pacific/Rarotonga" }, - { "CL", "America/Santiago" }, - { "CL", "Pacific/Easter" }, - { "CM", "Africa/Douala" }, - { "CN", "Asia/Shanghai" }, - { "CN", "Asia/Harbin" }, - { "CN", "Asia/Chongqing" }, - { "CN", "Asia/Urumqi" }, - { "CN", "Asia/Kashgar" }, - { "CO", "America/Bogota" }, - { "CR", "America/Costa_Rica" }, - { "CU", "America/Havana" }, - { "CV", "Atlantic/Cape_Verde" }, - { "CW", "America/Curacao" }, - { "CX", "Indian/Christmas" }, - { "CY", "Asia/Nicosia" }, - { "CZ", "Europe/Prague" }, - { "DE", "Europe/Berlin" }, - { "DE", "Europe/Busingen" }, - { "DJ", "Africa/Djibouti" }, - { "DK", "Europe/Copenhagen" }, - { "DM", "America/Dominica" }, - { "DO", "America/Santo_Domingo" }, - { "DZ", "Africa/Algiers" }, - { "EC", "America/Guayaquil" }, - { "EC", "Pacific/Galapagos" }, - { "EE", "Europe/Tallinn" }, - { "EG", "Africa/Cairo" }, - { "EH", "Africa/El_Aaiun" }, - { "ER", "Africa/Asmara" }, - { "ES", "Europe/Madrid" }, - { "ES", "Africa/Ceuta" }, - { "ES", "Atlantic/Canary" }, - { "ET", "Africa/Addis_Ababa" }, - { "FI", "Europe/Helsinki" }, - { "FJ", "Pacific/Fiji" }, - { "FK", "Atlantic/Stanley" }, - { "FM", "Pacific/Chuuk" }, - { "FM", "Pacific/Pohnpei" }, - { "FM", "Pacific/Kosrae" }, - { "FO", "Atlantic/Faroe" }, - { "FR", "Europe/Paris" }, - { "GA", "Africa/Libreville" }, - { "GB", "Europe/London" }, - { "GD", "America/Grenada" }, - { "GE", "Asia/Tbilisi" }, - { "GF", "America/Cayenne" }, - { "GG", "Europe/Guernsey" }, - { "GH", "Africa/Accra" }, - { "GI", "Europe/Gibraltar" }, - { "GL", "America/Godthab" }, - { "GL", "America/Danmarkshavn" }, - { "GL", "America/Scoresbysund" }, - { "GL", "America/Thule" }, - { "GM", "Africa/Banjul" }, - { "GN", "Africa/Conakry" }, - { "GP", "America/Guadeloupe" }, - { "GQ", "Africa/Malabo" }, - { "GR", "Europe/Athens" }, - { "GS", "Atlantic/South_Georgia" }, - { "GT", "America/Guatemala" }, - { "GU", "Pacific/Guam" }, - { "GW", "Africa/Bissau" }, - { "GY", "America/Guyana" }, - { "HK", "Asia/Hong_Kong" }, - { "HN", "America/Tegucigalpa" }, - { "HR", "Europe/Zagreb" }, - { "HT", "America/Port-au-Prince" }, - { "HU", "Europe/Budapest" }, - { "ID", "Asia/Jakarta" }, - { "ID", "Asia/Pontianak" }, - { "ID", "Asia/Makassar" }, - { "ID", "Asia/Jayapura" }, - { "IE", "Europe/Dublin" }, - { "IL", "Asia/Jerusalem" }, - { "IM", "Europe/Isle_of_Man" }, - { "IN", "Asia/Kolkata" }, - { "IO", "Indian/Chagos" }, - { "IQ", "Asia/Baghdad" }, - { "IR", "Asia/Tehran" }, - { "IS", "Atlantic/Reykjavik" }, - { "IT", "Europe/Rome" }, - { "JE", "Europe/Jersey" }, - { "JM", "America/Jamaica" }, - { "JO", "Asia/Amman" }, - { "JP", "Asia/Tokyo" }, - { "KE", "Africa/Nairobi" }, - { "KG", "Asia/Bishkek" }, - { "KH", "Asia/Phnom_Penh" }, - { "KI", "Pacific/Tarawa" }, - { "KI", "Pacific/Enderbury" }, - { "KI", "Pacific/Kiritimati" }, - { "KM", "Indian/Comoro" }, - { "KN", "America/St_Kitts" }, - { "KP", "Asia/Pyongyang" }, - { "KR", "Asia/Seoul" }, - { "KW", "Asia/Kuwait" }, - { "KY", "America/Cayman" }, - { "KZ", "Asia/Almaty" }, - { "KZ", "Asia/Qyzylorda" }, - { "KZ", "Asia/Aqtobe" }, - { "KZ", "Asia/Aqtau" }, - { "KZ", "Asia/Oral" }, - { "LA", "Asia/Vientiane" }, - { "LB", "Asia/Beirut" }, - { "LC", "America/St_Lucia" }, - { "LI", "Europe/Vaduz" }, - { "LK", "Asia/Colombo" }, - { "LR", "Africa/Monrovia" }, - { "LS", "Africa/Maseru" }, - { "LT", "Europe/Vilnius" }, - { "LU", "Europe/Luxembourg" }, - { "LV", "Europe/Riga" }, - { "LY", "Africa/Tripoli" }, - { "MA", "Africa/Casablanca" }, - { "MC", "Europe/Monaco" }, - { "MD", "Europe/Chisinau" }, - { "ME", "Europe/Podgorica" }, - { "MF", "America/Marigot" }, - { "MG", "Indian/Antananarivo" }, - { "MH", "Pacific/Majuro" }, - { "MH", "Pacific/Kwajalein" }, - { "MK", "Europe/Skopje" }, - { "ML", "Africa/Bamako" }, - { "MM", "Asia/Rangoon" }, - { "MN", "Asia/Ulaanbaatar" }, - { "MN", "Asia/Hovd" }, - { "MN", "Asia/Choibalsan" }, - { "MO", "Asia/Macau" }, - { "MP", "Pacific/Saipan" }, - { "MQ", "America/Martinique" }, - { "MR", "Africa/Nouakchott" }, - { "MS", "America/Montserrat" }, - { "MT", "Europe/Malta" }, - { "MU", "Indian/Mauritius" }, - { "MV", "Indian/Maldives" }, - { "MW", "Africa/Blantyre" }, - { "MX", "America/Mexico_City" }, - { "MX", "America/Cancun" }, - { "MX", "America/Merida" }, - { "MX", "America/Monterrey" }, - { "MX", "America/Matamoros" }, - { "MX", "America/Mazatlan" }, - { "MX", "America/Chihuahua" }, - { "MX", "America/Ojinaga" }, - { "MX", "America/Hermosillo" }, - { "MX", "America/Tijuana" }, - { "MX", "America/Santa_Isabel" }, - { "MX", "America/Bahia_Banderas" }, - { "MY", "Asia/Kuala_Lumpur" }, - { "MY", "Asia/Kuching" }, - { "MZ", "Africa/Maputo" }, - { "NA", "Africa/Windhoek" }, - { "NC", "Pacific/Noumea" }, - { "NE", "Africa/Niamey" }, - { "NF", "Pacific/Norfolk" }, - { "NG", "Africa/Lagos" }, - { "NI", "America/Managua" }, - { "NL", "Europe/Amsterdam" }, - { "NO", "Europe/Oslo" }, - { "NP", "Asia/Kathmandu" }, - { "NR", "Pacific/Nauru" }, - { "NU", "Pacific/Niue" }, - { "NZ", "Pacific/Auckland" }, - { "NZ", "Pacific/Chatham" }, - { "OM", "Asia/Muscat" }, - { "PA", "America/Panama" }, - { "PE", "America/Lima" }, - { "PF", "Pacific/Tahiti" }, - { "PF", "Pacific/Marquesas" }, - { "PF", "Pacific/Gambier" }, - { "PG", "Pacific/Port_Moresby" }, - { "PH", "Asia/Manila" }, - { "PK", "Asia/Karachi" }, - { "PL", "Europe/Warsaw" }, - { "PM", "America/Miquelon" }, - { "PN", "Pacific/Pitcairn" }, - { "PR", "America/Puerto_Rico" }, - { "PS", "Asia/Gaza" }, - { "PS", "Asia/Hebron" }, - { "PT", "Europe/Lisbon" }, - { "PT", "Atlantic/Madeira" }, - { "PT", "Atlantic/Azores" }, - { "PW", "Pacific/Palau" }, - { "PY", "America/Asuncion" }, - { "QA", "Asia/Qatar" }, - { "RE", "Indian/Reunion" }, - { "RO", "Europe/Bucharest" }, - { "RS", "Europe/Belgrade" }, - { "RU", "Europe/Kaliningrad" }, - { "RU", "Europe/Moscow" }, - { "RU", "Europe/Volgograd" }, - { "RU", "Europe/Samara" }, - { "RU", "Asia/Yekaterinburg" }, - { "RU", "Asia/Omsk" }, - { "RU", "Asia/Novosibirsk" }, - { "RU", "Asia/Novokuznetsk" }, - { "RU", "Asia/Krasnoyarsk" }, - { "RU", "Asia/Irkutsk" }, - { "RU", "Asia/Yakutsk" }, - { "RU", "Asia/Khandyga" }, - { "RU", "Asia/Vladivostok" }, - { "RU", "Asia/Sakhalin" }, - { "RU", "Asia/Ust-Nera" }, - { "RU", "Asia/Magadan" }, - { "RU", "Asia/Kamchatka" }, - { "RU", "Asia/Anadyr" }, - { "RW", "Africa/Kigali" }, - { "SA", "Asia/Riyadh" }, - { "SB", "Pacific/Guadalcanal" }, - { "SC", "Indian/Mahe" }, - { "SD", "Africa/Khartoum" }, - { "SE", "Europe/Stockholm" }, - { "SG", "Asia/Singapore" }, - { "SH", "Atlantic/St_Helena" }, - { "SI", "Europe/Ljubljana" }, - { "SJ", "Arctic/Longyearbyen" }, - { "SK", "Europe/Bratislava" }, - { "SL", "Africa/Freetown" }, - { "SM", "Europe/San_Marino" }, - { "SN", "Africa/Dakar" }, - { "SO", "Africa/Mogadishu" }, - { "SR", "America/Paramaribo" }, - { "SS", "Africa/Juba" }, - { "ST", "Africa/Sao_Tome" }, - { "SV", "America/El_Salvador" }, - { "SX", "America/Lower_Princes" }, - { "SY", "Asia/Damascus" }, - { "SZ", "Africa/Mbabane" }, - { "TC", "America/Grand_Turk" }, - { "TD", "Africa/Ndjamena" }, - { "TF", "Indian/Kerguelen" }, - { "TG", "Africa/Lome" }, - { "TH", "Asia/Bangkok" }, - { "TJ", "Asia/Dushanbe" }, - { "TK", "Pacific/Fakaofo" }, - { "TL", "Asia/Dili" }, - { "TM", "Asia/Ashgabat" }, - { "TN", "Africa/Tunis" }, - { "TO", "Pacific/Tongatapu" }, - { "TR", "Europe/Istanbul" }, - { "TT", "America/Port_of_Spain" }, - { "TV", "Pacific/Funafuti" }, - { "TW", "Asia/Taipei" }, - { "TZ", "Africa/Dar_es_Salaam" }, - { "UA", "Europe/Kiev" }, - { "UA", "Europe/Uzhgorod" }, - { "UA", "Europe/Zaporozhye" }, - { "UA", "Europe/Simferopol" }, - { "UG", "Africa/Kampala" }, - { "UM", "Pacific/Johnston" }, - { "UM", "Pacific/Midway" }, - { "UM", "Pacific/Wake" }, - { "US", "America/New_York" }, - { "US", "America/Detroit" }, - { "US", "America/Kentucky/Louisville" }, - { "US", "America/Kentucky/Monticello" }, - { "US", "America/Indiana/Indianapolis" }, - { "US", "America/Indiana/Vincennes" }, - { "US", "America/Indiana/Winamac" }, - { "US", "America/Indiana/Marengo" }, - { "US", "America/Indiana/Petersburg" }, - { "US", "America/Indiana/Vevay" }, - { "US", "America/Chicago" }, - { "US", "America/Indiana/Tell_City" }, - { "US", "America/Indiana/Knox" }, - { "US", "America/Menominee" }, - { "US", "America/North_Dakota/Center" }, - { "US", "America/North_Dakota/New_Salem" }, - { "US", "America/North_Dakota/Beulah" }, - { "US", "America/Denver" }, - { "US", "America/Boise" }, - { "US", "America/Phoenix" }, - { "US", "America/Los_Angeles" }, - { "US", "America/Anchorage" }, - { "US", "America/Juneau" }, - { "US", "America/Sitka" }, - { "US", "America/Yakutat" }, - { "US", "America/Nome" }, - { "US", "America/Adak" }, - { "US", "America/Metlakatla" }, - { "US", "Pacific/Honolulu" }, - { "UY", "America/Montevideo" }, - { "UZ", "Asia/Samarkand" }, - { "UZ", "Asia/Tashkent" }, - { "VA", "Europe/Vatican" }, - { "VC", "America/St_Vincent" }, - { "VE", "America/Caracas" }, - { "VG", "America/Tortola" }, - { "VI", "America/St_Thomas" }, - { "VN", "Asia/Ho_Chi_Minh" }, - { "VU", "Pacific/Efate" }, - { "WF", "Pacific/Wallis" }, - { "WS", "Pacific/Apia" }, - { "YE", "Asia/Aden" }, - { "YT", "Indian/Mayotte" }, - { "ZA", "Africa/Johannesburg" }, - { "ZM", "Africa/Lusaka" }, - { "ZW", "Africa/Harare" }, - // The mappings below are custom additions to zone.tab. - { "GB", "Etc/GMT" }, - { "GB", "Etc/UTC" }, - { "GB", "Etc/UCT" }, - }; - - for (size_t i = 0; i < arraysize(olson_code_data); ++i) - map_[olson_code_data[i].olson_code] = olson_code_data[i].country_code; - - // These are mapping from old codenames to new codenames. They are also - // part of public domain, and available at - // <http://www.ietf.org/timezones/data/backward>. - struct LinkData { - const char* old_code; - const char* new_code; - }; - static const LinkData link_data[] = { - { "Africa/Asmera", "Africa/Asmara" }, - { "Africa/Timbuktu", "Africa/Bamako" }, - { "America/Argentina/ComodRivadavia", "America/Argentina/Catamarca" }, - { "America/Atka", "America/Adak" }, - { "America/Buenos_Aires", "America/Argentina/Buenos_Aires" }, - { "America/Catamarca", "America/Argentina/Catamarca" }, - { "America/Coral_Harbour", "America/Atikokan" }, - { "America/Cordoba", "America/Argentina/Cordoba" }, - { "America/Ensenada", "America/Tijuana" }, - { "America/Fort_Wayne", "America/Indiana/Indianapolis" }, - { "America/Indianapolis", "America/Indiana/Indianapolis" }, - { "America/Jujuy", "America/Argentina/Jujuy" }, - { "America/Knox_IN", "America/Indiana/Knox" }, - { "America/Louisville", "America/Kentucky/Louisville" }, - { "America/Mendoza", "America/Argentina/Mendoza" }, - { "America/Porto_Acre", "America/Rio_Branco" }, - { "America/Rosario", "America/Argentina/Cordoba" }, - { "America/Virgin", "America/St_Thomas" }, - { "Asia/Ashkhabad", "Asia/Ashgabat" }, - { "Asia/Chungking", "Asia/Chongqing" }, - { "Asia/Dacca", "Asia/Dhaka" }, - { "Asia/Katmandu", "Asia/Kathmandu" }, - { "Asia/Calcutta", "Asia/Kolkata" }, - { "Asia/Macao", "Asia/Macau" }, - { "Asia/Tel_Aviv", "Asia/Jerusalem" }, - { "Asia/Saigon", "Asia/Ho_Chi_Minh" }, - { "Asia/Thimbu", "Asia/Thimphu" }, - { "Asia/Ujung_Pandang", "Asia/Makassar" }, - { "Asia/Ulan_Bator", "Asia/Ulaanbaatar" }, - { "Atlantic/Faeroe", "Atlantic/Faroe" }, - { "Atlantic/Jan_Mayen", "Europe/Oslo" }, - { "Australia/ACT", "Australia/Sydney" }, - { "Australia/Canberra", "Australia/Sydney" }, - { "Australia/LHI", "Australia/Lord_Howe" }, - { "Australia/NSW", "Australia/Sydney" }, - { "Australia/North", "Australia/Darwin" }, - { "Australia/Queensland", "Australia/Brisbane" }, - { "Australia/South", "Australia/Adelaide" }, - { "Australia/Tasmania", "Australia/Hobart" }, - { "Australia/Victoria", "Australia/Melbourne" }, - { "Australia/West", "Australia/Perth" }, - { "Australia/Yancowinna", "Australia/Broken_Hill" }, - { "Brazil/Acre", "America/Rio_Branco" }, - { "Brazil/DeNoronha", "America/Noronha" }, - { "Brazil/East", "America/Sao_Paulo" }, - { "Brazil/West", "America/Manaus" }, - { "Canada/Atlantic", "America/Halifax" }, - { "Canada/Central", "America/Winnipeg" }, - { "Canada/East-Saskatchewan", "America/Regina" }, - { "Canada/Eastern", "America/Toronto" }, - { "Canada/Mountain", "America/Edmonton" }, - { "Canada/Newfoundland", "America/St_Johns" }, - { "Canada/Pacific", "America/Vancouver" }, - { "Canada/Saskatchewan", "America/Regina" }, - { "Canada/Yukon", "America/Whitehorse" }, - { "Chile/Continental", "America/Santiago" }, - { "Chile/EasterIsland", "Pacific/Easter" }, - { "Cuba", "America/Havana" }, - { "Egypt", "Africa/Cairo" }, - { "Eire", "Europe/Dublin" }, - { "Europe/Belfast", "Europe/London" }, - { "Europe/Tiraspol", "Europe/Chisinau" }, - { "GB", "Europe/London" }, - { "GB-Eire", "Europe/London" }, - { "GMT+0", "Etc/GMT" }, - { "GMT-0", "Etc/GMT" }, - { "GMT0", "Etc/GMT" }, - { "Greenwich", "Etc/GMT" }, - { "Hongkong", "Asia/Hong_Kong" }, - { "Iceland", "Atlantic/Reykjavik" }, - { "Iran", "Asia/Tehran" }, - { "Israel", "Asia/Jerusalem" }, - { "Jamaica", "America/Jamaica" }, - { "Japan", "Asia/Tokyo" }, - { "Kwajalein", "Pacific/Kwajalein" }, - { "Libya", "Africa/Tripoli" }, - { "Mexico/BajaNorte", "America/Tijuana" }, - { "Mexico/BajaSur", "America/Mazatlan" }, - { "Mexico/General", "America/Mexico_City" }, - { "NZ", "Pacific/Auckland" }, - { "NZ-CHAT", "Pacific/Chatham" }, - { "Navajo", "America/Denver" }, - { "PRC", "Asia/Shanghai" }, - { "Pacific/Samoa", "Pacific/Pago_Pago" }, - { "Pacific/Yap", "Pacific/Chuuk" }, - { "Pacific/Truk", "Pacific/Chuuk" }, - { "Pacific/Ponape", "Pacific/Pohnpei" }, - { "Poland", "Europe/Warsaw" }, - { "Portugal", "Europe/Lisbon" }, - { "ROC", "Asia/Taipei" }, - { "ROK", "Asia/Seoul" }, - { "Singapore", "Asia/Singapore" }, - { "Turkey", "Europe/Istanbul" }, - { "UCT", "Etc/UCT" }, - { "US/Alaska", "America/Anchorage" }, - { "US/Aleutian", "America/Adak" }, - { "US/Arizona", "America/Phoenix" }, - { "US/Central", "America/Chicago" }, - { "US/East-Indiana", "America/Indiana/Indianapolis" }, - { "US/Eastern", "America/New_York" }, - { "US/Hawaii", "Pacific/Honolulu" }, - { "US/Indiana-Starke", "America/Indiana/Knox" }, - { "US/Michigan", "America/Detroit" }, - { "US/Mountain", "America/Denver" }, - { "US/Pacific", "America/Los_Angeles" }, - { "US/Samoa", "Pacific/Pago_Pago" }, - { "UTC", "Etc/UTC" }, - { "Universal", "Etc/UTC" }, - { "W-SU", "Europe/Moscow" }, - { "Zulu", "Etc/UTC" }, - }; - - for (size_t i = 0; i < arraysize(link_data); ++i) - map_[link_data[i].old_code] = map_[link_data[i].new_code]; - } - - friend struct DefaultSingletonTraits<TimezoneMap>; - - struct CompareCStrings { - bool operator()(const char* str1, const char* str2) const { - return strcmp(str1, str2) < 0; - } - }; - std::map<const char*, const char*, CompareCStrings> map_; - - DISALLOW_COPY_AND_ASSIGN(TimezoneMap); -}; - -} // namespace - std::string CountryCodeForCurrentTimezone() { std::unique_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault()); icu::UnicodeString id; - zone->getID(id); - std::string olson_code; - return TimezoneMap::GetInstance()->CountryCodeForTimezone( - id.toUTF8String(olson_code)); + // ICU returns '001' (world) for Etc/GMT. Preserve the old behavior + // only for Etc/GMT while returning an empty string for Etc/UTC and + // Etc/UCT because they're less likely to be chosen by mistake in UK in + // place of Europe/London (Briitish Time). + if (zone->getID(id) == UNICODE_STRING_SIMPLE("Etc/GMT")) + return "GB"; + char region_code[4]; + UErrorCode status = U_ZERO_ERROR; + int length = zone->getRegion(id, region_code, 4, status); + // Return an empty string if region_code is a 3-digit numeric code such + // as 001 (World) for Etc/UTC, Etc/UCT. + return (U_SUCCESS(status) && length == 2) + ? std::string(region_code, static_cast<size_t>(length)) + : std::string(); } } // namespace base
diff --git a/base/i18n/timezone.h b/base/i18n/timezone.h index f7fda94..7557d44f 100644 --- a/base/i18n/timezone.h +++ b/base/i18n/timezone.h
@@ -11,9 +11,12 @@ namespace base { -// Checks the system timezone and turns it into a two-character ASCII country -// code. This may fail (for example, it will always fail on Android), in which -// case it will return an empty string. +// Checks the system timezone and turns it into a two-character ISO 3166 country +// code. This may fail (for example, it used to always fail on Android), in +// which case it will return an empty string. It'll also return an empty string +// when the timezone is Etc/UTC or Etc/UCT, but will return 'GB" for Etc/GMT +// because people in the UK tends to select Etc/GMT by mistake instead of +// Europe/London (British Time). BASE_I18N_EXPORT std::string CountryCodeForCurrentTimezone(); } // namespace base
diff --git a/base/i18n/timezone_unittest.cc b/base/i18n/timezone_unittest.cc index 2cdcc42..57467dc 100644 --- a/base/i18n/timezone_unittest.cc +++ b/base/i18n/timezone_unittest.cc
@@ -11,10 +11,16 @@ TEST(TimezoneTest, CountryCodeForCurrentTimezone) { std::string country_code = CountryCodeForCurrentTimezone(); - // On some systems (such as Android or some flavors of Linux), icu may come up - // empty. + // On some systems (such as Android or some flavors of Linux), ICU may come up + // empty. With https://chromium-review.googlesource.com/c/512282/ , ICU will + // not fail any more. See also http://bugs.icu-project.org/trac/ticket/13208 . + // Even with that, ICU returns '001' (world) for region-agnostic timezones + // such as Etc/UTC and |CountryCodeForCurrentTimezone| returns an empty + // string so that the next fallback can be tried by a customer. + // TODO(jshin): Revise this to test for actual timezones using + // use ScopedRestoreICUDefaultTimezone. if (!country_code.empty()) - EXPECT_EQ(2U, country_code.size()); + EXPECT_EQ(2U, country_code.size()) << "country_code = " << country_code; } } // namespace
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc index 92fccb9..a07bc92 100644 --- a/base/trace_event/trace_log.cc +++ b/base/trace_event/trace_log.cc
@@ -1542,7 +1542,7 @@ DCHECK(handle.chunk_seq); DCHECK(handle.chunk_index <= TraceBufferChunk::kMaxChunkIndex); - DCHECK(handle.event_index < TraceBufferChunk::kTraceBufferChunkSize); + DCHECK(handle.event_index <= TraceBufferChunk::kTraceBufferChunkSize - 1); if (thread_local_event_buffer_.Get()) { TraceEvent* trace_event =
diff --git a/cc/paint/BUILD.gn b/cc/paint/BUILD.gn index 93438a6..7aaadb9 100644 --- a/cc/paint/BUILD.gn +++ b/cc/paint/BUILD.gn
@@ -60,6 +60,8 @@ "paint_text_blob_builder.h", "paint_typeface.cc", "paint_typeface.h", + "paint_typeface_transfer_cache_entry.cc", + "paint_typeface_transfer_cache_entry.h", "raw_memory_transfer_cache_entry.cc", "raw_memory_transfer_cache_entry.h", "record_paint_canvas.cc",
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc index 06bf08fe..2db5b54 100644 --- a/cc/paint/paint_op_reader.cc +++ b/cc/paint/paint_op_reader.cc
@@ -10,6 +10,7 @@ #include "cc/paint/paint_flags.h" #include "cc/paint/paint_op_buffer.h" #include "cc/paint/paint_shader.h" +#include "cc/paint/paint_typeface_transfer_cache_entry.h" #include "third_party/skia/include/core/SkFlattenableSerialization.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkRRect.h" @@ -19,8 +20,6 @@ namespace { uint32_t kMaxTypefacesCount = 128; -size_t kMaxFilenameSize = 1024; -size_t kMaxFamilyNameSize = 128; // If we have more than this many colors, abort deserialization. const size_t kMaxShaderColorsSupported = 10000; @@ -276,79 +275,20 @@ } typefaces->reserve(typefaces_count); for (uint32_t i = 0; i < typefaces_count; ++i) { - SkFontID id; - uint8_t type; - PaintTypeface typeface; - ReadSimple(&id); - ReadSimple(&type); - if (!valid_) + // TODO(vmpstr): This is meant to be transferred via a transfer cache, but + // for now just utilize the deserialization that the cache entry provides. + ServicePaintTypefaceTransferCacheEntry entry; + bool success = entry.Deserialize( + nullptr, + base::make_span(reinterpret_cast<uint8_t*>(const_cast<char*>(memory_)), + remaining_bytes_)); + if (!success) { + valid_ = false; return; - switch (static_cast<PaintTypeface::Type>(type)) { - case PaintTypeface::Type::kTestTypeface: - typeface = PaintTypeface::TestTypeface(); - break; - case PaintTypeface::Type::kSkTypeface: - // TODO(vmpstr): This shouldn't ever happen once everything is - // implemented. So this should be a failure (ie |valid_| = false). - break; - case PaintTypeface::Type::kFontConfigInterfaceIdAndTtcIndex: { - int font_config_interface_id = 0; - int ttc_index = 0; - ReadSimple(&font_config_interface_id); - ReadSimple(&ttc_index); - if (!valid_) - return; - typeface = PaintTypeface::FromFontConfigInterfaceIdAndTtcIndex( - font_config_interface_id, ttc_index); - break; - } - case PaintTypeface::Type::kFilenameAndTtcIndex: { - size_t size; - ReadSimple(&size); - if (!valid_ || size > kMaxFilenameSize) { - SetInvalid(); - return; - } - - std::unique_ptr<char[]> buffer(new char[size]); - ReadData(size, buffer.get()); - std::string filename(buffer.get(), size); - - int ttc_index = 0; - ReadSimple(&ttc_index); - if (!valid_) - return; - typeface = PaintTypeface::FromFilenameAndTtcIndex(filename, ttc_index); - break; - } - case PaintTypeface::Type::kFamilyNameAndFontStyle: { - size_t size; - ReadSimple(&size); - if (!valid_ || size > kMaxFamilyNameSize) { - SetInvalid(); - return; - } - - std::unique_ptr<char[]> buffer(new char[size]); - ReadData(size, buffer.get()); - std::string family_name(buffer.get(), size); - - int weight = 0; - int width = 0; - SkFontStyle::Slant slant = SkFontStyle::kUpright_Slant; - ReadSimple(&weight); - ReadSimple(&width); - ReadSimple(&slant); - if (!valid_) - return; - - typeface = PaintTypeface::FromFamilyNameAndFontStyle( - family_name, SkFontStyle(weight, width, slant)); - break; - } } - typeface.SetSkId(id); - typefaces->emplace_back(std::move(typeface)); + typefaces->emplace_back(entry.typeface()); + memory_ += entry.CachedSize(); + remaining_bytes_ -= entry.CachedSize(); } }
diff --git a/cc/paint/paint_op_writer.cc b/cc/paint/paint_op_writer.cc index f5b1c1a..4674969 100644 --- a/cc/paint/paint_op_writer.cc +++ b/cc/paint/paint_op_writer.cc
@@ -6,6 +6,7 @@ #include "cc/paint/paint_flags.h" #include "cc/paint/paint_shader.h" +#include "cc/paint/paint_typeface_transfer_cache_entry.h" #include "third_party/skia/include/core/SkFlattenableSerialization.h" #include "third_party/skia/include/core/SkTextBlob.h" @@ -144,36 +145,26 @@ WriteSimple(static_cast<uint32_t>(typefaces.size())); for (const auto& typeface : typefaces) { DCHECK(typeface); - WriteSimple(typeface.sk_id()); - WriteSimple(static_cast<uint8_t>(typeface.type())); - switch (typeface.type()) { - case PaintTypeface::Type::kTestTypeface: - // Nothing to serialize here. - break; - case PaintTypeface::Type::kSkTypeface: - // Nothing to do here. This should never be the case when everything is - // implemented. This should be a NOTREACHED() eventually. - break; - case PaintTypeface::Type::kFontConfigInterfaceIdAndTtcIndex: - WriteSimple(typeface.font_config_interface_id()); - WriteSimple(typeface.ttc_index()); - break; - case PaintTypeface::Type::kFilenameAndTtcIndex: - WriteSimple(typeface.filename().size()); - WriteData(typeface.filename().size(), typeface.filename().data()); - WriteSimple(typeface.ttc_index()); - break; - case PaintTypeface::Type::kFamilyNameAndFontStyle: - WriteSimple(typeface.family_name().size()); - WriteData(typeface.family_name().size(), typeface.family_name().data()); - WriteSimple(typeface.font_style().weight()); - WriteSimple(typeface.font_style().width()); - WriteSimple(typeface.font_style().slant()); - break; + // TODO(vmpstr): This is meant to be sent via a transfer cache, but for now + // just use the serialization of the client transfer cache entry. + ClientPaintTypefaceTransferCacheEntry entry(typeface); + size_t size = entry.SerializedSize(); + if (size > remaining_bytes_) { + valid_ = false; + return; } + bool success = entry.Serialize( + base::make_span(reinterpret_cast<uint8_t*>(memory_), size)); + if (!success) { + valid_ = false; + return; + } + + memory_ += size; + remaining_bytes_ -= size; + #if DCHECK_IS_ON() - if (typeface) - last_serialized_typeface_ids_.insert(typeface.sk_id()); + last_serialized_typeface_ids_.insert(typeface.sk_id()); #endif } } @@ -195,6 +186,8 @@ void PaintOpWriter::Write(const scoped_refptr<PaintTextBlob>& blob) { Write(blob->typefaces()); + if (!valid_) + return; Write(blob->ToSkTextBlob()); }
diff --git a/cc/paint/paint_typeface.h b/cc/paint/paint_typeface.h index 56bae2b..0e2f370 100644 --- a/cc/paint/paint_typeface.h +++ b/cc/paint/paint_typeface.h
@@ -18,7 +18,9 @@ kSkTypeface, kFontConfigInterfaceIdAndTtcIndex, kFilenameAndTtcIndex, - kFamilyNameAndFontStyle + kFamilyNameAndFontStyle, + // We need to update this if the list is modified. + kLastType = kFamilyNameAndFontStyle }; static PaintTypeface TestTypeface();
diff --git a/cc/paint/paint_typeface_transfer_cache_entry.cc b/cc/paint/paint_typeface_transfer_cache_entry.cc new file mode 100644 index 0000000..b05649c7 --- /dev/null +++ b/cc/paint/paint_typeface_transfer_cache_entry.cc
@@ -0,0 +1,228 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/paint/paint_typeface_transfer_cache_entry.h" + +namespace cc { +namespace { + +size_t kMaxFilenameSize = 1024; +size_t kMaxFamilyNameSize = 128; + +class DataWriter { + public: + explicit DataWriter(base::span<uint8_t> data) : data_(data) {} + + template <typename T> + void WriteSimple(const T& val) { + DCHECK_LE(sizeof(T), data_.size()); + *reinterpret_cast<T*>(data_.data()) = val; + data_ = data_.subspan(sizeof(T)); + } + void WriteData(size_t bytes, const void* input) { + DCHECK_LE(bytes, data_.size()); + memcpy(data_.data(), input, bytes); + data_ = data_.subspan(bytes); + } + + private: + base::span<uint8_t> data_; +}; + +class SizeCounter { + public: + SizeCounter() = default; + + template <typename T> + void WriteSimple(const T& val) { + size_ += sizeof(T); + } + void WriteData(size_t bytes, const void* input) { size_ += bytes; } + size_t size() const { return size_; } + + private: + size_t size_ = 0; +}; + +} // namespace + +ClientPaintTypefaceTransferCacheEntry::ClientPaintTypefaceTransferCacheEntry( + const PaintTypeface& typeface) + : typeface_(typeface) { + SizeCounter counter; + SerializeInternal(&counter); + size_ = counter.size(); +} + +ClientPaintTypefaceTransferCacheEntry:: + ~ClientPaintTypefaceTransferCacheEntry() = default; + +TransferCacheEntryType ClientPaintTypefaceTransferCacheEntry::Type() const { + return TransferCacheEntryType::kPaintTypeface; +} + +size_t ClientPaintTypefaceTransferCacheEntry::SerializedSize() const { + return size_; +} + +bool ClientPaintTypefaceTransferCacheEntry::Serialize( + base::span<uint8_t> data) const { + DataWriter writer(data); + return SerializeInternal(&writer); +} + +template <typename Writer> +bool ClientPaintTypefaceTransferCacheEntry::SerializeInternal( + Writer* writer) const { + writer->WriteSimple(typeface_.sk_id()); + writer->WriteSimple(static_cast<uint8_t>(typeface_.type())); + switch (typeface_.type()) { + case PaintTypeface::Type::kTestTypeface: + // Nothing to serialize here. + break; + case PaintTypeface::Type::kSkTypeface: + // Nothing to do here. This should never be the case when everything is + // implemented. This should be a NOTREACHED() eventually. + break; + case PaintTypeface::Type::kFontConfigInterfaceIdAndTtcIndex: + writer->WriteSimple(typeface_.font_config_interface_id()); + writer->WriteSimple(typeface_.ttc_index()); + break; + case PaintTypeface::Type::kFilenameAndTtcIndex: + writer->WriteSimple(typeface_.filename().size()); + writer->WriteData(typeface_.filename().size(), + typeface_.filename().data()); + writer->WriteSimple(typeface_.ttc_index()); + break; + case PaintTypeface::Type::kFamilyNameAndFontStyle: + writer->WriteSimple(typeface_.family_name().size()); + writer->WriteData(typeface_.family_name().size(), + typeface_.family_name().data()); + writer->WriteSimple(typeface_.font_style().weight()); + writer->WriteSimple(typeface_.font_style().width()); + writer->WriteSimple(typeface_.font_style().slant()); + break; + } + return true; +} + +ServicePaintTypefaceTransferCacheEntry:: + ServicePaintTypefaceTransferCacheEntry() = default; +ServicePaintTypefaceTransferCacheEntry:: + ~ServicePaintTypefaceTransferCacheEntry() = default; +TransferCacheEntryType ServicePaintTypefaceTransferCacheEntry::Type() const { + return TransferCacheEntryType::kPaintTypeface; +} + +size_t ServicePaintTypefaceTransferCacheEntry::CachedSize() const { + return size_; +} + +bool ServicePaintTypefaceTransferCacheEntry::Deserialize( + GrContext* context, + base::span<uint8_t> data) { + data_ = data; + size_t initial_size = data_.size(); + + SkFontID id; + uint8_t type; + ReadSimple(&id); + ReadSimple(&type); + if (!valid_ || type > static_cast<uint8_t>(PaintTypeface::Type::kLastType)) { + valid_ = false; + return false; + } + switch (static_cast<PaintTypeface::Type>(type)) { + case PaintTypeface::Type::kTestTypeface: + typeface_ = PaintTypeface::TestTypeface(); + break; + case PaintTypeface::Type::kSkTypeface: + // TODO(vmpstr): This shouldn't ever happen once everything is + // implemented. So this should be a failure (ie |valid_| = false). + break; + case PaintTypeface::Type::kFontConfigInterfaceIdAndTtcIndex: { + int font_config_interface_id = 0; + int ttc_index = 0; + ReadSimple(&font_config_interface_id); + ReadSimple(&ttc_index); + if (!valid_) + return false; + typeface_ = PaintTypeface::FromFontConfigInterfaceIdAndTtcIndex( + font_config_interface_id, ttc_index); + break; + } + case PaintTypeface::Type::kFilenameAndTtcIndex: { + size_t size; + ReadSimple(&size); + if (!valid_ || size > kMaxFilenameSize) { + valid_ = false; + return false; + } + + std::unique_ptr<char[]> buffer(new char[size]); + ReadData(size, buffer.get()); + std::string filename(buffer.get(), size); + + int ttc_index = 0; + ReadSimple(&ttc_index); + if (!valid_) + return false; + typeface_ = PaintTypeface::FromFilenameAndTtcIndex(filename, ttc_index); + break; + } + case PaintTypeface::Type::kFamilyNameAndFontStyle: { + size_t size; + ReadSimple(&size); + if (!valid_ || size > kMaxFamilyNameSize) { + valid_ = false; + return false; + } + + std::unique_ptr<char[]> buffer(new char[size]); + ReadData(size, buffer.get()); + std::string family_name(buffer.get(), size); + + int weight = 0; + int width = 0; + SkFontStyle::Slant slant = SkFontStyle::kUpright_Slant; + ReadSimple(&weight); + ReadSimple(&width); + ReadSimple(&slant); + if (!valid_) + return false; + + typeface_ = PaintTypeface::FromFamilyNameAndFontStyle( + family_name, SkFontStyle(weight, width, slant)); + break; + } + } + typeface_.SetSkId(id); + + // Set the size to however much data we read. + size_ = initial_size - data_.size(); + data_ = base::span<uint8_t>(nullptr); + return valid_; +} + +template <typename T> +void ServicePaintTypefaceTransferCacheEntry::ReadSimple(T* val) { + if (data_.size() < sizeof(T)) + valid_ = false; + if (!valid_) + return; + *val = *reinterpret_cast<T*>(data_.data()); + data_ = data_.subspan(sizeof(T)); +} + +void ServicePaintTypefaceTransferCacheEntry::ReadData(size_t bytes, + void* data) { + if (data_.size() < bytes) + valid_ = false; + if (!valid_) + return; + memcpy(data, data_.data(), bytes); + data_ = data_.subspan(bytes); +} + +} // namespace cc
diff --git a/cc/paint/paint_typeface_transfer_cache_entry.h b/cc/paint/paint_typeface_transfer_cache_entry.h new file mode 100644 index 0000000..d4249b2 --- /dev/null +++ b/cc/paint/paint_typeface_transfer_cache_entry.h
@@ -0,0 +1,57 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_PAINT_PAINT_TYPEFACE_TRANSFER_CACHE_ENTRY_H_ +#define CC_PAINT_PAINT_TYPEFACE_TRANSFER_CACHE_ENTRY_H_ + +#include "base/containers/span.h" +#include "cc/paint/paint_export.h" +#include "cc/paint/paint_typeface.h" +#include "cc/paint/transfer_cache_entry.h" + +namespace cc { + +class CC_PAINT_EXPORT ClientPaintTypefaceTransferCacheEntry + : public ClientTransferCacheEntry { + public: + explicit ClientPaintTypefaceTransferCacheEntry(const PaintTypeface& typeface); + ~ClientPaintTypefaceTransferCacheEntry() final; + TransferCacheEntryType Type() const final; + size_t SerializedSize() const final; + bool Serialize(base::span<uint8_t> data) const final; + + private: + template <typename Writer> + bool SerializeInternal(Writer* writer) const; + + const PaintTypeface typeface_; + size_t size_ = 0u; +}; + +class CC_PAINT_EXPORT ServicePaintTypefaceTransferCacheEntry + : public ServiceTransferCacheEntry { + public: + ServicePaintTypefaceTransferCacheEntry(); + ~ServicePaintTypefaceTransferCacheEntry() final; + TransferCacheEntryType Type() const final; + size_t CachedSize() const final; + bool Deserialize(GrContext* context, base::span<uint8_t> data) final; + + const PaintTypeface& typeface() const { return typeface_; } + + private: + template <typename T> + void ReadSimple(T* val); + + void ReadData(size_t bytes, void* data); + + PaintTypeface typeface_; + size_t size_ = 0; + bool valid_ = true; + base::span<uint8_t> data_; +}; + +} // namespace cc + +#endif // CC_PAINT_PAINT_TYPEFACE_TRANSFER_CACHE_ENTRY_H_
diff --git a/cc/paint/transfer_cache_entry.cc b/cc/paint/transfer_cache_entry.cc index ff4f0a5..fe407dd7 100644 --- a/cc/paint/transfer_cache_entry.cc +++ b/cc/paint/transfer_cache_entry.cc
@@ -8,6 +8,7 @@ #include "base/logging.h" #include "cc/paint/image_transfer_cache_entry.h" +#include "cc/paint/paint_typeface_transfer_cache_entry.h" #include "cc/paint/raw_memory_transfer_cache_entry.h" namespace cc { @@ -19,6 +20,8 @@ return std::make_unique<ServiceRawMemoryTransferCacheEntry>(); case TransferCacheEntryType::kImage: return std::make_unique<ServiceImageTransferCacheEntry>(); + case TransferCacheEntryType::kPaintTypeface: + return std::make_unique<ServicePaintTypefaceTransferCacheEntry>(); } NOTREACHED();
diff --git a/cc/paint/transfer_cache_entry.h b/cc/paint/transfer_cache_entry.h index 0d14361..ed09802 100644 --- a/cc/paint/transfer_cache_entry.h +++ b/cc/paint/transfer_cache_entry.h
@@ -23,8 +23,9 @@ enum class TransferCacheEntryType { kRawMemory, kImage, + kPaintTypeface, // Add new entries above this line, make sure to update kLast. - kLast = kImage, + kLast = kPaintTypeface, }; // An interface used on the client to serialize a transfer cache entry
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 8a3a457..a5925c2 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2922,6 +2922,11 @@ flag_descriptions::kEnableAutofillCreditCardUploadNewUiName, flag_descriptions::kEnableAutofillCreditCardUploadNewUiDescription, kOsDesktop, FEATURE_VALUE_TYPE(autofill::kAutofillUpstreamShowNewUi)}, + {"enable-autofill-credit-card-upload-send-pan-first-six", + flag_descriptions::kEnableAutofillCreditCardUploadSendPanFirstSixName, + flag_descriptions:: + kEnableAutofillCreditCardUploadSendPanFirstSixDescription, + kOsAll, FEATURE_VALUE_TYPE(autofill::kAutofillUpstreamSendPanFirstSix)}, {"enable-autofill-credit-card-ablation-experiment", flag_descriptions::kEnableAutofillCreditCardAblationExperimentDisplayName, flag_descriptions::kEnableAutofillCreditCardAblationExperimentDescription,
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc index 2923b0a..464d88b 100644 --- a/chrome/browser/autocomplete/search_provider_unittest.cc +++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -3290,18 +3290,6 @@ GURL("https://www.google.com/complete/search"), &google_template_url, metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client)); - // Non-HTTP page URL on different domain, yet with feature flag to allow - // this turned off. - { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - omnibox::kSearchProviderContextAllowHttpsUrls); - EXPECT_FALSE(SearchProvider::CanSendURL( - GURL("https://www.notgoogle.com/search"), - GURL("https://www.google.com/complete/search"), &google_template_url, - metrics::OmniboxEventProto::OTHER, SearchTermsData(), &client)); - } - // Non-HTTPS provider. EXPECT_FALSE(SearchProvider::CanSendURL( GURL("http://www.google.com/search"),
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc index 6f06d96..e5fafce 100644 --- a/chrome/browser/browser_process_platform_part_chromeos.cc +++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -193,12 +193,17 @@ system_clock_.reset(); } -void BrowserProcessPlatformPart::SetCompatibleCrosComponentPath( +void BrowserProcessPlatformPart::RegisterCompatibleCrosComponentPath( const std::string& name, const base::FilePath& path) { compatible_cros_components_[name] = path; } +void BrowserProcessPlatformPart::UnregisterCompatibleCrosComponentPath( + const std::string& name) { + compatible_cros_components_.erase(name); +} + bool BrowserProcessPlatformPart::IsCompatibleCrosComponent( const std::string& name) const { return compatible_cros_components_.count(name) > 0;
diff --git a/chrome/browser/browser_process_platform_part_chromeos.h b/chrome/browser/browser_process_platform_part_chromeos.h index 86e57d54f..a118650 100644 --- a/chrome/browser/browser_process_platform_part_chromeos.h +++ b/chrome/browser/browser_process_platform_part_chromeos.h
@@ -105,8 +105,11 @@ void DestroySystemClock(); // Saves the name and install path of a compatible component. - void SetCompatibleCrosComponentPath(const std::string& name, - const base::FilePath& path); + void RegisterCompatibleCrosComponentPath(const std::string& name, + const base::FilePath& path); + + // Removes the name and install path entry of a component. + void UnregisterCompatibleCrosComponentPath(const std::string& name); // Checks if the current installed component is compatible given a component // |name|. If compatible, sets |path| to be its installed path.
diff --git a/chrome/browser/chromeos/dbus/chrome_component_updater_service_provider_delegate.cc b/chrome/browser/chromeos/dbus/chrome_component_updater_service_provider_delegate.cc index 12bdf5e..ee6c8923 100644 --- a/chrome/browser/chromeos/dbus/chrome_component_updater_service_provider_delegate.cc +++ b/chrome/browser/chromeos/dbus/chrome_component_updater_service_provider_delegate.cc
@@ -16,8 +16,14 @@ void ChromeComponentUpdaterServiceProviderDelegate::LoadComponent( const std::string& name, - const base::Callback<void(const std::string&)>& load_callback) { - component_updater::CrOSComponent::LoadComponent(name, load_callback); + base::OnceCallback<void(const std::string&)> load_callback) { + component_updater::CrOSComponent::LoadComponent(name, + std::move(load_callback)); +} + +bool ChromeComponentUpdaterServiceProviderDelegate::UnloadComponent( + const std::string& name) { + return component_updater::CrOSComponent::UnloadComponent(name); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/chrome_component_updater_service_provider_delegate.h b/chrome/browser/chromeos/dbus/chrome_component_updater_service_provider_delegate.h index 9a50600..f8a146a 100644 --- a/chrome/browser/chromeos/dbus/chrome_component_updater_service_provider_delegate.h +++ b/chrome/browser/chromeos/dbus/chrome_component_updater_service_provider_delegate.h
@@ -20,7 +20,8 @@ // ComponentUpdaterServiceProvider::Delegate: void LoadComponent( const std::string& name, - const base::Callback<void(const std::string&)>& load_callback) override; + base::OnceCallback<void(const std::string&)> load_callback) override; + bool UnloadComponent(const std::string& name) override; private: DISALLOW_COPY_AND_ASSIGN(ChromeComponentUpdaterServiceProviderDelegate);
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc index a3e56a3e..83d3662a 100644 --- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -429,10 +429,6 @@ WizardController* controller = WizardController::default_controller(); if (controller && controller->current_screen()) controller->current_screen()->Hide(); - - if (LoginDisplayHost::default_host()) - LoginDisplayHost::default_host()->Finalize(base::OnceClosure()); - base::RunLoop().RunUntilIdle(); } void ExpectSuccessfulLogin(const UserContext& user_context) {
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc index 830ac748..8d67451 100644 --- a/chrome/browser/chromeos/login/login_browsertest.cc +++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -88,12 +88,6 @@ command_line->AppendSwitch(switches::kForceLoginManagerInTests); } - void TearDownOnMainThread() override { - // Close the login manager, which otherwise holds a KeepAlive that is not - // cleared in time by the end of the test. - LoginDisplayHost::default_host()->Finalize(base::OnceClosure()); - } - void SetUpOnMainThread() override { LoginDisplayHostWebUI::DisableRestrictiveProxyCheckForTest(); } @@ -251,9 +245,6 @@ EXPECT_TRUE(ui_test_utils::SendMouseMoveSync(gfx::Point())); EXPECT_TRUE(ash::Shell::Get()->cursor_manager()->IsCursorVisible()); - base::ThreadTaskRunnerHandle::Get()->DeleteSoon( - FROM_HERE, LoginDisplayHost::default_host()); - TestSystemTrayIsVisible(false); }
diff --git a/chrome/browser/chromeos/login/login_manager_test.cc b/chrome/browser/chromeos/login/login_manager_test.cc index 330e36b8..cfb289bb 100644 --- a/chrome/browser/chromeos/login/login_manager_test.cc +++ b/chrome/browser/chromeos/login/login_manager_test.cc
@@ -98,9 +98,7 @@ void LoginManagerTest::TearDownOnMainThread() { MixinBasedBrowserTest::TearDownOnMainThread(); - if (LoginDisplayHost::default_host()) - LoginDisplayHost::default_host()->Finalize(base::OnceClosure()); - base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); }
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.cc b/chrome/browser/chromeos/login/test/oobe_base_test.cc index e15b1253..933c107 100644 --- a/chrome/browser/chromeos/login/test/oobe_base_test.cc +++ b/chrome/browser/chromeos/login/test/oobe_base_test.cc
@@ -130,12 +130,6 @@ } void OobeBaseTest::TearDownOnMainThread() { - // If the login display is still showing, exit gracefully. - if (LoginDisplayHost::default_host()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&chrome::AttemptExit)); - content::RunMessageLoop(); - } EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); ExtensionApiTest::TearDownOnMainThread();
diff --git a/chrome/browser/chromeos/login/test/wizard_in_process_browser_test.cc b/chrome/browser/chromeos/login/test/wizard_in_process_browser_test.cc index 5c034b5..b5b7daa9 100644 --- a/chrome/browser/chromeos/login/test/wizard_in_process_browser_test.cc +++ b/chrome/browser/chromeos/login/test/wizard_in_process_browser_test.cc
@@ -46,9 +46,16 @@ void WizardInProcessBrowserTest::TearDownOnMainThread() { ASSERT_TRUE(base::MessageLoopForUI::IsCurrent()); - // LoginDisplayHost owns controllers and all windows. - base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, host_); - base::RunLoop().RunUntilIdle(); + if (!host_) + return; + + // LoginDisplayHost owns controllers and all windows. It needs to be destroyed + // here because the derived tests have clean-up code assuming LoginDisplayHost + // is gone. + base::RunLoop run_loop; + host_->Finalize(run_loop.QuitClosure()); + run_loop.Run(); + host_ = nullptr; } } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc index 5568418..0399bf52 100644 --- a/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc +++ b/chrome/browser/chromeos/login/ui/captive_portal_window_browsertest.cc
@@ -77,26 +77,19 @@ } void SetUpOnMainThread() override { - host_ = LoginDisplayHost::default_host(); content::WebContents* web_contents = - host_->GetWebUILoginView()->GetWebContents(); + LoginDisplayHost::default_host()->GetWebUILoginView()->GetWebContents(); captive_portal_window_proxy_.reset( new CaptivePortalWindowProxy(&delegate_, web_contents)); } void TearDownOnMainThread() override { captive_portal_window_proxy_.reset(); - - ASSERT_TRUE(base::MessageLoopForUI::IsCurrent()); - base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, host_); - base::RunLoop().RunUntilIdle(); } private: std::unique_ptr<CaptivePortalWindowProxy> captive_portal_window_proxy_; CaptivePortalWindowProxyStubDelegate delegate_; - - LoginDisplayHost* host_; }; IN_PROC_BROWSER_TEST_F(CaptivePortalWindowTest, Show) {
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc index 95a00c8..af6ac50 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -18,7 +18,6 @@ #include "base/location.h" #include "base/logging.h" #include "base/macros.h" -#include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" @@ -435,11 +434,8 @@ ui::InputDeviceManager::GetInstance()->AddObserver(this); - // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING - // because/ APP_TERMINATING will never be fired as long as this keeps - // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no - // browser instance that will block the shutdown. - registrar_.Add(this, chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, + // Close the login screen on NOTIFICATION_APP_TERMINATING. + registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, content::NotificationService::AllSources()); // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but @@ -600,13 +596,13 @@ switch (finalize_animation_type_) { case ANIMATION_NONE: - ShutdownDisplayHost(false); + ShutdownDisplayHost(); break; case ANIMATION_WORKSPACE: if (ash::Shell::HasInstance()) ScheduleWorkspaceAnimation(); - ShutdownDisplayHost(false); + ShutdownDisplayHost(); break; case ANIMATION_FADE_OUT: // Display host is deleted once animation is completed @@ -901,13 +897,13 @@ content::NotificationService::AllSources()); registrar_.Remove(this, chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, content::NotificationService::AllSources()); - } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) { - ShutdownDisplayHost(true); + } else if (type == chrome::NOTIFICATION_APP_TERMINATING) { + ShutdownDisplayHost(); } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) { // Browsers created before session start (windows opened by extensions, for // example) are ignored. OnBrowserCreated(); - registrar_.Remove(this, chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, + registrar_.Remove(this, chrome::NOTIFICATION_APP_TERMINATING, content::NotificationService::AllSources()); registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_OPENED, content::NotificationService::AllSources()); @@ -1034,21 +1030,19 @@ //////////////////////////////////////////////////////////////////////////////// // LoginDisplayHostWebUI, MultiUserWindowManager::Observer: void LoginDisplayHostWebUI::OnUserSwitchAnimationFinished() { - ShutdownDisplayHost(false); + ShutdownDisplayHost(); } //////////////////////////////////////////////////////////////////////////////// // LoginDisplayHostWebUI, private -void LoginDisplayHostWebUI::ShutdownDisplayHost(bool post_quit_task) { +void LoginDisplayHostWebUI::ShutdownDisplayHost() { if (shutting_down_) return; shutting_down_ = true; registrar_.RemoveAll(); base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); - if (post_quit_task) - base::RunLoop::QuitCurrentWhenIdleDeprecated(); } void LoginDisplayHostWebUI::ScheduleWorkspaceAnimation() { @@ -1069,14 +1063,14 @@ // is created before session start, which triggers the close of the login // window. In this case, we should shut down the display host directly. if (!login_window_) { - ShutdownDisplayHost(false); + ShutdownDisplayHost(); return; } ui::Layer* layer = login_window_->GetLayer(); ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); animation.AddObserver(new AnimationObserver( base::Bind(&LoginDisplayHostWebUI::ShutdownDisplayHost, - animation_weak_ptr_factory_.GetWeakPtr(), false))); + animation_weak_ptr_factory_.GetWeakPtr()))); animation.SetTransitionDuration( base::TimeDelta::FromMilliseconds(animation_speed_ms)); layer->SetOpacity(0);
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.h b/chrome/browser/chromeos/login/ui/login_display_host_webui.h index 01da177..e45df00 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_webui.h +++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.h
@@ -153,8 +153,7 @@ }; // Marks display host for deletion. - // If |post_quit_task| is true also posts Quit task to the MessageLoop. - void ShutdownDisplayHost(bool post_quit_task); + void ShutdownDisplayHost(); // Schedules workspace transition animation. void ScheduleWorkspaceAnimation();
diff --git a/chrome/browser/component_updater/cros_component_installer.cc b/chrome/browser/component_updater/cros_component_installer.cc index 9304f9cf..af82d18 100644 --- a/chrome/browser/component_updater/cros_component_installer.cc +++ b/chrome/browser/component_updater/cros_component_installer.cc
@@ -52,6 +52,18 @@ namespace component_updater { +namespace { +// TODO(xiaochu): add metrics for component usage (crbug.com/793052). +static void LogCustomUninstall(base::Optional<bool> result) {} +static std::string GenerateId(const std::string& sha2hashstr) { + // kIdSize is the count of a pair of hex in the sha2hash array. + // In string representation of sha2hash, size is doubled since each hex is + // represented by a single char. + return crx_file::id_util::GenerateIdFromHex( + sha2hashstr.substr(0, crx_file::id_util::kIdSize * 2)); +} +} // namespace + using ConfigMap = std::map<std::string, std::map<std::string, std::string>>; ComponentConfig::ComponentConfig(const std::string& name, @@ -102,6 +114,11 @@ } void CrOSComponentInstallerPolicy::OnCustomUninstall() { + g_browser_process->platform_part()->UnregisterCompatibleCrosComponentPath( + name); + + chromeos::DBusThreadManager::Get()->GetImageLoaderClient()->UnmountComponent( + name, base::BindOnce(&LogCustomUninstall)); } void CrOSComponentInstallerPolicy::ComponentReady( @@ -111,7 +128,7 @@ std::string min_env_version; if (manifest && manifest->GetString("min_env_version", &min_env_version)) { if (IsCompatible(env_version, min_env_version)) { - g_browser_process->platform_part()->SetCompatibleCrosComponentPath( + g_browser_process->platform_part()->RegisterCompatibleCrosComponentPath( GetName(), path); } } @@ -173,21 +190,18 @@ const std::string& name, base::OnceCallback<void(const std::string&)> load_callback) { DCHECK(g_browser_process->platform_part()->IsCompatibleCrosComponent(name)); - chromeos::ImageLoaderClient* loader = - chromeos::DBusThreadManager::Get()->GetImageLoaderClient(); - if (loader) { - base::FilePath path; - path = g_browser_process->platform_part()->GetCompatibleCrosComponentPath( - name); - // path is empty if no compatible component is available to load. - if (!path.empty()) { - loader->LoadComponentAtPath( - name, path, base::BindOnce(&LoadResult, std::move(load_callback))); - return; - } + const base::FilePath path = + g_browser_process->platform_part()->GetCompatibleCrosComponentPath(name); + // path is empty if no compatible component is available to load. + if (!path.empty()) { + chromeos::DBusThreadManager::Get() + ->GetImageLoaderClient() + ->LoadComponentAtPath( + name, path, base::BindOnce(&LoadResult, std::move(load_callback))); + } else { + base::PostTask(FROM_HERE, + base::BindOnce(std::move(load_callback), std::string())); } - base::PostTask(FROM_HERE, - base::BindOnce(std::move(load_callback), std::string())); } // It calls LoadComponentInternal to load the installed component. @@ -223,20 +237,19 @@ base::OnceCallback<void(const std::string&)> load_callback) { const ConfigMap components = CONFIG_MAP_CONTENT; const auto it = components.find(name); - if (name.empty() || it == components.end()) { + if (it == components.end()) { base::PostTask(FROM_HERE, base::BindOnce(std::move(load_callback), std::string())); return; } ComponentConfig config(it->first, it->second.find("env_version")->second, it->second.find("sha2hashstr")->second); - RegisterComponent(cus, config, - base::BindOnce(RegisterResult, cus, - crx_file::id_util::GenerateIdFromHex( - it->second.find("sha2hashstr")->second) - .substr(0, 32), - base::BindOnce(InstallResult, name, - std::move(load_callback)))); + RegisterComponent( + cus, config, + base::BindOnce( + RegisterResult, cus, + GenerateId(it->second.find("sha2hashstr")->second), + base::BindOnce(InstallResult, name, std::move(load_callback)))); } void CrOSComponent::LoadComponent( @@ -252,6 +265,19 @@ } } +bool CrOSComponent::UnloadComponent(const std::string& name) { + const ConfigMap components = CONFIG_MAP_CONTENT; + const auto it = components.find(name); + if (it == components.end()) { + // Component |name| does not exist. + return false; + } + component_updater::ComponentUpdateService* updater = + g_browser_process->component_updater(); + const std::string id = GenerateId(it->second.find("sha2hashstr")->second); + return updater->UnregisterComponent(id); +} + std::vector<ComponentConfig> CrOSComponent::GetInstalledComponents() { std::vector<ComponentConfig> configs; base::FilePath root;
diff --git a/chrome/browser/component_updater/cros_component_installer.h b/chrome/browser/component_updater/cros_component_installer.h index 9afcdd93..14ddfcd 100644 --- a/chrome/browser/component_updater/cros_component_installer.h +++ b/chrome/browser/component_updater/cros_component_installer.h
@@ -83,10 +83,16 @@ // This class contains functions used to register and install a component. class CrOSComponent { public: + // Installs a component and keeps it up-to-date. static void LoadComponent( const std::string& name, base::OnceCallback<void(const std::string&)> load_callback); + // Stops updating and removes a component. + // Returns true if the component was successfully unloaded + // or false if it couldn't be unloaded or already wasn't loaded. + static bool UnloadComponent(const std::string& name); + // Returns all installed components. static std::vector<ComponentConfig> GetInstalledComponents(); @@ -94,7 +100,6 @@ static void RegisterComponents(const std::vector<ComponentConfig>& configs); private: - CrOSComponent() {} static void RegisterResult(ComponentUpdateService* cus, const std::string& id, update_client::Callback install_callback);
diff --git a/chrome/browser/component_updater/cros_component_installer_unittest.cc b/chrome/browser/component_updater/cros_component_installer_unittest.cc index 16992ac..7f8f8d5 100644 --- a/chrome/browser/component_updater/cros_component_installer_unittest.cc +++ b/chrome/browser/component_updater/cros_component_installer_unittest.cc
@@ -64,9 +64,11 @@ std::string()); const base::FilePath kPath("/component/path/v0"); - bppp.SetCompatibleCrosComponentPath(kComponent, kPath); + bppp.RegisterCompatibleCrosComponentPath(kComponent, kPath); EXPECT_TRUE(bppp.IsCompatibleCrosComponent(kComponent)); - EXPECT_EQ(bppp.GetCompatibleCrosComponentPath("a"), kPath); + EXPECT_EQ(bppp.GetCompatibleCrosComponentPath(kComponent), kPath); + bppp.UnregisterCompatibleCrosComponentPath(kComponent); + EXPECT_FALSE(bppp.IsCompatibleCrosComponent(kComponent)); } TEST_F(CrOSComponentInstallerTest, ComponentReadyCorrectManifest) {
diff --git a/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h b/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h index 9b63355..7dc82e0f 100644 --- a/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h +++ b/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h
@@ -211,11 +211,16 @@ *error = kCheckedError; return false; } - // If the item was not checked and it is updated to be checked, set it to be - // checked. If the radio item was unchecked, nothing should happen. The - // radio item should remain checked because there should always be one item - // checked in the radio list. - if (checked && !item->checked()) { + + const bool should_toggle_checked = + // If radio item was unchecked nothing should happen. The radio item + // should remain checked because there should always be one item checked + // in the radio list. + (item->type() == MenuItem::RADIO && checked) || + // Checkboxes are always updated. + item->type() == MenuItem::CHECKBOX; + + if (should_toggle_checked) { if (!item->SetChecked(checked)) { *error = kCheckedError; return false;
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc index a3661f06..79e0b90 100644 --- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc +++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
@@ -13,7 +13,6 @@ #include "base/strings/stringprintf.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/test/https_forwarder.h" -#include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/policy/affiliation_test_helper.h" #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #include "chrome/browser/extensions/extension_apitest.h" @@ -37,7 +36,6 @@ #include "crypto/scoped_test_system_nss_key_slot.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/test_extension_registry_observer.h" -#include "extensions/browser/test_extension_registry_observer.h" #include "extensions/test/result_catcher.h" #include "google_apis/gaia/fake_gaia.h" #include "google_apis/gaia/gaia_constants.h" @@ -325,10 +323,6 @@ void TearDownOnMainThread() override { ExtensionApiTest::TearDownOnMainThread(); - if (chromeos::LoginDisplayHost::default_host()) - chromeos::LoginDisplayHost::default_host()->Finalize(base::OnceClosure()); - base::RunLoop().RunUntilIdle(); - if (GetParam().system_token_ == SYSTEM_TOKEN_EXISTS) { base::RunLoop loop; content::BrowserThread::PostTask( @@ -400,7 +394,6 @@ } private: - void SetUpTestSystemSlotOnIO(const base::Closure& done_callback) { test_system_slot_.reset(new crypto::ScopedTestSystemNSSKeySlot()); ASSERT_TRUE(test_system_slot_->ConstructedSuccessfully());
diff --git a/chrome/browser/extensions/extension_context_menu_browsertest.cc b/chrome/browser/extensions/extension_context_menu_browsertest.cc index 30e3ef8..7766a6f6 100644 --- a/chrome/browser/extensions/extension_context_menu_browsertest.cc +++ b/chrome/browser/extensions/extension_context_menu_browsertest.cc
@@ -852,3 +852,41 @@ browser()->profile()->DestroyOffTheRecordProfile(); ASSERT_EQ(1u, GetItems().size()); } + +// Tests updating checkboxes' checked state to true and false. +IN_PROC_BROWSER_TEST_F(ExtensionContextMenuBrowserTest, UpdateCheckboxes) { + ExtensionTestMessageListener listener_context_menu_created("Menu created", + false); + + const extensions::Extension* extension = + LoadContextMenuExtension("checkboxes"); + ASSERT_TRUE(extension); + + ASSERT_TRUE(listener_context_menu_created.WaitUntilSatisfied()); + + GURL page_url("http://www.google.com"); + + // Create and build our test context menu. + std::unique_ptr<TestRenderViewContextMenu> menu( + TestRenderViewContextMenu::Create(GetWebContents(), page_url, GURL(), + GURL())); + + VerifyRadioItemSelectionState(menu.get(), extension->id(), "checkbox1", + false); + VerifyRadioItemSelectionState(menu.get(), extension->id(), "checkbox2", true); + + ExtensionTestMessageListener listener_item1_clicked("onclick normal item", + false); + ExtensionTestMessageListener listener_unchecked_checkbox2( + "checkbox2 unchecked", false); + // Clicking the regular item calls chrome.contextMenus.update to uncheck the + // second checkbox item. + ExecuteCommand(menu.get(), extension->id(), "item1"); + ASSERT_TRUE(listener_item1_clicked.WaitUntilSatisfied()); + ASSERT_TRUE(listener_unchecked_checkbox2.WaitUntilSatisfied()); + + VerifyRadioItemSelectionState(menu.get(), extension->id(), "checkbox1", + false); + VerifyRadioItemSelectionState(menu.get(), extension->id(), "checkbox2", + false); +}
diff --git a/chrome/browser/extensions/launch_util.cc b/chrome/browser/extensions/launch_util.cc index 23986968..024624e 100644 --- a/chrome/browser/extensions/launch_util.cc +++ b/chrome/browser/extensions/launch_util.cc
@@ -98,10 +98,7 @@ LaunchContainer manifest_launch_container = AppLaunchInfo::GetLaunchContainer(extension); - const LaunchContainer kInvalidLaunchContainer = - static_cast<LaunchContainer>(-1); - - LaunchContainer result = kInvalidLaunchContainer; + base::Optional<LaunchContainer> result; if (manifest_launch_container == LAUNCH_CONTAINER_PANEL) { // Apps with app.launch.container = 'panel' should always respect the @@ -137,12 +134,12 @@ } // All paths should set |result|. - if (result == kInvalidLaunchContainer) { + if (!result) { DLOG(FATAL) << "Failed to set a launch container."; result = LAUNCH_CONTAINER_TAB; } - return result; + return *result; } bool HasPreferredLaunchContainer(const ExtensionPrefs* prefs,
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index a7fc91c..8a750c7 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -299,6 +299,14 @@ "If enabled, displays a new save card bubble/infobar design when offering " "to upload credit cards to Google Payments."; +const char kEnableAutofillCreditCardUploadSendPanFirstSixName[] = + "Send first six digits of PAN when deciding whether to offer Autofill " + "credit card upload"; +const char kEnableAutofillCreditCardUploadSendPanFirstSixDescription[] = + "If enabled, when deciding whether to offer credit card upload to Google " + "Payments, sends the first six digits of the card number to avoid cases " + "where card upload is likely to fail."; + const char kEnableAutofillSendBillingCustomerNumberName[] = "Enable autofill sending billing customer number when calling Google " "Payments";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 68ef234e..524022a 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -210,6 +210,9 @@ extern const char kEnableAutofillCreditCardUploadNewUiName[]; extern const char kEnableAutofillCreditCardUploadNewUiDescription[]; +extern const char kEnableAutofillCreditCardUploadSendPanFirstSixName[]; +extern const char kEnableAutofillCreditCardUploadSendPanFirstSixDescription[]; + extern const char kEnableAutofillSendBillingCustomerNumberName[]; extern const char kEnableAutofillSendBillingCustomerNumberDescription[];
diff --git a/chrome/browser/resources/md_extensions/item.html b/chrome/browser/resources/md_extensions/item.html index 27f2390..c9c013e5 100644 --- a/chrome/browser/resources/md_extensions/item.html +++ b/chrome/browser/resources/md_extensions/item.html
@@ -208,7 +208,7 @@ if="[[computeSourceIndicatorIcon_(data.*)]]"> <div id="source-indicator"> <div class="source-icon-wrapper" role="img" - aria-labelledby="source-indicator-text"> + aria-label$="[[computeSourceIndicatorText_(data.*)]]"> <iron-icon icon="[[computeSourceIndicatorIcon_(data.*)]]"> </iron-icon> </div>
diff --git a/chrome/browser/service_process/service_process_control_browsertest.cc b/chrome/browser/service_process/service_process_control_browsertest.cc index 00436d9..393b401f 100644 --- a/chrome/browser/service_process/service_process_control_browsertest.cc +++ b/chrome/browser/service_process/service_process_control_browsertest.cc
@@ -220,8 +220,8 @@ // This tests the case when a service process is launched when the browser // starts but we try to launch it again while setting up Cloud Print. -// Flaky on Mac. Flaky on Windows. http://crbug.com/517420 -#if defined(OS_MACOSX) || defined(OS_WIN) +// Flaky on Mac. http://crbug.com/517420 +#if defined(OS_MACOSX) #define MAYBE_LaunchTwice DISABLED_LaunchTwice #else #define MAYBE_LaunchTwice LaunchTwice @@ -256,8 +256,8 @@ FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); } -// Flaky on Mac and Windows. http://crbug.com/517420 -#if defined(OS_MACOSX) || defined(OS_WIN) +// Flaky on Mac. http://crbug.com/517420 +#if defined(OS_MACOSX) #define MAYBE_MultipleLaunchTasks DISABLED_MultipleLaunchTasks #else #define MAYBE_MultipleLaunchTasks MultipleLaunchTasks @@ -278,8 +278,8 @@ EXPECT_EQ(0, launch_count); } -// Flaky on Mac and Windows. http://crbug.com/517420 -#if defined(OS_MACOSX) || defined(OS_WIN) +// Flaky on Mac. http://crbug.com/517420 +#if defined(OS_MACOSX) #define MAYBE_SameLaunchTask DISABLED_SameLaunchTask #else #define MAYBE_SameLaunchTask SameLaunchTask @@ -300,8 +300,8 @@ // Tests whether disconnecting from the service IPC causes the service process // to die. -// Flaky on Mac and Windows. http://crbug.com/517420 -#if defined(OS_MACOSX) || defined(OS_WIN) +// Flaky on Mac. http://crbug.com/517420 +#if defined(OS_MACOSX) #define MAYBE_DieOnDisconnect DISABLED_DieOnDisconnect #else #define MAYBE_DieOnDisconnect DieOnDisconnect @@ -315,8 +315,8 @@ Disconnect(); } -// Flaky on Mac and Windows. http://crbug.com/517420 -#if defined(OS_MACOSX) || defined(OS_WIN) +// Flaky on Mac. http://crbug.com/517420 +#if defined(OS_MACOSX) #define MAYBE_ForceShutdown DISABLED_ForceShutdown #else #define MAYBE_ForceShutdown ForceShutdown @@ -333,8 +333,8 @@ ForceServiceProcessShutdown(version_info::GetVersionNumber(), service_pid); } -// Flaky on Mac and Windows. http://crbug.com/517420 -#if defined(OS_MACOSX) || defined(OS_WIN) +// Flaky on Mac. http://crbug.com/517420 +#if defined(OS_MACOSX) #define MAYBE_CheckPid DISABLED_CheckPid #else #define MAYBE_CheckPid CheckPid @@ -360,9 +360,8 @@ base::TimeDelta())); } -// Histograms disabled on OSX (http://crbug.com/406227) and Windows -// (http://crbug.com/517420). -#if defined(OS_MACOSX) || defined(OS_WIN) +// Histograms disabled on OSX http://crbug.com/406227 +#if defined(OS_MACOSX) #define MAYBE_HistogramsTimeout DISABLED_HistogramsTimeout #define MAYBE_Histograms DISABLED_Histograms #else
diff --git a/chrome/browser/sync/test/integration/configuration_refresher.cc b/chrome/browser/sync/test/integration/configuration_refresher.cc new file mode 100644 index 0000000..6cabcc8 --- /dev/null +++ b/chrome/browser/sync/test/integration/configuration_refresher.cc
@@ -0,0 +1,24 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/test/integration/configuration_refresher.h" + +#include "components/sync/base/model_type.h" +#include "components/sync/driver/sync_service.h" + +ConfigurationRefresher::ConfigurationRefresher() : scoped_observer_(this) {} + +ConfigurationRefresher::~ConfigurationRefresher() {} + +void ConfigurationRefresher::Observe(syncer::SyncService* sync_service) { + scoped_observer_.Add(sync_service); +} + +void ConfigurationRefresher::OnSyncConfigurationCompleted( + syncer::SyncService* sync_service) { + // Only allowed to trigger refresh/schedule nudges for protocol types, things + // like PROXY_TABS are not allowed. + sync_service->TriggerRefresh(syncer::Intersection( + sync_service->GetActiveDataTypes(), syncer::ProtocolTypes())); +}
diff --git a/chrome/browser/sync/test/integration/configuration_refresher.h b/chrome/browser/sync/test/integration/configuration_refresher.h new file mode 100644 index 0000000..ae141ee --- /dev/null +++ b/chrome/browser/sync/test/integration/configuration_refresher.h
@@ -0,0 +1,35 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_CONFIGURATION_REFRESHER_H_ +#define CHROME_BROWSER_SYNC_TEST_INTEGRATION_CONFIGURATION_REFRESHER_H_ + +#include "base/macros.h" +#include "base/scoped_observer.h" +#include "components/sync/driver/sync_service_observer.h" + +// Triggers a GetUpdates via refresh for any observed SyncService after a +// configuration. This class was created to be used in conjunction with fake +// invalidations. It turns out there's a race during configuration, after the +// initial GetUpdates was called, but before invalidations were re-subscribed to +// that caused updates to be missed. This resulted in some flakey test cases, +// see crbug,com/644367 for more details. This class fills the gap by forcing a +// GetUpdates after configuration to fetch anything missed while a client was +// not subscribed to invalidation(s). +class ConfigurationRefresher : public syncer::SyncServiceObserver { + public: + ConfigurationRefresher(); + ~ConfigurationRefresher() override; + void Observe(syncer::SyncService* sync_service); + + private: + // syncer::SyncServiceObserver implementation. + void OnSyncConfigurationCompleted(syncer::SyncService* sync_service) override; + + ScopedObserver<syncer::SyncService, ConfigurationRefresher> scoped_observer_; + + DISALLOW_COPY_AND_ASSIGN(ConfigurationRefresher); +}; + +#endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_CONFIGURATION_REFRESHER_H_
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc index 4515ef5..aecab0aa 100644 --- a/chrome/browser/sync/test/integration/sync_test.cc +++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -217,6 +217,7 @@ : test_type_(test_type), server_type_(SERVER_TYPE_UNDECIDED), num_clients_(-1), + configuration_refresher_(std::make_unique<ConfigurationRefresher>()), use_verifier_(true), create_gaia_account_at_runtime_(false) { sync_datatype_helper::AssociateWithTest(this); @@ -642,6 +643,8 @@ invalidation_service->DisableSelfNotifications(); } fake_server_invalidation_services_[index] = invalidation_service; + configuration_refresher_->Observe( + ProfileSyncServiceFactory::GetForProfile(GetProfile(index))); } else { invalidation::P2PInvalidationService* p2p_invalidation_service = static_cast<invalidation::P2PInvalidationService*>( @@ -774,10 +777,10 @@ } } + // Delete things that unsubscribe in destructor before their targets are gone. invalidation_forwarders_.clear(); sync_refreshers_.clear(); - fake_server_invalidation_services_.clear(); - clients_.clear(); + configuration_refresher_.reset(); } void SyncTest::SetUpOnMainThread() {
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h index afd9893..898ecd5 100644 --- a/chrome/browser/sync/test/integration/sync_test.h +++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/process/process.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/test/integration/configuration_refresher.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/sync/base/model_type.h" #include "components/sync/protocol/sync_protocol_error.h" @@ -432,6 +433,9 @@ std::vector<fake_server::FakeServerInvalidationService*> fake_server_invalidation_services_; + // Triggers a GetUpdates via refresh after a configuration. + std::unique_ptr<ConfigurationRefresher> configuration_refresher_; + // Sync profile against which changes to individual profiles are verified. We // don't need a corresponding verifier sync client because the contents of the // verifier profile are strictly local, and are not meant to be synced.
diff --git a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc index 537f07ec..1d279a3 100644 --- a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
@@ -1860,7 +1860,7 @@ ASSERT_TRUE(IsEncryptionComplete(1)); ASSERT_TRUE(GetSyncService(1)->IsPassphraseRequired()); - // Client 1 adds bookmarks between the first two and between the second two. + // Client 0 adds bookmarks between the first two and between the second two. ASSERT_NE(nullptr, AddURL(0, 1, IndexedURLTitle(3), GURL(IndexedURL(3)))); ASSERT_NE(nullptr, AddURL(0, 3, IndexedURLTitle(4), GURL(IndexedURL(4)))); EXPECT_FALSE(AllModelsMatchVerifier());
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc index 3b2bf76..5ff69f6e 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -290,13 +290,11 @@ int hit_test = widget()->non_client_view()->NonClientHitTest(point_in_view_coords); if (hit_test == HTCAPTION) { - menu_model_adapter_.reset(new views::MenuModelAdapter( + menu_runner_ = std::make_unique<views::MenuRunner>( menu_model_.get(), + views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU, base::Bind(&ChromeNativeAppWindowViewsAuraAsh::OnMenuClosed, - base::Unretained(this)))); - menu_runner_.reset(new views::MenuRunner( - menu_model_adapter_->CreateMenu(), - views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU)); + base::Unretained(this))); menu_runner_->RunMenuAt(source->GetWidget(), NULL, gfx::Rect(p, gfx::Size(0, 0)), views::MENU_ANCHOR_TOPLEFT, source_type); @@ -576,7 +574,6 @@ void ChromeNativeAppWindowViewsAuraAsh::OnMenuClosed() { menu_runner_.reset(); - menu_model_adapter_.reset(); menu_model_.reset(); }
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h index be3e2ca7..18af222c 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h
@@ -25,7 +25,6 @@ } namespace views { -class MenuModelAdapter; class MenuRunner; } @@ -130,7 +129,7 @@ FRIEND_TEST_ALL_PREFIXES(ShapedAppWindowTargeterTest, ResizeInsetsWithinBounds); - // Callback for MenuModelAdapter + // Callback for MenuRunner void OnMenuClosed(); // Helper function which returns true if in tablet mode, the auto hide @@ -146,7 +145,6 @@ // Used to show the system menu. std::unique_ptr<ui::MenuModel> menu_model_; - std::unique_ptr<views::MenuModelAdapter> menu_model_adapter_; std::unique_ptr<views::MenuRunner> menu_runner_; // Used for displaying the toast with instructions on exiting fullscreen.
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h index 09d6302..188f732d 100644 --- a/chrome/browser/ui/views/frame/browser_frame.h +++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -121,7 +121,7 @@ ui::MenuModel* GetSystemMenuModel(); private: - // Callback for MenuModelAdapter. + // Callback for MenuRunner. void OnMenuClosed(); NativeBrowserFrame* native_browser_frame_;
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc index 3b3dc141..9e52afd 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -83,7 +83,7 @@ UMA_HISTOGRAM_BOOLEAN("Printing.CUPS.IppAttributesSuccess", success); } -// Parsees |printer_uri| into its components and written into |uri|. Returns +// Parses |printer_uri| into its components and written into |uri|. Returns // true if the uri was parsed successfully, returns false otherwise. No changes // are made to |uri| if this function returns false. bool ParseUri(const std::string& printer_uri, PrinterUri* uri) { @@ -181,9 +181,9 @@ return host; } -// Returns a JSON representation of |printer| as a CupsPrinterInfo. Note it's -// possible that this function returns a nullptr if the printer url is not in -// the right format. +// Returns a JSON representation of |printer| as a CupsPrinterInfo. If the +// printer uri cannot be parsed, the relevant fields are populated with default +// values. std::unique_ptr<base::DictionaryValue> GetPrinterInfo(const Printer& printer) { std::unique_ptr<base::DictionaryValue> printer_info = CreateEmptyPrinterInfo(); @@ -196,7 +196,13 @@ PrinterUri uri; if (!ParseUri(printer.uri(), &uri)) { - return nullptr; + // Uri is invalid so we set default values. + LOG(WARNING) << "Could not parse uri. Defaulting values"; + printer_info->SetString("printerAddress", ""); + printer_info->SetString("printerQueue", ""); + printer_info->SetString("printerProtocol", + "ipp"); // IPP is our default protocol. + return printer_info; } if (base::ToLowerASCII(uri.scheme) == "usb") { @@ -363,11 +369,9 @@ auto printers_list = base::MakeUnique<base::ListValue>(); for (const Printer& printer : printers) { - // TODO(skau): Theoretically |printer_info| should not be a nullptr as we - // should not allow adding an invalid configured printer to PrinterManager. - auto printer_info = GetPrinterInfo(printer); - if (printer_info) - printers_list->Append(std::move(printer_info)); + // Some of these printers could be invalid but we want to allow the user + // to edit them. crbug.com/778383 + printers_list->Append(GetPrinterInfo(printer)); } auto response = base::MakeUnique<base::DictionaryValue>(); @@ -816,14 +820,10 @@ std::unique_ptr<base::ListValue> printers_list = base::MakeUnique<base::ListValue>(); for (const Printer& printer : automatic_printers_) { - auto printer_info = GetPrinterInfo(printer); - if (printer_info) - printers_list->Append(std::move(printer_info)); + printers_list->Append(GetPrinterInfo(printer)); } for (const Printer& printer : discovered_printers_) { - auto printer_info = GetPrinterInfo(printer); - if (printer_info) - printers_list->Append(std::move(printer_info)); + printers_list->Append(GetPrinterInfo(printer)); } FireWebUIListener("on-printer-discovered", *printers_list);
diff --git a/chrome/browser/vr/service/DEPS b/chrome/browser/vr/service/DEPS index 1d7233d..ac9c5de 100644 --- a/chrome/browser/vr/service/DEPS +++ b/chrome/browser/vr/service/DEPS
@@ -1,3 +1,4 @@ include_rules = [ "+device/vr", + "+content/public/common/service_manager_connection.h", ]
diff --git a/chrome/browser/vr/service/vr_device_manager.cc b/chrome/browser/vr/service/vr_device_manager.cc index 1fcc1ba..5b3fd890 100644 --- a/chrome/browser/vr/service/vr_device_manager.cc +++ b/chrome/browser/vr/service/vr_device_manager.cc
@@ -11,11 +11,13 @@ #include "base/memory/singleton.h" #include "build/build_config.h" #include "chrome/common/chrome_features.h" +#include "content/public/common/service_manager_connection.h" #include "device/vr/features/features.h" #include "device/vr/vr_device_provider.h" #if defined(OS_ANDROID) #include "device/vr/android/gvr/gvr_device_provider.h" +#include "device/vr/orientation/orientation_device_provider.h" #endif #if BUILDFLAG(ENABLE_OPENVR) @@ -26,14 +28,23 @@ namespace { VRDeviceManager* g_vr_device_manager = nullptr; -} +} // namespace VRDeviceManager* VRDeviceManager::GetInstance() { if (!g_vr_device_manager) { // Register VRDeviceProviders for the current platform ProviderList providers; + #if defined(OS_ANDROID) providers.emplace_back(std::make_unique<device::GvrDeviceProvider>()); + + content::ServiceManagerConnection* connection = + content::ServiceManagerConnection::GetForProcess(); + if (connection) { + providers.emplace_back( + std::make_unique<device::VROrientationDeviceProvider>( + connection->GetConnector())); + } #endif #if BUILDFLAG(ENABLE_OPENVR) @@ -51,6 +62,7 @@ VRDeviceManager::VRDeviceManager(ProviderList providers) : providers_(std::move(providers)) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); CHECK(!g_vr_device_manager); g_vr_device_manager = this; } @@ -68,8 +80,10 @@ // when they are created. InitializeProviders(); - for (const DeviceMap::value_type& map_entry : devices_) - service->ConnectDevice(map_entry.second); + for (const DeviceMap::value_type& map_entry : devices_) { + if (!map_entry.second->IsFallbackDevice() || devices_.size() == 1) + service->ConnectDevice(map_entry.second); + } if (AreAllProvidersInitialized()) service->InitializationComplete(); @@ -95,9 +109,21 @@ if (device->GetId() == device::VR_DEVICE_LAST_ID) return; + // If we were previously using a fallback device, remove it. + // TODO(offenwanger): This has the potential to cause device change events to + // fire in rapid succession. This should be discussed and resolved when we + // start to actually add and remove devices. + if (devices_.size() == 1 && devices_.begin()->second->IsFallbackDevice()) { + device::VRDevice* device = devices_.begin()->second; + for (VRServiceImpl* service : services_) + service->RemoveDevice(device); + } + devices_[device->GetId()] = device; - for (VRServiceImpl* service : services_) - service->ConnectDevice(device); + if (!device->IsFallbackDevice() || devices_.size() == 1) { + for (VRServiceImpl* service : services_) + service->ConnectDevice(device); + } } void VRDeviceManager::RemoveDevice(device::VRDevice* device) { @@ -111,6 +137,12 @@ service->RemoveDevice(device); devices_.erase(it); + + if (devices_.size() == 1 && devices_.begin()->second->IsFallbackDevice()) { + device::VRDevice* device = devices_.begin()->second; + for (VRServiceImpl* service : services_) + service->ConnectDevice(device); + } } device::VRDevice* VRDeviceManager::GetDevice(unsigned int index) {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 37552a9..fcc9d0e 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -4892,6 +4892,8 @@ "../browser/sync/test/integration/await_match_status_change_checker.h", "../browser/sync/test/integration/bookmarks_helper.cc", "../browser/sync/test/integration/bookmarks_helper.h", + "../browser/sync/test/integration/configuration_refresher.cc", + "../browser/sync/test/integration/configuration_refresher.h", "../browser/sync/test/integration/dictionary_helper.cc", "../browser/sync/test/integration/dictionary_helper.h", "../browser/sync/test/integration/dictionary_load_observer.cc",
diff --git a/chrome/test/data/extensions/context_menus/checkboxes/manifest.json b/chrome/test/data/extensions/context_menus/checkboxes/manifest.json new file mode 100644 index 0000000..b99daf45 --- /dev/null +++ b/chrome/test/data/extensions/context_menus/checkboxes/manifest.json
@@ -0,0 +1,11 @@ +{ + "name" : "Context Menus Test Extension", + "description": "Tests context menu checkbox update", + "version" : "0.1", + "manifest_version": 2, + "permissions": [ "contextMenus"], + "background": { + "scripts": ["test.js"] + } +} +
diff --git a/chrome/test/data/extensions/context_menus/checkboxes/test.js b/chrome/test/data/extensions/context_menus/checkboxes/test.js new file mode 100644 index 0000000..4d626fa --- /dev/null +++ b/chrome/test/data/extensions/context_menus/checkboxes/test.js
@@ -0,0 +1,60 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +window.onload = function() { + createFirstCheckbox() + .then(createSecondCheckbox) + .then(checkSecondCheckbox) + .then(createNormalMenuItem) + .then(function() { + chrome.test.sendMessage('Menu created'); + }); +}; + +function createFirstCheckbox() { + return new Promise(function(resolve, reject) { + chrome.contextMenus.create({ + id: 'checkbox1', + type: 'checkbox', + title: 'Checkbox 1', + onclick: function() { + chrome.test.sendMessage('onclick checkbox 1'); + } + }, resolve); + }); +} + +function createSecondCheckbox() { + return new Promise(function(resolve, reject) { + chrome.contextMenus.create({ + id: 'checkbox2', + type: 'checkbox', + title: 'Checkbox 2', + onclick: function() { + chrome.test.sendMessage('onclick checkbox 2'); + } + }, resolve); + }); +} + +function checkSecondCheckbox() { + return new Promise(function(resolve, reject) { + chrome.contextMenus.update('checkbox2', {checked: true}, resolve); + }); +} + +function createNormalMenuItem() { + return new Promise(function(resolve, reject) { + chrome.contextMenus.create({ + id: 'item1', + title: 'Item 1', + onclick: function() { + chrome.test.sendMessage('onclick normal item'); + chrome.contextMenus.update('checkbox2', {checked: false}, function() { + chrome.test.sendMessage('checkbox2 unchecked'); + }); + } + }, resolve); + }); +}
diff --git a/chromeos/dbus/fake_image_loader_client.cc b/chromeos/dbus/fake_image_loader_client.cc index 9dcef0b..8ed20de 100644 --- a/chromeos/dbus/fake_image_loader_client.cc +++ b/chromeos/dbus/fake_image_loader_client.cc
@@ -41,4 +41,10 @@ std::move(callback).Run(base::nullopt); } +void FakeImageLoaderClient::UnmountComponent( + const std::string& name, + DBusMethodCallback<bool> callback) { + std::move(callback).Run(base::nullopt); +} + } // namespace chromeos
diff --git a/chromeos/dbus/fake_image_loader_client.h b/chromeos/dbus/fake_image_loader_client.h index 24898b8..c2cc00f 100644 --- a/chromeos/dbus/fake_image_loader_client.h +++ b/chromeos/dbus/fake_image_loader_client.h
@@ -36,6 +36,8 @@ void RequestComponentVersion( const std::string& name, DBusMethodCallback<std::string> callback) override; + void UnmountComponent(const std::string& name, + DBusMethodCallback<bool> callback) override; private: DISALLOW_COPY_AND_ASSIGN(FakeImageLoaderClient);
diff --git a/chromeos/dbus/image_loader_client.cc b/chromeos/dbus/image_loader_client.cc index bad965a..a23a300 100644 --- a/chromeos/dbus/image_loader_client.cc +++ b/chromeos/dbus/image_loader_client.cc
@@ -87,6 +87,17 @@ std::move(callback))); } + void UnmountComponent(const std::string& name, + DBusMethodCallback<bool> callback) override { + dbus::MethodCall method_call(imageloader::kImageLoaderServiceInterface, + imageloader::kUnmountComponent); + dbus::MessageWriter writer(&method_call); + writer.AppendString(name); + proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::BindOnce(&ImageLoaderClientImpl::OnBoolMethod, + std::move(callback))); + } + protected: // DBusClient override. void Init(dbus::Bus* bus) override {
diff --git a/chromeos/dbus/image_loader_client.h b/chromeos/dbus/image_loader_client.h index 8880ccee..57210bf0 100644 --- a/chromeos/dbus/image_loader_client.h +++ b/chromeos/dbus/image_loader_client.h
@@ -50,6 +50,10 @@ virtual void RemoveComponent(const std::string& name, DBusMethodCallback<bool> callback) = 0; + // Unmounts all mount points given component |name|. + virtual void UnmountComponent(const std::string& name, + DBusMethodCallback<bool> callback) = 0; + // Factory function, creates a new instance and returns ownership. // For normal usage, access the singleton via DBusThreadManager::Get(). static ImageLoaderClient* Create();
diff --git a/chromeos/dbus/services/component_updater_service_provider.cc b/chromeos/dbus/services/component_updater_service_provider.cc index ac95151..8fe15e5 100644 --- a/chromeos/dbus/services/component_updater_service_provider.cc +++ b/chromeos/dbus/services/component_updater_service_provider.cc
@@ -33,6 +33,14 @@ weak_ptr_factory_.GetWeakPtr()), base::Bind(&ComponentUpdaterServiceProvider::OnExported, weak_ptr_factory_.GetWeakPtr())); + + exported_object->ExportMethod( + kComponentUpdaterServiceInterface, + kComponentUpdaterServiceUnloadComponentMethod, + base::Bind(&ComponentUpdaterServiceProvider::UnloadComponent, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&ComponentUpdaterServiceProvider::OnExported, + weak_ptr_factory_.GetWeakPtr())); } void ComponentUpdaterServiceProvider::OnExported( @@ -82,4 +90,23 @@ } } +void ComponentUpdaterServiceProvider::UnloadComponent( + dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender) { + dbus::MessageReader reader(method_call); + std::string component_name; + if (reader.PopString(&component_name)) { + if (delegate_->UnloadComponent(component_name)) { + response_sender.Run(dbus::Response::FromMethodCall(method_call)); + } else { + response_sender.Run(dbus::ErrorResponse::FromMethodCall( + method_call, kErrorInternalError, "Failed to unload component")); + } + } else { + response_sender.Run(dbus::ErrorResponse::FromMethodCall( + method_call, kErrorInvalidArgs, + "Missing component name string argument.")); + } +} + } // namespace chromeos
diff --git a/chromeos/dbus/services/component_updater_service_provider.h b/chromeos/dbus/services/component_updater_service_provider.h index 7ccb088a..2aacd281 100644 --- a/chromeos/dbus/services/component_updater_service_provider.h +++ b/chromeos/dbus/services/component_updater_service_provider.h
@@ -22,19 +22,25 @@ namespace chromeos { -// This class exports a "LoadComponent" D-Bus method that installs a component -// and return the installed path (if successful) or an error message -// (on failure): +// This class exports D-Bus methods that manage components: // +// LoadComponent: // % dbus-send --system --type=method_call --print-reply // --dest=org.chromium.ComponentUpdaterService // /org/chromium/ComponentUpdaterService // org.chromium.ComponentUpdaterService.LoadComponent // "string:|component name|" // -// -> method return sender=:1.42 -> destination=:1.43 reply_serial=2 +// % string "/run/imageloader/|component name|/|version|" // -// string "/run/imageloader/|component name|/|version|" +// UnloadComponent: +// % dbus-send --system --type=method_call --print-reply +// --dest=org.chromium.ComponentUpdaterService +// /org/chromium/ComponentUpdaterService +// org.chromium.ComponentUpdaterService.UnloadComponent +// "string:|component name|" +// +// % (returns empty response on success and error response on failure) class CHROMEOS_EXPORT ComponentUpdaterServiceProvider : public CrosDBusService::ServiceProviderInterface { public: @@ -47,7 +53,9 @@ virtual void LoadComponent( const std::string& name, - const base::Callback<void(const std::string&)>& load_callback) = 0; + base::OnceCallback<void(const std::string&)> load_callback) = 0; + + virtual bool UnloadComponent(const std::string& name) = 0; private: DISALLOW_COPY_AND_ASSIGN(Delegate); @@ -75,6 +83,10 @@ dbus::ExportedObject::ResponseSender response_sender, const std::string& result); + // Called on UI thread in response to a D-Bus request. + void UnloadComponent(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender response_sender); + std::unique_ptr<Delegate> delegate_; // Keep this last so that all weak pointers will be invalidated at the // beginning of destruction.
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc index e20b03de..f0118990 100644 --- a/components/autofill/core/browser/autofill_experiments.cc +++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -65,6 +65,8 @@ "AutofillUpstreamAllowAllEmailDomains", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillUpstreamRequestCvcIfMissing{ "AutofillUpstreamRequestCvcIfMissing", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kAutofillUpstreamSendPanFirstSix{ + "AutofillUpstreamSendPanFirstSix", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillUpstreamShowGoogleLogo{ "AutofillUpstreamShowGoogleLogo", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kAutofillUpstreamShowNewUi{ @@ -293,6 +295,10 @@ #endif } +bool IsAutofillUpstreamSendPanFirstSixExperimentEnabled() { + return base::FeatureList::IsEnabled(kAutofillUpstreamSendPanFirstSix); +} + bool IsAutofillUpstreamShowGoogleLogoExperimentEnabled() { #if defined(OS_ANDROID) return false;
diff --git a/components/autofill/core/browser/autofill_experiments.h b/components/autofill/core/browser/autofill_experiments.h index 6221cf2..c6d770c8 100644 --- a/components/autofill/core/browser/autofill_experiments.h +++ b/components/autofill/core/browser/autofill_experiments.h
@@ -44,6 +44,7 @@ extern const base::Feature kAutofillToolkitViewsCreditCardDialogsMac; extern const base::Feature kAutofillUpstreamAllowAllEmailDomains; extern const base::Feature kAutofillUpstreamRequestCvcIfMissing; +extern const base::Feature kAutofillUpstreamSendPanFirstSix; extern const base::Feature kAutofillUpstreamShowGoogleLogo; extern const base::Feature kAutofillUpstreamShowNewUi; extern const base::Feature kAutofillUpstreamUseAutofillProfileComparator; @@ -141,6 +142,11 @@ // in the offer to save bubble if it was not detected during the checkout flow. bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled(); +// Returns whether the experiment is enabled where Chrome Upstream sends the +// first six digits of the card PAN to Google Payments to help determine whether +// card upload is possible. +bool IsAutofillUpstreamSendPanFirstSixExperimentEnabled(); + // Returns whether the experiment is enabled where Chrome Upstream displays a // Google Logo in the save card bubble/infobar. bool IsAutofillUpstreamShowGoogleLogoExperimentEnabled();
diff --git a/components/autofill/core/browser/credit_card_save_manager.cc b/components/autofill/core/browser/credit_card_save_manager.cc index 2c54aec..16708ef 100644 --- a/components/autofill/core/browser/credit_card_save_manager.cc +++ b/components/autofill/core/browser/credit_card_save_manager.cc
@@ -159,6 +159,10 @@ return; } + if (IsAutofillUpstreamSendPanFirstSixExperimentEnabled()) { + upload_request_.active_experiments.push_back( + kAutofillUpstreamSendPanFirstSix.name); + } if (IsAutofillUpstreamShowNewUiExperimentEnabled()) { upload_request_.active_experiments.push_back( kAutofillUpstreamShowNewUi.name); @@ -169,9 +173,11 @@ } // All required data is available, start the upload process. - payments_client_->GetUploadDetails(upload_request_.profiles, - upload_request_.active_experiments, - app_locale_); + payments_client_->GetUploadDetails( + upload_request_.profiles, + base::UTF16ToASCII(CreditCard::StripSeparators(card.number())) + .substr(0, 6), + upload_request_.active_experiments, app_locale_); } bool CreditCardSaveManager::IsCreditCardUploadEnabled() {
diff --git a/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/credit_card_save_manager_unittest.cc index abfbf1f..d4e5b14 100644 --- a/components/autofill/core/browser/credit_card_save_manager_unittest.cc +++ b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -105,8 +105,10 @@ ~TestPaymentsClient() override {} void GetUploadDetails(const std::vector<AutofillProfile>& addresses, + const std::string& pan_first_six, const std::vector<const char*>& active_experiments, const std::string& app_locale) override { + pan_first_six_ = pan_first_six; active_experiments_ = active_experiments; save_delegate_->OnDidGetUploadDetails( app_locale == "en-US" ? AutofillClient::SUCCESS @@ -122,6 +124,7 @@ } std::string server_id_; + std::string pan_first_six_; std::vector<const char*> active_experiments_; void SetSaveDelegate(payments::PaymentsClientSaveDelegate* save_delegate) { @@ -343,6 +346,10 @@ bool credit_card_was_uploaded() { return credit_card_was_uploaded_; } + const std::string GetPanFirstSix() const { + return test_payments_client_->pan_first_six_; + } + const std::vector<const char*>& GetActiveExperiments() const { return test_payments_client_->active_experiments_; } @@ -414,6 +421,10 @@ kAutofillUpstreamRequestCvcIfMissing); } + void EnableAutofillUpstreamSendPanFirstSixExperiment() { + scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamSendPanFirstSix); + } + void EnableAutofillUpstreamShowGoogleLogoExperiment() { scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamShowGoogleLogo); } @@ -1421,38 +1432,6 @@ } TEST_F(CreditCardSaveManagerTest, - UploadCreditCard_DoNotAddNewUiFlagStateToRequestIfExperimentOff) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->set_credit_card_upload_enabled(true); - - // Create, fill and submit an address form in order to establish a recent - // profile which can be selected for the upload request. - FormData address_form; - test::CreateTestAddressFormData(&address_form); - FormsSeen(std::vector<FormData>(1, address_form)); - ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); - FormSubmitted(address_form); - - // Set up our credit card form data. - FormData credit_card_form; - CreateTestCreditCardFormData(&credit_card_form, true, false); - FormsSeen(std::vector<FormData>(1, credit_card_form)); - - // Edit the data, and submit. - credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); - credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16("11"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); - credit_card_form.fields[4].value = ASCIIToUTF16("123"); - - // Confirm upload happened and the new UI flag was not sent in the request. - EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); - FormSubmitted(credit_card_form); - EXPECT_TRUE(credit_card_save_manager_->credit_card_was_uploaded()); - EXPECT_TRUE(credit_card_save_manager_->GetActiveExperiments().empty()); -} - -TEST_F(CreditCardSaveManagerTest, UploadCreditCard_AddShowGoogleLogoFlagStateToRequestIfExperimentOn) { EnableAutofillUpstreamShowGoogleLogoExperiment(); personal_data_.ClearProfiles(); @@ -1486,39 +1465,6 @@ EXPECT_THAT(credit_card_save_manager_->GetActiveExperiments(), UnorderedElementsAre(kAutofillUpstreamShowGoogleLogo.name)); } - -TEST_F(CreditCardSaveManagerTest, - UploadCreditCard_DoNotAddShowGoogleLogoFlagStateToRequestIfExpOff) { - personal_data_.ClearProfiles(); - credit_card_save_manager_->set_credit_card_upload_enabled(true); - - // Create, fill and submit an address form in order to establish a recent - // profile which can be selected for the upload request. - FormData address_form; - test::CreateTestAddressFormData(&address_form); - FormsSeen(std::vector<FormData>(1, address_form)); - ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); - FormSubmitted(address_form); - - // Set up our credit card form data. - FormData credit_card_form; - CreateTestCreditCardFormData(&credit_card_form, true, false); - FormsSeen(std::vector<FormData>(1, credit_card_form)); - - // Edit the data, and submit. - credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); - credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); - credit_card_form.fields[2].value = ASCIIToUTF16("11"); - credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); - credit_card_form.fields[4].value = ASCIIToUTF16("123"); - - // Confirm upload happened and the show Google logo flag was not sent in the - // request. - EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); - FormSubmitted(credit_card_form); - EXPECT_TRUE(credit_card_save_manager_->credit_card_was_uploaded()); - EXPECT_TRUE(credit_card_save_manager_->GetActiveExperiments().empty()); -} #endif TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) { @@ -2521,4 +2467,74 @@ EXPECT_FALSE(credit_card_save_manager_->credit_card_was_uploaded()); } +TEST_F(CreditCardSaveManagerTest, + UploadCreditCard_DoNotAddAnyFlagStatesToRequestIfExperimentsOff) { + personal_data_.ClearProfiles(); + credit_card_save_manager_->set_credit_card_upload_enabled(true); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111"); + credit_card_form.fields[2].value = ASCIIToUTF16("11"); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + // Confirm upload happened and that no experiment flag state was sent in the + // request. + EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); + FormSubmitted(credit_card_form); + EXPECT_TRUE(credit_card_save_manager_->credit_card_was_uploaded()); + EXPECT_TRUE(credit_card_save_manager_->GetActiveExperiments().empty()); +} + +TEST_F(CreditCardSaveManagerTest, UploadCreditCard_AddPanFirstSixToRequest) { + EnableAutofillUpstreamSendPanFirstSixExperiment(); + personal_data_.ClearProfiles(); + credit_card_save_manager_->set_credit_card_upload_enabled(true); + + // Create, fill and submit an address form in order to establish a recent + // profile which can be selected for the upload request. + FormData address_form; + test::CreateTestAddressFormData(&address_form); + FormsSeen(std::vector<FormData>(1, address_form)); + ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form); + FormSubmitted(address_form); + + // Set up our credit card form data. + FormData credit_card_form; + CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master"); + credit_card_form.fields[1].value = ASCIIToUTF16("4444333322221111"); + credit_card_form.fields[2].value = ASCIIToUTF16("11"); + credit_card_form.fields[3].value = ASCIIToUTF16(NextYear()); + credit_card_form.fields[4].value = ASCIIToUTF16("123"); + + // Confirm that the first six digits of the credit card number were included + // in the request. + EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0); + FormSubmitted(credit_card_form); + EXPECT_TRUE(credit_card_save_manager_->credit_card_was_uploaded()); + EXPECT_EQ(credit_card_save_manager_->GetPanFirstSix(), "444433"); + // Confirm that the "send pan first six" experiment flag was sent in the + // request. + EXPECT_THAT(credit_card_save_manager_->GetActiveExperiments(), + UnorderedElementsAre(kAutofillUpstreamSendPanFirstSix.name)); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc index bae77b9..d2440a8b 100644 --- a/components/autofill/core/browser/payments/payments_client.cc +++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -261,10 +261,12 @@ class GetUploadDetailsRequest : public PaymentsRequest { public: GetUploadDetailsRequest(const std::vector<AutofillProfile>& addresses, + const std::string& pan_first_six, const std::vector<const char*>& active_experiments, const std::string& app_locale, PaymentsClientSaveDelegate* delegate) : addresses_(addresses), + pan_first_six_(pan_first_six), active_experiments_(active_experiments), app_locale_(app_locale), delegate_(delegate) {} @@ -294,6 +296,10 @@ } request_dict.Set("address", std::move(addresses)); + if (IsAutofillUpstreamSendPanFirstSixExperimentEnabled() && + !pan_first_six_.empty()) + request_dict.SetString("pan_first6", pan_first_six_); + SetActiveExperiments(active_experiments_, &request_dict); std::string request_content; @@ -320,6 +326,7 @@ private: const std::vector<AutofillProfile> addresses_; + const std::string pan_first_six_; const std::vector<const char*> active_experiments_; std::string app_locale_; PaymentsClientSaveDelegate* delegate_; @@ -477,11 +484,13 @@ void PaymentsClient::GetUploadDetails( const std::vector<AutofillProfile>& addresses, + const std::string& pan_first_six, const std::vector<const char*>& active_experiments, const std::string& app_locale) { DCHECK(save_delegate_); IssueRequest(std::make_unique<GetUploadDetailsRequest>( - addresses, active_experiments, app_locale, save_delegate_), + addresses, pan_first_six, active_experiments, app_locale, + save_delegate_), false); }
diff --git a/components/autofill/core/browser/payments/payments_client.h b/components/autofill/core/browser/payments/payments_client.h index ea083af..b48a7674 100644 --- a/components/autofill/core/browser/payments/payments_client.h +++ b/components/autofill/core/browser/payments/payments_client.h
@@ -129,12 +129,14 @@ // Determine if the user meets the Payments service's conditions for upload. // The service uses |addresses| (from which names and phone numbers are - // removed) and |app_locale| to determine which legal message to display. If - // the conditions are met, the legal message will be returned via - // OnDidGetUploadDetails. |active_experiments| is used by payments server to - // track requests that were triggered by enabled features. + // removed) and |app_locale| to determine which legal message to display. + // |pan_first_six| is the first six digits of the number of the credit card + // being considered for upload. If the conditions are met, the legal message + // will be returned via OnDidGetUploadDetails. |active_experiments| is used by + // Payments server to track requests that were triggered by enabled features. virtual void GetUploadDetails( const std::vector<AutofillProfile>& addresses, + const std::string& pan_first_six, const std::vector<const char*>& active_experiments, const std::string& app_locale);
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc index 0820d33e..f1751c48 100644 --- a/components/autofill/core/browser/payments/payments_client_unittest.cc +++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -61,6 +61,10 @@ kAutofillSendBillingCustomerNumber); } + void EnableAutofillUpstreamSendPanFirstSixExperiment() { + scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamSendPanFirstSix); + } + // PaymentsClientUnmaskDelegate: void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result, const std::string& real_pan) override { @@ -99,8 +103,8 @@ void StartGettingUploadDetails() { token_service_->AddAccount("example@gmail.com"); identity_provider_->LogIn("example@gmail.com"); - client_->GetUploadDetails(BuildTestProfiles(), std::vector<const char*>(), - "language-LOCALE"); + client_->GetUploadDetails(BuildTestProfiles(), /*pan_first_six=*/"411111", + std::vector<const char*>(), "language-LOCALE"); } void StartUploading(bool include_cvc) { @@ -264,6 +268,26 @@ EXPECT_TRUE(GetUploadData().find("0090") == std::string::npos); } +TEST_F(PaymentsClientTest, + GetDetailsIncludesPanFirstSixInRequestIfExperimentOn) { + EnableAutofillUpstreamSendPanFirstSixExperiment(); + + StartGettingUploadDetails(); + + // Verify that the value of pan_first_six was included in the request. + EXPECT_TRUE(GetUploadData().find("\"pan_first6\":\"411111\"") != + std::string::npos); +} + +TEST_F(PaymentsClientTest, + GetDetailsDoesNotIncludePanFirstSixInRequestIfExperimentOff) { + StartGettingUploadDetails(); + + // Verify that the value of pan_first_six was left out of the request. + EXPECT_TRUE(GetUploadData().find("\"pan_first6\":\"411111\"") == + std::string::npos); +} + TEST_F(PaymentsClientTest, UploadSuccessWithoutServerId) { StartUploading(/*include_cvc=*/true); IssueOAuthToken();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc index d2ce9a1d..9d025c1 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -163,11 +163,7 @@ secure_proxy_checker_.reset( new SecureProxyChecker(basic_url_request_context_getter)); - warmup_url_fetcher_.reset(new WarmupURLFetcher( - url_request_context_getter, - base::BindRepeating( - &DataReductionProxyConfig::HandleWarmupFetcherResponse, - base::Unretained(this)))); + warmup_url_fetcher_.reset(new WarmupURLFetcher(url_request_context_getter)); if (ShouldAddDefaultProxyBypassRules()) AddDefaultProxyBypassRules(); @@ -182,7 +178,6 @@ void DataReductionProxyConfig::OnNewClientConfigFetched() { DCHECK(thread_checker_.CalledOnValidThread()); ReloadConfig(); - FetchWarmupURL(); } void DataReductionProxyConfig::ReloadConfig() { @@ -206,26 +201,6 @@ return IsDataReductionProxy(request->proxy_server(), proxy_info); } -bool DataReductionProxyConfig::IsDataReductionProxyServerCore( - const net::ProxyServer& proxy_server) const { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(IsDataReductionProxy(proxy_server, nullptr /* proxy_info */)); - - const net::HostPortPair& host_port_pair = proxy_server.host_port_pair(); - - const std::vector<DataReductionProxyServer>& data_reduction_proxy_servers = - config_values_->proxies_for_http(); - - const auto proxy_it = std::find_if( - data_reduction_proxy_servers.begin(), data_reduction_proxy_servers.end(), - [&host_port_pair](const DataReductionProxyServer& proxy) { - return proxy.proxy_server().is_valid() && - proxy.proxy_server().host_port_pair().Equals(host_port_pair); - }); - - return proxy_it->IsCoreProxy(); -} - bool DataReductionProxyConfig::IsDataReductionProxy( const net::ProxyServer& proxy_server, DataReductionProxyTypeInfo* proxy_info) const { @@ -438,56 +413,6 @@ network_properties_manager_ = manager; } -void DataReductionProxyConfig::HandleWarmupFetcherResponse( - const net::ProxyServer& proxy_server, - bool success_response) { - DCHECK(thread_checker_.CalledOnValidThread()); - - // Check the proxy server used, or disable all data saver proxies? - if (!IsDataReductionProxy(proxy_server, nullptr)) { - // No need to do anything here. - return; - } - - bool is_secure_drp_proxy = proxy_server.is_https() || proxy_server.is_quic(); - bool is_core_proxy = IsDataReductionProxyServerCore(proxy_server); - if (is_secure_drp_proxy && is_core_proxy) { - UMA_HISTOGRAM_BOOLEAN( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.Core", - success_response); - } else if (is_secure_drp_proxy && !is_core_proxy) { - UMA_HISTOGRAM_BOOLEAN( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - success_response); - } else if (!is_secure_drp_proxy && is_core_proxy) { - UMA_HISTOGRAM_BOOLEAN( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "InsecureProxy.Core", - success_response); - } else { - UMA_HISTOGRAM_BOOLEAN( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "InsecureProxy.NonCore", - success_response); - } - - bool warmup_url_failed_past = - network_properties_manager_->HasWarmupURLProbeFailed(is_secure_drp_proxy, - is_core_proxy); - - network_properties_manager_->SetHasWarmupURLProbeFailed( - is_secure_drp_proxy, is_core_proxy, - !success_response /* warmup failed */); - - if (warmup_url_failed_past != - network_properties_manager_->HasWarmupURLProbeFailed(is_secure_drp_proxy, - is_core_proxy)) { - ReloadConfig(); - } -} - void DataReductionProxyConfig::HandleSecureProxyCheckResponse( const std::string& response, const net::URLRequestStatus& status,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h index f9e518f..f176edd 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -216,13 +216,6 @@ // Returns the ID of the current network by calling the platform APIs. virtual std::string GetCurrentNetworkID() const; - // Callback that is executed when the warmup URL fetch is complete. - // |proxy_server| is the proxy server over which the warmup URL was fetched. - // |success_response| is true if the fetching of the URL was successful or - // not. - void HandleWarmupFetcherResponse(const net::ProxyServer& proxy_server, - bool success_response); - private: friend class MockDataReductionProxyConfig; friend class TestDataReductionProxyConfig; @@ -297,12 +290,6 @@ // Fetches the warmup URL. void FetchWarmupURL(); - // Returns true if |proxy_server| is a core data reduction proxy server. - // Should be called only if |proxy_server| is a valid data reduction proxy - // server. - bool IsDataReductionProxyServerCore( - const net::ProxyServer& proxy_server) const; - // URL fetcher used for performing the secure proxy check. std::unique_ptr<SecureProxyChecker> secure_proxy_checker_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc index 0a2eaf0..f4329f7 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -159,10 +159,6 @@ context_->Init(); - // Disable fetching of warmup URL to avoid generating extra traffic which - // would need to be satisfied using mock sockets. - test_context_->DisableWarmupURLFetch(); - test_context_->InitSettings(); ResetBackoffEntryReleaseTime(); test_context_->test_config_client()->SetNow(base::Time::UnixEpoch());
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h index 046df80..acd97fa 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -107,7 +107,6 @@ void SetCurrentNetworkID(const std::string& network_id); using DataReductionProxyConfig::UpdateConfigForTesting; - using DataReductionProxyConfig::HandleWarmupFetcherResponse; private: bool GetIsCaptivePortal() const override;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc index 2e614778..faa0d94 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -75,8 +75,6 @@ for (const net::ProxyServer& proxy : proxies_for_http) proxy_strings.push_back(proxy.ToURI()); - // Proxies specified via kDataReductionProxyHttpProxies command line switch - // have type ProxyServer::UNSPECIFIED_TYPE. base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( data_reduction_proxy::switches::kDataReductionProxyHttpProxies, base::JoinString(proxy_strings, ";")); @@ -1051,129 +1049,4 @@ *request.get(), *previews_decider.get())); } -TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherResponse) { - base::HistogramTester histogram_tester; - const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK); - const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI( - "https://origin.net:443", net::ProxyServer::SCHEME_HTTP); - const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI( - "fallback.net:80", net::ProxyServer::SCHEME_HTTP); - const net::ProxyServer kNonDataSaverProxy = net::ProxyServer::FromURI( - "https://non-data-saver-proxy.net:443", net::ProxyServer::SCHEME_HTTP); - - SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy}); - ResetSettings(); - - // The proxy is enabled. - test_config()->UpdateConfigForTesting(true, true, true); - test_config()->OnNewClientConfigFetched(); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}), - GetConfiguredProxiesForHttp()); - - // Report failed warmup for a non-DataSaver proxy, and verify that it does not - // change the list of data saver proxies. - test_config()->HandleWarmupFetcherResponse(net::ProxyServer(), - false /* success_response */); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}), - GetConfiguredProxiesForHttp()); - - // Report successful warmup of |kHttpsProxy|. - test_config()->HandleWarmupFetcherResponse(kHttpsProxy, true); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}), - GetConfiguredProxiesForHttp()); - histogram_tester.ExpectUniqueSample( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - 1, 1); - - // Report failed warmup |kHttpsProxy| and verify it is removed from the list - // of proxies. - test_config()->HandleWarmupFetcherResponse(kHttpsProxy, false); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}), - GetConfiguredProxiesForHttp()); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - 0, 1); - - // Report failed warmup |kHttpsProxy| again, and verify it does not change the - // list of proxies. - test_config()->HandleWarmupFetcherResponse(kHttpsProxy, false); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}), - GetConfiguredProxiesForHttp()); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - 0, 2); - - // |kHttpsProxy| should now be added back to the list of proxies. - test_config()->HandleWarmupFetcherResponse(kHttpsProxy, true); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}), - GetConfiguredProxiesForHttp()); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - 1, 2); - - // Report successful warmup |kHttpsProxy| again, and verify that there is no - // change in the list of proxies.. - test_config()->HandleWarmupFetcherResponse(kHttpsProxy, true); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}), - GetConfiguredProxiesForHttp()); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - 1, 3); - - // |kHttpsProxy| should be removed again from the list of proxies. - test_config()->HandleWarmupFetcherResponse(kHttpsProxy, false); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}), - GetConfiguredProxiesForHttp()); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - 0, 3); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - 1, 3); - - // Now report failed warmup for |kHttpProxy| and verify that it is also - // removed from the list of proxies. - test_config()->HandleWarmupFetcherResponse(kHttpProxy, false); - EXPECT_EQ(std::vector<net::ProxyServer>({}), GetConfiguredProxiesForHttp()); - histogram_tester.ExpectUniqueSample( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "InsecureProxy.NonCore", - 0, 1); - - // Both proxies should be added back. - test_config()->HandleWarmupFetcherResponse(kHttpsProxy, true); - test_config()->HandleWarmupFetcherResponse(kHttpProxy, true); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}), - GetConfiguredProxiesForHttp()); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - 0, 3); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "SecureProxy.NonCore", - 1, 4); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "InsecureProxy.NonCore", - 0, 1); - histogram_tester.ExpectBucketCount( - "DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch." - "InsecureProxy.NonCore", - 1, 1); - - // If the warmup URL is unsuccessfully fetched using a non-data saver proxy, - // then there is no change in the list of proxies. - test_config()->HandleWarmupFetcherResponse(kNonDataSaverProxy, false); - EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}), - GetConfiguredProxiesForHttp()); -} - } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc index 365de618..735738e 100644 --- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc +++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
@@ -4,7 +4,6 @@ #include "components/data_reduction_proxy/core/browser/warmup_url_fetcher.h" -#include "base/callback.h" #include "base/guid.h" #include "base/metrics/histogram_macros.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" @@ -12,7 +11,6 @@ #include "components/data_reduction_proxy/core/common/data_reduction_proxy_util.h" #include "components/data_use_measurement/core/data_use_user_data.h" #include "net/base/load_flags.h" -#include "net/http/http_status_code.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_request_context_getter.h" @@ -22,10 +20,8 @@ WarmupURLFetcher::WarmupURLFetcher( const scoped_refptr<net::URLRequestContextGetter>& - url_request_context_getter, - WarmupURLFetcherCallback callback) - : url_request_context_getter_(url_request_context_getter), - callback_(callback) { + url_request_context_getter) + : url_request_context_getter_(url_request_context_getter) { DCHECK(url_request_context_getter_); } @@ -115,23 +111,7 @@ util::ConvertNetProxySchemeToProxyScheme( source->ProxyServerUsed().scheme()), PROXY_SCHEME_MAX); - - if (!source->GetStatus().is_success() && - source->GetStatus().error() == net::ERR_INTERNET_DISCONNECTED) { - // Fetching failed due to Internet unavailability, and not due to some - // error. Set the proxy server to unknown. - callback_.Run(net::ProxyServer(), true); - return; - } } - - bool success_response = - source->GetStatus().status() == net::URLRequestStatus::SUCCESS && - source->GetResponseCode() == net::HTTP_NO_CONTENT && - source->GetResponseHeaders() && - HasDataReductionProxyViaHeader(*(source->GetResponseHeaders()), - nullptr /* has_intermediary */); - callback_.Run(source->ProxyServerUsed(), success_response); } } // namespace data_reduction_proxy \ No newline at end of file
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.h b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.h index f470b32..0e9b61c 100644 --- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.h +++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.h
@@ -7,7 +7,6 @@ #include <utility> -#include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "net/url_request/url_fetcher_delegate.h" @@ -16,7 +15,6 @@ namespace net { -class ProxyServer; class URLFetcher; class URLRequestContextGetter; @@ -27,14 +25,8 @@ // URLFetcherDelegate for fetching the warmup URL. class WarmupURLFetcher : public net::URLFetcherDelegate { public: - // The proxy server that was used to fetch the request, and whether the fetch - // was successful. - typedef base::RepeatingCallback<void(const net::ProxyServer&, bool)> - WarmupURLFetcherCallback; - - WarmupURLFetcher(const scoped_refptr<net::URLRequestContextGetter>& - url_request_context_getter, - WarmupURLFetcherCallback callback); + explicit WarmupURLFetcher(const scoped_refptr<net::URLRequestContextGetter>& + url_request_context_getter); ~WarmupURLFetcher() override; @@ -54,10 +46,6 @@ // The URLFetcher being used for fetching the warmup URL. std::unique_ptr<net::URLFetcher> fetcher_; - // Callback that should be executed when the fetching of the warmup URL is - // completed. - WarmupURLFetcherCallback callback_; - DISALLOW_COPY_AND_ASSIGN(WarmupURLFetcher); };
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc index 9821129..b8dad96 100644 --- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc +++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
@@ -6,7 +6,6 @@ #include <vector> -#include "base/bind_helpers.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" @@ -28,33 +27,14 @@ public: WarmupURLFetcherTest(const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter) - : WarmupURLFetcher(url_request_context_getter, - base::BindRepeating( - &WarmupURLFetcherTest::HandleWarmupFetcherResponse, - base::Unretained(this))) {} + : WarmupURLFetcher(url_request_context_getter) {} ~WarmupURLFetcherTest() override {} - size_t callback_received_count() const { return callback_received_count_; } - const net::ProxyServer& proxy_server_last() const { - return proxy_server_last_; - } - bool success_response_last() const { return success_response_last_; } - using WarmupURLFetcher::FetchWarmupURL; using WarmupURLFetcher::GetWarmupURLWithQueryParam; private: - void HandleWarmupFetcherResponse(const net::ProxyServer& proxy_server, - bool success_response) { - callback_received_count_++; - proxy_server_last_ = proxy_server; - success_response_last_ = success_response; - } - - size_t callback_received_count_ = 0; - net::ProxyServer proxy_server_last_; - bool success_response_last_ = false; DISALLOW_COPY_AND_ASSIGN(WarmupURLFetcherTest); }; @@ -90,7 +70,7 @@ EXPECT_TRUE(query_param_different); } -TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLNoViaHeader) { +TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURL) { base::HistogramTester histogram_tester; base::MessageLoopForIO message_loop; const std::string config = "foobarbaz"; @@ -133,66 +113,6 @@ "DataReductionProxy.WarmupURL.ProxySchemeUsed", util::ConvertNetProxySchemeToProxyScheme(net::ProxyServer::SCHEME_DIRECT), 1); - - EXPECT_EQ(1u, warmup_url_fetcher.callback_received_count()); - EXPECT_EQ(net::ProxyServer::SCHEME_DIRECT, - warmup_url_fetcher.proxy_server_last().scheme()); - // success_response_last() should be false since the response does not contain - // the via header. - EXPECT_FALSE(warmup_url_fetcher.success_response_last()); -} - -TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLWithViaHeader) { - base::HistogramTester histogram_tester; - base::MessageLoopForIO message_loop; - const std::string config = "foobarbaz"; - std::vector<std::unique_ptr<net::SocketDataProvider>> socket_data_providers; - net::MockClientSocketFactory mock_socket_factory; - net::MockRead success_reads[3]; - success_reads[0] = net::MockRead( - "HTTP/1.1 204 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n"); - success_reads[1] = net::MockRead(net::ASYNC, config.c_str(), config.length()); - success_reads[2] = net::MockRead(net::SYNCHRONOUS, net::OK); - - socket_data_providers.push_back( - (base::MakeUnique<net::StaticSocketDataProvider>( - success_reads, arraysize(success_reads), nullptr, 0))); - mock_socket_factory.AddSocketDataProvider(socket_data_providers.back().get()); - - std::unique_ptr<net::TestURLRequestContext> test_request_context( - new net::TestURLRequestContext(true)); - - test_request_context->set_client_socket_factory(&mock_socket_factory); - test_request_context->Init(); - scoped_refptr<net::URLRequestContextGetter> request_context_getter = - new net::TestURLRequestContextGetter(message_loop.task_runner(), - std::move(test_request_context)); - - WarmupURLFetcherTest warmup_url_fetcher(request_context_getter); - warmup_url_fetcher.FetchWarmupURL(); - base::RunLoop().RunUntilIdle(); - - histogram_tester.ExpectUniqueSample( - "DataReductionProxy.WarmupURL.FetchInitiated", 1, 1); - histogram_tester.ExpectUniqueSample( - "DataReductionProxy.WarmupURL.FetchSuccessful", 1, 1); - histogram_tester.ExpectUniqueSample("DataReductionProxy.WarmupURL.NetError", - net::OK, 1); - histogram_tester.ExpectUniqueSample( - "DataReductionProxy.WarmupURL.HttpResponseCode", net::HTTP_NO_CONTENT, 1); - histogram_tester.ExpectUniqueSample( - "DataReductionProxy.WarmupURL.HasViaHeader", 1, 1); - histogram_tester.ExpectUniqueSample( - "DataReductionProxy.WarmupURL.ProxySchemeUsed", - util::ConvertNetProxySchemeToProxyScheme(net::ProxyServer::SCHEME_DIRECT), - 1); - - EXPECT_EQ(1u, warmup_url_fetcher.callback_received_count()); - EXPECT_EQ(net::ProxyServer::SCHEME_DIRECT, - warmup_url_fetcher.proxy_server_last().scheme()); - // success_response_last() should be true since the response contains the via - // header. - EXPECT_TRUE(warmup_url_fetcher.success_response_last()); } TEST(WarmupURLFetcherTest, TestConnectionResetFetchWarmupURL) { @@ -235,10 +155,6 @@ 0); histogram_tester.ExpectTotalCount( "DataReductionProxy.WarmupURL.ProxySchemeUsed", 0); - EXPECT_EQ(1u, warmup_url_fetcher.callback_received_count()); - EXPECT_EQ(net::ProxyServer::SCHEME_INVALID, - warmup_url_fetcher.proxy_server_last().scheme()); - EXPECT_FALSE(warmup_url_fetcher.success_response_last()); } } // namespace
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc index eccf2bd..ddb01aa 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc
@@ -50,10 +50,6 @@ return net_proxy_servers; } -bool DataReductionProxyServer::IsCoreProxy() const { - return proxy_type_ == ProxyServer_ProxyType_CORE; -} - ProxyServer_ProxyType DataReductionProxyServer::GetProxyTypeForTesting() const { return proxy_type_; }
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_server.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_server.h index 24767124..000267c7 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_server.h +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_server.h
@@ -35,8 +35,6 @@ const std::vector<DataReductionProxyServer>& data_reduction_proxy_servers); - bool IsCoreProxy() const; - // Returns |proxy_type_| for verification by tests. ProxyServer_ProxyType GetProxyTypeForTesting() const;
diff --git a/components/omnibox/browser/base_search_provider.cc b/components/omnibox/browser/base_search_provider.cc index e6fb1e6..4800d933 100644 --- a/components/omnibox/browser/base_search_provider.cc +++ b/components/omnibox/browser/base_search_provider.cc
@@ -345,17 +345,9 @@ if (IsNTPPage(page_classification)) return false; - // Only allow HTTP URLs or HTTPS URLs. For HTTPS URLs, require that either - // the appropriate feature flag is enabled or the URL is the same domain as - // the search provider. - const bool scheme_allowed = - (current_page_url.scheme() == url::kHttpScheme) || - ((current_page_url.scheme() == url::kHttpsScheme) && - (base::FeatureList::IsEnabled( - omnibox::kSearchProviderContextAllowHttpsUrls) || - net::registry_controlled_domains::SameDomainOrHost( - current_page_url, suggest_url, - net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES))); + // Only allow HTTP URLs or HTTPS URLs. + const bool scheme_allowed = (current_page_url.scheme() == url::kHttpScheme) || + (current_page_url.scheme() == url::kHttpsScheme); if (!scheme_allowed) return false;
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc index 450d46f..1c03cbb 100644 --- a/components/omnibox/browser/omnibox_field_trial.cc +++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -83,13 +83,6 @@ #endif }; -// Feature used to enable the transmission of HTTPS URLs as part of the -// context to the suggest server (assuming SearchProvider is permitted to -// transmit URLs for context in the first place). -const base::Feature kSearchProviderContextAllowHttpsUrls{ - "OmniboixSearchProviderContextAllowHttpsUrls", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Feature used for the Zero Suggest Redirect to Chrome Field Trial. const base::Feature kZeroSuggestRedirectToChrome{ "ZeroSuggestRedirectToChrome", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h index 0dffa8b..2ffeb6a 100644 --- a/components/omnibox/browser/omnibox_field_trial.h +++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -40,7 +40,6 @@ extern const base::Feature kEnableClipboardProvider; extern const base::Feature kAndroidChromeHomePersonalizedSuggestions; extern const base::Feature kSearchProviderWarmUpOnFocus; -extern const base::Feature kSearchProviderContextAllowHttpsUrls; extern const base::Feature kZeroSuggestRedirectToChrome; extern const base::Feature kZeroSuggestSwapTitleAndUrl; extern const base::Feature kDisplayTitleForCurrentUrl;
diff --git a/components/signin/ios/browser/BUILD.gn b/components/signin/ios/browser/BUILD.gn index 58c4fb0..53bcf126 100644 --- a/components/signin/ios/browser/BUILD.gn +++ b/components/signin/ios/browser/BUILD.gn
@@ -18,6 +18,8 @@ "profile_oauth2_token_service_ios_delegate.mm", "profile_oauth2_token_service_ios_provider.h", "profile_oauth2_token_service_ios_provider.mm", + "wait_for_network_callback_helper.cc", + "wait_for_network_callback_helper.h", ] deps = [ @@ -71,6 +73,7 @@ "account_consistency_service_unittest.mm", "active_state_manager_impl_unittest.mm", "profile_oauth2_token_service_ios_delegate_unittest.mm", + "wait_for_network_callback_helper_unittest.cc", ] deps = [
diff --git a/components/signin/ios/browser/ios_signin_client.cc b/components/signin/ios/browser/ios_signin_client.cc index e98a753..dd6da1b 100644 --- a/components/signin/ios/browser/ios_signin_client.cc +++ b/components/signin/ios/browser/ios_signin_client.cc
@@ -19,9 +19,9 @@ signin_error_controller_(signin_error_controller), cookie_settings_(cookie_settings), host_content_settings_map_(host_content_settings_map), - token_web_data_(token_web_data) { + token_web_data_(token_web_data), + callback_helper_(std::make_unique<WaitForNetworkCallbackHelper>()) { signin_error_controller_->AddObserver(this); - net::NetworkChangeNotifier::AddNetworkChangeObserver(this); } IOSSigninClient::~IOSSigninClient() { @@ -29,7 +29,7 @@ } void IOSSigninClient::Shutdown() { - net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); + callback_helper_.reset(); } scoped_refptr<TokenWebData> IOSSigninClient::GetDatabase() { @@ -89,24 +89,8 @@ return subscription; } -void IOSSigninClient::OnNetworkChanged( - net::NetworkChangeNotifier::ConnectionType type) { - if (type >= net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE) - return; - - for (const base::Closure& callback : delayed_callbacks_) - callback.Run(); - - delayed_callbacks_.clear(); -} - void IOSSigninClient::DelayNetworkCall(const base::Closure& callback) { - // Don't bother if we don't have any kind of network connection. - if (net::NetworkChangeNotifier::IsOffline()) { - delayed_callbacks_.push_back(callback); - } else { - callback.Run(); - } + callback_helper_->HandleCallback(callback); } std::unique_ptr<GaiaAuthFetcher> IOSSigninClient::CreateGaiaAuthFetcher(
diff --git a/components/signin/ios/browser/ios_signin_client.h b/components/signin/ios/browser/ios_signin_client.h index c65fdbb..010f5cd 100644 --- a/components/signin/ios/browser/ios_signin_client.h +++ b/components/signin/ios/browser/ios_signin_client.h
@@ -12,13 +12,12 @@ #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/signin/core/browser/signin_client.h" #include "components/signin/core/browser/signin_error_controller.h" -#include "net/base/network_change_notifier.h" #include "net/url_request/url_request_context_getter.h" +#include "components/signin/ios/browser/wait_for_network_callback_helper.h" // iOS specific signin client. class IOSSigninClient : public SigninClient, - public net::NetworkChangeNotifier::NetworkChangeObserver, public SigninErrorController::Observer { public: IOSSigninClient( @@ -57,10 +56,6 @@ // KeyedService implementation. void Shutdown() override; - // net::NetworkChangeController::NetworkChangeObserver implementation. - void OnNetworkChanged( - net::NetworkChangeNotifier::ConnectionType type) override; - private: PrefService* pref_service_; net::URLRequestContextGetter* url_request_context_; @@ -68,7 +63,7 @@ scoped_refptr<content_settings::CookieSettings> cookie_settings_; scoped_refptr<HostContentSettingsMap> host_content_settings_map_; scoped_refptr<TokenWebData> token_web_data_; - std::list<base::Closure> delayed_callbacks_; + std::unique_ptr<WaitForNetworkCallbackHelper> callback_helper_; DISALLOW_COPY_AND_ASSIGN(IOSSigninClient); };
diff --git a/components/signin/ios/browser/wait_for_network_callback_helper.cc b/components/signin/ios/browser/wait_for_network_callback_helper.cc new file mode 100644 index 0000000..fcec9a5f --- /dev/null +++ b/components/signin/ios/browser/wait_for_network_callback_helper.cc
@@ -0,0 +1,33 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/signin/ios/browser/wait_for_network_callback_helper.h" + +WaitForNetworkCallbackHelper::WaitForNetworkCallbackHelper() { + net::NetworkChangeNotifier::AddNetworkChangeObserver(this); +} + +WaitForNetworkCallbackHelper::~WaitForNetworkCallbackHelper() { + net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); +} + +void WaitForNetworkCallbackHelper::OnNetworkChanged( + net::NetworkChangeNotifier::ConnectionType type) { + if (net::NetworkChangeNotifier::IsOffline()) + return; + + for (const base::Closure& callback : delayed_callbacks_) + callback.Run(); + + delayed_callbacks_.clear(); +} + +void WaitForNetworkCallbackHelper::HandleCallback( + const base::Closure& callback) { + if (net::NetworkChangeNotifier::IsOffline()) { + delayed_callbacks_.push_back(callback); + } else { + callback.Run(); + } +}
diff --git a/components/signin/ios/browser/wait_for_network_callback_helper.h b/components/signin/ios/browser/wait_for_network_callback_helper.h new file mode 100644 index 0000000..6e77513 --- /dev/null +++ b/components/signin/ios/browser/wait_for_network_callback_helper.h
@@ -0,0 +1,36 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SIGNIN_IOS_BROWSER_WAIT_FOR_NETWORK_CALLBACK_HELPER_H_ +#define COMPONENTS_SIGNIN_IOS_BROWSER_WAIT_FOR_NETWORK_CALLBACK_HELPER_H_ + +#include <list> + +#include "base/callback.h" +#include "base/macros.h" +#include "net/base/network_change_notifier.h" + +// Class used for delaying callbacks when the network connection is offline and +// invoking them when the network connection becomes online. +class WaitForNetworkCallbackHelper + : public net::NetworkChangeNotifier::NetworkChangeObserver { + public: + WaitForNetworkCallbackHelper(); + ~WaitForNetworkCallbackHelper() override; + + // net::NetworkChangeController::NetworkChangeObserver implementation. + void OnNetworkChanged( + net::NetworkChangeNotifier::ConnectionType type) override; + + // If offline, saves the |callback| to be called later when online. Otherwise, + // invokes immediately. + void HandleCallback(const base::Closure& callback); + + private: + std::list<base::Closure> delayed_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(WaitForNetworkCallbackHelper); +}; + +#endif // COMPONENTS_SIGNIN_IOS_BROWSER_WAIT_FOR_NETWORK_CALLBACK_HELPER_H_
diff --git a/components/signin/ios/browser/wait_for_network_callback_helper_unittest.cc b/components/signin/ios/browser/wait_for_network_callback_helper_unittest.cc new file mode 100644 index 0000000..78fe1ca --- /dev/null +++ b/components/signin/ios/browser/wait_for_network_callback_helper_unittest.cc
@@ -0,0 +1,53 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/signin/ios/browser/wait_for_network_callback_helper.h" + +#include "base/bind.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "net/base/mock_network_change_notifier.h" +#include "testing/gtest/include/gtest/gtest.h" + +// A test fixture to test WaitForNetworkCallbackHelper. +class WaitForNetworkCallbackHelperTest : public testing::Test { + public: + void CallbackFunction() { num_callbacks_invoked_++; } + + protected: + WaitForNetworkCallbackHelperTest() : num_callbacks_invoked_(0) {} + + int num_callbacks_invoked_; + base::test::ScopedTaskEnvironment scoped_task_environment_; + net::test::MockNetworkChangeNotifier network_change_notifier_; + WaitForNetworkCallbackHelper callback_helper_; +}; + +TEST_F(WaitForNetworkCallbackHelperTest, CallbackInvokedImmediately) { + network_change_notifier_.SetConnectionType( + net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI); + callback_helper_.HandleCallback( + base::Bind(&WaitForNetworkCallbackHelperTest::CallbackFunction, + base::Unretained(this))); + EXPECT_EQ(1, num_callbacks_invoked_); +} + +TEST_F(WaitForNetworkCallbackHelperTest, CallbackInvokedLater) { + network_change_notifier_.SetConnectionType( + net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE); + callback_helper_.HandleCallback( + base::Bind(&WaitForNetworkCallbackHelperTest::CallbackFunction, + base::Unretained(this))); + callback_helper_.HandleCallback( + base::Bind(&WaitForNetworkCallbackHelperTest::CallbackFunction, + base::Unretained(this))); + EXPECT_EQ(0, num_callbacks_invoked_); + + network_change_notifier_.SetConnectionType( + net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI); + network_change_notifier_.NotifyObserversOfConnectionTypeChangeForTests( + net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI); + scoped_task_environment_.RunUntilIdle(); + EXPECT_EQ(2, num_callbacks_invoked_); +}
diff --git a/components/sync/engine_impl/cycle/nudge_tracker.cc b/components/sync/engine_impl/cycle/nudge_tracker.cc index 22f20e2d..40d26e5 100644 --- a/components/sync/engine_impl/cycle/nudge_tracker.cc +++ b/components/sync/engine_impl/cycle/nudge_tracker.cc
@@ -142,7 +142,7 @@ base::TimeDelta NudgeTracker::RecordLocalRefreshRequest(ModelTypeSet types) { for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) { TypeTrackerMap::const_iterator tracker_it = type_trackers_.find(it.Get()); - DCHECK(tracker_it != type_trackers_.end()); + DCHECK(tracker_it != type_trackers_.end()) << ModelTypeToString(it.Get()); tracker_it->second->RecordLocalRefreshRequest(); } return local_refresh_nudge_delay_;
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index 3da036b..0873afd 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -829,6 +829,19 @@ data->display->Resize(size); } +void GpuProcessTransportFactory::SetDisplayColorMatrix( + ui::Compositor* compositor, + const SkMatrix44& matrix) { + PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor); + if (it == per_compositor_data_.end()) + return; + PerCompositorData* data = it->second.get(); + DCHECK(data); + + if (data->display) + data->display->SetColorMatrix(matrix); +} + void GpuProcessTransportFactory::SetDisplayColorSpace( ui::Compositor* compositor, const gfx::ColorSpace& blending_color_space,
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h index a2c6a967..f59fcc5 100644 --- a/content/browser/compositor/gpu_process_transport_factory.h +++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -86,6 +86,8 @@ void SetDisplayVisible(ui::Compositor* compositor, bool visible) override; void ResizeDisplay(ui::Compositor* compositor, const gfx::Size& size) override; + void SetDisplayColorMatrix(ui::Compositor* compositor, + const SkMatrix44& matrix) override; void SetDisplayColorSpace(ui::Compositor* compositor, const gfx::ColorSpace& blending_color_space, const gfx::ColorSpace& output_color_space) override;
diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc index 2ce0aa2..888831be 100644 --- a/content/browser/compositor/viz_process_transport_factory.cc +++ b/content/browser/compositor/viz_process_transport_factory.cc
@@ -248,6 +248,15 @@ // Do nothing and resize when a CompositorFrame with a new size arrives. } +void VizProcessTransportFactory::SetDisplayColorMatrix( + ui::Compositor* compositor, + const SkMatrix44& matrix) { + auto iter = compositor_data_map_.find(compositor); + if (iter == compositor_data_map_.end() || !iter->second.display_private) + return; + iter->second.display_private->SetDisplayColorMatrix(gfx::Transform(matrix)); +} + void VizProcessTransportFactory::SetDisplayColorSpace( ui::Compositor* compositor, const gfx::ColorSpace& blending_color_space,
diff --git a/content/browser/compositor/viz_process_transport_factory.h b/content/browser/compositor/viz_process_transport_factory.h index 61e4cea..76f3201 100644 --- a/content/browser/compositor/viz_process_transport_factory.h +++ b/content/browser/compositor/viz_process_transport_factory.h
@@ -82,6 +82,8 @@ void SetDisplayVisible(ui::Compositor* compositor, bool visible) override; void ResizeDisplay(ui::Compositor* compositor, const gfx::Size& size) override; + void SetDisplayColorMatrix(ui::Compositor* compositor, + const SkMatrix44& matrix) override; void SetDisplayColorSpace(ui::Compositor* compositor, const gfx::ColorSpace& blending_color_space, const gfx::ColorSpace& output_color_space) override;
diff --git a/content/browser/download/parallel_download_utils.cc b/content/browser/download/parallel_download_utils.cc index 49fc009..f559998 100644 --- a/content/browser/download/parallel_download_utils.cc +++ b/content/browser/download/parallel_download_utils.cc
@@ -15,15 +15,15 @@ namespace { // Default value for |kMinSliceSizeFinchKey|, when no parameter is specified. -const int64_t kMinSliceSizeParallelDownload = 2097152; +const int64_t kMinSliceSizeParallelDownload = 1365333; // Default value for |kParallelRequestCountFinchKey|, when no parameter is // specified. -const int kParallelRequestCount = 2; +const int kParallelRequestCount = 3; // The default remaining download time in seconds required for parallel request // creation. -const int kDefaultRemainingTimeInSeconds = 10; +const int kDefaultRemainingTimeInSeconds = 2; // TODO(qinmin): replace this with a comparator operator in // DownloadItem::ReceivedSlice.
diff --git a/content/browser/media/media_canplaytype_browsertest.cc b/content/browser/media/media_canplaytype_browsertest.cc index 15bd97d..db8a7fe 100644 --- a/content/browser/media/media_canplaytype_browsertest.cc +++ b/content/browser/media/media_canplaytype_browsertest.cc
@@ -324,10 +324,6 @@ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"1\"'")); EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"theora, 1\"'")); - EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8\"'")); - EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8.0\"'")); - EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8, opus\"'")); - EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp8, vorbis\"'")); EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp08\"'")); EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"vp08.00.01.08.02.01.01.00\"'")); @@ -599,7 +595,7 @@ // by default. This test needs to be merged into the existing mp4 and webm // before release as well. http://crbug.com/784607 EXPECT_EQ(kProbably, CanPlay("'video/webm; codecs=\"av1\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"av1\"'")); + EXPECT_EQ(kProbably, CanPlay("'video/mp4; codecs=\"av1\"'")); } #endif // BUILDFLAG(ENABLE_AV1_DECODER) @@ -676,6 +672,10 @@ CanPlay("'video/ogg; codecs=\"theora, vorbis\"'")); EXPECT_EQ(kOggVideoProbably, CanPlay("'video/ogg; codecs=\"flac, opus, vorbis\"'")); + EXPECT_EQ(kOggVideoProbably, CanPlay("'video/ogg; codecs=\"vp8\"'")); + EXPECT_EQ(kOggVideoProbably, CanPlay("'video/ogg; codecs=\"vp8.0\"'")); + EXPECT_EQ(kOggVideoProbably, CanPlay("'video/ogg; codecs=\"vp8, opus\"'")); + EXPECT_EQ(kOggVideoProbably, CanPlay("'video/ogg; codecs=\"vp8, vorbis\"'")); TestOGGUnacceptableCombinations("video/ogg"); @@ -714,8 +714,8 @@ EXPECT_EQ(kProbably, CanPlay("'audio/ogg; codecs=\"flac\"'")); // See CodecSupportTest_mp4 for more flac combos. - EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"flac\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"flac\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mp4; codecs=\"flac\"'")); + EXPECT_EQ(kProbably, CanPlay("'video/mp4; codecs=\"flac\"'")); EXPECT_EQ(kNot, CanPlay("'video/flac'")); EXPECT_EQ(kNot, CanPlay("'video/x-flac'")); @@ -744,11 +744,11 @@ EXPECT_EQ(kNot, CanPlay("'video/x-mp3'")); // audio/mpeg without a codecs parameter (RFC 3003 compliant) - EXPECT_EQ(kPropProbably, CanPlay("'audio/mpeg'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mpeg'")); // audio/mpeg with mp3 in codecs parameter. (Not RFC compliant, but // very common in the wild so it is a defacto standard). - EXPECT_EQ(kPropProbably, CanPlay("'audio/mpeg; codecs=\"mp3\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mpeg; codecs=\"mp3\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc1\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"avc3\"'")); @@ -760,8 +760,8 @@ EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.67\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.68\"'")); // The next two results are wrong due to https://crbug.com/592889. - EXPECT_EQ(kPropProbably, CanPlay("'audio/mpeg; codecs=\"mp4a.69\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'audio/mpeg; codecs=\"mp4a.6B\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mpeg; codecs=\"mp4a.69\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mpeg; codecs=\"mp4a.6B\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.40.2\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mpeg; codecs=\"mp4a.40.02\"'")); @@ -770,7 +770,7 @@ TestMPEGUnacceptableCombinations("audio/mpeg"); // audio/mp3 does not allow any codecs parameter - EXPECT_EQ(kPropProbably, CanPlay("'audio/mp3'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mp3'")); EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc1\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"avc3\"'")); @@ -792,7 +792,7 @@ EXPECT_EQ(kNot, CanPlay("'audio/mp3; codecs=\"mp3\"'")); // audio/x-mp3 does not allow any codecs parameter - EXPECT_EQ(kPropProbably, CanPlay("'audio/x-mp3'")); + EXPECT_EQ(kProbably, CanPlay("'audio/x-mp3'")); EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc1\"'")); EXPECT_EQ(kNot, CanPlay("'audio/x-mp3; codecs=\"avc3\"'")); @@ -815,7 +815,7 @@ } IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) { - EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4'")); + EXPECT_EQ(kMaybe, CanPlay("'video/mp4'")); EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1\"'")); EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3\"'")); @@ -838,8 +838,8 @@ EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.66\"'")); EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.67\"'")); EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.68\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.69\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.6B\"'")); + EXPECT_EQ(kProbably, CanPlay("'video/mp4; codecs=\"mp4a.69\"'")); + EXPECT_EQ(kProbably, CanPlay("'video/mp4; codecs=\"mp4a.6B\"'")); EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.40.2\"'")); EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp4a.40.02\"'")); @@ -890,8 +890,8 @@ EXPECT_EQ(kHevcSupported, CanPlay("'video/mp4; codecs=\"hvc1.1.6.L93.B0, mp4a.40.5\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"vp09.00.10.08\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"flac\"'")); + EXPECT_EQ(kProbably, CanPlay("'video/mp4; codecs=\"vp09.00.10.08\"'")); + EXPECT_EQ(kProbably, CanPlay("'video/mp4; codecs=\"flac\"'")); EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"avc1.4D401E, flac\"'")); EXPECT_EQ(kPropProbably, @@ -899,7 +899,7 @@ TestMPEGUnacceptableCombinations("video/mp4"); // This result is incorrect. See https://crbug.com/592889. - EXPECT_EQ(kPropProbably, CanPlay("'video/mp4; codecs=\"mp3\"'")); + EXPECT_EQ(kProbably, CanPlay("'video/mp4; codecs=\"mp3\"'")); EXPECT_EQ(kPropMaybe, CanPlay("'video/x-m4v'")); @@ -973,12 +973,12 @@ TestMPEGUnacceptableCombinations("video/x-m4v"); - EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4'")); + EXPECT_EQ(kMaybe, CanPlay("'audio/mp4'")); EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.66\"'")); EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.67\"'")); EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.68\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.69\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.6B\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mp4; codecs=\"mp4a.69\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mp4; codecs=\"mp4a.6B\"'")); EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4; codecs=\"mp4a.40\"'")); EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.2\"'")); @@ -987,7 +987,7 @@ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.05\"'")); EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.40.29\"'")); - EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"flac\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mp4; codecs=\"flac\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc1\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"avc3\"'")); @@ -1013,7 +1013,7 @@ TestMPEGUnacceptableCombinations("audio/mp4"); // This result is incorrect. See https://crbug.com/592889. - EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp3\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mp4; codecs=\"mp3\"'")); EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a'")); @@ -1366,10 +1366,10 @@ EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.67\"'")); EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.68\"'")); // MP3. - EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.69\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mp4; codecs=\"mp4a.69\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6A\"'")); // MP3. - EXPECT_EQ(kPropProbably, CanPlay("'audio/mp4; codecs=\"mp4a.6B\"'")); + EXPECT_EQ(kProbably, CanPlay("'audio/mp4; codecs=\"mp4a.6B\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6b\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6C\"'")); EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"mp4a.6D\"'")); @@ -1540,16 +1540,11 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_NewVp9Variants) { const std::string kSupportedMimeTypes[] = {"video/webm", "video/mp4"}; for (const auto& mime_type : kSupportedMimeTypes) { - // MP4 support is conditional on supporting proprietary codecs. - const char* kTestProbably = kProbably; - if (base::EndsWith(mime_type, "mp4", base::CompareCase::SENSITIVE)) - kTestProbably = kPropProbably; - // Profile 2 and 3 support is currently disabled on ARM and MIPS. #if defined(ARCH_CPU_ARM_FAMILY) || defined(ARCH_CPU_MIPS_FAMILY) const char* kVP9Profile2And3Probably = kNot; #else - const char* kVP9Profile2And3Probably = kTestProbably; + const char* kVP9Profile2And3Probably = kProbably; #endif // E.g. "'video/webm; " @@ -1559,15 +1554,15 @@ EXPECT_EQ(kNot, CanPlay(prefix + "codecs=\"vp09.00.-1.08\"'")); // Test a few valid strings. - EXPECT_EQ(kTestProbably, CanPlay(prefix + "codecs=\"vp09.00.10.08\"'")); - EXPECT_EQ(kTestProbably, + EXPECT_EQ(kProbably, CanPlay(prefix + "codecs=\"vp09.00.10.08\"'")); + EXPECT_EQ(kProbably, CanPlay(prefix + "codecs=\"vp09.00.10.08.00.01.01.01.00\"'")); - EXPECT_EQ(kTestProbably, + EXPECT_EQ(kProbably, CanPlay(prefix + "codecs=\"vp09.00.10.08.01.02.02.02.00\"'")); // Profiles 0 and 1 are always supported supported. Profiles 2 and 3 are // only supported on certain architectures. - EXPECT_EQ(kTestProbably, CanPlay(prefix + "codecs=\"vp09.01.10.08\"'")); + EXPECT_EQ(kProbably, CanPlay(prefix + "codecs=\"vp09.01.10.08\"'")); EXPECT_EQ(kVP9Profile2And3Probably, CanPlay(prefix + "codecs=\"vp09.02.10.08\"'")); EXPECT_EQ(kVP9Profile2And3Probably,
diff --git a/content/browser/media/media_capabilities_browsertest.cc b/content/browser/media/media_capabilities_browsertest.cc index e8084e8..3c3e816 100644 --- a/content/browser/media/media_capabilities_browsertest.cc +++ b/content/browser/media/media_capabilities_browsertest.cc
@@ -133,6 +133,11 @@ kSupported, CanDecodeVideo(config_type, "'video/webm; codecs=\"vp09.00.10.08\"'")); + // VP09 is available in MP4 container irrespective of USE_PROPRIETARY_CODECS. + EXPECT_EQ( + kSupported, + CanDecodeVideo(config_type, "'video/mp4; codecs=\"vp09.00.10.08\"'")); + // Supported when built with USE_PROPRIETARY_CODECS EXPECT_EQ(kPropSupported, CanDecodeVideo(config_type, "'video/mp4; codecs=\"avc1.42E01E\"'")); @@ -142,9 +147,6 @@ CanDecodeVideo(config_type, "'video/mp4; codecs=\"avc1.42701E\"'")); EXPECT_EQ(kPropSupported, CanDecodeVideo(config_type, "'video/mp4; codecs=\"avc1.42F01E\"'")); - EXPECT_EQ( - kPropSupported, - CanDecodeVideo(config_type, "'video/mp4; codecs=\"vp09.00.10.08\"'")); // Test a handful of invalid strings. EXPECT_EQ(kUnsupported, @@ -172,14 +174,14 @@ CanDecodeAudio(config_type, "'audio/webm; codecs=\"opus\"'")); EXPECT_EQ(kSupported, CanDecodeAudio(config_type, "'audio/webm; codecs=\"vorbis\"'")); + EXPECT_EQ(kSupported, + CanDecodeAudio(config_type, "'audio/mp4; codecs=\"flac\"'")); + EXPECT_EQ(kSupported, CanDecodeAudio(config_type, "'audio/mpeg'")); // Supported when built with USE_PROPRIETARY_CODECS EXPECT_EQ(kPropSupported, CanDecodeAudio(config_type, "'audio/mp4; codecs=\"mp4a.40.02\"'")); EXPECT_EQ(kPropSupported, CanDecodeAudio(config_type, "'audio/aac'")); - EXPECT_EQ(kPropSupported, - CanDecodeAudio(config_type, "'audio/mp4; codecs=\"flac\"'")); - EXPECT_EQ(kPropSupported, CanDecodeAudio(config_type, "'audio/mpeg'")); // Test a handful of invalid strings. EXPECT_EQ(kUnsupported, @@ -219,7 +221,7 @@ CanDecodeAudio(config_type, "'audio/ogg; codecs=\"opus\"'")); // MP3 is only supported via audio/mpeg for MSE. - EXPECT_EQ(prop_type_supported, + EXPECT_EQ(type_supported, CanDecodeAudio(config_type, "'audio/mp4; codecs=\"mp4a.69\"'")); // Ogg not supported in MSE.
diff --git a/content/browser/pointer_lock_browsertest.cc b/content/browser/pointer_lock_browsertest.cc index dc8530c0..42070cd 100644 --- a/content/browser/pointer_lock_browsertest.cc +++ b/content/browser/pointer_lock_browsertest.cc
@@ -33,7 +33,6 @@ MockRenderWidgetHostView(RenderWidgetHost* host, bool is_guest_view_hack) : RenderWidgetHostViewAura(host, is_guest_view_hack, - false /* enable_surface_synchronization */, false /* is_mus_browser_plugin_guest */), host_(RenderWidgetHostImpl::From(host)) {} ~MockRenderWidgetHostView() override {
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc index d9d14af8..175c06d 100644 --- a/content/browser/renderer_host/delegated_frame_host.cc +++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -86,7 +86,8 @@ void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) { frame_evictor_->SetVisible(true); - if (!has_primary_surface_ && !released_front_lock_.get()) { + if (!enable_surface_synchronization_ && !HasFallbackSurface() && + !released_front_lock_.get()) { if (compositor_) released_front_lock_ = compositor_->GetCompositorLock(nullptr); } @@ -116,7 +117,7 @@ switches::kDisableResizeLock)) return; - if (!has_primary_surface_) + if (!HasFallbackSurface()) return; if (!client_->DelegatedFrameCanCreateResizeLock()) @@ -237,7 +238,7 @@ const gfx::PointF& point, RenderWidgetHostViewBase* target_view, gfx::PointF* transformed_point) { - if (!has_primary_surface_) + if (!HasFallbackSurface()) return false; return target_view->TransformPointToLocalCoordSpace( @@ -265,6 +266,18 @@ support_->DidNotProduceFrame(ack); } +bool DelegatedFrameHost::HasPrimarySurface() const { + const viz::SurfaceId* primary_surface_id = + client_->DelegatedFrameHostGetLayer()->GetPrimarySurfaceId(); + return primary_surface_id && primary_surface_id->is_valid(); +} + +bool DelegatedFrameHost::HasFallbackSurface() const { + const viz::SurfaceId* fallback_surface_id = + client_->DelegatedFrameHostGetLayer()->GetFallbackSurfaceId(); + return fallback_surface_id && fallback_surface_id->is_valid(); +} + bool DelegatedFrameHost::ShouldSkipFrame(const gfx::Size& size_in_dip) { if (!resize_lock_) return false; @@ -286,20 +299,13 @@ } void DelegatedFrameHost::WasResized() { - if (client_->DelegatedFrameHostDesiredSizeInDIP() != - current_frame_size_in_dip_ && - !client_->DelegatedFrameHostIsVisible()) { - EvictDelegatedFrame(); - } - - if (enable_surface_synchronization_) { + if (enable_surface_synchronization_ && + client_->DelegatedFrameHostIsVisible()) { current_frame_size_in_dip_ = client_->DelegatedFrameHostDesiredSizeInDIP(); viz::SurfaceId surface_id(frame_sink_id_, client_->GetLocalSurfaceId()); client_->DelegatedFrameHostGetLayer()->SetShowPrimarySurface( surface_id, current_frame_size_in_dip_, GetSurfaceReferenceFactory()); - has_primary_surface_ = true; - frame_evictor_->SwappedFrame(client_->DelegatedFrameHostIsVisible()); if (compositor_) compositor_->OnChildResizing(); // Input throttling and guttering are handled differently when surface @@ -307,6 +313,12 @@ return; } + if (client_->DelegatedFrameHostDesiredSizeInDIP() != + current_frame_size_in_dip_ && + !client_->DelegatedFrameHostIsVisible()) { + EvictDelegatedFrame(); + } + // If |create_resize_lock_after_commit_| is true, we're waiting to recreate // an expired resize lock after the next UI frame is submitted, so don't // make a lock here. @@ -323,7 +335,7 @@ } void DelegatedFrameHost::UpdateGutters() { - if (!has_primary_surface_ || enable_surface_synchronization_) { + if (!HasFallbackSurface() || enable_surface_synchronization_) { right_gutter_.reset(); bottom_gutter_.reset(); return; @@ -429,7 +441,7 @@ // To avoid unnecessary browser composites, try to go directly to the Surface // rather than through the Layer (which goes through the browser compositor). - if (has_primary_surface_ && + if (HasFallbackSurface() && request_copy_of_output_callback_for_testing_.is_null()) { support_->RequestCopyOfSurface(std::move(request)); } else { @@ -508,15 +520,8 @@ bool result = support_->SubmitCompositorFrame( local_surface_id, std::move(frame), std::move(hit_test_region_list)); DCHECK(result); - - DCHECK(enable_surface_synchronization_ || has_primary_surface_); } - if (!enable_surface_synchronization_) { - if (has_primary_surface_) - frame_evictor_->SwappedFrame(client_->DelegatedFrameHostIsVisible()); - // Note: the frame may have been evicted immediately. - } } void DelegatedFrameHost::ClearDelegatedFrame() { @@ -565,27 +570,24 @@ if (!enable_surface_synchronization_) { client_->DelegatedFrameHostGetLayer()->SetShowPrimarySurface( surface_info.id(), frame_size_in_dip, GetSurfaceReferenceFactory()); - has_primary_surface_ = true; } - // If surface synchronization is enabled, and we don't have a primary surface - // then that means it has been evicted, and so we have nothing to do here. - if (!has_primary_surface_) - return; - client_->DelegatedFrameHostGetLayer()->SetFallbackSurfaceId( surface_info.id()); local_surface_id_ = surface_info.id().local_surface_id(); // Surface synchronization deals with resizes in WasResized(). - if (enable_surface_synchronization_) - return; + if (!enable_surface_synchronization_) { + released_front_lock_ = nullptr; + current_frame_size_in_dip_ = frame_size_in_dip; + CheckResizeLock(); - released_front_lock_ = nullptr; - current_frame_size_in_dip_ = frame_size_in_dip; - CheckResizeLock(); + UpdateGutters(); + } - UpdateGutters(); + if (HasFallbackSurface()) + frame_evictor_->SwappedFrame(client_->DelegatedFrameHostIsVisible()); + // Note: the frame may have been evicted immediately. } void DelegatedFrameHost::OnFrameTokenChanged(uint32_t frame_token) { @@ -604,11 +606,19 @@ return; } - if (!has_primary_surface_) + if (!HasFallbackSurface()) return; + + if (enable_surface_synchronization_) { + client_->DelegatedFrameHostGetLayer()->SetFallbackSurfaceId( + viz::SurfaceId()); + support_->EvictCurrentSurface(); + frame_evictor_->DiscardedFrame(); + return; + } + client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent(); support_->EvictCurrentSurface(); - has_primary_surface_ = false; resize_lock_.reset(); frame_evictor_->DiscardedFrame(); UpdateGutters();
diff --git a/content/browser/renderer_host/delegated_frame_host.h b/content/browser/renderer_host/delegated_frame_host.h index 6766d00..c7a0c51 100644 --- a/content/browser/renderer_host/delegated_frame_host.h +++ b/content/browser/renderer_host/delegated_frame_host.h
@@ -198,7 +198,8 @@ return support_.get(); } - bool HasPrimarySurfaceForTesting() const { return has_primary_surface_; } + bool HasPrimarySurface() const; + bool HasFallbackSurface() const; void OnCompositingDidCommitForTesting(ui::Compositor* compositor) { OnCompositingDidCommit(compositor); @@ -346,7 +347,6 @@ bool needs_begin_frame_ = false; - bool has_primary_surface_ = false; viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink_ = nullptr;
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 429dff66..0f867aa 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -1099,8 +1099,7 @@ std::unique_ptr<RenderWidgetHostViewBase> view; #if defined(USE_AURA) view.reset(new RenderWidgetHostViewAura( - host_.get(), false, false /* enable_surface_synchronization */, - false /* is_mus_browser_plugin_guest */)); + host_.get(), false, false /* is_mus_browser_plugin_guest */)); // TODO(derat): Call this on all platforms: http://crbug.com/102450. view->InitAsChild(nullptr); #elif defined(OS_ANDROID)
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 46a5b64..10c475f 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/command_line.h" +#include "base/debug/stack_trace.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" @@ -20,6 +21,7 @@ #include "build/build_config.h" #include "cc/layers/layer.h" #include "cc/trees/layer_tree_settings.h" +#include "components/viz/common/features.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/common/frame_sinks/copy_output_result.h" #include "components/viz/common/gl_helper.h" @@ -389,10 +391,8 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura( RenderWidgetHost* host, bool is_guest_view_hack, - bool enable_surface_synchronization, bool is_mus_browser_plugin_guest) : host_(RenderWidgetHostImpl::From(host)), - enable_surface_synchronization_(enable_surface_synchronization), is_mus_browser_plugin_guest_(is_mus_browser_plugin_guest), window_(nullptr), in_shutdown_(false), @@ -1988,7 +1988,7 @@ base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableViz); delegated_frame_host_ = std::make_unique<DelegatedFrameHost>( frame_sink_id_, delegated_frame_host_client_.get(), - enable_surface_synchronization_, enable_viz); + features::IsSurfaceSynchronizationEnabled(), enable_viz); if (renderer_compositor_frame_sink_) { delegated_frame_host_->DidCreateNewRendererCompositorFrameSink(
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 8e29d81..80e0dee 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -97,7 +97,6 @@ // |is_mus_browser_plugin_guest| can be removed at the same time. RenderWidgetHostViewAura(RenderWidgetHost* host, bool is_guest_view_hack, - bool enable_surface_synchronization, bool is_mus_browser_plugin_guest); // RenderWidgetHostView implementation. @@ -512,8 +511,6 @@ // The model object. RenderWidgetHostImpl* const host_; - const bool enable_surface_synchronization_; - const bool is_mus_browser_plugin_guest_; // NOTE: this is null if |is_mus_browser_plugin_guest_| is true.
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index a75f6aa0..10cab06 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -23,6 +23,7 @@ #include "base/test/simple_test_tick_clock.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "components/viz/common/features.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/common/gl_helper.h" @@ -499,11 +500,9 @@ class FakeRenderWidgetHostViewAura : public RenderWidgetHostViewAura { public: FakeRenderWidgetHostViewAura(RenderWidgetHost* widget, - bool is_guest_view_hack, - bool enable_surface_synchronization) + bool is_guest_view_hack) : RenderWidgetHostViewAura(widget, is_guest_view_hack, - enable_surface_synchronization, false /* is_mus_browser_plugin_guest */), delegated_frame_host_client_( new FakeDelegatedFrameHostClientAura(this)) { @@ -560,7 +559,11 @@ } bool HasPrimarySurface() const { - return GetDelegatedFrameHost()->HasPrimarySurfaceForTesting(); + return GetDelegatedFrameHost()->HasPrimarySurface(); + } + + bool HasFallbackSurface() const { + return GetDelegatedFrameHost()->HasFallbackSurface(); } bool released_front_lock_active() const { @@ -707,7 +710,7 @@ std::move(delegated_frame_host_client); } - void SetUpEnvironment(bool enable_surface_synchronization) { + void SetUpEnvironment() { mojo_feature_list_.InitAndEnableFeature(features::kMojoInputMessages); ImageTransportFactory::SetFactory( std::make_unique<NoTransportImageTransportFactory>()); @@ -730,8 +733,7 @@ delegates_.back()->set_widget_host(parent_host_); const bool is_mus_browser_plugin_guest = false; parent_view_ = new RenderWidgetHostViewAura( - parent_host_, is_guest_view_hack_, enable_surface_synchronization, - is_mus_browser_plugin_guest); + parent_host_, is_guest_view_hack_, is_mus_browser_plugin_guest); parent_view_->InitAsChild(nullptr); aura::client::ParentWindowWithContext(parent_view_->GetNativeView(), aura_test_helper_->root_window(), @@ -743,8 +745,7 @@ process_host_, routing_id); delegates_.back()->set_widget_host(widget_host_); widget_host_->Init(); - view_ = new FakeRenderWidgetHostViewAura(widget_host_, is_guest_view_hack_, - enable_surface_synchronization); + view_ = new FakeRenderWidgetHostViewAura(widget_host_, is_guest_view_hack_); base::RunLoop().RunUntilIdle(); } @@ -777,9 +778,7 @@ ImageTransportFactory::Terminate(); } - void SetUp() override { - SetUpEnvironment(false /* enable_surface_synchronization */); - } + void SetUp() override { SetUpEnvironment(); } void TearDown() override { TearDownEnvironment(); } @@ -912,8 +911,13 @@ class RenderWidgetHostViewAuraSurfaceSynchronizationTest : public RenderWidgetHostViewAuraTest { void SetUp() override { - SetUpEnvironment(true /* enable_surface_synchronization */); + surface_synchronization_feature_list_.InitAndEnableFeature( + features::kEnableSurfaceSynchronization); + SetUpEnvironment(); } + + private: + base::test::ScopedFeatureList surface_synchronization_feature_list_; }; class RenderWidgetHostViewAuraWheelScrollLatchingEnabledTest @@ -3123,7 +3127,7 @@ view_->SetSize(gfx::Size(300, 300)); ASSERT_TRUE(view_->HasPrimarySurface()); EXPECT_EQ(gfx::Size(300, 300), view_->window_->layer()->size()); - EXPECT_FALSE(view_->window_->layer()->GetFallbackSurfaceId()->is_valid()); + EXPECT_FALSE(view_->HasFallbackSurface()); EXPECT_EQ(gfx::Size(300, 300), view_->delegated_frame_host_->CurrentFrameSizeInDipForTesting()); @@ -3134,7 +3138,7 @@ EXPECT_EQ(gfx::Size(400, 400), view_->delegated_frame_host_->CurrentFrameSizeInDipForTesting()); - // Submitting a CompositorFrame should update the fallback SurfaceInfo + // Submitting a CompositorFrame should update the fallback SurfaceId view_->SubmitCompositorFrame( kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, gfx::Size(400, 400), gfx::Rect(400, 400)), @@ -3142,31 +3146,6 @@ EXPECT_EQ(gfx::Size(400, 400), view_->window_->layer()->size()); } -// This test verifies that even if the primary surface is evicted after -// the view is hidden, when it is shown again, the layer is repopulated. -TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest, HideThenShow) { - view_->InitAsChild(nullptr); - aura::client::ParentWindowWithContext( - view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), - gfx::Rect()); - - EXPECT_FALSE(view_->HasPrimarySurface()); - ASSERT_TRUE(view_->delegated_frame_host_); - - view_->SetSize(gfx::Size(300, 300)); - ASSERT_TRUE(view_->HasPrimarySurface()); - EXPECT_EQ(gfx::Size(300, 300), view_->window_->layer()->size()); - EXPECT_EQ(gfx::Size(300, 300), - view_->delegated_frame_host_->CurrentFrameSizeInDipForTesting()); - - view_->Hide(); - view_->delegated_frame_host_->ClearDelegatedFrame(); - ASSERT_FALSE(view_->HasPrimarySurface()); - - view_->Show(); - ASSERT_TRUE(view_->HasPrimarySurface()); -} - // This test verifies that the primary SurfaceInfo is updated on device scale // factor changes. TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest, @@ -3226,9 +3205,7 @@ // This test verifies that frame eviction plays well with surface // synchronizaton. This test is similar to -// RenderWidgetHostViewAuraTest.DiscardDelegatedFrame but resizes instead -// of submitting frame as that's when the primary surface is set when -// surface synchronization is on. +// RenderWidgetHostViewAuraTest.DiscardDelegatedFrame. TEST_F(RenderWidgetHostViewAuraSurfaceSynchronizationTest, DiscardDelegatedFrames) { view_->InitAsChild(nullptr); @@ -3237,6 +3214,8 @@ FrameEvictionManager::GetInstance()->GetMaxNumberOfSavedFrames(); ASSERT_LE(2u, max_renderer_frames); size_t renderer_count = max_renderer_frames + 1; + gfx::Rect view_rect(100, 100); + gfx::Size frame_size = view_rect.size(); std::unique_ptr<RenderWidgetHostImpl* []> hosts( new RenderWidgetHostImpl*[renderer_count]); @@ -3251,8 +3230,7 @@ process_host_, routing_id); delegates_.back()->set_widget_host(hosts[i]); hosts[i]->Init(); - views[i] = new FakeRenderWidgetHostViewAura( - hosts[i], false, true /* enable_surface_synchronization */); + views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false); // Prevent frames from being skipped due to resize, this test does not // run a UI compositor so the DelegatedFrameHost doesn't get the chance // to release its resize lock once it receives a frame of the expected @@ -3262,64 +3240,101 @@ aura::client::ParentWindowWithContext( views[i]->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), gfx::Rect()); - // Make each renderer visible, resize it, then make it invisible. + views[i]->SetSize(view_rect.size()); + ASSERT_TRUE(views[i]->HasPrimarySurface()); + } + + // Make each renderer visible, and swap a frame on it, then make it invisible. + for (size_t i = 0; i < renderer_count; ++i) { views[i]->Show(); - views[i]->SetSize(gfx::Size(300, 300)); - EXPECT_TRUE(views[i]->HasPrimarySurface()); + ASSERT_TRUE(views[i]->HasPrimarySurface()); + ASSERT_FALSE(views[i]->HasFallbackSurface()); + views[i]->SubmitCompositorFrame( + kArbitraryLocalSurfaceId, + MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); + ASSERT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); views[i]->Hide(); } // There should be max_renderer_frames with a frame in it, and one without it. // Since the logic is LRU eviction, the first one should be without. - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); for (size_t i = 1; i < renderer_count; ++i) - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); // LRU renderer is [0], make it visible, it shouldn't evict anything yet. views[0]->Show(); - EXPECT_TRUE(views[0]->HasPrimarySurface()); - EXPECT_FALSE(views[1]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); + EXPECT_TRUE(views[1]->HasFallbackSurface()); - // Resize [0], it should evict the next LRU [1]. - views[0]->SetSize(gfx::Size(300, 300)); - EXPECT_TRUE(views[0]->HasPrimarySurface()); - EXPECT_FALSE(views[1]->HasPrimarySurface()); + // Swap a frame on it, it should evict the next LRU [1]. + views[0]->SubmitCompositorFrame( + kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), + nullptr); + EXPECT_TRUE(views[0]->HasFallbackSurface()); + EXPECT_FALSE(views[1]->HasFallbackSurface()); views[0]->Hide(); - // LRU renderer is [1], still hidden. Resize it, it should evict + // LRU renderer is [1], still hidden. Swap a frame on it, it should evict // the next LRU [2]. - views[1]->Show(); - views[1]->SetSize(gfx::Size(300, 300)); - views[1]->Hide(); - EXPECT_TRUE(views[0]->HasPrimarySurface()); - EXPECT_TRUE(views[1]->HasPrimarySurface()); - EXPECT_FALSE(views[2]->HasPrimarySurface()); + views[1]->SubmitCompositorFrame( + kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), + nullptr); + EXPECT_TRUE(views[0]->HasFallbackSurface()); + EXPECT_TRUE(views[1]->HasFallbackSurface()); + EXPECT_FALSE(views[2]->HasFallbackSurface()); for (size_t i = 3; i < renderer_count; ++i) - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); - // Make all renderers but [0] visible and resize them, keep [0] + // Make all renderers but [0] visible and swap a frame on them, keep [0] // hidden, it becomes the LRU. for (size_t i = 1; i < renderer_count; ++i) { views[i]->Show(); - views[i]->SetSize(gfx::Size(300, 300)); - EXPECT_TRUE(views[i]->HasPrimarySurface()); + // The renderers who don't have a frame should be waiting. The ones that + // have a frame should not. + views[i]->SubmitCompositorFrame( + kArbitraryLocalSurfaceId, + MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); + EXPECT_TRUE(views[i]->HasFallbackSurface()); } - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); - // Resize [0], it should be evicted immediately. - views[0]->SetSize(gfx::Size(300, 300)); - EXPECT_FALSE(views[0]->HasPrimarySurface()); + // Swap a frame on [0], it should be evicted immediately. + views[0]->SubmitCompositorFrame( + kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), + nullptr); + EXPECT_FALSE(views[0]->HasFallbackSurface()); // Make [0] visible, and swap a frame on it. Nothing should be evicted // although we're above the limit. views[0]->Show(); - views[0]->SetSize(gfx::Size(300, 300)); + views[0]->SubmitCompositorFrame( + kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), + nullptr); for (size_t i = 0; i < renderer_count; ++i) - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); // Make [0] hidden, it should evict its frame. views[0]->Hide(); - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); + + // Make [0] visible, don't give it a frame, it should be waiting. + views[0]->Show(); + // Make [0] hidden, it should stop waiting. + views[0]->Hide(); + + // Make [1] hidden, resize it. It should drop its frame. + views[1]->Hide(); + EXPECT_TRUE(views[1]->HasFallbackSurface()); + gfx::Size size2(200, 200); + viz::LocalSurfaceId id2 = parent_local_surface_id_allocator_.GenerateId(); + views[1]->SetSize(size2); + EXPECT_FALSE(views[1]->HasFallbackSurface()); + // Show it, it should block until we give it a frame. + views[1]->Show(); + views[1]->SubmitCompositorFrame( + id2, MakeDelegatedFrame(1.f, size2, gfx::Rect(size2)), nullptr); for (size_t i = 0; i < renderer_count; ++i) { views[i]->Destroy(); @@ -3350,8 +3365,7 @@ process_host_, routing_id); delegates_.back()->set_widget_host(hosts[i]); hosts[i]->Init(); - views[i] = new FakeRenderWidgetHostViewAura( - hosts[i], false, false /* enable_surface_synchronization */); + views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false); // Prevent frames from being skipped due to resize, this test does not // run a UI compositor so the DelegatedFrameHost doesn't get the chance // to release its resize lock once it receives a frame of the expected @@ -3371,20 +3385,20 @@ views[i]->SubmitCompositorFrame( kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); views[i]->Hide(); } // There should be max_renderer_frames with a frame in it, and one without it. // Since the logic is LRU eviction, the first one should be without. - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); for (size_t i = 1; i < renderer_count; ++i) - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); // LRU renderer is [0], make it visible, it shouldn't evict anything yet. views[0]->Show(); - EXPECT_FALSE(views[0]->HasPrimarySurface()); - EXPECT_TRUE(views[1]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); + EXPECT_TRUE(views[1]->HasFallbackSurface()); // Since [0] doesn't have a frame, it should be waiting for the renderer to // give it one. EXPECT_TRUE(views[0]->released_front_lock_active()); @@ -3393,8 +3407,8 @@ views[0]->SubmitCompositorFrame( kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); - EXPECT_TRUE(views[0]->HasPrimarySurface()); - EXPECT_FALSE(views[1]->HasPrimarySurface()); + EXPECT_TRUE(views[0]->HasFallbackSurface()); + EXPECT_FALSE(views[1]->HasFallbackSurface()); // Now that [0] got a frame, it shouldn't be waiting any more. EXPECT_FALSE(views[0]->released_front_lock_active()); views[0]->Hide(); @@ -3404,11 +3418,11 @@ views[1]->SubmitCompositorFrame( kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); - EXPECT_TRUE(views[0]->HasPrimarySurface()); - EXPECT_TRUE(views[1]->HasPrimarySurface()); - EXPECT_FALSE(views[2]->HasPrimarySurface()); + EXPECT_TRUE(views[0]->HasFallbackSurface()); + EXPECT_TRUE(views[1]->HasFallbackSurface()); + EXPECT_FALSE(views[2]->HasFallbackSurface()); for (size_t i = 3; i < renderer_count; ++i) - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); // Make all renderers but [0] visible and swap a frame on them, keep [0] // hidden, it becomes the LRU. @@ -3417,22 +3431,22 @@ // The renderers who don't have a frame should be waiting. The ones that // have a frame should not. // In practice, [1] has a frame, but anything after has its frame evicted. - EXPECT_EQ(!views[i]->HasPrimarySurface(), + EXPECT_EQ(!views[i]->HasFallbackSurface(), views[i]->released_front_lock_active()); views[i]->SubmitCompositorFrame( kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); // Now everyone has a frame. EXPECT_FALSE(views[i]->released_front_lock_active()); - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); } - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); // Swap a frame on [0], it should be evicted immediately. views[0]->SubmitCompositorFrame( kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); // Make [0] visible, and swap a frame on it. Nothing should be evicted // although we're above the limit. @@ -3444,11 +3458,11 @@ nullptr); EXPECT_FALSE(views[0]->released_front_lock_active()); for (size_t i = 0; i < renderer_count; ++i) - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); // Make [0] hidden, it should evict its frame. views[0]->Hide(); - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); // Make [0] visible, don't give it a frame, it should be waiting. views[0]->Show(); @@ -3459,11 +3473,11 @@ // Make [1] hidden, resize it. It should drop its frame. views[1]->Hide(); - EXPECT_TRUE(views[1]->HasPrimarySurface()); + EXPECT_TRUE(views[1]->HasFallbackSurface()); gfx::Size size2(200, 200); viz::LocalSurfaceId id2 = parent_local_surface_id_allocator_.GenerateId(); views[1]->SetSize(size2); - EXPECT_FALSE(views[1]->HasPrimarySurface()); + EXPECT_FALSE(views[1]->HasFallbackSurface()); // Show it, it should block until we give it a frame. views[1]->Show(); EXPECT_TRUE(views[1]->released_front_lock_active()); @@ -3500,8 +3514,7 @@ process_host_, routing_id); delegates_.back()->set_widget_host(hosts[i]); hosts[i]->Init(); - views[i] = new FakeRenderWidgetHostViewAura( - hosts[i], false, false /* enable_surface_synchronization */); + views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false); views[i]->InitAsChild(nullptr); aura::client::ParentWindowWithContext( views[i]->GetNativeView(), @@ -3518,26 +3531,26 @@ i ? parent_local_surface_id_allocator_.GenerateId() : kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); } // If we hide [0], then [0] should be evicted. views[0]->Hide(); - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); // If we lock [0] before hiding it, then [0] should not be evicted. views[0]->Show(); views[0]->SubmitCompositorFrame( kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); - EXPECT_TRUE(views[0]->HasPrimarySurface()); + EXPECT_TRUE(views[0]->HasFallbackSurface()); views[0]->GetDelegatedFrameHost()->LockResources(); views[0]->Hide(); - EXPECT_TRUE(views[0]->HasPrimarySurface()); + EXPECT_TRUE(views[0]->HasFallbackSurface()); // If we unlock [0] now, then [0] should be evicted. views[0]->GetDelegatedFrameHost()->UnlockResources(); - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); for (size_t i = 0; i < renderer_count; ++i) { views[i]->Destroy(); @@ -3575,8 +3588,7 @@ process_host_, routing_id); delegates_.back()->set_widget_host(hosts[i]); hosts[i]->Init(); - views[i] = new FakeRenderWidgetHostViewAura( - hosts[i], false, false /* enable_surface_synchronization */); + views[i] = new FakeRenderWidgetHostViewAura(hosts[i], false); views[i]->InitAsChild(nullptr); aura::client::ParentWindowWithContext( views[i]->GetNativeView(), @@ -3592,27 +3604,27 @@ views[i]->SubmitCompositorFrame( kArbitraryLocalSurfaceId, MakeDelegatedFrame(1.f, frame_size, view_rect), nullptr); - EXPECT_TRUE(views[i]->HasPrimarySurface()); + EXPECT_TRUE(views[i]->HasFallbackSurface()); } // If we hide one, it should not get evicted. views[0]->Hide(); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(views[0]->HasPrimarySurface()); + EXPECT_TRUE(views[0]->HasFallbackSurface()); // Using a lesser memory pressure event however, should evict. SimulateMemoryPressure( base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(views[0]->HasPrimarySurface()); + EXPECT_FALSE(views[0]->HasFallbackSurface()); // Check the same for a higher pressure event. views[1]->Hide(); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(views[1]->HasPrimarySurface()); + EXPECT_TRUE(views[1]->HasFallbackSurface()); SimulateMemoryPressure( base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(views[1]->HasPrimarySurface()); + EXPECT_FALSE(views[1]->HasFallbackSurface()); for (size_t i = 0; i < renderer_count; ++i) { views[i]->Destroy(); @@ -6029,7 +6041,6 @@ // This instance is destroyed in the TearDown method below. view_ = new RenderWidgetHostViewAura( contents()->GetRenderViewHost()->GetWidget(), false, - false /* enable_surface_synchronization */, false /* is_mus_browser_plugin_guest */); }
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc index ceafaba..7d17c87 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -545,7 +545,6 @@ completed_overscroll_gesture_(OVERSCROLL_NONE), navigation_overlay_(nullptr), init_rwhv_with_null_parent_for_testing_(false) { - enable_surface_synchronization_ = features::IsSurfaceSynchronizationEnabled(); } void WebContentsViewAura::SetDelegateForTesting( @@ -905,7 +904,6 @@ ? g_create_render_widget_host_view(render_widget_host, is_guest_view_hack) : new RenderWidgetHostViewAura(render_widget_host, is_guest_view_hack, - enable_surface_synchronization_, is_mus_browser_plugin_guest_); view->InitAsChild(GetRenderWidgetHostViewParent()); @@ -936,7 +934,6 @@ // |is_mus_browser_plugin_guest| is always false for them. const bool is_mus_browser_plugin_guest = false; return new RenderWidgetHostViewAura(render_widget_host, false, - enable_surface_synchronization_, is_mus_browser_plugin_guest); }
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h index 7b2078f5..3e0cf1b 100644 --- a/content/browser/web_contents/web_contents_view_aura.h +++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -201,8 +201,6 @@ const bool is_mus_browser_plugin_guest_; - bool enable_surface_synchronization_ = false; - // NOTE: this is null when running in mus and |is_mus_browser_plugin_guest_|. std::unique_ptr<aura::Window> window_;
diff --git a/content/child/OWNERS b/content/child/OWNERS index 2029635..e9510bd4 100644 --- a/content/child/OWNERS +++ b/content/child/OWNERS
@@ -1,8 +1,5 @@ haraken@chromium.org -# For Blink API usage -dglazkov@chromium.org - # AppCache per-file appcache*=michaeln@chromium.org
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index fb1f64a..01c869c 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -228,7 +228,13 @@ // Whether a download can be handled by parallel jobs. const base::Feature kParallelDownloading{ - "ParallelDownloading", base::FEATURE_DISABLED_BY_DEFAULT}; + "ParallelDownloading", +#if defined(OS_ANDROID) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; // Whether document level event listeners should default 'passive' to true. const base::Feature kPassiveDocumentEventListeners{
diff --git a/content/renderer/OWNERS b/content/renderer/OWNERS index 91c0867c..c367d110 100644 --- a/content/renderer/OWNERS +++ b/content/renderer/OWNERS
@@ -1,8 +1,5 @@ haraken@chromium.org -# For Blink API usage -dglazkov@chromium.org - # Mac Sandbox profiles. per-file *.sb=set noparent per-file *.sb=rsesek@chromium.org
diff --git a/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc b/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc index 96b3648..a1f790e 100644 --- a/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc +++ b/content/shell/renderer/layout_test/layout_test_content_renderer_client.cc
@@ -30,6 +30,7 @@ #include "content/shell/test_runner/web_test_runner.h" #include "content/shell/test_runner/web_view_test_proxy.h" #include "content/test/mock_webclipboard_impl.h" +#include "gin/modules/module_registry.h" #include "media/base/audio_latency.h" #include "media/base/mime_util.h" #include "media/media_features.h"
diff --git a/device/BUILD.gn b/device/BUILD.gn index 1144edb..03053e04 100644 --- a/device/BUILD.gn +++ b/device/BUILD.gn
@@ -251,6 +251,8 @@ if (enable_vr && is_android) { sources += [ + "vr/orientation/orientation_device_provider_unittest.cc", + "vr/orientation/orientation_device_unittest.cc", "vr/vr_device_base_unittest.cc", "vr/vr_display_impl_unittest.cc", ] @@ -260,6 +262,8 @@ "//device/vr:fakes", "//device/vr:java", "//device/vr:mojo_bindings", + "//services/device/public/cpp/generic_sensor", + "//ui/display", ] } }
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn index 27081d6..05ee861 100644 --- a/device/vr/BUILD.gn +++ b/device/vr/BUILD.gn
@@ -22,6 +22,10 @@ "features", ] sources += [ + "orientation/orientation_device.cc", + "orientation/orientation_device.h", + "orientation/orientation_device_provider.cc", + "orientation/orientation_device_provider.h", "vr_device.h", "vr_device_base.cc", "vr_device_base.h", @@ -34,6 +38,9 @@ "//base", "//gpu/ipc/common:interfaces", "//mojo/public/cpp/bindings", + "//services/device/public/cpp/generic_sensor", + "//services/service_manager/public/cpp", + "//ui/display", "//ui/gfx", ] @@ -110,6 +117,10 @@ defines = [ "DEVICE_VR_IMPLEMENTATION" ] sources = [ + "test/fake_orientation_provider.cc", + "test/fake_orientation_provider.h", + "test/fake_sensor_provider.cc", + "test/fake_sensor_provider.h", "test/fake_vr_device.cc", "test/fake_vr_device.h", "test/fake_vr_device_provider.cc", @@ -128,6 +139,7 @@ ":vr", "//base", "//mojo/public/cpp/bindings", + "//services/device/public/cpp/generic_sensor", "//testing/gmock", ] }
diff --git a/device/vr/DEPS b/device/vr/DEPS index eca72cd..5714690 100644 --- a/device/vr/DEPS +++ b/device/vr/DEPS
@@ -2,8 +2,10 @@ "+device/gamepad/public/cpp/gamepads.h", "+gpu/command_buffer/common/mailbox_holder.h", "+jni", + "+services/device/public", "+third_party/WebKit/public/platform/modules/vr/vr_service.mojom.h", "+third_party/gvr-android-sdk/src", "+third_party/openvr/src/headers/openvr.h", + "+ui/display", "+ui/gfx", ]
diff --git a/device/vr/orientation/orientation_device.cc b/device/vr/orientation/orientation_device.cc new file mode 100644 index 0000000..3913108 --- /dev/null +++ b/device/vr/orientation/orientation_device.cc
@@ -0,0 +1,211 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <math.h> + +#include "base/memory/ptr_util.h" +#include "base/numerics/math_constants.h" +#include "base/time/time.h" +#include "device/vr/orientation/orientation_device.h" +#include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h" +#include "services/device/public/interfaces/sensor_provider.mojom.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/quaternion.h" +#include "ui/gfx/geometry/vector3d_f.h" + +namespace device { + +using mojom::SensorType; +using gfx::Quaternion; +using gfx::Vector3dF; + +namespace { +static constexpr int kDefaultPumpFrequencyHz = 60; + +mojom::VRDisplayInfoPtr CreateVRDisplayInfo(unsigned int id) { + static const char DEVICE_NAME[] = "VR Orientation Device"; + + mojom::VRDisplayInfoPtr display_info = mojom::VRDisplayInfo::New(); + display_info->index = id; + display_info->displayName = DEVICE_NAME; + display_info->capabilities = mojom::VRDisplayCapabilities::New(); + display_info->capabilities->hasPosition = false; + display_info->capabilities->hasExternalDisplay = false; + display_info->capabilities->canPresent = false; + + return display_info; +} + +display::Display::Rotation GetRotation() { + display::Screen* screen = display::Screen::GetScreen(); + if (!screen) { + // If we can't get rotation we'll assume it's 0. + return display::Display::ROTATE_0; + } + + return screen->GetPrimaryDisplay().rotation(); +} + +} // namespace + +VROrientationDevice::VROrientationDevice( + mojom::SensorProviderPtr* sensor_provider, + base::OnceClosure ready_callback) + : ready_callback_(std::move(ready_callback)), binding_(this) { + (*sensor_provider) + ->GetSensor(SensorType::ABSOLUTE_ORIENTATION_QUATERNION, + base::BindOnce(&VROrientationDevice::SensorReady, + base::Unretained(this))); + + SetVRDisplayInfo(CreateVRDisplayInfo(GetId())); +} + +VROrientationDevice::~VROrientationDevice() = default; + +void VROrientationDevice::SensorReady( + device::mojom::SensorInitParamsPtr params) { + if (!params) { + // This means that there are no orientation sensors on this device. + HandleSensorError(); + std::move(ready_callback_).Run(); + return; + } + + constexpr size_t kReadBufferSize = sizeof(device::SensorReadingSharedBuffer); + + DCHECK_EQ(0u, params->buffer_offset % kReadBufferSize); + + device::PlatformSensorConfiguration default_config = + params->default_configuration; + + sensor_.Bind(std::move(params->sensor)); + + binding_.Bind(std::move(params->client_request)); + + shared_buffer_handle_ = std::move(params->memory); + DCHECK(!shared_buffer_); + shared_buffer_ = shared_buffer_handle_->MapAtOffset(kReadBufferSize, + params->buffer_offset); + + if (!shared_buffer_) { + // If we cannot read data, we cannot supply a device. + HandleSensorError(); + std::move(ready_callback_).Run(); + return; + } + + const device::SensorReadingSharedBuffer* buffer = + static_cast<const device::SensorReadingSharedBuffer*>( + shared_buffer_.get()); + shared_buffer_reader_.reset( + new device::SensorReadingSharedBufferReader(buffer)); + + default_config.set_frequency(kDefaultPumpFrequencyHz); + sensor_.set_connection_error_handler(base::BindOnce( + &VROrientationDevice::HandleSensorError, base::Unretained(this))); + sensor_->ConfigureReadingChangeNotifications(false /* disabled */); + sensor_->AddConfiguration( + default_config, + base::BindOnce(&VROrientationDevice::OnSensorAddConfiguration, + base::Unretained(this))); +} + +// Mojo callback for Sensor::AddConfiguration(). +void VROrientationDevice::OnSensorAddConfiguration(bool success) { + if (!success) { + // Sensor config is not supported so we can't provide sensor events. + HandleSensorError(); + } else { + // We're good to go. + available_ = true; + } + + std::move(ready_callback_).Run(); +} + +void VROrientationDevice::RaiseError() { + HandleSensorError(); +} + +void VROrientationDevice::HandleSensorError() { + sensor_.reset(); + shared_buffer_handle_.reset(); + shared_buffer_.reset(); + binding_.Close(); +} + +void VROrientationDevice::OnMagicWindowPoseRequest( + mojom::VRMagicWindowProvider::GetPoseCallback callback) { + mojom::VRPosePtr pose = mojom::VRPose::New(); + pose->orientation.emplace(4); + + SensorReading latest_reading; + // If the reading fails just return the last pose that we got. + if (shared_buffer_reader_->GetReading(&latest_reading)) { + latest_pose_.set_x(latest_reading.orientation_quat.x); + latest_pose_.set_y(latest_reading.orientation_quat.y); + latest_pose_.set_z(latest_reading.orientation_quat.z); + latest_pose_.set_w(latest_reading.orientation_quat.w); + + latest_pose_ = + WorldSpaceToUserOrientedSpace(SensorSpaceToWorldSpace(latest_pose_)); + } + + pose->orientation.value()[0] = latest_pose_.x(); + pose->orientation.value()[1] = latest_pose_.y(); + pose->orientation.value()[2] = latest_pose_.z(); + pose->orientation.value()[3] = latest_pose_.w(); + + std::move(callback).Run(std::move(pose)); +} + +Quaternion VROrientationDevice::SensorSpaceToWorldSpace(Quaternion q) { + display::Display::Rotation rotation = GetRotation(); + + if (rotation == display::Display::ROTATE_90) { + // Rotate the sensor reading to account for the screen rotation. + q = q * Quaternion(Vector3dF(0, 0, 1), -base::kPiDouble / 2); + } else if (rotation == display::Display::ROTATE_270) { + // Rotate the sensor reading to account for the screen rotation the other + // way. + q = q * Quaternion(Vector3dF(0, 0, 1), base::kPiDouble / 2); + } + + // Tilt the view up to have the y axis as the vertical axis instead of z + q = Quaternion(Vector3dF(1, 0, 0), -base::kPiDouble / 2) * q; + + return q; +} + +Quaternion VROrientationDevice::WorldSpaceToUserOrientedSpace(Quaternion q) { + if (!base_pose_) { + // Check that q is valid by checking if the length is not 0 (it should + // technically always be 1, but this accounts for rounding errors). + if (!(q.Length() > .1)) { + // q is invalid. Do not use for base pose. + return q; + } + + // A base pose to read the initial forward direction off of. + base_pose_ = q; + + // Extract the yaw from base pose to use as the base forward direction. + base_pose_->set_x(0); + base_pose_->set_z(0); + base_pose_ = base_pose_->Normalized(); + } + + // Adjust the base forward on the orientation to where the original forward + // was. + q = base_pose_->inverse() * q; + + return q; +} + +bool VROrientationDevice::IsFallbackDevice() { + return true; +}; + +} // namespace device \ No newline at end of file
diff --git a/device/vr/orientation/orientation_device.h b/device/vr/orientation/orientation_device.h new file mode 100644 index 0000000..8090c48d --- /dev/null +++ b/device/vr/orientation/orientation_device.h
@@ -0,0 +1,69 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_VR_ORIENTATION_DEVICE_H +#define DEVICE_VR_ORIENTATION_DEVICE_H + +#include <memory> + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "base/threading/simple_thread.h" +#include "device/vr/vr_device_base.h" +#include "device/vr/vr_service.mojom.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/device/public/interfaces/sensor_provider.mojom.h" +#include "ui/gfx/geometry/quaternion.h" + +namespace device { + +class SensorReadingSharedBufferReader; + +// This class connects the orientation sensor events to the Web VR apis. +class DEVICE_VR_EXPORT VROrientationDevice : public VRDeviceBase, + public mojom::SensorClient { + public: + VROrientationDevice(mojom::SensorProviderPtr* sensor_provider, + base::OnceClosure ready_callback); + ~VROrientationDevice() override; + + // VRDeviceBase + void OnMagicWindowPoseRequest( + mojom::VRMagicWindowProvider::GetPoseCallback callback) override; + + bool IsFallbackDevice() override; + + // Indicates whether the device was able to connect to orientation events. + bool IsAvailable() const { return available_; } + + private: + // SensorClient Functions. + void RaiseError() override; + void SensorReadingChanged() override {} + + // Sensor event reaction functions. + void SensorReady(device::mojom::SensorInitParamsPtr params); + void HandleSensorError(); + void OnSensorAddConfiguration(bool success); + + gfx::Quaternion SensorSpaceToWorldSpace(gfx::Quaternion q); + gfx::Quaternion WorldSpaceToUserOrientedSpace(gfx::Quaternion q); + + bool available_ = false; + base::OnceClosure ready_callback_; + + // The initial state of the world used to define forwards. + base::Optional<gfx::Quaternion> base_pose_; + gfx::Quaternion latest_pose_; + + mojom::SensorPtr sensor_; + mojo::ScopedSharedBufferHandle shared_buffer_handle_; + mojo::ScopedSharedBufferMapping shared_buffer_; + std::unique_ptr<SensorReadingSharedBufferReader> shared_buffer_reader_; + mojo::Binding<mojom::SensorClient> binding_; +}; + +} // namespace device + +#endif // DEVICE_VR_ORIENTATION_DEVICE_H
diff --git a/device/vr/orientation/orientation_device_provider.cc b/device/vr/orientation/orientation_device_provider.cc new file mode 100644 index 0000000..ff733d85 --- /dev/null +++ b/device/vr/orientation/orientation_device_provider.cc
@@ -0,0 +1,61 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/vr/orientation/orientation_device_provider.h" + +#include "base/callback.h" +#include "device/vr/orientation/orientation_device.h" +#include "services/device/public/interfaces/sensor_provider.mojom.h" +#include "services/service_manager/public/cpp/connector.h" +#include "services/service_manager/public/cpp/identity.h" + +namespace device { + +VROrientationDeviceProvider::VROrientationDeviceProvider( + service_manager::Connector* connector) { + connector->BindInterface(device::mojom::kServiceName, + mojo::MakeRequest(&sensor_provider_)); +} + +VROrientationDeviceProvider::~VROrientationDeviceProvider() = default; + +void VROrientationDeviceProvider::Initialize( + base::RepeatingCallback<void(VRDevice*)> add_device_callback, + base::RepeatingCallback<void(VRDevice*)> remove_device_callback, + base::OnceClosure initialization_complete) { + if (device_ && device_->IsAvailable()) { + add_device_callback.Run(device_.get()); + return; + } + + if (!device_) { + device_ = std::make_unique<VROrientationDevice>( + &sensor_provider_, + base::BindOnce(&VROrientationDeviceProvider::DeviceInitialized, + base::Unretained(this))); + add_device_callback_ = add_device_callback; + initialized_callback_ = std::move(initialization_complete); + } +} + +bool VROrientationDeviceProvider::Initialized() { + return initialized_; +}; + +void VROrientationDeviceProvider::DeviceInitialized() { + // This should only be called after the device is initialized. + DCHECK(device_); + // This should only be called once. + DCHECK(!initialized_); + + // If the device successfully connected to the orientation APIs, provide it. + if (device_->IsAvailable()) { + add_device_callback_.Run(device_.get()); + } + + initialized_ = true; + std::move(initialized_callback_).Run(); +} + +} // namespace device
diff --git a/device/vr/orientation/orientation_device_provider.h b/device/vr/orientation/orientation_device_provider.h new file mode 100644 index 0000000..f9852dc --- /dev/null +++ b/device/vr/orientation/orientation_device_provider.h
@@ -0,0 +1,50 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_VR_ORIENTATION_DEVICE_PROVIDER_H +#define DEVICE_VR_ORIENTATION_DEVICE_PROVIDER_H + +#include <memory> + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "device/vr/orientation/orientation_device.h" +#include "device/vr/vr_device_provider.h" +#include "device/vr/vr_export.h" +#include "services/device/public/interfaces/constants.mojom.h" +#include "services/device/public/interfaces/sensor_provider.mojom.h" +#include "services/service_manager/public/cpp/connector.h" + +namespace device { + +class DEVICE_VR_EXPORT VROrientationDeviceProvider : public VRDeviceProvider { + public: + VROrientationDeviceProvider(service_manager::Connector* connector); + ~VROrientationDeviceProvider() override; + + void Initialize( + base::RepeatingCallback<void(VRDevice*)> add_device_callback, + base::RepeatingCallback<void(VRDevice*)> remove_device_callback, + base::OnceClosure initialization_complete) override; + + bool Initialized() override; + + private: + void DeviceInitialized(); + + bool initialized_ = false; + + device::mojom::SensorProviderPtr sensor_provider_; + + std::unique_ptr<VROrientationDevice> device_; + + base::RepeatingCallback<void(VRDevice*)> add_device_callback_; + base::OnceClosure initialized_callback_; + + DISALLOW_COPY_AND_ASSIGN(VROrientationDeviceProvider); +}; + +} // namespace device + +#endif // DEVICE_VR_ORIENTATION_DEVICE_PROVIDER_H
diff --git a/device/vr/orientation/orientation_device_provider_unittest.cc b/device/vr/orientation/orientation_device_provider_unittest.cc new file mode 100644 index 0000000..1c7a30d --- /dev/null +++ b/device/vr/orientation/orientation_device_provider_unittest.cc
@@ -0,0 +1,207 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <utility> +#include <vector> + +#include "base/callback.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "base/test/test_simple_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "device/vr/orientation/orientation_device.h" +#include "device/vr/orientation/orientation_device_provider.h" +#include "device/vr/test/fake_orientation_provider.h" +#include "device/vr/test/fake_sensor_provider.h" +#include "services/device/public/cpp/generic_sensor/sensor_reading.h" +#include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h" +#include "services/device/public/cpp/generic_sensor/sensor_traits.h" +#include "services/device/public/interfaces/sensor.mojom.h" +#include "services/device/public/interfaces/sensor_provider.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/quaternion.h" + +namespace device { + +class VROrientationDeviceProviderTest : public testing::Test { + protected: + VROrientationDeviceProviderTest() = default; + ~VROrientationDeviceProviderTest() override = default; + void SetUp() override { + fake_sensor_provider_ = std::make_unique<FakeSensorProvider>(); + + fake_sensor_ = std::make_unique<FakeOrientationSensor>( + mojo::MakeRequest(&sensor_ptr_)); + shared_buffer_handle_ = mojo::SharedBufferHandle::Create( + sizeof(SensorReadingSharedBuffer) * + static_cast<uint64_t>(mojom::SensorType::LAST)); + + service_manager::mojom::ConnectorRequest request; + connector_ = service_manager::Connector::Create(&request); + service_manager::Connector::TestApi test_api(connector_.get()); + test_api.OverrideBinderForTesting( + mojom::kServiceName, mojom::SensorProvider::Name_, + base::BindRepeating(&FakeSensorProvider::Bind, + base::Unretained(fake_sensor_provider_.get()))); + + provider_ = std::make_unique<VROrientationDeviceProvider>(connector_.get()); + + scoped_task_environment_.RunUntilIdle(); + } + + void TearDown() override {} + + void InitializeDevice(mojom::SensorInitParamsPtr params) { + // Be sure GetSensor goes through so the callback is set. + scoped_task_environment_.RunUntilIdle(); + + fake_sensor_provider_->CallCallback(std::move(params)); + + // Allow the callback call to go through. + scoped_task_environment_.RunUntilIdle(); + } + + mojom::SensorInitParamsPtr FakeInitParams() { + auto init_params = mojom::SensorInitParams::New(); + init_params->sensor = std::move(sensor_ptr_); + init_params->default_configuration = PlatformSensorConfiguration( + SensorTraits<mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION>:: + kDefaultFrequency); + + init_params->client_request = mojo::MakeRequest(&sensor_client_ptr_); + + init_params->memory = shared_buffer_handle_->Clone( + mojo::SharedBufferHandle::AccessMode::READ_ONLY); + + init_params->buffer_offset = SensorReadingSharedBuffer::GetOffset( + mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION); + + return init_params; + } + + base::RepeatingCallback<void(VRDevice*)> DeviceCallbackFailIfCalled() { + return base::BindRepeating([](VRDevice* device) { FAIL(); }); + }; + + base::RepeatingCallback<void(VRDevice*)> DeviceCallbackMustBeCalled( + base::RunLoop* loop) { + return base::BindRepeating( + [](base::OnceClosure quit_closure, VRDevice* device) { + ASSERT_TRUE(device); + std::move(quit_closure).Run(); + }, + loop->QuitClosure()); + }; + + base::OnceClosure ClosureFailIfCalled() { + return base::BindOnce([]() { FAIL(); }); + }; + + base::OnceClosure ClosureMustBeCalled(base::RunLoop* loop) { + return base::BindOnce( + [](base::OnceClosure quit_closure) { std::move(quit_closure).Run(); }, + loop->QuitClosure()); + }; + + // Needed for MakeRequest to work. + base::test::ScopedTaskEnvironment scoped_task_environment_; + + std::unique_ptr<VROrientationDeviceProvider> provider_; + + std::unique_ptr<FakeSensorProvider> fake_sensor_provider_; + mojom::SensorProviderPtr sensor_provider_ptr_; + + // Fake Sensor Init params objects + std::unique_ptr<FakeOrientationSensor> fake_sensor_; + mojom::SensorPtrInfo sensor_ptr_; + mojo::ScopedSharedBufferHandle shared_buffer_handle_; + mojom::SensorClientPtr sensor_client_ptr_; + + std::unique_ptr<service_manager::Connector> connector_; + + DISALLOW_COPY_AND_ASSIGN(VROrientationDeviceProviderTest); +}; + +TEST_F(VROrientationDeviceProviderTest, InitializationTest) { + // Check that without running anything, the provider will not be initialized. + EXPECT_FALSE(provider_->Initialized()); +} + +TEST_F(VROrientationDeviceProviderTest, InitializationCallbackSuccessTest) { + base::RunLoop wait_for_device; + base::RunLoop wait_for_init; + + provider_->Initialize(DeviceCallbackMustBeCalled(&wait_for_device), + DeviceCallbackFailIfCalled(), + ClosureMustBeCalled(&wait_for_init)); + + InitializeDevice(FakeInitParams()); + + wait_for_init.Run(); + wait_for_device.Run(); + + EXPECT_TRUE(provider_->Initialized()); +} + +TEST_F(VROrientationDeviceProviderTest, InitializationCallbackFailureTest) { + base::RunLoop wait_for_init; + + provider_->Initialize(DeviceCallbackFailIfCalled(), + DeviceCallbackFailIfCalled(), + ClosureMustBeCalled(&wait_for_init)); + + InitializeDevice(nullptr); + + // Wait for the initialization to finish. + wait_for_init.Run(); + EXPECT_TRUE(provider_->Initialized()); +} + +TEST_F(VROrientationDeviceProviderTest, SecondInitializationSuccessTest) { + base::RunLoop wait_for_device; + base::RunLoop wait_for_init; + + provider_->Initialize(DeviceCallbackMustBeCalled(&wait_for_device), + DeviceCallbackFailIfCalled(), + ClosureMustBeCalled(&wait_for_init)); + + InitializeDevice(FakeInitParams()); + + // Wait for the initialization to finish. + wait_for_init.Run(); + wait_for_device.Run(); + + base::RunLoop second_wait_for_device; + + EXPECT_TRUE(provider_->Initialized()); + + // If we run initialize again, we should only call add device. + provider_->Initialize(DeviceCallbackMustBeCalled(&second_wait_for_device), + DeviceCallbackFailIfCalled(), ClosureFailIfCalled()); + + second_wait_for_device.Run(); +} + +TEST_F(VROrientationDeviceProviderTest, SecondInitializationFailureTest) { + base::RunLoop wait_for_init; + + provider_->Initialize(DeviceCallbackFailIfCalled(), + DeviceCallbackFailIfCalled(), + ClosureMustBeCalled(&wait_for_init)); + + InitializeDevice(nullptr); + + wait_for_init.Run(); + + EXPECT_TRUE(provider_->Initialized()); + + // If we call again on a failure, nothing should be called. + provider_->Initialize(DeviceCallbackFailIfCalled(), + DeviceCallbackFailIfCalled(), ClosureFailIfCalled()); +} + +} // namespace device
diff --git a/device/vr/orientation/orientation_device_unittest.cc b/device/vr/orientation/orientation_device_unittest.cc new file mode 100644 index 0000000..b9a23d4 --- /dev/null +++ b/device/vr/orientation/orientation_device_unittest.cc
@@ -0,0 +1,338 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <utility> +#include <vector> + +#include "base/callback.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "base/test/test_simple_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "device/vr/orientation/orientation_device.h" +#include "device/vr/test/fake_orientation_provider.h" +#include "device/vr/test/fake_sensor_provider.h" +#include "services/device/public/cpp/generic_sensor/sensor_reading.h" +#include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h" +#include "services/device/public/cpp/generic_sensor/sensor_traits.h" +#include "services/device/public/interfaces/sensor.mojom.h" +#include "services/device/public/interfaces/sensor_provider.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/quaternion.h" + +namespace device { + +namespace { + +class FakeScreen : public display::Screen { + public: + FakeScreen() = default; + ~FakeScreen() override = default; + display::Display GetPrimaryDisplay() const override { return display; }; + + // Unused functions + gfx::Point GetCursorScreenPoint() override { return gfx::Point(); }; + bool IsWindowUnderCursor(gfx::NativeWindow window) override { return false; }; + gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override { + return nullptr; + } + display::Display GetDisplayNearestWindow( + gfx::NativeWindow window) const override { + return display; + } + display::Display GetDisplayNearestPoint( + const gfx::Point& point) const override { + return display; + } + int GetNumDisplays() const override { return 0; }; + display::Display GetDisplayMatching( + const gfx::Rect& match_rect) const override { + return display; + } + void AddObserver(display::DisplayObserver* observer) override {} + void RemoveObserver(display::DisplayObserver* observer) override {} + const std::vector<display::Display>& GetAllDisplays() const override { + return displays; + } + + display::Display display; + const std::vector<display::Display> displays; +}; + +} // namespace + +class VROrientationDeviceTest : public testing::Test { + public: + void onDisplaySynced() {} + + protected: + VROrientationDeviceTest() = default; + ~VROrientationDeviceTest() override = default; + void SetUp() override { + fake_sensor_provider_ = std::make_unique<FakeSensorProvider>( + mojo::MakeRequest(&sensor_provider_ptr_)); + + fake_sensor_ = std::make_unique<FakeOrientationSensor>( + mojo::MakeRequest(&sensor_ptr_)); + shared_buffer_handle_ = mojo::SharedBufferHandle::Create( + sizeof(SensorReadingSharedBuffer) * + static_cast<uint64_t>(mojom::SensorType::LAST)); + + fake_screen_ = std::make_unique<FakeScreen>(); + + display::Screen::SetScreenInstance(fake_screen_.get()); + + scoped_task_environment_.RunUntilIdle(); + } + + void TearDown() override { shared_buffer_handle_.reset(); } + + double GetBufferOffset() { + return SensorReadingSharedBuffer::GetOffset( + mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION); + } + + void InitializeDevice(mojom::SensorInitParamsPtr params) { + base::RunLoop loop; + + device_ = std::make_unique<VROrientationDevice>( + &sensor_provider_ptr_, base::BindOnce( + [](base::OnceClosure quit_closure) { + // The callback was called. + std::move(quit_closure).Run(); + }, + loop.QuitClosure())); + + // Complete the creation of device_ by letting the GetSensor function go + // through. + scoped_task_environment_.RunUntilIdle(); + + fake_sensor_provider_->CallCallback(std::move(params)); + scoped_task_environment_.RunUntilIdle(); + + // Ensure that the callback is called. + loop.Run(); + } + + void DeviceReadPose(gfx::Quaternion input_q, + base::OnceCallback<void(mojom::VRPosePtr)> callback) { + // If the device isn't available we can't read a quaternion from it + ASSERT_TRUE(device_->IsAvailable()); + + WriteToBuffer(input_q); + + base::RunLoop loop; + + device_->OnMagicWindowPoseRequest(base::BindOnce( + [](base::OnceClosure quit_closure, + base::OnceCallback<void(mojom::VRPosePtr)> callback, + mojom::VRPosePtr ptr) { + std::move(callback).Run(std::move(ptr)); + std::move(quit_closure).Run(); + }, + loop.QuitClosure(), std::move(callback))); + + scoped_task_environment_.RunUntilIdle(); + + // Ensure the pose request callback runs. + loop.Run(); + } + + mojom::SensorInitParamsPtr FakeInitParams() { + auto init_params = mojom::SensorInitParams::New(); + init_params->sensor = std::move(sensor_ptr_); + init_params->default_configuration = PlatformSensorConfiguration( + SensorTraits<mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION>:: + kDefaultFrequency); + + init_params->client_request = mojo::MakeRequest(&sensor_client_ptr_); + + init_params->memory = shared_buffer_handle_->Clone( + mojo::SharedBufferHandle::AccessMode::READ_ONLY); + + init_params->buffer_offset = GetBufferOffset(); + + return init_params; + } + + void WriteToBuffer(gfx::Quaternion q) { + mojo::ScopedSharedBufferMapping shared_buffer = + shared_buffer_handle_->MapAtOffset( + mojom::SensorInitParams::kReadBufferSizeForTests, + GetBufferOffset()); + + SensorReadingSharedBuffer* buffer = + static_cast<SensorReadingSharedBuffer*>(shared_buffer.get()); + + auto& seqlock = buffer->seqlock.value(); + seqlock.WriteBegin(); + buffer->reading.orientation_quat.x = q.x(); + buffer->reading.orientation_quat.y = q.y(); + buffer->reading.orientation_quat.z = q.z(); + buffer->reading.orientation_quat.w = q.w(); + seqlock.WriteEnd(); + } + + void SetRotation(display::Display::Rotation rotation) { + fake_screen_->display.set_rotation(rotation); + } + + // Needed for MakeRequest to work. + base::test::ScopedTaskEnvironment scoped_task_environment_; + + std::unique_ptr<VROrientationDevice> device_; + std::unique_ptr<FakeSensorProvider> fake_sensor_provider_; + mojom::SensorProviderPtr sensor_provider_ptr_; + + // Fake Sensor Init params objects + std::unique_ptr<FakeOrientationSensor> fake_sensor_; + mojom::SensorPtrInfo sensor_ptr_; + mojo::ScopedSharedBufferHandle shared_buffer_handle_; + mojom::SensorClientPtr sensor_client_ptr_; + + std::unique_ptr<FakeScreen> fake_screen_; + + DISALLOW_COPY_AND_ASSIGN(VROrientationDeviceTest); +}; + +TEST_F(VROrientationDeviceTest, InitializationTest) { + // Check that without running anything, the device will return not available, + // without crashing. + + device_ = std::make_unique<VROrientationDevice>(&sensor_provider_ptr_, + base::BindOnce([]() {})); + scoped_task_environment_.RunUntilIdle(); + + EXPECT_FALSE(device_->IsAvailable()); +} + +TEST_F(VROrientationDeviceTest, SensorNotAvailableTest) { + // If the provider calls back with nullptr, there are no sensors available. + + InitializeDevice(nullptr); + + EXPECT_FALSE(device_->IsAvailable()); +} + +TEST_F(VROrientationDeviceTest, SensorIsAvailableTest) { + // Tests that with proper params the device initializes without mishap. + + InitializeDevice(FakeInitParams()); + + EXPECT_TRUE(device_->IsAvailable()); +} + +TEST_F(VROrientationDeviceTest, GetOrientationTest) { + // Tests that OnMagicWindowPoseRequest returns a pose ptr without mishap. + + InitializeDevice(FakeInitParams()); + + DeviceReadPose( + gfx::Quaternion(0, 0, 0, 1), + base::BindOnce([](mojom::VRPosePtr ptr) { EXPECT_TRUE(ptr); })); +} + +TEST_F(VROrientationDeviceTest, OrientationDefaultForwardTest) { + InitializeDevice(FakeInitParams()); + + // Set forward to 0 degrees + DeviceReadPose(gfx::Quaternion(0, 0, 0, 1), + base::BindOnce([](mojom::VRPosePtr ptr) { + EXPECT_NEAR(ptr->orientation->at(0), -0.707, 0.001); + EXPECT_NEAR(ptr->orientation->at(1), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(2), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(3), 0.707, 0.001); + })); + + // Now a 90 degree rotation around x in device space should be default pose in + // vr space. + DeviceReadPose(gfx::Quaternion(0.707, 0, 0, 0.707), + base::BindOnce([](mojom::VRPosePtr ptr) { + EXPECT_NEAR(ptr->orientation->at(0), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(1), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(2), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(3), 1, 0.001); + })); +} + +TEST_F(VROrientationDeviceTest, OrientationSetForwardTest) { + InitializeDevice(FakeInitParams()); + + // Hold device upright and rotation 45 degrees to left in device space for + // setting the forward. With the device upright, this causes the first reading + // to be the default pose. + DeviceReadPose(gfx::Quaternion(0.653, 0.271, 0.271, 0.653), + base::BindOnce([](mojom::VRPosePtr ptr) { + EXPECT_NEAR(ptr->orientation->at(0), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(1), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(2), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(3), 1, 0.001); + })); + + // Now hold upright and straigt produces a 45 degree rotation to the right + DeviceReadPose(gfx::Quaternion(0.707, 0, 0, 0.707), + base::BindOnce([](mojom::VRPosePtr ptr) { + EXPECT_NEAR(ptr->orientation->at(0), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(1), -0.383, 0.001); + EXPECT_NEAR(ptr->orientation->at(2), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(3), 0.924, 0.001); + })); +} + +TEST_F(VROrientationDeviceTest, OrientationLandscape90Test) { + InitializeDevice(FakeInitParams()); + + SetRotation(display::Display::ROTATE_90); + + // Tilting the device up and twisting to the side should be default in + // landscape mode. + DeviceReadPose(gfx::Quaternion(0.5, -0.5, 0.5, 0.5), + base::BindOnce([](mojom::VRPosePtr ptr) { + EXPECT_NEAR(ptr->orientation->at(0), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(1), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(2), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(3), 1, 0.001); + })); + + // Rotating the device 45 left from base pose should cause 45 degree left + // rotation around y in VR space. + DeviceReadPose(gfx::Quaternion(0.653, -0.271, 0.653, 0.271), + base::BindOnce([](mojom::VRPosePtr ptr) { + EXPECT_NEAR(ptr->orientation->at(0), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(1), 0.382, 0.001); + EXPECT_NEAR(ptr->orientation->at(2), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(3), 0.924, 0.001); + })); +} + +TEST_F(VROrientationDeviceTest, OrientationLandscape270Test) { + SetRotation(display::Display::ROTATE_270); + + InitializeDevice(FakeInitParams()); + + // Tilting the device up and twisting to the side should be default in + // landscape mode (twist the other way from what we'd need for ROTATE_90). + DeviceReadPose(gfx::Quaternion(0.5, 0.5, -0.5, 0.5), + base::BindOnce([](mojom::VRPosePtr ptr) { + EXPECT_NEAR(ptr->orientation->at(0), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(1), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(2), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(3), 1, 0.001); + })); + + // Rotating the device 45 left from base pose should cause 45 degree left + // rotation around y in VR space + DeviceReadPose(gfx::Quaternion(0.271, 0.653, -0.271, 0.653), + base::BindOnce([](mojom::VRPosePtr ptr) { + EXPECT_NEAR(ptr->orientation->at(0), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(1), 0.382, 0.001); + EXPECT_NEAR(ptr->orientation->at(2), 0, 0.001); + EXPECT_NEAR(ptr->orientation->at(3), 0.924, 0.001); + })); +} + +} // namespace device
diff --git a/device/vr/test/fake_orientation_provider.cc b/device/vr/test/fake_orientation_provider.cc new file mode 100644 index 0000000..7c93a9eb --- /dev/null +++ b/device/vr/test/fake_orientation_provider.cc
@@ -0,0 +1,25 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/vr/test/fake_orientation_provider.h" + +#include "services/device/public/interfaces/sensor.mojom.h" + +namespace device { + +FakeOrientationSensor::FakeOrientationSensor(mojom::SensorRequest request) + : binding_(this) { + binding_.Bind(std::move(request)); +} + +FakeOrientationSensor::~FakeOrientationSensor() = default; + +// The called functions +void FakeOrientationSensor::AddConfiguration( + const PlatformSensorConfiguration& configuration, + AddConfigurationCallback callback) { + std::move(callback).Run(true); +} + +} // namespace device \ No newline at end of file
diff --git a/device/vr/test/fake_orientation_provider.h b/device/vr/test/fake_orientation_provider.h new file mode 100644 index 0000000..f0341cb5 --- /dev/null +++ b/device/vr/test/fake_orientation_provider.h
@@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_VR_TEST_FAKE_ORIENTATION_PROVIDER_H_ +#define DEVICE_VR_TEST_FAKE_ORIENTATION_PROVIDER_H_ + +#include "mojo/public/cpp/bindings/binding.h" +#include "services/device/public/interfaces/sensor.mojom.h" + +namespace device { + +class FakeOrientationSensor : public mojom::Sensor { + public: + FakeOrientationSensor(mojom::SensorRequest request); + ~FakeOrientationSensor() override; + + void AddConfiguration(const PlatformSensorConfiguration& configuration, + AddConfigurationCallback callback) override; + void ConfigureReadingChangeNotifications(bool enabled) override {} + + void GetDefaultConfiguration( + GetDefaultConfigurationCallback callback) override {} + void RemoveConfiguration( + const PlatformSensorConfiguration& configuration) override {} + void Suspend() override {} + void Resume() override {} + + private: + mojo::Binding<mojom::Sensor> binding_; + + DISALLOW_COPY_AND_ASSIGN(FakeOrientationSensor); +}; + +} // namespace device + +#endif // DEVICE_VR_TEST_FAKE_ORIENTATION_PROVIDER_H_ \ No newline at end of file
diff --git a/device/vr/test/fake_sensor_provider.cc b/device/vr/test/fake_sensor_provider.cc new file mode 100644 index 0000000..d9b82f92 --- /dev/null +++ b/device/vr/test/fake_sensor_provider.cc
@@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/vr/test/fake_sensor_provider.h" + +#include "services/device/public/interfaces/sensor.mojom.h" +#include "services/device/public/interfaces/sensor_provider.mojom.h" + +namespace device { + +FakeSensorProvider::FakeSensorProvider() : binding_(this) {} + +FakeSensorProvider::FakeSensorProvider(mojom::SensorProviderRequest request) + : binding_(this) { + binding_.Bind(std::move(request)); +} + +FakeSensorProvider::~FakeSensorProvider() { + if (callback_) + std::move(callback_).Run(nullptr); +} + +void FakeSensorProvider::Bind(mojo::ScopedMessagePipeHandle handle) { + binding_.Bind(mojom::SensorProviderRequest(std::move(handle))); +} + +void FakeSensorProvider::GetSensor(mojom::SensorType type, + GetSensorCallback callback) { + callback_ = std::move(callback); +} + +void FakeSensorProvider::CallCallback(mojom::SensorInitParamsPtr param) { + std::move(callback_).Run(std::move(param)); +} + +} // namespace device \ No newline at end of file
diff --git a/device/vr/test/fake_sensor_provider.h b/device/vr/test/fake_sensor_provider.h new file mode 100644 index 0000000..583f15e --- /dev/null +++ b/device/vr/test/fake_sensor_provider.h
@@ -0,0 +1,31 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_VR_TEST_FAKE_SENSOR_PROVIDER_H_ +#define DEVICE_VR_TEST_FAKE_SENSOR_PROVIDER_H_ + +#include "mojo/public/cpp/bindings/binding.h" +#include "services/device/public/interfaces/sensor.mojom.h" +#include "services/device/public/interfaces/sensor_provider.mojom.h" + +namespace device { + +class FakeSensorProvider : public mojom::SensorProvider { + public: + FakeSensorProvider(); + explicit FakeSensorProvider(mojom::SensorProviderRequest request); + ~FakeSensorProvider() override; + + void Bind(mojo::ScopedMessagePipeHandle handle); + void GetSensor(mojom::SensorType type, GetSensorCallback callback) override; + void CallCallback(mojom::SensorInitParamsPtr param); + + private: + mojo::Binding<mojom::SensorProvider> binding_; + GetSensorCallback callback_; +}; + +} // namespace device + +#endif // DEVICE_VR_TEST_FAKE_SENSOR_PROVIDER_H_ \ No newline at end of file
diff --git a/device/vr/vr_device.h b/device/vr/vr_device.h index 96163b9..2f8e732 100644 --- a/device/vr/vr_device.h +++ b/device/vr/vr_device.h
@@ -42,6 +42,9 @@ virtual mojom::VRDisplayInfoPtr GetVRDisplayInfo() = 0; virtual void SetMagicWindowEnabled(bool enabled) = 0; + // The fallback device should only be provided in lieu of other devices. + virtual bool IsFallbackDevice() = 0; + // TODO(mthiesse): The browser should handle browser-side exiting of // presentation before device/ is even aware presentation is being exited. // Then the browser should call ExitPresent() on Device, which does device/
diff --git a/device/vr/vr_device_base.cc b/device/vr/vr_device_base.cc index 30dcd2cd..993904f 100644 --- a/device/vr/vr_device_base.cc +++ b/device/vr/vr_device_base.cc
@@ -46,6 +46,10 @@ SetPresentingDisplay(nullptr); } +bool VRDeviceBase::IsFallbackDevice() { + return false; +}; + mojom::VRDisplayInfoPtr VRDeviceBase::GetVRDisplayInfo() { DCHECK(display_info_); return display_info_.Clone();
diff --git a/device/vr/vr_device_base.h b/device/vr/vr_device_base.h index d3fb897..a4d0abe 100644 --- a/device/vr/vr_device_base.h +++ b/device/vr/vr_device_base.h
@@ -39,6 +39,7 @@ mojom::VRPresentationProviderRequest request, mojom::VRDisplayHost::RequestPresentCallback callback); virtual void ExitPresent(); + bool IsFallbackDevice() override; void AddDisplay(VRDisplayImpl* display); void RemoveDisplay(VRDisplayImpl* display);
diff --git a/extensions/browser/api/runtime/runtime_api.cc b/extensions/browser/api/runtime/runtime_api.cc index dccf5601..2ad713f 100644 --- a/extensions/browser/api/runtime/runtime_api.cc +++ b/extensions/browser/api/runtime/runtime_api.cc
@@ -235,8 +235,8 @@ content::BrowserContext* browser_context, const Extension* extension, UninstallReason reason) { - RuntimeEventRouter::OnExtensionUninstalled( - browser_context_, extension->id(), reason); + RuntimeEventRouter::OnExtensionUninstalled(browser_context_, extension->id(), + reason); } void RuntimeAPI::Shutdown() { @@ -572,6 +572,12 @@ return; } + // Blacklisted extensions should not open uninstall_url. + if (extensions::ExtensionPrefs::Get(context)->IsExtensionBlacklisted( + extension_id)) { + return; + } + RuntimeAPI::GetFactoryInstance()->Get(context)->OpenURL(uninstall_url); }
diff --git a/extensions/browser/api/runtime/runtime_apitest.cc b/extensions/browser/api/runtime/runtime_apitest.cc index e6cbc03..2999bdd 100644 --- a/extensions/browser/api/runtime/runtime_apitest.cc +++ b/extensions/browser/api/runtime/runtime_apitest.cc
@@ -6,15 +6,19 @@ #include "chrome/browser/apps/app_browsertest_util.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_function_test_utils.h" +#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/test_extension_dir.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/test/browser_test_utils.h" #include "extensions/browser/api/runtime/runtime_api.h" +#include "extensions/browser/blacklist_state.h" #include "extensions/browser/extension_dialog_auto_confirm.h" +#include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/test_extension_registry_observer.h" #include "extensions/test/result_catcher.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "url/url_constants.h" // Tests the privileged components of chrome.runtime. IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimePrivileged) { @@ -48,6 +52,15 @@ namespace { +const char kUninstallUrl[] = "http://www.google.com/"; + +std::string GetActiveUrl(Browser* browser) { + return browser->tab_strip_model() + ->GetActiveWebContents() + ->GetLastCommittedURL() + .spec(); +} + class RuntimeAPIUpdateTest : public ExtensionApiTest { public: RuntimeAPIUpdateTest() {} @@ -214,4 +227,56 @@ } } +// Tests that when a blacklisted extension with a set uninstall url is +// uninstalled, its uninstall url does not open. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, + DoNotOpenUninstallUrlForBlacklistedExtensions) { + // Load an extension that has set an uninstall url. + scoped_refptr<const extensions::Extension> extension = + LoadExtension(test_data_dir_.AppendASCII("runtime") + .AppendASCII("uninstall_url") + .AppendASCII("sets_uninstall_url")); + + ASSERT_TRUE(extension.get()); + extension_service()->AddExtension(extension.get()); + ASSERT_TRUE(extension_service()->IsExtensionEnabled(extension->id())); + + // Uninstall the extension and expect its uninstall url to open. + extension_service()->UninstallExtension( + extension->id(), extensions::UNINSTALL_REASON_USER_INITIATED, NULL); + TabStripModel* tabs = browser()->tab_strip_model(); + + EXPECT_EQ(2, tabs->count()); + content::WaitForLoadStop(tabs->GetActiveWebContents()); + // Verify the uninstall url + EXPECT_EQ(kUninstallUrl, GetActiveUrl(browser())); + + // Close the tab pointing to the uninstall url. + tabs->CloseWebContentsAt(tabs->active_index(), 0); + EXPECT_EQ(1, tabs->count()); + EXPECT_EQ("about:blank", GetActiveUrl(browser())); + + // Load the same extension again, except blacklist it after installation. + extension = LoadExtension(test_data_dir_.AppendASCII("runtime") + .AppendASCII("uninstall_url") + .AppendASCII("sets_uninstall_url")); + extension_service()->AddExtension(extension.get()); + ASSERT_TRUE(extension_service()->IsExtensionEnabled(extension->id())); + + // Blacklist extension. + extensions::ExtensionPrefs::Get(profile())->SetExtensionBlacklistState( + extension->id(), extensions::BlacklistState::BLACKLISTED_MALWARE); + + // Uninstalling a blacklisted extension should not open its uninstall url. + TestExtensionRegistryObserver observer(ExtensionRegistry::Get(profile()), + extension->id()); + extension_service()->UninstallExtension( + extension->id(), extensions::UNINSTALL_REASON_USER_INITIATED, NULL); + observer.WaitForExtensionUninstalled(); + + EXPECT_EQ(1, tabs->count()); + content::WaitForLoadStop(tabs->GetActiveWebContents()); + EXPECT_EQ(url::kAboutBlankURL, GetActiveUrl(browser())); +} + } // namespace extensions
diff --git a/extensions/browser/guest_view/extension_view/whitelist/OWNERS b/extensions/browser/guest_view/extension_view/whitelist/OWNERS index 1be42c1..0a3bc083 100644 --- a/extensions/browser/guest_view/extension_view/whitelist/OWNERS +++ b/extensions/browser/guest_view/extension_view/whitelist/OWNERS
@@ -6,7 +6,6 @@ brettw@chromium.org cpu@chromium.org darin@chromium.org -dglazkov@chromium.org jam@chromium.org jochen@chromium.org
diff --git a/gin/BUILD.gn b/gin/BUILD.gn index 5341919..39bd188c 100644 --- a/gin/BUILD.gn +++ b/gin/BUILD.gn
@@ -30,6 +30,15 @@ "isolate_holder.cc", "modules/console.cc", "modules/console.h", + "modules/file_module_provider.cc", + "modules/file_module_provider.h", + "modules/module_registry.cc", + "modules/module_registry.h", + "modules/module_registry_observer.h", + "modules/module_runner_delegate.cc", + "modules/module_runner_delegate.h", + "modules/timer.cc", + "modules/timer.h", "object_template_builder.cc", "object_template_builder.h", "per_context_data.cc", @@ -122,9 +131,20 @@ source_set("gin_test") { testonly = true sources = [ + "test/file.cc", + "test/file.h", + "test/file_runner.cc", + "test/file_runner.h", + "test/gc.cc", + "test/gc.h", + "test/gtest.cc", + "test/gtest.h", "test/v8_test.cc", "test/v8_test.h", ] + data = [ + "test/expect.js", + ] public_deps = [ ":gin", @@ -149,10 +169,13 @@ "converter_unittest.cc", "data_object_builder_unittest.cc", "interceptor_unittest.cc", + "modules/module_registry_unittest.cc", + "modules/timer_unittest.cc", "per_context_data_unittest.cc", "shell/gin_shell_unittest.cc", "shell_runner_unittest.cc", "test/run_all_unittests.cc", + "test/run_js_tests.cc", "v8_isolate_memory_dump_provider_unittest.cc", "v8_platform_unittest.cc", "wrappable_unittest.cc", @@ -168,7 +191,10 @@ configs += [ "//v8:external_startup_data" ] data = [ + "modules/module_registry_unittests.js", "shell/hello_world.js", + "test/file_unittests.js", + "test/gtest_unittests.js", "../OWNERS", ]
diff --git a/gin/modules/console.cc b/gin/modules/console.cc index 8786392b..63fc41e 100644 --- a/gin/modules/console.cc +++ b/gin/modules/console.cc
@@ -9,31 +9,41 @@ #include "base/strings/string_util.h" #include "gin/arguments.h" #include "gin/converter.h" +#include "gin/object_template_builder.h" +#include "gin/per_isolate_data.h" +#include "gin/public/wrapper_info.h" + +using v8::ObjectTemplate; namespace gin { namespace { -void Log(const v8::FunctionCallbackInfo<v8::Value>& info) { - Arguments args(info); +void Log(Arguments* args) { std::vector<std::string> messages; - if (!args.GetRemaining(&messages)) { - args.ThrowError(); + if (!args->GetRemaining(&messages)) { + args->ThrowError(); return; } printf("%s\n", base::JoinString(messages, " ").c_str()); } +WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; + } // namespace -// static -void Console::Register(v8::Isolate* isolate, - v8::Local<v8::ObjectTemplate> templ) { - v8::Local<v8::FunctionTemplate> log_templ = - v8::FunctionTemplate::New(isolate, Log); - log_templ->RemovePrototype(); +const char Console::kModuleName[] = "console"; - templ->Set(StringToSymbol(isolate, "log"), log_templ); +v8::Local<v8::Value> Console::GetModule(v8::Isolate* isolate) { + PerIsolateData* data = PerIsolateData::From(isolate); + v8::Local<ObjectTemplate> templ = data->GetObjectTemplate(&g_wrapper_info); + if (templ.IsEmpty()) { + templ = ObjectTemplateBuilder(isolate) + .SetMethod("log", Log) + .Build(); + data->SetObjectTemplate(&g_wrapper_info, templ); + } + return templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); } } // namespace gin
diff --git a/gin/modules/console.h b/gin/modules/console.h index 4b68aa1..ff8061ba 100644 --- a/gin/modules/console.h +++ b/gin/modules/console.h
@@ -14,8 +14,8 @@ // we'd like to evolve the API to match window.console in browsers. class GIN_EXPORT Console { public: - static void Register(v8::Isolate* isolate, - v8::Local<v8::ObjectTemplate> templ); + static const char kModuleName[]; + static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); }; } // namespace gin
diff --git a/gin/modules/file_module_provider.cc b/gin/modules/file_module_provider.cc new file mode 100644 index 0000000..2edb6088 --- /dev/null +++ b/gin/modules/file_module_provider.cc
@@ -0,0 +1,74 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/modules/file_module_provider.h" + +#include <stddef.h> + +#include "base/bind.h" +#include "base/files/file_util.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" +#include "base/strings/string_split.h" +#include "base/threading/thread_task_runner_handle.h" +#include "gin/converter.h" + +namespace gin { + +namespace { + +void AttempToLoadModule(const base::WeakPtr<Runner>& runner, + const std::vector<base::FilePath>& search_paths, + const std::string& id) { + if (!runner) + return; + + std::vector<std::string> components = base::SplitString( + id, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + + base::FilePath path; + for (size_t i = 0; i < components.size(); ++i) { + // TODO(abarth): Technically the path components can be UTF-8. We don't + // handle that case correctly yet. + path = path.AppendASCII(components[i]); + } + path = path.AddExtension(FILE_PATH_LITERAL("js")); + + for (size_t i = 0; i < search_paths.size(); ++i) { + std::string source; + if (!ReadFileToString(search_paths[i].Append(path), &source)) + continue; + + Runner::Scope scope(runner.get()); + runner->Run(source, id); + return; + } + LOG(ERROR) << "Failed to load module from disk: " << id; +} + +} // namespace + +FileModuleProvider::FileModuleProvider( + const std::vector<base::FilePath>& search_paths) + : search_paths_(search_paths) { +} + +FileModuleProvider::~FileModuleProvider() = default; + +void FileModuleProvider::AttempToLoadModules( + Runner* runner, const std::set<std::string>& ids) { + std::set<std::string> modules = ids; + for (std::set<std::string>::const_iterator it = modules.begin(); + it != modules.end(); ++it) { + const std::string& id = *it; + if (attempted_ids_.count(id)) + continue; + attempted_ids_.insert(id); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(AttempToLoadModule, runner->GetWeakPtr(), + search_paths_, id)); + } +} + +} // namespace gin
diff --git a/gin/modules/file_module_provider.h b/gin/modules/file_module_provider.h new file mode 100644 index 0000000..7c03887 --- /dev/null +++ b/gin/modules/file_module_provider.h
@@ -0,0 +1,45 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_MODULES_FILE_MODULE_PROVIDER_H_ +#define GIN_MODULES_FILE_MODULE_PROVIDER_H_ + +#include <set> +#include <string> +#include <vector> + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "gin/gin_export.h" +#include "gin/runner.h" + +namespace gin { + +// FileModuleProvider knows how to load AMD modules off disk. It searches for +// modules in the directories indiciated by |search_paths|. Although we still +// read from the file system on the main thread, we'll eventually want to move +// the reads to a background thread. +class GIN_EXPORT FileModuleProvider { + public: + explicit FileModuleProvider( + const std::vector<base::FilePath>& search_paths); + ~FileModuleProvider(); + + // Searches for modules with |ids| in the file system. If found, the modules + // will be executed asynchronously by |runner|. + void AttempToLoadModules(Runner* runner, const std::set<std::string>& ids); + + private: + std::vector<base::FilePath> search_paths_; + + // We'll only search for a given module once. We remember the set of modules + // we've already looked for in |attempted_ids_|. + std::set<std::string> attempted_ids_; + + DISALLOW_COPY_AND_ASSIGN(FileModuleProvider); +}; + +} // namespace gin + +#endif // GIN_MODULES_FILE_MODULE_PROVIDER_H_
diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc new file mode 100644 index 0000000..cf61f7d --- /dev/null +++ b/gin/modules/module_registry.cc
@@ -0,0 +1,289 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/modules/module_registry.h" + +#include <stddef.h> +#include <stdint.h> +#include <string> +#include <utility> +#include <vector> + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "gin/arguments.h" +#include "gin/converter.h" +#include "gin/modules/module_registry_observer.h" +#include "gin/per_context_data.h" +#include "gin/per_isolate_data.h" +#include "gin/public/wrapper_info.h" +#include "gin/runner.h" + +using v8::Context; +using v8::External; +using v8::Function; +using v8::FunctionTemplate; +using v8::Isolate; +using v8::Local; +using v8::Object; +using v8::ObjectTemplate; +using v8::Persistent; +using v8::StackTrace; +using v8::String; +using v8::Value; + +namespace gin { + +struct PendingModule { + PendingModule(); + ~PendingModule(); + + std::string id; + std::vector<std::string> dependencies; + Persistent<Value> factory; +}; + +PendingModule::PendingModule() = default; + +PendingModule::~PendingModule() { + factory.Reset(); +} + +namespace { + +// Key for base::SupportsUserData::Data. +const char kModuleRegistryKey[] = "ModuleRegistry"; + +struct ModuleRegistryData : public base::SupportsUserData::Data { + std::unique_ptr<ModuleRegistry> registry; +}; + +void Define(const v8::FunctionCallbackInfo<Value>& info) { + Arguments args(info); + + if (!info.Length()) + return args.ThrowTypeError("At least one argument is required."); + + std::string id; + std::vector<std::string> dependencies; + v8::Local<Value> factory; + + if (!args.PeekNext().IsEmpty() && args.PeekNext()->IsString()) + args.GetNext(&id); + if (!args.PeekNext().IsEmpty() && args.PeekNext()->IsArray()) + args.GetNext(&dependencies); + if (!args.GetNext(&factory)) + return args.ThrowError(); + + std::unique_ptr<PendingModule> pending(new PendingModule); + pending->id = id; + pending->dependencies = dependencies; + pending->factory.Reset(args.isolate(), factory); + + ModuleRegistry* registry = + ModuleRegistry::From(args.isolate()->GetCurrentContext()); + registry->AddPendingModule(args.isolate(), std::move(pending)); +} + +WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; + +Local<FunctionTemplate> GetDefineTemplate(Isolate* isolate) { + PerIsolateData* data = PerIsolateData::From(isolate); + Local<FunctionTemplate> templ = data->GetFunctionTemplate( + &g_wrapper_info); + if (templ.IsEmpty()) { + templ = FunctionTemplate::New(isolate, Define); + templ->RemovePrototype(); + data->SetFunctionTemplate(&g_wrapper_info, templ); + } + return templ; +} + +} // namespace + +ModuleRegistry::ModuleRegistry(Isolate* isolate) + : modules_(isolate, Object::New(isolate)) { +} + +ModuleRegistry::~ModuleRegistry() { + modules_.Reset(); +} + +// static +void ModuleRegistry::RegisterGlobals(Isolate* isolate, + v8::Local<ObjectTemplate> templ) { + templ->Set(StringToSymbol(isolate, "define"), GetDefineTemplate(isolate)); +} + +// static +bool ModuleRegistry::InstallGlobals(v8::Isolate* isolate, + v8::Local<v8::Object> obj) { + v8::Local<v8::Function> function; + auto maybe_function = + GetDefineTemplate(isolate)->GetFunction(isolate->GetCurrentContext()); + if (!maybe_function.ToLocal(&function)) + return false; + return SetProperty(isolate, obj, StringToSymbol(isolate, "define"), function); +} + +// static +ModuleRegistry* ModuleRegistry::From(v8::Local<Context> context) { + PerContextData* data = PerContextData::From(context); + if (!data) + return NULL; + + ModuleRegistryData* registry_data = static_cast<ModuleRegistryData*>( + data->GetUserData(kModuleRegistryKey)); + if (!registry_data) { + // PerContextData takes ownership of ModuleRegistryData. + registry_data = new ModuleRegistryData; + registry_data->registry.reset(new ModuleRegistry(context->GetIsolate())); + data->SetUserData(kModuleRegistryKey, base::WrapUnique(registry_data)); + } + return registry_data->registry.get(); +} + +void ModuleRegistry::AddObserver(ModuleRegistryObserver* observer) { + observer_list_.AddObserver(observer); +} + +void ModuleRegistry::RemoveObserver(ModuleRegistryObserver* observer) { + observer_list_.RemoveObserver(observer); +} + +void ModuleRegistry::AddBuiltinModule(Isolate* isolate, const std::string& id, + v8::Local<Value> module) { + DCHECK(!id.empty()); + RegisterModule(isolate, id, module); +} + +void ModuleRegistry::AddPendingModule(Isolate* isolate, + std::unique_ptr<PendingModule> pending) { + const std::string pending_id = pending->id; + const std::vector<std::string> pending_dependencies = pending->dependencies; + AttemptToLoad(isolate, std::move(pending)); + for (auto& observer : observer_list_) + observer.OnDidAddPendingModule(pending_id, pending_dependencies); +} + +void ModuleRegistry::LoadModule(Isolate* isolate, + const std::string& id, + LoadModuleCallback callback) { + if (available_modules_.find(id) != available_modules_.end()) { + // Should we call the callback asynchronously? + callback.Run(GetModule(isolate, id)); + return; + } + waiting_callbacks_.insert(std::make_pair(id, callback)); + + for (size_t i = 0; i < pending_modules_.size(); ++i) { + if (pending_modules_[i]->id == id) + return; + } + + unsatisfied_dependencies_.insert(id); +} + +bool ModuleRegistry::RegisterModule(Isolate* isolate, + const std::string& id, + v8::Local<Value> module) { + if (id.empty() || module.IsEmpty()) + return false; + + v8::Local<Object> modules = Local<Object>::New(isolate, modules_); + if (!SetProperty(isolate, modules, StringToSymbol(isolate, id), module)) + return false; + unsatisfied_dependencies_.erase(id); + available_modules_.insert(id); + + std::pair<LoadModuleCallbackMap::iterator, LoadModuleCallbackMap::iterator> + range = waiting_callbacks_.equal_range(id); + std::vector<LoadModuleCallback> callbacks; + callbacks.reserve(waiting_callbacks_.count(id)); + for (LoadModuleCallbackMap::iterator it = range.first; it != range.second; + ++it) { + callbacks.push_back(it->second); + } + waiting_callbacks_.erase(range.first, range.second); + for (std::vector<LoadModuleCallback>::iterator it = callbacks.begin(); + it != callbacks.end(); + ++it) { + // Should we call the callback asynchronously? + it->Run(module); + } + return true; +} + +bool ModuleRegistry::CheckDependencies(PendingModule* pending) { + size_t num_missing_dependencies = 0; + size_t len = pending->dependencies.size(); + for (size_t i = 0; i < len; ++i) { + const std::string& dependency = pending->dependencies[i]; + if (available_modules_.count(dependency)) + continue; + unsatisfied_dependencies_.insert(dependency); + num_missing_dependencies++; + } + return num_missing_dependencies == 0; +} + +bool ModuleRegistry::Load(Isolate* isolate, + std::unique_ptr<PendingModule> pending) { + if (!pending->id.empty() && available_modules_.count(pending->id)) + return true; // We've already loaded this module. + + uint32_t argc = static_cast<uint32_t>(pending->dependencies.size()); + std::vector<v8::Local<Value> > argv(argc); + for (uint32_t i = 0; i < argc; ++i) + argv[i] = GetModule(isolate, pending->dependencies[i]); + + v8::Local<Value> module = Local<Value>::New(isolate, pending->factory); + + v8::Local<Function> factory; + if (ConvertFromV8(isolate, module, &factory)) { + PerContextData* data = PerContextData::From(isolate->GetCurrentContext()); + Runner* runner = data->runner(); + module = runner->Call(factory, runner->global(), argc, + argv.empty() ? NULL : &argv.front()); + if (pending->id.empty()) + ConvertFromV8(isolate, factory->GetScriptOrigin().ResourceName(), + &pending->id); + } + + return RegisterModule(isolate, pending->id, module); +} + +bool ModuleRegistry::AttemptToLoad(Isolate* isolate, + std::unique_ptr<PendingModule> pending) { + if (!CheckDependencies(pending.get())) { + pending_modules_.push_back(std::move(pending)); + return false; + } + return Load(isolate, std::move(pending)); +} + +v8::Local<v8::Value> ModuleRegistry::GetModule(v8::Isolate* isolate, + const std::string& id) { + v8::Local<Object> modules = Local<Object>::New(isolate, modules_); + v8::Local<String> key = StringToSymbol(isolate, id); + DCHECK(modules->HasOwnProperty(isolate->GetCurrentContext(), key).FromJust()); + return modules->Get(isolate->GetCurrentContext(), key).ToLocalChecked(); +} + +void ModuleRegistry::AttemptToLoadMoreModules(Isolate* isolate) { + bool keep_trying = true; + while (keep_trying) { + keep_trying = false; + PendingModuleVector pending_modules; + pending_modules.swap(pending_modules_); + for (size_t i = 0; i < pending_modules.size(); ++i) { + std::unique_ptr<PendingModule> pending(std::move(pending_modules[i])); + pending_modules[i] = NULL; + if (AttemptToLoad(isolate, std::move(pending))) + keep_trying = true; + } + } +} + +} // namespace gin
diff --git a/gin/modules/module_registry.h b/gin/modules/module_registry.h new file mode 100644 index 0000000..c1d3a00 --- /dev/null +++ b/gin/modules/module_registry.h
@@ -0,0 +1,111 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_MODULES_MODULE_REGISTRY_H_ +#define GIN_MODULES_MODULE_REGISTRY_H_ + +#include <list> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/observer_list.h" +#include "gin/gin_export.h" +#include "v8/include/v8.h" + +namespace gin { + +class ModuleRegistryObserver; +struct PendingModule; + +// This class implements the Asynchronous Module Definition (AMD) API. +// https://github.com/amdjs/amdjs-api/wiki/AMD +// +// Our implementation isn't complete yet. Missing features: +// 1) Built-in support for require, exports, and module. +// 2) Path resoltuion in module names. +// +// For these reasons, we don't have an "amd" property on the "define" +// function. The spec says we should only add that property once our +// implementation complies with the specification. +// +class GIN_EXPORT ModuleRegistry { + public: + typedef base::Callback<void (v8::Local<v8::Value>)> LoadModuleCallback; + + virtual ~ModuleRegistry(); + + static ModuleRegistry* From(v8::Local<v8::Context> context); + + static void RegisterGlobals(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> templ); + + // Installs the necessary functions needed for modules. + // WARNING: this may execute script in the page. + static bool InstallGlobals(v8::Isolate* isolate, v8::Local<v8::Object> obj); + + void AddObserver(ModuleRegistryObserver* observer); + void RemoveObserver(ModuleRegistryObserver* observer); + + // The caller must have already entered our context. + void AddBuiltinModule(v8::Isolate* isolate, const std::string& id, + v8::Local<v8::Value> module); + + // The caller must have already entered our context. + void AddPendingModule(v8::Isolate* isolate, + std::unique_ptr<PendingModule> pending); + + void LoadModule(v8::Isolate* isolate, + const std::string& id, + LoadModuleCallback callback); + + // The caller must have already entered our context. + void AttemptToLoadMoreModules(v8::Isolate* isolate); + + const std::set<std::string>& available_modules() const { + return available_modules_; + } + + const std::set<std::string>& unsatisfied_dependencies() const { + return unsatisfied_dependencies_; + } + + private: + typedef std::vector<std::unique_ptr<PendingModule>> PendingModuleVector; + typedef std::multimap<std::string, LoadModuleCallback> LoadModuleCallbackMap; + + explicit ModuleRegistry(v8::Isolate* isolate); + + bool Load(v8::Isolate* isolate, std::unique_ptr<PendingModule> pending); + bool RegisterModule(v8::Isolate* isolate, + const std::string& id, + v8::Local<v8::Value> module); + + bool CheckDependencies(PendingModule* pending); + bool AttemptToLoad(v8::Isolate* isolate, + std::unique_ptr<PendingModule> pending); + + v8::Local<v8::Value> GetModule(v8::Isolate* isolate, const std::string& id); + + std::set<std::string> available_modules_; + std::set<std::string> unsatisfied_dependencies_; + + LoadModuleCallbackMap waiting_callbacks_; + + PendingModuleVector pending_modules_; + v8::Persistent<v8::Object> modules_; + + base::ObserverList<ModuleRegistryObserver> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(ModuleRegistry); +}; + +} // namespace gin + +#endif // GIN_MODULES_MODULE_REGISTRY_H_
diff --git a/gin/modules/module_registry_observer.h b/gin/modules/module_registry_observer.h new file mode 100644 index 0000000..68ee4ad --- /dev/null +++ b/gin/modules/module_registry_observer.h
@@ -0,0 +1,31 @@ +// 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 GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_ +#define GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_ + +#include <string> +#include <vector> + +#include "gin/gin_export.h" + +namespace gin { + +// Notified of interesting events from ModuleRegistry. +class GIN_EXPORT ModuleRegistryObserver { + public: + // Called from AddPendingModule(). |id| is the id/name of the module and + // |dependencies| this list of modules |id| depends upon. + virtual void OnDidAddPendingModule( + const std::string& id, + const std::vector<std::string>& dependencies) = 0; + + protected: + virtual ~ModuleRegistryObserver() {} +}; + +} // namespace gin + +#endif // GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_ +
diff --git a/gin/modules/module_registry_unittest.cc b/gin/modules/module_registry_unittest.cc new file mode 100644 index 0000000..3921539 --- /dev/null +++ b/gin/modules/module_registry_unittest.cc
@@ -0,0 +1,167 @@ +// 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 "gin/modules/module_registry.h" + +#include <stdint.h> + +#include <memory> + +#include "base/bind.h" +#include "base/macros.h" +#include "gin/modules/module_registry_observer.h" +#include "gin/modules/module_runner_delegate.h" +#include "gin/public/context_holder.h" +#include "gin/public/isolate_holder.h" +#include "gin/shell_runner.h" +#include "gin/test/v8_test.h" +#include "v8/include/v8.h" + +namespace gin { + +namespace { + +struct TestHelper { + TestHelper(v8::Isolate* isolate) + : delegate(std::vector<base::FilePath>()), + runner(new ShellRunner(&delegate, isolate)), + scope(runner.get()) { + } + + ModuleRunnerDelegate delegate; + std::unique_ptr<ShellRunner> runner; + Runner::Scope scope; +}; + +class ModuleRegistryObserverImpl : public ModuleRegistryObserver { + public: + ModuleRegistryObserverImpl() : did_add_count_(0) {} + + void OnDidAddPendingModule( + const std::string& id, + const std::vector<std::string>& dependencies) override { + did_add_count_++; + id_ = id; + dependencies_ = dependencies; + } + + int did_add_count() { return did_add_count_; } + const std::string& id() const { return id_; } + const std::vector<std::string>& dependencies() const { return dependencies_; } + + private: + int did_add_count_; + std::string id_; + std::vector<std::string> dependencies_; + + DISALLOW_COPY_AND_ASSIGN(ModuleRegistryObserverImpl); +}; + +void NestedCallback(v8::Local<v8::Value> value) { + FAIL() << "Should not be called"; +} + +void OnModuleLoaded(TestHelper* helper, + v8::Isolate* isolate, + int64_t* counter, + v8::Local<v8::Value> value) { + ASSERT_TRUE(value->IsNumber()); + v8::Local<v8::Integer> int_value = v8::Local<v8::Integer>::Cast(value); + *counter += int_value->Value(); + ModuleRegistry::From(helper->runner->GetContextHolder()->context()) + ->LoadModule(isolate, "two", base::Bind(NestedCallback)); +} + +void OnModuleLoadedNoOp(v8::Local<v8::Value> value) { + ASSERT_TRUE(value->IsNumber()); +} + +} // namespace + +typedef V8Test ModuleRegistryTest; + +// Verifies ModuleRegistry is not available after ContextHolder has been +// deleted. +TEST_F(ModuleRegistryTest, DestroyedWithContext) { + v8::Isolate::Scope isolate_scope(instance_->isolate()); + v8::HandleScope handle_scope(instance_->isolate()); + v8::Local<v8::Context> context = v8::Context::New( + instance_->isolate(), NULL, v8::Local<v8::ObjectTemplate>()); + { + ContextHolder context_holder(instance_->isolate()); + context_holder.SetContext(context); + ModuleRegistry* registry = ModuleRegistry::From(context); + EXPECT_TRUE(registry != NULL); + } + ModuleRegistry* registry = ModuleRegistry::From(context); + EXPECT_TRUE(registry == NULL); +} + +// Verifies ModuleRegistryObserver is notified appropriately. +TEST_F(ModuleRegistryTest, ModuleRegistryObserverTest) { + TestHelper helper(instance_->isolate()); + std::string source = + "define('id', ['dep1', 'dep2'], function() {" + " return function() {};" + "});"; + + ModuleRegistryObserverImpl observer; + ModuleRegistry::From(helper.runner->GetContextHolder()->context())-> + AddObserver(&observer); + helper.runner->Run(source, "script"); + ModuleRegistry::From(helper.runner->GetContextHolder()->context())-> + RemoveObserver(&observer); + EXPECT_EQ(1, observer.did_add_count()); + EXPECT_EQ("id", observer.id()); + ASSERT_EQ(2u, observer.dependencies().size()); + EXPECT_EQ("dep1", observer.dependencies()[0]); + EXPECT_EQ("dep2", observer.dependencies()[1]); +} + +// Verifies that multiple LoadModule calls for the same module are handled +// correctly. +TEST_F(ModuleRegistryTest, LoadModuleTest) { + TestHelper helper(instance_->isolate()); + int64_t counter = 0; + std::string source = + "define('one', [], function() {" + " return 1;" + "});"; + + ModuleRegistry::LoadModuleCallback callback = + base::Bind(OnModuleLoaded, &helper, instance_->isolate(), &counter); + for (int i = 0; i < 3; i++) { + ModuleRegistry::From(helper.runner->GetContextHolder()->context()) + ->LoadModule(instance_->isolate(), "one", callback); + } + EXPECT_EQ(0, counter); + helper.runner->Run(source, "script"); + EXPECT_EQ(3, counter); +} + +// Verifies that explicitly loading a module that's already pending does +// not cause the ModuleRegistry's unsatisfied_dependency set to grow. +TEST_F(ModuleRegistryTest, UnsatisfiedDependenciesTest) { + TestHelper helper(instance_->isolate()); + std::string source = + "define('one', ['no_such_module'], function(nsm) {" + " return 1;" + "});"; + ModuleRegistry* registry = + ModuleRegistry::From(helper.runner->GetContextHolder()->context()); + + std::set<std::string> no_such_module_set; + no_such_module_set.insert("no_such_module"); + + // Adds one unsatisfied dependency on "no-such-module". + helper.runner->Run(source, "script"); + EXPECT_EQ(no_such_module_set, registry->unsatisfied_dependencies()); + + // Should have no effect on the unsatisfied_dependencies set. + ModuleRegistry::LoadModuleCallback callback = base::Bind(OnModuleLoadedNoOp); + registry->LoadModule(instance_->isolate(), "one", callback); + EXPECT_EQ(no_such_module_set, registry->unsatisfied_dependencies()); +} + +} // namespace gin
diff --git a/gin/modules/module_registry_unittests.js b/gin/modules/module_registry_unittests.js new file mode 100644 index 0000000..ca70148 --- /dev/null +++ b/gin/modules/module_registry_unittests.js
@@ -0,0 +1,30 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +define("module0", function() { + return { + "foo": "bar", + } +}); + +define("module2", [ + "gtest", + "module0", + "module1" + ], function(gtest, module0, module1) { + gtest.expectEqual(module0.foo, "bar", + "module0.foo is " + module0.foo); + gtest.expectFalse(module0.bar, + "module0.bar is " + module0.bar); + gtest.expectEqual(module1.baz, "qux", + "module1.baz is " + module1.baz); + gtest.expectFalse(module1.qux, + "module1.qux is " + module1.qux); + + this.result = "PASS"; +}); + +define("module1", { + "baz": "qux", +});
diff --git a/gin/modules/module_runner_delegate.cc b/gin/modules/module_runner_delegate.cc new file mode 100644 index 0000000..0634fff3 --- /dev/null +++ b/gin/modules/module_runner_delegate.cc
@@ -0,0 +1,66 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/modules/module_runner_delegate.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "gin/modules/module_registry.h" +#include "gin/object_template_builder.h" +#include "gin/public/context_holder.h" + +namespace gin { + +ModuleRunnerDelegate::ModuleRunnerDelegate( + const std::vector<base::FilePath>& search_paths) + : module_provider_(search_paths) { +} + +ModuleRunnerDelegate::~ModuleRunnerDelegate() = default; + +void ModuleRunnerDelegate::AddBuiltinModule(const std::string& id, + ModuleGetter getter) { + builtin_modules_[id] = base::Bind(getter); +} + +void ModuleRunnerDelegate::AddBuiltinModule(const std::string& id, + const ModuleGetterCallback& getter) { + builtin_modules_[id] = getter; +} + +void ModuleRunnerDelegate::AttemptToLoadMoreModules(Runner* runner) { + ModuleRegistry* registry = ModuleRegistry::From( + runner->GetContextHolder()->context()); + registry->AttemptToLoadMoreModules(runner->GetContextHolder()->isolate()); + module_provider_.AttempToLoadModules( + runner, registry->unsatisfied_dependencies()); +} + +v8::Local<v8::ObjectTemplate> ModuleRunnerDelegate::GetGlobalTemplate( + ShellRunner* runner, + v8::Isolate* isolate) { + v8::Local<v8::ObjectTemplate> templ = ObjectTemplateBuilder(isolate).Build(); + ModuleRegistry::RegisterGlobals(isolate, templ); + return templ; +} + +void ModuleRunnerDelegate::DidCreateContext(ShellRunner* runner) { + ShellRunnerDelegate::DidCreateContext(runner); + + v8::Local<v8::Context> context = runner->GetContextHolder()->context(); + ModuleRegistry* registry = ModuleRegistry::From(context); + + v8::Isolate* isolate = runner->GetContextHolder()->isolate(); + + for (BuiltinModuleMap::const_iterator it = builtin_modules_.begin(); + it != builtin_modules_.end(); ++it) { + registry->AddBuiltinModule(isolate, it->first, it->second.Run(isolate)); + } +} + +void ModuleRunnerDelegate::DidRunScript(ShellRunner* runner) { + AttemptToLoadMoreModules(runner); +} + +} // namespace gin
diff --git a/gin/modules/module_runner_delegate.h b/gin/modules/module_runner_delegate.h new file mode 100644 index 0000000..f49594c --- /dev/null +++ b/gin/modules/module_runner_delegate.h
@@ -0,0 +1,57 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_MODULES_MODULE_RUNNER_DELEGATE_H_ +#define GIN_MODULES_MODULE_RUNNER_DELEGATE_H_ + +#include <map> + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "gin/gin_export.h" +#include "gin/modules/file_module_provider.h" +#include "gin/shell_runner.h" +#include "v8/include/v8.h" + +namespace gin { + +typedef v8::Local<v8::Value> (*ModuleGetter)(v8::Isolate* isolate); +typedef base::Callback<v8::Local<v8::Value>(v8::Isolate*)> ModuleGetterCallback; + +// Emebedders that use AMD modules will probably want to use a RunnerDelegate +// that inherits from ModuleRunnerDelegate. ModuleRunnerDelegate lets embedders +// register built-in modules and routes module requests to FileModuleProvider. +class GIN_EXPORT ModuleRunnerDelegate : public ShellRunnerDelegate { + public: + explicit ModuleRunnerDelegate( + const std::vector<base::FilePath>& search_paths); + ~ModuleRunnerDelegate() override; + + void AddBuiltinModule(const std::string& id, ModuleGetter getter); + void AddBuiltinModule(const std::string& id, + const ModuleGetterCallback& getter); + + protected: + void AttemptToLoadMoreModules(Runner* runner); + + private: + typedef std::map<std::string, ModuleGetterCallback> BuiltinModuleMap; + + // From ShellRunnerDelegate: + v8::Local<v8::ObjectTemplate> GetGlobalTemplate( + ShellRunner* runner, + v8::Isolate* isolate) override; + void DidCreateContext(ShellRunner* runner) override; + void DidRunScript(ShellRunner* runner) override; + + BuiltinModuleMap builtin_modules_; + FileModuleProvider module_provider_; + + DISALLOW_COPY_AND_ASSIGN(ModuleRunnerDelegate); +}; + +} // namespace gin + +#endif // GIN_MODULES_MODULE_RUNNER_DELEGATE_H_
diff --git a/gin/modules/timer.cc b/gin/modules/timer.cc new file mode 100644 index 0000000..1f60900 --- /dev/null +++ b/gin/modules/timer.cc
@@ -0,0 +1,112 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/modules/timer.h" + +#include "base/bind.h" +#include "gin/object_template_builder.h" +#include "gin/per_context_data.h" + +namespace gin { + +namespace { + +v8::Local<v8::Private> GetHiddenPropertyName(v8::Isolate* isolate) { + return v8::Private::ForApi(isolate, gin::StringToV8(isolate, "::gin::Timer")); +} + +} // namespace + +// Timer ======================================================================= + +gin::WrapperInfo Timer::kWrapperInfo = { gin::kEmbedderNativeGin }; + +// static +Handle<Timer> Timer::Create(TimerType type, v8::Isolate* isolate, int delay_ms, + v8::Local<v8::Function> function) { + return CreateHandle(isolate, new Timer(isolate, type == TYPE_REPEATING, + delay_ms, function)); +} + +ObjectTemplateBuilder Timer::GetObjectTemplateBuilder(v8::Isolate* isolate) { + // We use Unretained() here because we directly own timer_, so we know it will + // be alive when these methods are called. + return Wrappable<Timer>::GetObjectTemplateBuilder(isolate) + .SetMethod("cancel", + base::Bind(&base::Timer::Stop, base::Unretained(&timer_))) + .SetMethod("reset", + base::Bind(&base::Timer::Reset, base::Unretained(&timer_))); +} + +Timer::Timer(v8::Isolate* isolate, bool repeating, int delay_ms, + v8::Local<v8::Function> function) + : timer_(false, repeating), + runner_(PerContextData::From( + isolate->GetCurrentContext())->runner()->GetWeakPtr()), + weak_factory_(this) { + GetWrapper(runner_->GetContextHolder()->isolate()) + .ToLocalChecked() + ->SetPrivate(isolate->GetCurrentContext(), GetHiddenPropertyName(isolate), + function) + .FromJust(); + timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms), + base::Bind(&Timer::OnTimerFired, weak_factory_.GetWeakPtr())); +} + +Timer::~Timer() = default; + +void Timer::OnTimerFired() { + // This can happen in spite of the weak callback because it is possible for + // a gin::Handle<> to keep this object alive past when the isolate it is part + // of is destroyed. + if (!runner_.get()) { + return; + } + + Runner::Scope scope(runner_.get()); + v8::Isolate* isolate = runner_->GetContextHolder()->isolate(); + + v8::Local<v8::Object> wrapper; + if (!GetWrapper(isolate).ToLocal(&wrapper)) { + return; + } + + v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( + wrapper + ->GetPrivate(runner_->GetContextHolder()->context(), + GetHiddenPropertyName(isolate)) + .ToLocalChecked()); + runner_->Call(function, v8::Undefined(isolate), 0, NULL); +} + + +// TimerModule ================================================================= + +const char TimerModule::kName[] = "timer"; +WrapperInfo TimerModule::kWrapperInfo = { kEmbedderNativeGin }; + +// static +Handle<TimerModule> TimerModule::Create(v8::Isolate* isolate) { + return CreateHandle(isolate, new TimerModule()); +} + +// static +v8::Local<v8::Value> TimerModule::GetModule(v8::Isolate* isolate) { + return Create(isolate)->GetWrapper(isolate).ToLocalChecked(); +} + +TimerModule::TimerModule() = default; + +TimerModule::~TimerModule() = default; + +ObjectTemplateBuilder TimerModule::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return Wrappable<TimerModule>::GetObjectTemplateBuilder(isolate) + .SetMethod("createOneShot", + base::Bind(&Timer::Create, Timer::TYPE_ONE_SHOT)) + .SetMethod("createRepeating", + base::Bind(&Timer::Create, Timer::TYPE_REPEATING)); +} + +} // namespace gin
diff --git a/gin/modules/timer.h b/gin/modules/timer.h new file mode 100644 index 0000000..1b7f613 --- /dev/null +++ b/gin/modules/timer.h
@@ -0,0 +1,65 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_MODULES_TIMER_H_ +#define GIN_MODULES_TIMER_H_ + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "gin/gin_export.h" +#include "gin/handle.h" +#include "gin/runner.h" +#include "gin/wrappable.h" +#include "v8/include/v8.h" + +namespace gin { + +class ObjectTemplateBuilder; + +// A simple scriptable timer that can work in one-shot or repeating mode. +class GIN_EXPORT Timer : public Wrappable<Timer> { + public: + enum TimerType { + TYPE_ONE_SHOT, + TYPE_REPEATING + }; + + static WrapperInfo kWrapperInfo; + static Handle<Timer> Create(TimerType type, v8::Isolate* isolate, + int delay_ms, v8::Local<v8::Function> function); + + ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) override; + + private: + Timer(v8::Isolate* isolate, bool repeating, int delay_ms, + v8::Local<v8::Function> function); + ~Timer() override; + void OnTimerFired(); + + base::Timer timer_; + base::WeakPtr<gin::Runner> runner_; + base::WeakPtrFactory<Timer> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(Timer); +}; + + +class GIN_EXPORT TimerModule : public Wrappable<TimerModule> { + public: + static const char kName[]; + static WrapperInfo kWrapperInfo; + static Handle<TimerModule> Create(v8::Isolate* isolate); + static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); + + private: + TimerModule(); + ~TimerModule() override; + + ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) override; +}; + +} // namespace gin + +#endif // GIN_MODULES_TIMER_H_
diff --git a/gin/modules/timer_unittest.cc b/gin/modules/timer_unittest.cc new file mode 100644 index 0000000..2490d23 --- /dev/null +++ b/gin/modules/timer_unittest.cc
@@ -0,0 +1,148 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/modules/timer.h" + +#include <memory> + +#include "base/run_loop.h" +#include "base/single_thread_task_runner.h" +#include "gin/handle.h" +#include "gin/object_template_builder.h" +#include "gin/public/isolate_holder.h" +#include "gin/shell_runner.h" +#include "gin/test/v8_test.h" +#include "gin/try_catch.h" +#include "gin/wrappable.h" +#include "v8/include/v8.h" + +namespace gin { + +namespace { + +class Result : public Wrappable<Result> { + public: + static WrapperInfo kWrapperInfo; + static Handle<Result> Create(v8::Isolate* isolate) { + return CreateHandle(isolate, new Result()); + } + + int count() const { return count_; } + void set_count(int count) { count_ = count; } + + void Quit() { base::RunLoop::QuitCurrentDeprecated(); } + + private: + Result() : count_(0) { + } + + ~Result() override = default; + + ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) override { + return Wrappable<Result>::GetObjectTemplateBuilder(isolate) + .SetProperty("count", &Result::count, &Result::set_count) + .SetMethod("quit", &Result::Quit); + } + + int count_; +}; + +WrapperInfo Result::kWrapperInfo = { gin::kEmbedderNativeGin }; + +struct TestHelper { + TestHelper(v8::Isolate* isolate) + : runner(new ShellRunner(&delegate, isolate)), + scope(runner.get()), + timer_module(TimerModule::Create(isolate)), + result(Result::Create(isolate)) { + EXPECT_FALSE(runner->global().IsEmpty()); + runner->global()->Set(StringToV8(isolate, "timer"), + timer_module->GetWrapper(isolate).ToLocalChecked()); + runner->global()->Set(StringToV8(isolate, "result"), + result->GetWrapper(isolate).ToLocalChecked()); + } + + ShellRunnerDelegate delegate; + std::unique_ptr<ShellRunner> runner; + Runner::Scope scope; + Handle<TimerModule> timer_module; + Handle<Result> result; +}; + +} // namespace + +typedef V8Test TimerUnittest; + +TEST_F(TimerUnittest, OneShot) { + TestHelper helper(instance_->isolate()); + std::string source = + "timer.createOneShot(0, function() {" + " result.count++;" + "});"; + + helper.runner->Run(source, "script"); + EXPECT_EQ(0, helper.result->count()); + + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, helper.result->count()); +} + +TEST_F(TimerUnittest, OneShotCancel) { + TestHelper helper(instance_->isolate()); + std::string source = + "var t = timer.createOneShot(0, function() {" + " result.count++;" + "});" + "t.cancel()"; + + helper.runner->Run(source, "script"); + EXPECT_EQ(0, helper.result->count()); + + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0, helper.result->count()); +} + +TEST_F(TimerUnittest, Repeating) { + TestHelper helper(instance_->isolate()); + + // TODO(aa): Cannot do: if (++result.count == 3) because of v8 bug. Create + // test case and report. + std::string source = + "var t = timer.createRepeating(0, function() {" + " result.count++;" + " if (result.count == 3) {" + " /* Cancel the timer to prevent a hang when ScopedTaskEnvironment " + " flushes main thread tasks. */" + " t.cancel();" + " result.quit();" + " }" + "});"; + + helper.runner->Run(source, "script"); + EXPECT_EQ(0, helper.result->count()); + + base::RunLoop().Run(); + EXPECT_EQ(3, helper.result->count()); +} + +TEST_F(TimerUnittest, TimerCallbackToDestroyedRunner) { + TestHelper helper(instance_->isolate()); + std::string source = + "timer.createOneShot(0, function() {" + " result.count++;" + "});"; + + helper.runner->Run(source, "script"); + EXPECT_EQ(0, helper.result->count()); + + // Destroy runner, which should destroy the timer object we created. + helper.runner.reset(NULL); + base::RunLoop().RunUntilIdle(); + + // Timer should not have run because it was deleted. + EXPECT_EQ(0, helper.result->count()); +} + +} // namespace gin
diff --git a/gin/runner.h b/gin/runner.h index 928275d5..a898b03 100644 --- a/gin/runner.h +++ b/gin/runner.h
@@ -25,6 +25,10 @@ // context by creating an instance of Runner::Scope on the stack. virtual void Run(const std::string& source, const std::string& resource_name) = 0; + virtual v8::Local<v8::Value> Call(v8::Local<v8::Function> function, + v8::Local<v8::Value> receiver, + int argc, + v8::Local<v8::Value> argv[]) = 0; virtual ContextHolder* GetContextHolder() = 0; v8::Local<v8::Object> global() {
diff --git a/gin/shell/gin_main.cc b/gin/shell/gin_main.cc index 12c74b8..a28ca155 100644 --- a/gin/shell/gin_main.cc +++ b/gin/shell/gin_main.cc
@@ -18,9 +18,8 @@ #include "base/threading/thread_task_runner_handle.h" #include "gin/array_buffer.h" #include "gin/modules/console.h" -#include "gin/object_template_builder.h" +#include "gin/modules/module_runner_delegate.h" #include "gin/public/isolate_holder.h" -#include "gin/shell_runner.h" #include "gin/try_catch.h" #include "gin/v8_initializer.h" @@ -41,20 +40,20 @@ runner->Run(Load(path), path.AsUTF8Unsafe()); } -class GinShellRunnerDelegate : public ShellRunnerDelegate { - public: - GinShellRunnerDelegate() {} +std::vector<base::FilePath> GetModuleSearchPaths() { + std::vector<base::FilePath> module_base(1); + CHECK(base::GetCurrentDirectory(&module_base[0])); + return module_base; +} - v8::Local<v8::ObjectTemplate> GetGlobalTemplate( - ShellRunner* runner, - v8::Isolate* isolate) override { - v8::Local<v8::ObjectTemplate> templ = - ObjectTemplateBuilder(isolate).Build(); - gin::Console::Register(isolate, templ); - return templ; +class GinShellRunnerDelegate : public ModuleRunnerDelegate { + public: + GinShellRunnerDelegate() : ModuleRunnerDelegate(GetModuleSearchPaths()) { + AddBuiltinModule(Console::kModuleName, Console::GetModule); } void UnhandledException(ShellRunner* runner, TryCatch& try_catch) override { + ModuleRunnerDelegate::UnhandledException(runner, try_catch); LOG(ERROR) << try_catch.GetStackTrace(); }
diff --git a/gin/shell/hello_world.js b/gin/shell/hello_world.js index 6f091000..7216fbd1 100644 --- a/gin/shell/hello_world.js +++ b/gin/shell/hello_world.js
@@ -2,4 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -log("Hello World"); +define(["console"], function(console) { + console.log("Hello World"); +});
diff --git a/gin/shell_runner.cc b/gin/shell_runner.cc index f052428..b98240a1 100644 --- a/gin/shell_runner.cc +++ b/gin/shell_runner.cc
@@ -5,6 +5,7 @@ #include "gin/shell_runner.h" #include "gin/converter.h" +#include "gin/modules/module_registry.h" #include "gin/per_context_data.h" #include "gin/public/context_holder.h" #include "gin/try_catch.h" @@ -75,6 +76,24 @@ Run(script); } +v8::Local<v8::Value> ShellRunner::Call(v8::Local<v8::Function> function, + v8::Local<v8::Value> receiver, + int argc, + v8::Local<v8::Value> argv[]) { + TryCatch try_catch(GetContextHolder()->isolate()); + delegate_->WillRunScript(this); + + auto maybe_result = + function->Call(GetContextHolder()->context(), receiver, argc, argv); + + delegate_->DidRunScript(this); + v8::Local<v8::Value> result; + if (!maybe_result.ToLocal(&result)) + delegate_->UnhandledException(this, try_catch); + + return result; +} + ContextHolder* ShellRunner::GetContextHolder() { return context_holder_.get(); }
diff --git a/gin/shell_runner.h b/gin/shell_runner.h index 10c92df..f7651f0 100644 --- a/gin/shell_runner.h +++ b/gin/shell_runner.h
@@ -48,6 +48,10 @@ // Runner overrides: void Run(const std::string& source, const std::string& resource_name) override; + v8::Local<v8::Value> Call(v8::Local<v8::Function> function, + v8::Local<v8::Value> receiver, + int argc, + v8::Local<v8::Value> argv[]) override; ContextHolder* GetContextHolder() override; private:
diff --git a/gin/shell_runner_unittest.cc b/gin/shell_runner_unittest.cc index a2dc656f..65a7db9 100644 --- a/gin/shell_runner_unittest.cc +++ b/gin/shell_runner_unittest.cc
@@ -24,7 +24,8 @@ namespace gin { -TEST(RunnerTest, Run) { +// TODO(yzshen): crbug.com/793480 +TEST(RunnerTest, DISABLED_Run) { base::test::ScopedTaskEnvironment scoped_task_environment; std::string source = "this.result = 'PASS';\n";
diff --git a/gin/test/expect.js b/gin/test/expect.js new file mode 100644 index 0000000..597b5b1 --- /dev/null +++ b/gin/test/expect.js
@@ -0,0 +1,299 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +define(function() { + // Equality function based on isEqual in + // Underscore.js 1.5.2 + // http://underscorejs.org + // (c) 2009-2013 Jeremy Ashkenas, + // DocumentCloud, + // and Investigative Reporters & Editors + // Underscore may be freely distributed under the MIT license. + // + function has(obj, key) { + return obj.hasOwnProperty(key); + } + function isFunction(obj) { + return typeof obj === 'function'; + } + function isArrayBufferClass(className) { + return className == '[object ArrayBuffer]' || + className.match(/\[object \w+\d+(Clamped)?Array\]/); + } + // Internal recursive comparison function for `isEqual`. + function eq(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the Harmony `egal` proposal: + // http://wiki.ecmascript.org/doku.php?id=harmony:egal. + if (a === b) + return a !== 0 || 1 / a == 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) + return a === b; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className != toString.call(b)) + return false; + switch (className) { + // Strings, numbers, dates, and booleans are compared by value. + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; + // thus, `"5"` is equivalent to `new String("5")`. + return a == String(b); + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is + // performed for other numeric values. + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are + // compared by their millisecond representations. Note that invalid + // dates with millisecond representations of `NaN` are not equivalent. + return +a == +b; + // RegExps are compared by their source patterns and flags. + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') + return false; + // Assume equality for cyclic structures. The algorithm for detecting + // cyclic structures is adapted from ES 5.1 section 15.12.3, abstract + // operation `JO`. + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] == a) + return bStack[length] == b; + } + // Objects with different constructors are not equivalent, but `Object`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) && + isFunction(bCtor) && (bCtor instanceof bCtor)) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + var size = 0, result = true; + // Recursively compare Maps, objects and arrays. + if (className == '[object Array]' || isArrayBufferClass(className)) { + // Compare array lengths to determine if a deep comparison is necessary. + size = a.length; + result = size == b.length; + if (result) { + // Deep compare the contents, ignoring non-numeric properties. + while (size--) { + if (!(result = eq(a[size], b[size], aStack, bStack))) + break; + } + } + } else if (className == '[object Map]') { + result = a.size == b.size; + if (result) { + var entries = a.entries(); + for (var e = entries.next(); result && !e.done; e = entries.next()) { + var key = e.value[0]; + var value = e.value[1]; + result = b.has(key) && eq(value, b.get(key), aStack, bStack); + } + } + } else { + // Deep compare objects. + for (var key in a) { + if (has(a, key)) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack))) + break; + } + } + // Ensure that both objects contain the same number of properties. + if (result) { + for (key in b) { + if (has(b, key) && !(size--)) + break; + } + result = !size; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return result; + }; + + function describe(subjects) { + var descriptions = []; + Object.getOwnPropertyNames(subjects).forEach(function(name) { + if (name === "Description") + descriptions.push(subjects[name]); + else + descriptions.push(name + ": " + JSON.stringify(subjects[name])); + }); + return descriptions.join(" "); + } + + var predicates = {}; + + predicates.toBe = function(actual, expected) { + return { + "result": actual === expected, + "message": describe({ + "Actual": actual, + "Expected": expected, + }), + }; + }; + + predicates.toEqual = function(actual, expected) { + return { + "result": eq(actual, expected, [], []), + "message": describe({ + "Actual": actual, + "Expected": expected, + }), + }; + }; + + predicates.toBeDefined = function(actual) { + return { + "result": typeof actual !== "undefined", + "message": describe({ + "Actual": actual, + "Description": "Expected a defined value", + }), + }; + }; + + predicates.toBeUndefined = function(actual) { + // Recall: undefined is just a global variable. :) + return { + "result": typeof actual === "undefined", + "message": describe({ + "Actual": actual, + "Description": "Expected an undefined value", + }), + }; + }; + + predicates.toBeNull = function(actual) { + // Recall: typeof null === "object". + return { + "result": actual === null, + "message": describe({ + "Actual": actual, + "Expected": null, + }), + }; + }; + + predicates.toBeTruthy = function(actual) { + return { + "result": !!actual, + "message": describe({ + "Actual": actual, + "Description": "Expected a truthy value", + }), + }; + }; + + predicates.toBeFalsy = function(actual) { + return { + "result": !!!actual, + "message": describe({ + "Actual": actual, + "Description": "Expected a falsy value", + }), + }; + }; + + predicates.toContain = function(actual, element) { + return { + "result": (function () { + for (var i = 0; i < actual.length; ++i) { + if (eq(actual[i], element, [], [])) + return true; + } + return false; + })(), + "message": describe({ + "Actual": actual, + "Element": element, + }), + }; + }; + + predicates.toBeLessThan = function(actual, reference) { + return { + "result": actual < reference, + "message": describe({ + "Actual": actual, + "Reference": reference, + }), + }; + }; + + predicates.toBeGreaterThan = function(actual, reference) { + return { + "result": actual > reference, + "message": describe({ + "Actual": actual, + "Reference": reference, + }), + }; + }; + + predicates.toThrow = function(actual) { + return { + "result": (function () { + if (!isFunction(actual)) + throw new TypeError; + try { + actual(); + } catch (ex) { + return true; + } + return false; + })(), + "message": "Expected function to throw", + }; + } + + function negate(predicate) { + return function() { + var outcome = predicate.apply(null, arguments); + outcome.result = !outcome.result; + return outcome; + } + } + + function check(predicate) { + return function() { + var outcome = predicate.apply(null, arguments); + if (outcome.result) + return; + throw outcome.message; + }; + } + + function Condition(actual) { + this.not = {}; + Object.getOwnPropertyNames(predicates).forEach(function(name) { + var bound = predicates[name].bind(null, actual); + this[name] = check(bound); + this.not[name] = check(negate(bound)); + }, this); + } + + return function(actual) { + return new Condition(actual); + }; +});
diff --git a/gin/test/file.cc b/gin/test/file.cc new file mode 100644 index 0000000..38efbb4 --- /dev/null +++ b/gin/test/file.cc
@@ -0,0 +1,88 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/test/file.h" + +#include <iostream> + +#include "base/bind.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "gin/arguments.h" +#include "gin/converter.h" +#include "gin/object_template_builder.h" +#include "gin/per_isolate_data.h" +#include "gin/public/wrapper_info.h" + +using v8::ObjectTemplate; + +namespace gin { + +namespace { + +v8::Local<v8::Value> ReadFileToString(gin::Arguments* args) { + std::string filename; + if (!args->GetNext(&filename)) + return v8::Null(args->isolate()); + + const base::FilePath& path = base::FilePath::FromUTF8Unsafe(filename); + std::string contents; + if (!ReadFileToString(path, &contents)) + return v8::Null(args->isolate()); + + return gin::Converter<std::string>::ToV8(args->isolate(), contents); +} + +v8::Local<v8::Value> GetSourceRootDirectory(gin::Arguments* args) { + base::FilePath path; + if (!PathService::Get(base::DIR_SOURCE_ROOT, &path)) + return v8::Null(args->isolate()); + return gin::Converter<std::string>::ToV8(args->isolate(), + path.AsUTF8Unsafe()); +} + +v8::Local<v8::Value> GetFilesInDirectory(gin::Arguments* args) { + std::string filename; + if (!args->GetNext(&filename)) + return v8::Null(args->isolate()); + + const base::FilePath& path = base::FilePath::FromUTF8Unsafe(filename); + if (!base::DirectoryExists(path)) + return v8::Null(args->isolate()); + + std::vector<std::string> names; + base::FileEnumerator e(path, false, base::FileEnumerator::FILES); + for (base::FilePath name = e.Next(); !name.empty(); name = e.Next()) { + names.push_back(name.BaseName().AsUTF8Unsafe()); + } + + v8::Local<v8::Value> v8_names; + if (!TryConvertToV8(args->isolate(), names, &v8_names)) + return v8::Null(args->isolate()); + return v8_names; +} + +gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin }; + +} // namespace + +const char File::kModuleName[] = "file"; + +v8::Local<v8::Value> File::GetModule(v8::Isolate* isolate) { + gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); + v8::Local<ObjectTemplate> templ = data->GetObjectTemplate(&g_wrapper_info); + if (templ.IsEmpty()) { + templ = gin::ObjectTemplateBuilder(isolate) + .SetMethod("readFileToString", ReadFileToString) + .SetMethod("getFilesInDirectory", GetFilesInDirectory) + .SetMethod("getSourceRootDirectory", GetSourceRootDirectory) + .Build(); + data->SetObjectTemplate(&g_wrapper_info, templ); + } + return templ->NewInstance(); +} + +} // namespace gin
diff --git a/gin/test/file.h b/gin/test/file.h new file mode 100644 index 0000000..a4acd59 --- /dev/null +++ b/gin/test/file.h
@@ -0,0 +1,21 @@ +// 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 GIN_TEST_FILE_H_ +#define GIN_TEST_FILE_H_ + +#include "v8/include/v8.h" + +namespace gin { + +class File { + public: + static const char kModuleName[]; + static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); +}; + +} // namespace gin + +#endif // GIN_TEST_FILE_H_ +
diff --git a/gin/test/file_runner.cc b/gin/test/file_runner.cc new file mode 100644 index 0000000..39ece62 --- /dev/null +++ b/gin/test/file_runner.cc
@@ -0,0 +1,94 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/test/file_runner.h" + +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "base/threading/thread_task_runner_handle.h" +#include "gin/array_buffer.h" +#include "gin/converter.h" +#include "gin/modules/console.h" +#include "gin/modules/module_registry.h" +#include "gin/public/context_holder.h" +#include "gin/public/isolate_holder.h" +#include "gin/test/file.h" +#include "gin/test/gc.h" +#include "gin/test/gtest.h" +#include "gin/try_catch.h" +#include "gin/v8_initializer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gin { + +namespace { + +std::vector<base::FilePath> GetModuleSearchPaths() { + std::vector<base::FilePath> search_paths(2); + PathService::Get(base::DIR_SOURCE_ROOT, &search_paths[0]); + PathService::Get(base::DIR_EXE, &search_paths[1]); + search_paths[1] = search_paths[1].AppendASCII("gen"); + return search_paths; +} + +} // namespace + +FileRunnerDelegate::FileRunnerDelegate() + : ModuleRunnerDelegate(GetModuleSearchPaths()) { + AddBuiltinModule(Console::kModuleName, Console::GetModule); + AddBuiltinModule(GTest::kModuleName, GTest::GetModule); + AddBuiltinModule(GC::kModuleName, GC::GetModule); + AddBuiltinModule(File::kModuleName, File::GetModule); +} + +FileRunnerDelegate::~FileRunnerDelegate() = default; + +void FileRunnerDelegate::UnhandledException(ShellRunner* runner, + TryCatch& try_catch) { + ModuleRunnerDelegate::UnhandledException(runner, try_catch); + FAIL() << try_catch.GetStackTrace(); +} + +void RunTestFromFile(const base::FilePath& path, FileRunnerDelegate* delegate, + bool run_until_idle) { + ASSERT_TRUE(base::PathExists(path)) << path.LossyDisplayName(); + std::string source; + ASSERT_TRUE(ReadFileToString(path, &source)); + + base::test::ScopedTaskEnvironment scoped_task_environment; + +#ifdef V8_USE_EXTERNAL_STARTUP_DATA + gin::V8Initializer::LoadV8Snapshot(); + gin::V8Initializer::LoadV8Natives(); +#ifdef USE_V8_CONTEXT_SNAPSHOT + gin::V8Initializer::LoadV8ContextSnapshot(); +#endif // USE_V8_CONTEXT_SNAPSHOT +#endif // V8_USE_EXTERNAL_STARTUP_DATA + + gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode, + gin::IsolateHolder::kStableV8Extras, + gin::ArrayBufferAllocator::SharedInstance()); + + gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get()); + gin::ShellRunner runner(delegate, instance.isolate()); + { + gin::Runner::Scope scope(&runner); + instance.isolate()->SetCaptureStackTraceForUncaughtExceptions(true); + runner.Run(source, path.AsUTF8Unsafe()); + + if (run_until_idle) { + base::RunLoop().RunUntilIdle(); + } else { + base::RunLoop().Run(); + } + + v8::Local<v8::Value> result = runner.global()->Get( + StringToSymbol(runner.GetContextHolder()->isolate(), "result")); + EXPECT_EQ("PASS", V8ToString(result)); + } +} + +} // namespace gin
diff --git a/gin/test/file_runner.h b/gin/test/file_runner.h new file mode 100644 index 0000000..b20859a --- /dev/null +++ b/gin/test/file_runner.h
@@ -0,0 +1,38 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_TEST_FILE_RUNNER_H_ +#define GIN_TEST_FILE_RUNNER_H_ + +#include "base/compiler_specific.h" +#include "base/files/file_path.h" +#include "base/macros.h" +#include "gin/modules/module_runner_delegate.h" +#include "gin/runner.h" + +namespace gin { + +// FileRunnerDelegate is a simple RunnerDelegate that's useful for running +// tests. The FileRunnerDelegate provides built-in modules for "console" and +// "gtest" that are useful when writing unit tests. +// +// TODO(abarth): Rename FileRunnerDelegate to TestRunnerDelegate. +class FileRunnerDelegate : public ModuleRunnerDelegate { + public: + FileRunnerDelegate(); + ~FileRunnerDelegate() override; + + private: + // From ModuleRunnerDelegate: + void UnhandledException(ShellRunner* runner, TryCatch& try_catch) override; + + DISALLOW_COPY_AND_ASSIGN(FileRunnerDelegate); +}; + +void RunTestFromFile(const base::FilePath& path, FileRunnerDelegate* delegate, + bool run_until_idle = true); + +} // namespace gin + +#endif // GIN_TEST_FILE_RUNNER_H_
diff --git a/gin/test/file_unittests.js b/gin/test/file_unittests.js new file mode 100644 index 0000000..8c25806 --- /dev/null +++ b/gin/test/file_unittests.js
@@ -0,0 +1,37 @@ +// 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. + +define([ + "gin/test/expect", + "file" + ], function(expect, file) { + + function isString(x) { + return toString.call(x) === '[object String]' + } + + var rootDir = file.getSourceRootDirectory(); + expect(isString(rootDir)).toBeTruthy(); + + var noArgsNull = file.getFilesInDirectory(); + expect(noArgsNull).toBeNull(); + + var files = file.getFilesInDirectory(rootDir); + expect(Array.isArray(files)).toBeTruthy(); + + var nsdNull = file.getFilesInDirectory(rootDir + "/no_such_dir"); + expect(nsdNull).toBeNull(); + + var owners = file.readFileToString(rootDir + "/OWNERS"); + expect(isString(owners)).toBeTruthy(); + expect(owners.length).toBeGreaterThan(0); + + noArgsNull = file.readFileToString(); + expect(noArgsNull).toBeNull(); + + var nsfNull = file.readFileToString(rootDir + "/no_such_file"); + expect(nsfNull).toBeNull(); + + this.result = "PASS"; +});
diff --git a/gin/test/gc.cc b/gin/test/gc.cc new file mode 100644 index 0000000..4cd67e1 --- /dev/null +++ b/gin/test/gc.cc
@@ -0,0 +1,41 @@ +// 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 "gin/test/gc.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "gin/arguments.h" +#include "gin/converter.h" +#include "gin/function_template.h" +#include "gin/object_template_builder.h" +#include "gin/per_isolate_data.h" +#include "gin/public/wrapper_info.h" +#include "gin/wrappable.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gin { + +namespace { +WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; +} // namespace + +const char GC::kModuleName[] = "gc"; + +v8::Local<v8::Value> GC::GetModule(v8::Isolate* isolate) { + PerIsolateData* data = PerIsolateData::From(isolate); + v8::Local<v8::ObjectTemplate> templ = + data->GetObjectTemplate(&g_wrapper_info); + if (templ.IsEmpty()) { + templ = ObjectTemplateBuilder(isolate) + .SetMethod("collectGarbage", + base::Bind(&v8::Isolate::LowMemoryNotification, + base::Unretained(isolate))) + .Build(); + data->SetObjectTemplate(&g_wrapper_info, templ); + } + return templ->NewInstance(); +} + +} // namespace gin
diff --git a/gin/test/gc.h b/gin/test/gc.h new file mode 100644 index 0000000..25917ef --- /dev/null +++ b/gin/test/gc.h
@@ -0,0 +1,21 @@ +// 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 GIN_TEST_GC_H_ +#define GIN_TEST_GC_H_ + +#include "v8/include/v8.h" + +namespace gin { + +// This module provides bindings to the garbage collector. +class GC { + public: + static const char kModuleName[]; + static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); +}; + +} // namespace gin + +#endif // GIN_TEST_GC_H_
diff --git a/gin/test/gtest.cc b/gin/test/gtest.cc new file mode 100644 index 0000000..76aaf1f --- /dev/null +++ b/gin/test/gtest.cc
@@ -0,0 +1,62 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/test/gtest.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "gin/arguments.h" +#include "gin/converter.h" +#include "gin/function_template.h" +#include "gin/object_template_builder.h" +#include "gin/per_isolate_data.h" +#include "gin/public/wrapper_info.h" +#include "gin/wrappable.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gin { + +namespace { + +void Fail(const std::string& description) { + FAIL() << description; +} + +void ExpectTrue(bool condition, const std::string& description) { + EXPECT_TRUE(condition) << description; +} + +void ExpectFalse(bool condition, const std::string& description) { + EXPECT_FALSE(condition) << description; +} + +void ExpectEqual(const v8::Local<v8::Value> expected, + const v8::Local<v8::Value> actual, + const std::string& description) { + EXPECT_TRUE(expected->StrictEquals(actual)) << description; +} + +WrapperInfo g_wrapper_info = { kEmbedderNativeGin }; + +} // namespace + +const char GTest::kModuleName[] = "gtest"; + +v8::Local<v8::Value> GTest::GetModule(v8::Isolate* isolate) { + PerIsolateData* data = PerIsolateData::From(isolate); + v8::Local<v8::ObjectTemplate> templ = + data->GetObjectTemplate(&g_wrapper_info); + if (templ.IsEmpty()) { + templ = ObjectTemplateBuilder(isolate) + .SetMethod("fail", Fail) + .SetMethod("expectTrue", ExpectTrue) + .SetMethod("expectFalse", ExpectFalse) + .SetMethod("expectEqual", ExpectEqual) + .Build(); + data->SetObjectTemplate(&g_wrapper_info, templ); + } + return templ->NewInstance(); +} + +} // namespace gin
diff --git a/gin/test/gtest.h b/gin/test/gtest.h new file mode 100644 index 0000000..8f4332d0 --- /dev/null +++ b/gin/test/gtest.h
@@ -0,0 +1,23 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_TEST_GTEST_H_ +#define GIN_TEST_GTEST_H_ + +#include "v8/include/v8.h" + +namespace gin { + +// This module provides bindings to gtest. Most tests should use an idiomatic +// JavaScript testing API, but this module is available for tests that need a +// low-level integration with gtest. +class GTest { + public: + static const char kModuleName[]; + static v8::Local<v8::Value> GetModule(v8::Isolate* isolate); +}; + +} // namespace gin + +#endif // GIN_TEST_GTEST_H_
diff --git a/gin/test/gtest_unittests.js b/gin/test/gtest_unittests.js new file mode 100644 index 0000000..1d566d5 --- /dev/null +++ b/gin/test/gtest_unittests.js
@@ -0,0 +1,11 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +define(["gtest"], function(gtest) { + gtest.expectTrue(true, "true is true"); + gtest.expectFalse(false, "false is false"); + gtest.expectTrue(this, "this is " + this); + + this.result = "PASS"; +});
diff --git a/gin/test/run_js_tests.cc b/gin/test/run_js_tests.cc new file mode 100644 index 0000000..b83dc9f2 --- /dev/null +++ b/gin/test/run_js_tests.cc
@@ -0,0 +1,43 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "gin/test/file_runner.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gin { +namespace { + +base::FilePath BasePath() { + base::FilePath path; + PathService::Get(base::DIR_SOURCE_ROOT, &path); + return path.AppendASCII("gin"); +} + +void RunTest(const base::FilePath& path) { + FileRunnerDelegate delegate; + RunTestFromFile(path, &delegate); +} + +TEST(JSTest, File) { + RunTest(BasePath() + .AppendASCII("test") + .AppendASCII("file_unittests.js")); +} + +TEST(JSTest, GTest) { + RunTest(BasePath() + .AppendASCII("test") + .AppendASCII("gtest_unittests.js")); +} + +TEST(JSTest, ModuleRegistry) { + RunTest(BasePath() + .AppendASCII("modules") + .AppendASCII("module_registry_unittests.js")); +} + +} // namespace +} // gin
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index 7c512768..0831eed9 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -2268,6 +2268,17 @@ - (void)presentNewTabTipBubble { DCHECK(self.browserState); + // If the BVC is not visible, do not present the bubble. + if (!self.viewVisible) + return; + // Do not present the bubble if there is no current or if the current tab is + // the NTP. + Tab* currentTab = [self.tabModel currentTab]; + if (!currentTab) + return; + if (currentTab.webState->GetVisibleURL() == kChromeUINewTabURL) + return; + NSString* text = l10n_util::GetNSStringWithFixup(IDS_IOS_NEW_TAB_IPH_PROMOTION_TEXT); CGPoint tabSwitcherAnchor; @@ -2317,6 +2328,10 @@ DCHECK(self.browserState); DCHECK([_toolbarCoordinator respondsToSelector:@selector(anchorPointForToolsMenuButton:)]); + // If the BVC is not visible, do not present the bubble. + if (!self.viewVisible) + return; + NSString* text = l10n_util::GetNSStringWithFixup( IDS_IOS_NEW_INCOGNITO_TAB_IPH_PROMOTION_TEXT); CGPoint toolsButtonAnchor = [_toolbarCoordinator
diff --git a/ios/chrome/browser/ui/fullscreen/BUILD.gn b/ios/chrome/browser/ui/fullscreen/BUILD.gn index 243bd524..820772ff 100644 --- a/ios/chrome/browser/ui/fullscreen/BUILD.gn +++ b/ios/chrome/browser/ui/fullscreen/BUILD.gn
@@ -53,6 +53,8 @@ "fullscreen_web_state_list_observer.mm", "fullscreen_web_state_observer.h", "fullscreen_web_state_observer.mm", + "voice_over_fullscreen_disabler.h", + "voice_over_fullscreen_disabler.mm", ] configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h index 5d89062..2ea797d1 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.h
@@ -17,6 +17,7 @@ class FullscreenMediator; class FullscreenModel; class FullscreenWebStateListObserver; +@class VoiceOverFullscreenDisabler; class WebStateList; // An object that observes scrolling events in the main content area and @@ -71,6 +72,8 @@ std::unique_ptr<FullscreenModel> model_; // The bridge used to forward brodcasted UI to |model_|. __strong ChromeBroadcastOberverBridge* bridge_ = nil; + // A helper object that disables fullscreen when VoiceOver is enabled. + __strong VoiceOverFullscreenDisabler* voice_over_disabler_ = nil; // Object that manages sending signals to FullscreenControllerObservers. std::unique_ptr<FullscreenMediator> mediator_; // A WebStateListObserver that updates |model_| for WebStateList changes.
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm index f6425d65..6633595f 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_controller.mm
@@ -10,6 +10,7 @@ #import "ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h" +#import "ios/chrome/browser/ui/fullscreen/voice_over_fullscreen_disabler.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -20,6 +21,8 @@ model_(base::MakeUnique<FullscreenModel>()), bridge_( [[ChromeBroadcastOberverBridge alloc] initWithObserver:model_.get()]), + voice_over_disabler_( + [[VoiceOverFullscreenDisabler alloc] initWithController:this]), mediator_(base::MakeUnique<FullscreenMediator>(this, model_.get())) { DCHECK(broadcaster_); [broadcaster_ addObserver:bridge_ @@ -67,6 +70,7 @@ void FullscreenController::Shutdown() { mediator_->Disconnect(); + [voice_over_disabler_ disconnect]; if (web_state_list_observer_) web_state_list_observer_->Disconnect(); [broadcaster_ removeObserver:bridge_
diff --git a/ios/chrome/browser/ui/fullscreen/voice_over_fullscreen_disabler.h b/ios/chrome/browser/ui/fullscreen/voice_over_fullscreen_disabler.h new file mode 100644 index 0000000..df77e9e --- /dev/null +++ b/ios/chrome/browser/ui/fullscreen/voice_over_fullscreen_disabler.h
@@ -0,0 +1,24 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_FULLSCREEN_VOICE_OVER_FULLSCREEN_DISABLER_H_ +#define IOS_CHROME_BROWSER_UI_FULLSCREEN_VOICE_OVER_FULLSCREEN_DISABLER_H_ + +#import <UIKit/UIKit.h> + +class FullscreenController; + +// Helper class that handles disabling fullscreen while VoiceOver is enabled. +@interface VoiceOverFullscreenDisabler : NSObject + +- (nullable instancetype)initWithController: + (nonnull FullscreenController*)controller NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)init NS_UNAVAILABLE; + +// Stops observing VoiceOver notifications. +- (void)disconnect; + +@end + +#endif // IOS_CHROME_BROWSER_UI_FULLSCREEN_VOICE_OVER_FULLSCREEN_DISABLER_H_
diff --git a/ios/chrome/browser/ui/fullscreen/voice_over_fullscreen_disabler.mm b/ios/chrome/browser/ui/fullscreen/voice_over_fullscreen_disabler.mm new file mode 100644 index 0000000..7cae7336 --- /dev/null +++ b/ios/chrome/browser/ui/fullscreen/voice_over_fullscreen_disabler.mm
@@ -0,0 +1,72 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/fullscreen/voice_over_fullscreen_disabler.h" + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h" +#import "ios/chrome/browser/ui/fullscreen/scoped_fullscreen_disabler.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface VoiceOverFullscreenDisabler () { + // The disabler created when VoiceOver is enabled. + std::unique_ptr<ScopedFullscreenDisabler> _disabler; +} +// The FullscreenController being enabled/disabled for VoiceOver. +@property(nonatomic, readonly, nonnull) FullscreenController* controller; +// Creates or destroys |_disabler| depending on whether VoiceOver is enabled. +- (void)voiceOverStatusChanged; +@end + +@implementation VoiceOverFullscreenDisabler +@synthesize controller = _controller; + +- (instancetype)initWithController:(FullscreenController*)controller { + if (self = [super init]) { + _controller = controller; + DCHECK(_controller); + if (@available(iOS 11, *)) { + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(voiceOverStatusChanged) + name:UIAccessibilityVoiceOverStatusDidChangeNotification + object:nil]; + } else { + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(voiceOverStatusChanged) + name:UIAccessibilityVoiceOverStatusChanged + object:nil]; + } + if (UIAccessibilityIsVoiceOverRunning()) + _disabler = base::MakeUnique<ScopedFullscreenDisabler>(_controller); + } + return self; +} + +- (void)dealloc { + // |-disconnect| should be called before deallocation. + DCHECK(!_controller); +} + +#pragma mark Public + +- (void)disconnect { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + _controller = nullptr; +} + +#pragma mark Private + +- (void)voiceOverStatusChanged { + _disabler = UIAccessibilityIsVoiceOverRunning() + ? base::MakeUnique<ScopedFullscreenDisabler>(_controller) + : nullptr; +} + +@end
diff --git a/ios/chrome/browser/web/resources/payment_request.js b/ios/chrome/browser/web/resources/payment_request.js index b36821d1..9c2bf73 100644 --- a/ios/chrome/browser/web/resources/payment_request.js +++ b/ios/chrome/browser/web/resources/payment_request.js
@@ -180,13 +180,14 @@ */ __gCrWeb['paymentRequestManager'].validatePaymentCurrencyAmount = function( amount, amountName) { - var value = String(amount.value); - if (value > __gCrWeb['paymentRequestManager'].MAX_STRING_LENGTH) { + // Convert the value to String if it isn't already one. + amount.value = String(amount.value); + if (amount.value > __gCrWeb['paymentRequestManager'].MAX_STRING_LENGTH) { throw new TypeError( amountName + ' value cannot be longer than ' + __gCrWeb['paymentRequestManager'].MAX_STRING_LENGTH + ' characters'); } - if (!/^-?[0-9]+(\.[0-9]+)?$/.test(value)) { + if (!/^-?[0-9]+(\.[0-9]+)?$/.test(amount.value)) { throw new TypeError( amountName + ' value is not a valid decimal monetary value'); }
diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc index 850b909d5..9c929b21 100644 --- a/media/base/mime_util_internal.cc +++ b/media/base/mime_util_internal.cc
@@ -261,7 +261,7 @@ const CodecSet ogg_audio_codecs{FLAC, OPUS, VORBIS}; #if !defined(OS_ANDROID) - CodecSet ogg_video_codecs{THEORA}; + CodecSet ogg_video_codecs{THEORA, VP8}; #else CodecSet ogg_video_codecs; #endif // !defined(OS_ANDROID) @@ -279,32 +279,38 @@ CodecSet webm_codecs(webm_audio_codecs); webm_codecs.insert(webm_video_codecs.begin(), webm_video_codecs.end()); -#if BUILDFLAG(USE_PROPRIETARY_CODECS) const CodecSet mp3_codecs{MP3}; + + CodecSet mp4_audio_codecs; + mp4_audio_codecs.emplace(MP3); + mp4_audio_codecs.emplace(FLAC); + + // Only VP9 with valid codec string vp09.xx.xx.xx.xx.xx.xx.xx is supported. + // See ParseVp9CodecID for details. + CodecSet mp4_video_codecs; + mp4_video_codecs.emplace(VP9); + +#if BUILDFLAG(USE_PROPRIETARY_CODECS) const CodecSet aac{MPEG2_AAC, MPEG4_AAC}; + mp4_audio_codecs.insert(aac.begin(), aac.end()); CodecSet avc_and_aac(aac); avc_and_aac.emplace(H264); - CodecSet mp4_audio_codecs(aac); - mp4_audio_codecs.emplace(MP3); - mp4_audio_codecs.emplace(FLAC); #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) mp4_audio_codecs.emplace(AC3); mp4_audio_codecs.emplace(EAC3); #endif // BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) - CodecSet mp4_video_codecs; mp4_video_codecs.emplace(H264); #if BUILDFLAG(ENABLE_HEVC_DEMUXING) mp4_video_codecs.emplace(HEVC); #endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) - // Only VP9 with valid codec string vp09.xx.xx.xx.xx.xx.xx.xx is supported. - // See ParseVp9CodecID for details. - mp4_video_codecs.emplace(VP9); + #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) mp4_video_codecs.emplace(DOLBY_VISION); #endif // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) #if BUILDFLAG(ENABLE_AV1_DECODER) if (base::FeatureList::IsEnabled(kAv1Decoder)) mp4_video_codecs.emplace(AV1); @@ -312,7 +318,6 @@ CodecSet mp4_codecs(mp4_audio_codecs); mp4_codecs.insert(mp4_video_codecs.begin(), mp4_video_codecs.end()); -#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) const CodecSet implicit_codec; AddContainerWithCodecs("audio/wav", wav_codecs, false); @@ -328,15 +333,15 @@ // TODO(ddorwin): Should the application type support Opus? AddContainerWithCodecs("application/ogg", ogg_codecs, false); AddContainerWithCodecs("audio/flac", implicit_codec, false); + AddContainerWithCodecs("audio/mpeg", mp3_codecs, false); // Allow "mp3". + AddContainerWithCodecs("audio/mp3", implicit_codec, false); + AddContainerWithCodecs("audio/x-mp3", implicit_codec, false); + AddContainerWithCodecs("audio/mp4", mp4_audio_codecs, false); + DCHECK(!mp4_video_codecs.empty()); + AddContainerWithCodecs("video/mp4", mp4_codecs, false); #if BUILDFLAG(USE_PROPRIETARY_CODECS) - AddContainerWithCodecs("audio/mpeg", mp3_codecs, true); // Allow "mp3". - AddContainerWithCodecs("audio/mp3", implicit_codec, true); - AddContainerWithCodecs("audio/x-mp3", implicit_codec, true); AddContainerWithCodecs("audio/aac", implicit_codec, true); // AAC / ADTS. - AddContainerWithCodecs("audio/mp4", mp4_audio_codecs, true); - DCHECK(!mp4_video_codecs.empty()); - AddContainerWithCodecs("video/mp4", mp4_codecs, true); // These strings are supported for backwards compatibility only and thus only // support the codecs needed for compatibility. AddContainerWithCodecs("audio/x-m4a", aac, true); @@ -516,6 +521,19 @@ void MimeUtil::RemoveProprietaryMediaTypesAndCodecs() { for (const auto& container : proprietary_media_containers_) media_format_map_.erase(container); + + // TODO(chcunningham): Delete this hack (really this whole test-only method). + // This is done as short term workaround for LayoutTests to pass. MP4 is no + // longer proprietary, but may still contain proprietary codecs (e.g. AVC). + // Many layout tests only check for container support and may break (absent + // this hack) if run on a non-proprietary build. This mess is being fixed in + // https://chromium-review.googlesource.com/c/chromium/src/+/807604 + media_format_map_.erase("video/mp4"); + media_format_map_.erase("audio/mp4"); + media_format_map_.erase("audio/mpeg"); + media_format_map_.erase("audio/mp3"); + media_format_map_.erase("audio/x-mp3"); + allow_proprietary_codecs_ = false; } @@ -970,7 +988,6 @@ case INVALID_CODEC: case AC3: case EAC3: - case MP3: case MPEG2_AAC: case MPEG4_AAC: case H264: @@ -978,6 +995,7 @@ case DOLBY_VISION: return true; + case MP3: case PCM: case VORBIS: case OPUS:
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc index a358d0a..e541c9c 100644 --- a/media/base/mime_util_unittest.cc +++ b/media/base/mime_util_unittest.cc
@@ -172,32 +172,26 @@ "application/vnd.apple.mpegurl")); EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType("audio/mpegurl")); EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType("audio/x-mpegurl")); - -#if BUILDFLAG(USE_PROPRIETARY_CODECS) EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp4")); - EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-m4a")); - EXPECT_TRUE(IsSupportedMediaMimeType("video/mp4")); - EXPECT_TRUE(IsSupportedMediaMimeType("video/x-m4v")); - EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp3")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-mp3")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/mpeg")); + EXPECT_TRUE(IsSupportedMediaMimeType("video/mp4")); + +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-m4a")); + EXPECT_TRUE(IsSupportedMediaMimeType("video/x-m4v")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/aac")); #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) EXPECT_TRUE(IsSupportedMediaMimeType("video/mp2t")); #else EXPECT_FALSE(IsSupportedMediaMimeType("video/mp2t")); -#endif -#else - EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp4")); - EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-m4a")); - EXPECT_FALSE(IsSupportedMediaMimeType("video/mp4")); - EXPECT_FALSE(IsSupportedMediaMimeType("video/x-m4v")); +#endif // BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) - EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp3")); - EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-mp3")); - EXPECT_FALSE(IsSupportedMediaMimeType("audio/mpeg")); +#else + EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-m4a")); + EXPECT_FALSE(IsSupportedMediaMimeType("video/x-m4v")); EXPECT_FALSE(IsSupportedMediaMimeType("audio/aac")); #endif // USE_PROPRIETARY_CODECS EXPECT_FALSE(IsSupportedMediaMimeType("video/mp3")); @@ -328,11 +322,9 @@ EXPECT_EQ(kCodecAAC, out_codec); } - // Valid FLAC string when proprietary codecs are supported. FLAC-in-MP4 - // currently requires proprietary codecs to demux mp4. - EXPECT_EQ(kUsePropCodecs, - ParseAudioCodecString("audio/mp4", "flac", &out_is_ambiguous, - &out_codec)); + // Valid FLAC string with MP4. Neither decoding nor demuxing is proprietary. + EXPECT_TRUE(ParseAudioCodecString("audio/mp4", "flac", &out_is_ambiguous, + &out_codec)); if (kUsePropCodecs) { EXPECT_FALSE(out_is_ambiguous); EXPECT_EQ(kCodecFLAC, out_codec);
diff --git a/media/base/test_helpers.h b/media/base/test_helpers.h index 3df27b11..99940f4 100644 --- a/media/base/test_helpers.h +++ b/media/base/test_helpers.h
@@ -241,6 +241,11 @@ CONTAINS_STRING(arg, ", which is after the frame's PTS"); } +MATCHER_P2(CodecUnsupportedInContainer, codec, container, "") { + return CONTAINS_STRING(arg, std::string(codec) + "' is not supported for '" + + std::string(container)); +} + MATCHER_P(FoundStream, stream_type_string, "") { return CONTAINS_STRING( arg, "found_" + std::string(stream_type_string) + "_stream\":true");
diff --git a/media/cdm/BUILD.gn b/media/cdm/BUILD.gn index de39dee0..ddb8b07c 100644 --- a/media/cdm/BUILD.gn +++ b/media/cdm/BUILD.gn
@@ -28,6 +28,8 @@ sources = [ "aes_decryptor.cc", "aes_decryptor.h", + "cenc_utils.cc", + "cenc_utils.h", "default_cdm_factory.cc", "default_cdm_factory.h", "json_web_key.cc", @@ -49,13 +51,6 @@ configs += [ "//media:subcomponent_config" ] - if (proprietary_codecs) { - sources += [ - "cenc_utils.cc", - "cenc_utils.h", - ] - } - if (enable_library_cdms) { deps += [ ":cdm_api",
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc index 067563c1..a4ff4e5 100644 --- a/media/cdm/aes_decryptor.cc +++ b/media/cdm/aes_decryptor.cc
@@ -24,13 +24,10 @@ #include "media/base/limits.h" #include "media/base/video_decoder_config.h" #include "media/base/video_frame.h" +#include "media/cdm/cenc_utils.h" #include "media/cdm/json_web_key.h" #include "media/media_features.h" -#if BUILDFLAG(USE_PROPRIETARY_CODECS) -#include "media/cdm/cenc_utils.h" -#endif - namespace media { namespace { @@ -319,7 +316,6 @@ keys.push_back(init_data); break; case EmeInitDataType::CENC: -#if BUILDFLAG(USE_PROPRIETARY_CODECS) // |init_data| is a set of 0 or more concatenated 'pssh' boxes. if (!GetKeyIdsForCommonSystemId(init_data, &keys)) { promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0, @@ -327,11 +323,6 @@ return; } break; -#else - promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0, - "Initialization data type CENC is not supported."); - return; -#endif case EmeInitDataType::KEYIDS: { std::string init_data_string(init_data.begin(), init_data.end()); std::string error_message;
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc index d89a432..39b30f7 100644 --- a/media/cdm/aes_decryptor_unittest.cc +++ b/media/cdm/aes_decryptor_unittest.cc
@@ -591,18 +591,11 @@ 0x00, 0x00, 0x00, 0x00 // datasize }; -#if BUILDFLAG(USE_PROPRIETARY_CODECS) EXPECT_CALL(cdm_client_, OnSessionMessage(NotEmpty(), _, IsJSONDictionary())); cdm_->CreateSessionAndGenerateRequest( CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::CENC, std::vector<uint8_t>(init_data, init_data + arraysize(init_data)), CreateSessionPromise(RESOLVED)); -#else - cdm_->CreateSessionAndGenerateRequest( - CdmSessionType::TEMPORARY_SESSION, EmeInitDataType::CENC, - std::vector<uint8_t>(init_data, init_data + arraysize(init_data)), - CreateSessionPromise(REJECTED)); -#endif } TEST_P(AesDecryptorTest, CreateSessionWithKeyIdsInitData) {
diff --git a/media/cdm/cdm_adapter_unittest.cc b/media/cdm/cdm_adapter_unittest.cc index 29771df7..c70fc59 100644 --- a/media/cdm/cdm_adapter_unittest.cc +++ b/media/cdm/cdm_adapter_unittest.cc
@@ -295,11 +295,7 @@ std::vector<uint8_t> key_id(kKeyIdAsPssh, kKeyIdAsPssh + arraysize(kKeyIdAsPssh)); -#if BUILDFLAG(USE_PROPRIETARY_CODECS) CreateSessionAndExpect(EmeInitDataType::CENC, key_id, SUCCESS); -#else - CreateSessionAndExpect(EmeInitDataType::CENC, key_id, FAILURE); -#endif } TEST_F(CdmAdapterTest, CreateSessionWithBadData) {
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index e6b14732..01de632 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc
@@ -3104,13 +3104,17 @@ ChunkDemuxer::Status expected = ChunkDemuxer::kNotSupported; #if BUILDFLAG(USE_PROPRIETARY_CODECS) + #if defined(OS_ANDROID) if (HasPlatformDecoderSupport()) expected = ChunkDemuxer::kOk; #else expected = ChunkDemuxer::kOk; -#endif -#endif +#endif // defined(OS_ANDROID) + +#else + EXPECT_MEDIA_LOG(CodecUnsupportedInContainer("avc1.4D4041", "video/mp4")); +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) EXPECT_EQ(AddId("source_id", "video/mp4", "avc1.4D4041"), expected); } @@ -3120,9 +3124,6 @@ TEST_P(ChunkDemuxerTest, CodecIDsThatAreNotRFC6381Compliant) { ChunkDemuxer::Status expected = ChunkDemuxer::kNotSupported; -#if BUILDFLAG(USE_PROPRIETARY_CODECS) - expected = ChunkDemuxer::kOk; -#endif const char* codec_ids[] = { // GPAC places leading zeros on the audio object type. "mp4a.40.02", @@ -3130,6 +3131,12 @@ }; for (size_t i = 0; i < arraysize(codec_ids); ++i) { +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + expected = ChunkDemuxer::kOk; +#else + EXPECT_MEDIA_LOG(CodecUnsupportedInContainer(codec_ids[i], "audio/mp4")); +#endif + ChunkDemuxer::Status result = AddId("source_id", "audio/mp4", codec_ids[i]); EXPECT_EQ(result, expected) @@ -4876,11 +4883,7 @@ } TEST_P(ChunkDemuxerTest, Mp4Vp9CodecSupport) { - ChunkDemuxer::Status expected = ChunkDemuxer::kNotSupported; -#if BUILDFLAG(USE_PROPRIETARY_CODECS) - expected = ChunkDemuxer::kOk; -#endif - + ChunkDemuxer::Status expected = ChunkDemuxer::kOk; EXPECT_EQ(AddId("source_id", "video/mp4", "vp09.00.10.08"), expected); }
diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc index 2effed7..c958632 100644 --- a/media/filters/stream_parser_factory.cc +++ b/media/filters/stream_parser_factory.cc
@@ -16,6 +16,7 @@ #include "build/build_config.h" #include "media/base/media.h" #include "media/base/media_switches.h" +#include "media/formats/mp4/mp4_stream_parser.h" #include "media/formats/mpeg/adts_stream_parser.h" #include "media/formats/mpeg/mpeg1_audio_stream_parser.h" #include "media/formats/webm/webm_stream_parser.h" @@ -27,11 +28,10 @@ #endif #if BUILDFLAG(USE_PROPRIETARY_CODECS) +#include "media/formats/mp4/es_descriptor.h" #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) #include "media/formats/mp2t/mp2t_stream_parser.h" #endif -#include "media/formats/mp4/es_descriptor.h" -#include "media/formats/mp4/mp4_stream_parser.h" #endif namespace media { @@ -113,16 +113,6 @@ } #if BUILDFLAG(USE_PROPRIETARY_CODECS) -bool CheckIfMseFlacInIsobmffEnabled(const std::string& codec_id, - MediaLog* media_log) { - return base::FeatureList::IsEnabled(kMseFlacInIsobmff); -} - -// AAC Object Type IDs that Chrome supports. -static const int kAACLCObjectType = 2; -static const int kAACSBRObjectType = 5; -static const int kAACPSObjectType = 29; - static int GetMP4AudioObjectType(const std::string& codec_id, MediaLog* media_log) { // From RFC 6381 section 3.3 (ISO Base Media File Format Name Space): @@ -147,6 +137,11 @@ return -1; } +// AAC Object Type IDs that Chrome supports. +static const int kAACLCObjectType = 2; +static const int kAACSBRObjectType = 5; +static const int kAACPSObjectType = 29; + bool ValidateMP4ACodecID(const std::string& codec_id, MediaLog* media_log) { int audio_object_type = GetMP4AudioObjectType(codec_id, media_log); if (audio_object_type == kAACLCObjectType || @@ -165,12 +160,13 @@ "avc1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_H264}; static const CodecInfo kH264AVC3CodecInfo = { "avc3.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_H264}; + #if BUILDFLAG(ENABLE_HEVC_DEMUXING) static const CodecInfo kHEVCHEV1CodecInfo = { "hev1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_HEVC}; static const CodecInfo kHEVCHVC1CodecInfo = { "hvc1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_HEVC}; -#endif +#endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) static const CodecInfo kDolbyVisionAVCCodecInfo1 = { "dva1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_DOLBYVISION}; @@ -181,18 +177,13 @@ "dvh1.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_DOLBYVISION}; static const CodecInfo kDolbyVisionHEVCCodecInfo2 = { "dvhe.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_DOLBYVISION}; -#endif -#endif -static const CodecInfo kMPEG4VP09CodecInfo = { - "vp09.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_VP9}; +#endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) +#endif // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) static const CodecInfo kMPEG4AACCodecInfo = {"mp4a.40.*", CodecInfo::AUDIO, &ValidateMP4ACodecID, CodecInfo::HISTOGRAM_MPEG4AAC}; static const CodecInfo kMPEG2AACLCCodecInfo = { "mp4a.67", CodecInfo::AUDIO, nullptr, CodecInfo::HISTOGRAM_MPEG2AAC}; -static const CodecInfo kMPEG4FLACCodecInfo = {"flac", CodecInfo::AUDIO, - &CheckIfMseFlacInIsobmffEnabled, - CodecInfo::HISTOGRAM_FLAC}; #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) // The 'ac-3' and 'ec-3' are mime codec ids for AC3 and EAC3 according to @@ -213,9 +204,34 @@ CodecInfo::HISTOGRAM_EAC3}; static const CodecInfo kEAC3CodecInfo3 = {"mp4a.A6", CodecInfo::AUDIO, nullptr, CodecInfo::HISTOGRAM_EAC3}; -#endif +#endif // BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) -static const CodecInfo* const kVideoMP4Codecs[] = {&kH264AVC1CodecInfo, +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) + +static const CodecInfo kMP3CodecInfo = {nullptr, CodecInfo::AUDIO, nullptr, + CodecInfo::HISTOGRAM_MP3}; +static const CodecInfo* const kAudioMP3Codecs[] = {&kMP3CodecInfo, nullptr}; + +static StreamParser* BuildMP3Parser(const std::vector<std::string>& codecs, + MediaLog* media_log) { + return new MPEG1AudioStreamParser(); +} + +bool CheckIfMseFlacInIsobmffEnabled(const std::string& codec_id, + MediaLog* media_log) { + return base::FeatureList::IsEnabled(kMseFlacInIsobmff); +} + +static const CodecInfo kMPEG4VP09CodecInfo = { + "vp09.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_VP9}; +static const CodecInfo kMPEG4FLACCodecInfo = {"flac", CodecInfo::AUDIO, + &CheckIfMseFlacInIsobmffEnabled, + CodecInfo::HISTOGRAM_FLAC}; + +static const CodecInfo* const kVideoMP4Codecs[] = {&kMPEG4FLACCodecInfo, + &kMPEG4VP09CodecInfo, +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + &kH264AVC1CodecInfo, &kH264AVC3CodecInfo, #if BUILDFLAG(ENABLE_HEVC_DEMUXING) &kHEVCHEV1CodecInfo, @@ -229,18 +245,19 @@ &kDolbyVisionHEVCCodecInfo2, #endif #endif - &kMPEG4VP09CodecInfo, &kMPEG4AACCodecInfo, &kMPEG2AACLCCodecInfo, - &kMPEG4FLACCodecInfo, +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) #if BUILDFLAG(ENABLE_AV1_DECODER) &kAV1CodecInfo, #endif nullptr}; -static const CodecInfo* const kAudioMP4Codecs[] = {&kMPEG4AACCodecInfo, +static const CodecInfo* const kAudioMP4Codecs[] = {&kMPEG4FLACCodecInfo, +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + &kMPEG4AACCodecInfo, &kMPEG2AACLCCodecInfo, - &kMPEG4FLACCodecInfo, + #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) &kAC3CodecInfo1, &kAC3CodecInfo2, @@ -248,7 +265,8 @@ &kEAC3CodecInfo1, &kEAC3CodecInfo2, &kEAC3CodecInfo3, -#endif +#endif // BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) nullptr}; static StreamParser* BuildMP4Parser(const std::vector<std::string>& codecs, @@ -266,7 +284,10 @@ for (size_t i = 0; i < codecs.size(); ++i) { std::string codec_id = codecs[i]; - if (base::MatchPattern(codec_id, kMPEG2AACLCCodecInfo.pattern)) { + if (base::MatchPattern(codec_id, kMPEG4FLACCodecInfo.pattern)) { + has_flac = true; +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + } else if (base::MatchPattern(codec_id, kMPEG2AACLCCodecInfo.pattern)) { audio_object_types.insert(mp4::kISO_13818_7_AAC_LC); } else if (base::MatchPattern(codec_id, kMPEG4AACCodecInfo.pattern)) { int audio_object_type = GetMP4AudioObjectType(codec_id, media_log); @@ -279,8 +300,6 @@ has_sbr = true; break; } - } else if (base::MatchPattern(codec_id, kMPEG4FLACCodecInfo.pattern)) { - has_flac = true; #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) } else if (base::MatchPattern(codec_id, kAC3CodecInfo1.pattern) || base::MatchPattern(codec_id, kAC3CodecInfo2.pattern) || @@ -290,23 +309,14 @@ base::MatchPattern(codec_id, kEAC3CodecInfo2.pattern) || base::MatchPattern(codec_id, kEAC3CodecInfo3.pattern)) { audio_object_types.insert(mp4::kEAC3); -#endif +#endif // BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) } } return new mp4::MP4StreamParser(audio_object_types, has_sbr, has_flac); } - -static const CodecInfo kMP3CodecInfo = {nullptr, CodecInfo::AUDIO, nullptr, - CodecInfo::HISTOGRAM_MP3}; - -static const CodecInfo* const kAudioMP3Codecs[] = {&kMP3CodecInfo, nullptr}; - -static StreamParser* BuildMP3Parser(const std::vector<std::string>& codecs, - MediaLog* media_log) { - return new MPEG1AudioStreamParser(); -} - +#if BUILDFLAG(USE_PROPRIETARY_CODECS) static const CodecInfo kADTSCodecInfo = {nullptr, CodecInfo::AUDIO, nullptr, CodecInfo::HISTOGRAM_MPEG4AAC}; static const CodecInfo* const kAudioADTSCodecs[] = {&kADTSCodecInfo, nullptr}; @@ -351,17 +361,18 @@ return new media::mp2t::Mp2tStreamParser(has_sbr); } -#endif -#endif +#endif // ENABLE_MSE_MPEG2TS_STREAM_PARSER +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) static const SupportedTypeInfo kSupportedTypeInfo[] = { {"video/webm", &BuildWebMParser, kVideoWebMCodecs}, {"audio/webm", &BuildWebMParser, kAudioWebMCodecs}, -#if BUILDFLAG(USE_PROPRIETARY_CODECS) - {"audio/aac", &BuildADTSParser, kAudioADTSCodecs}, {"audio/mpeg", &BuildMP3Parser, kAudioMP3Codecs}, + // NOTE: Including proprietary MP4 codecs is gated by build flags above. {"video/mp4", &BuildMP4Parser, kVideoMP4Codecs}, {"audio/mp4", &BuildMP4Parser, kAudioMP4Codecs}, +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + {"audio/aac", &BuildADTSParser, kAudioADTSCodecs}, #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) {"video/mp2t", &BuildMP2TParser, kVideoMP2TCodecs}, #endif
diff --git a/media/formats/BUILD.gn b/media/formats/BUILD.gn index 27254557..c38fa3e 100644 --- a/media/formats/BUILD.gn +++ b/media/formats/BUILD.gn
@@ -20,6 +20,25 @@ "ac3/ac3_util.h", "common/offset_byte_queue.cc", "common/offset_byte_queue.h", + "mp4/box_definitions.cc", + "mp4/box_definitions.h", + "mp4/box_reader.cc", + "mp4/box_reader.h", + "mp4/es_descriptor.cc", + "mp4/es_descriptor.h", + "mp4/fourccs.h", + "mp4/mp4_stream_parser.cc", + "mp4/mp4_stream_parser.h", + "mp4/parse_result.h", + "mp4/rcheck.h", + "mp4/sample_to_group_iterator.cc", + "mp4/sample_to_group_iterator.h", + "mp4/track_run_iterator.cc", + "mp4/track_run_iterator.h", + "mpeg/mpeg1_audio_stream_parser.cc", + "mpeg/mpeg1_audio_stream_parser.h", + "mpeg/mpeg_audio_stream_parser_base.cc", + "mpeg/mpeg_audio_stream_parser_base.h", "webm/webm_audio_client.cc", "webm/webm_audio_client.h", "webm/webm_cluster_parser.cc", @@ -70,29 +89,10 @@ "mp4/avc.h", "mp4/bitstream_converter.cc", "mp4/bitstream_converter.h", - "mp4/box_definitions.cc", - "mp4/box_definitions.h", - "mp4/box_reader.cc", - "mp4/box_reader.h", - "mp4/es_descriptor.cc", - "mp4/es_descriptor.h", - "mp4/fourccs.h", - "mp4/mp4_stream_parser.cc", - "mp4/mp4_stream_parser.h", - "mp4/parse_result.h", - "mp4/rcheck.h", - "mp4/sample_to_group_iterator.cc", - "mp4/sample_to_group_iterator.h", - "mp4/track_run_iterator.cc", - "mp4/track_run_iterator.h", "mpeg/adts_constants.cc", "mpeg/adts_constants.h", "mpeg/adts_stream_parser.cc", "mpeg/adts_stream_parser.h", - "mpeg/mpeg1_audio_stream_parser.cc", - "mpeg/mpeg1_audio_stream_parser.h", - "mpeg/mpeg_audio_stream_parser_base.cc", - "mpeg/mpeg_audio_stream_parser_base.h", ] }
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc index ea6926ca..78c6b2d9 100644 --- a/media/formats/mp4/box_definitions.cc +++ b/media/formats/mp4/box_definitions.cc
@@ -14,20 +14,23 @@ #include "media/base/media_switches.h" #include "media/base/video_types.h" #include "media/base/video_util.h" -#include "media/formats/mp4/avc.h" #include "media/formats/mp4/es_descriptor.h" #include "media/formats/mp4/rcheck.h" #include "media/media_features.h" -#include "media/video/h264_parser.h" #include "third_party/libaom/av1_features.h" +#if BUILDFLAG(USE_PROPRIETARY_CODECS) +#include "media/formats/mp4/avc.h" +#include "media/video/h264_parser.h" // nogncheck + #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) #include "media/formats/mp4/dolby_vision.h" -#endif +#endif // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) #if BUILDFLAG(ENABLE_HEVC_DEMUXING) #include "media/formats/mp4/hevc.h" -#endif +#endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) namespace media { namespace mp4 { @@ -577,6 +580,7 @@ return true; } +#if BUILDFLAG(USE_PROPRIETARY_CODECS) AVCDecoderConfigurationRecord::AVCDecoderConfigurationRecord() : version(0), profile_indication(0), @@ -636,6 +640,7 @@ return true; } +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) VPCodecConfigurationRecord::VPCodecConfigurationRecord() : profile(VIDEO_CODEC_PROFILE_UNKNOWN) {} @@ -731,6 +736,7 @@ const FourCC actual_format = format == FOURCC_ENCV ? sinf.format.format : format; switch (actual_format) { +#if BUILDFLAG(USE_PROPRIETARY_CODECS) case FOURCC_AVC1: case FOURCC_AVC3: { DVLOG(2) << __func__ << " reading AVCDecoderConfigurationRecord (avcC)"; @@ -813,6 +819,7 @@ } #endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) #endif // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) case FOURCC_VP09: { DVLOG(2) << __func__ << " parsing VPCodecConfigurationRecord (vpcC)"; std::unique_ptr<VPCodecConfigurationRecord> vp_config( @@ -855,6 +862,7 @@ const FourCC actual_format = format == FOURCC_ENCV ? sinf.format.format : format; switch (actual_format) { +#if BUILDFLAG(USE_PROPRIETARY_CODECS) case FOURCC_AVC1: case FOURCC_AVC3: #if BUILDFLAG(ENABLE_HEVC_DEMUXING) @@ -869,6 +877,7 @@ case FOURCC_DVA1: case FOURCC_DVAV: #endif // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) case FOURCC_VP09: return true; #if BUILDFLAG(ENABLE_AV1_DECODER) @@ -902,8 +911,13 @@ object_type = es_desc.object_type(); - if (es_desc.IsAAC(object_type)) + if (es_desc.IsAAC(object_type)) { +#if BUILDFLAG(USE_PROPRIETARY_CODECS) RCHECK(aac.Parse(es_desc.decoder_specific_info(), reader->media_log())); +#else + return false; +#endif + } return true; }
diff --git a/media/formats/mp4/box_definitions.h b/media/formats/mp4/box_definitions.h index 9a0a711c0..62ec5eb 100644 --- a/media/formats/mp4/box_definitions.h +++ b/media/formats/mp4/box_definitions.h
@@ -210,6 +210,7 @@ std::string name; }; +#if BUILDFLAG(USE_PROPRIETARY_CODECS) struct MEDIA_EXPORT AVCDecoderConfigurationRecord : Box { DECLARE_BOX_METHODS(AVCDecoderConfigurationRecord); @@ -235,6 +236,7 @@ private: bool ParseInternal(BufferReader* reader, MediaLog* media_log); }; +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) struct MEDIA_EXPORT VPCodecConfigurationRecord : Box { DECLARE_BOX_METHODS(VPCodecConfigurationRecord); @@ -272,7 +274,9 @@ DECLARE_BOX_METHODS(ElementaryStreamDescriptor); uint8_t object_type; +#if BUILDFLAG(USE_PROPRIETARY_CODECS) AAC aac; +#endif }; struct MEDIA_EXPORT FlacSpecificBox : Box {
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc index d93cebc..cb389ad 100644 --- a/media/formats/mp4/mp4_stream_parser.cc +++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -285,7 +285,6 @@ if (desc_idx >= samp_descr.audio_entries.size()) desc_idx = 0; const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx]; - const AAC& aac = entry.esds.aac; // For encrypted audio streams entry.format is FOURCC_ENCA and actual // format is in entry.sinf.format.format. @@ -324,6 +323,7 @@ channel_layout = GuessChannelLayout(entry.channelcount); sample_per_second = entry.samplerate; extra_data = entry.dfla.stream_info; +#if BUILDFLAG(USE_PROPRIETARY_CODECS) } else { uint8_t audio_type = entry.esds.object_type; #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) @@ -346,6 +346,7 @@ // Check if it is MPEG4 AAC defined in ISO 14496 Part 3 or // supported MPEG2 AAC varients. if (ESDescriptor::IsAAC(audio_type)) { + const AAC& aac = entry.esds.aac; codec = kCodecAAC; channel_layout = aac.GetChannelLayout(has_sbr_); sample_per_second = aac.GetOutputSamplesPerSecond(has_sbr_); @@ -368,6 +369,7 @@ << static_cast<int>(audio_type) << " in esds."; return false; } +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) } SampleFormat sample_format; @@ -596,6 +598,7 @@ encrypted_media_init_data_cb_.Run(EmeInitDataType::CENC, init_data); } +#if BUILDFLAG(USE_PROPRIETARY_CODECS) bool MP4StreamParser::PrepareAACBuffer( const AAC& aac_config, std::vector<uint8_t>* frame_buf, @@ -613,6 +616,7 @@ } return true; } +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) ParseResult MP4StreamParser::EnqueueSample(BufferQueueMap* buffers) { DCHECK_EQ(state_, kEmittingSamples); @@ -732,11 +736,17 @@ } if (audio) { - if (ESDescriptor::IsAAC(runs_->audio_description().esds.object_type) && - !PrepareAACBuffer(runs_->audio_description().esds.aac, - &frame_buf, &subsamples)) { - MEDIA_LOG(ERROR, media_log_) << "Failed to prepare AAC sample for decode"; + if (ESDescriptor::IsAAC(runs_->audio_description().esds.object_type)) { +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + if (!PrepareAACBuffer(runs_->audio_description().esds.aac, &frame_buf, + &subsamples)) { + MEDIA_LOG(ERROR, media_log_) + << "Failed to prepare AAC sample for decode"; + return ParseResult::kError; + } +#else return ParseResult::kError; +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) } }
diff --git a/media/formats/mp4/mp4_stream_parser.h b/media/formats/mp4/mp4_stream_parser.h index ff1d84a..97bdfd6 100644 --- a/media/formats/mp4/mp4_stream_parser.h +++ b/media/formats/mp4/mp4_stream_parser.h
@@ -20,6 +20,10 @@ #include "media/formats/mp4/parse_result.h" #include "media/formats/mp4/track_run_iterator.h" +#if BUILDFLAG(USE_PROPRIETARY_CODECS) +#include "media/formats/mp4/aac.h" +#endif + namespace media { namespace mp4 { @@ -73,9 +77,11 @@ void ChangeState(State new_state); bool EmitConfigs(); +#if BUILDFLAG(USE_PROPRIETARY_CODECS) bool PrepareAACBuffer(const AAC& aac_config, std::vector<uint8_t>* frame_buf, std::vector<SubsampleEntry>* subsamples) const; +#endif ParseResult EnqueueSample(BufferQueueMap* buffers); bool SendAndFlushSamples(BufferQueueMap* buffers);
diff --git a/media/mojo/common/BUILD.gn b/media/mojo/common/BUILD.gn index 637252e..72d6a25d 100644 --- a/media/mojo/common/BUILD.gn +++ b/media/mojo/common/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "media_type_converters.cc", "media_type_converters.h", + "mojo_data_pipe_read_write.cc", + "mojo_data_pipe_read_write.h", "mojo_decoder_buffer_converter.cc", "mojo_decoder_buffer_converter.h", ] @@ -45,6 +47,7 @@ sources = [ "media_type_converters_unittest.cc", + "mojo_data_pipe_read_write_unittest.cc", "mojo_decoder_buffer_converter_unittest.cc", "mojo_shared_buffer_video_frame_unittest.cc", ]
diff --git a/media/mojo/common/mojo_data_pipe_read_write.cc b/media/mojo/common/mojo_data_pipe_read_write.cc new file mode 100644 index 0000000..067e681 --- /dev/null +++ b/media/mojo/common/mojo_data_pipe_read_write.cc
@@ -0,0 +1,247 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/mojo/common/mojo_data_pipe_read_write.h" + +#include <memory> + +#include "base/logging.h" +#include "base/memory/ptr_util.h" + +namespace media { + +namespace { + +bool IsPipeReadWriteError(MojoResult result) { + return result != MOJO_RESULT_OK && result != MOJO_RESULT_SHOULD_WAIT; +} + +} // namespace + +// MojoDataPipeReader + +MojoDataPipeReader::MojoDataPipeReader( + mojo::ScopedDataPipeConsumerHandle consumer_handle) + : consumer_handle_(std::move(consumer_handle)), + pipe_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL) { + DVLOG(1) << __func__; + + MojoResult result = pipe_watcher_.Watch( + consumer_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, + MOJO_WATCH_CONDITION_SATISFIED, + base::BindRepeating(&MojoDataPipeReader::OnPipeReadable, + base::Unretained(this))); + if (result != MOJO_RESULT_OK) { + DVLOG(1) << __func__ + << ": Failed to start watching the pipe. result=" << result; + consumer_handle_.reset(); + } +} + +MojoDataPipeReader::~MojoDataPipeReader() { + DVLOG(1) << __func__; +} + +void MojoDataPipeReader::CompleteCurrentRead() { + DVLOG(4) << __func__; + DCHECK(!done_cb_.is_null()); + current_buffer_size_ = 0; + std::move(done_cb_).Run(true); +} + +void MojoDataPipeReader::Read(uint8_t* buffer, + uint32_t num_bytes, + DoneCB done_cb) { + DVLOG(3) << __func__; + // Read() can not be called when there is another reading request in process. + DCHECK(!current_buffer_size_); + DCHECK(!done_cb.is_null()); + if (!num_bytes) { + std::move(done_cb).Run(true); + return; + } + + if (!consumer_handle_.is_valid()) { + VLOG(1) << __func__ << ": Data pipe was closed."; + std::move(done_cb).Run(false); + return; + } + + current_buffer_size_ = num_bytes; + current_buffer_ = buffer; + bytes_read_ = 0; + done_cb_ = std::move(done_cb); + + pipe_watcher_.ArmOrNotify(); +} + +void MojoDataPipeReader::OnPipeReadable(MojoResult result, + const mojo::HandleSignalsState& state) { + DVLOG(4) << __func__ << "(" << result << ", " << state.readable() << ")"; + + if (result != MOJO_RESULT_OK) { + OnPipeError(result); + return; + } + + DCHECK(state.readable()); + DCHECK_GT(current_buffer_size_, bytes_read_); + uint32_t num_bytes = current_buffer_size_ - bytes_read_; + if (current_buffer_) { + result = consumer_handle_->ReadData(current_buffer_ + bytes_read_, + &num_bytes, MOJO_READ_DATA_FLAG_NONE); + } else { + result = consumer_handle_->ReadData(nullptr, &num_bytes, + MOJO_READ_DATA_FLAG_DISCARD); + } + + if (IsPipeReadWriteError(result)) { + OnPipeError(result); + } else { + if (result == MOJO_RESULT_OK) { + DCHECK_GT(num_bytes, 0u); + bytes_read_ += num_bytes; + if (bytes_read_ == current_buffer_size_) { + CompleteCurrentRead(); + return; + } + } + pipe_watcher_.ArmOrNotify(); + } +} + +void MojoDataPipeReader::OnPipeError(MojoResult result) { + DVLOG(1) << __func__ << "(" << result << ")"; + DCHECK(IsPipeReadWriteError(result)); + + consumer_handle_.reset(); + + if (current_buffer_) { + DVLOG(1) << __func__ << ": reading from data pipe failed. result=" << result + << ", buffer size=" << current_buffer_size_ + << ", num_bytes(read)=" << bytes_read_; + bytes_read_ = 0; + current_buffer_ = nullptr; + current_buffer_size_ = 0; + DCHECK(!done_cb_.is_null()); + std::move(done_cb_).Run(false); + } +} + +bool MojoDataPipeReader::IsPipeValid() const { + return consumer_handle_.is_valid(); +} + +// MojoDataPipeWriter + +MojoDataPipeWriter::MojoDataPipeWriter( + mojo::ScopedDataPipeProducerHandle producer_handle) + : producer_handle_(std::move(producer_handle)), + pipe_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL) { + DVLOG(1) << __func__; + + MojoResult result = pipe_watcher_.Watch( + producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_WATCH_CONDITION_SATISFIED, + base::BindRepeating(&MojoDataPipeWriter::OnPipeWritable, + base::Unretained(this))); + if (result != MOJO_RESULT_OK) { + DVLOG(1) << __func__ + << ": Failed to start watching the pipe. result=" << result; + producer_handle_.reset(); + } +} + +MojoDataPipeWriter::~MojoDataPipeWriter() { + DVLOG(1) << __func__; +} + +void MojoDataPipeWriter::Write(const uint8_t* buffer, + uint32_t buffer_size, + DoneCB done_cb) { + DVLOG(3) << __func__; + // Write() can not be called when another writing request is in process. + DCHECK(!current_buffer_); + DCHECK(!done_cb.is_null()); + if (!buffer_size) { + std::move(done_cb).Run(true); + return; + } + DCHECK(buffer); + + // Cannot write if the pipe is already closed. + if (!producer_handle_.is_valid()) { + DVLOG(1) << __func__ + << ": Failed to write buffer becuase the pipe is already closed"; + std::move(done_cb).Run(false); + return; + } + + current_buffer_ = buffer; + current_buffer_size_ = buffer_size; + bytes_written_ = 0; + done_cb_ = std::move(done_cb); + pipe_watcher_.ArmOrNotify(); +} + +void MojoDataPipeWriter::OnPipeWritable(MojoResult result, + const mojo::HandleSignalsState& state) { + if (result != MOJO_RESULT_OK) { + OnPipeError(result); + return; + } + + DCHECK(state.writable()); + DCHECK(current_buffer_); + DCHECK_GT(current_buffer_size_, bytes_written_); + uint32_t num_bytes = current_buffer_size_ - bytes_written_; + + result = producer_handle_->WriteData(current_buffer_ + bytes_written_, + &num_bytes, MOJO_WRITE_DATA_FLAG_NONE); + + if (IsPipeReadWriteError(result)) { + OnPipeError(result); + } else { + if (result == MOJO_RESULT_OK) { + DCHECK_GT(num_bytes, 0u); + bytes_written_ += num_bytes; + if (bytes_written_ == current_buffer_size_) { + CompleteCurrentWrite(); + return; + } + } + pipe_watcher_.ArmOrNotify(); + } +} + +void MojoDataPipeWriter::CompleteCurrentWrite() { + DVLOG(4) << __func__; + DCHECK(!done_cb_.is_null()); + current_buffer_ = nullptr; + std::move(done_cb_).Run(true); +} + +void MojoDataPipeWriter::OnPipeError(MojoResult result) { + DVLOG(1) << __func__ << "(" << result << ")"; + DCHECK(IsPipeReadWriteError(result)); + + producer_handle_.reset(); + + if (current_buffer_) { + DVLOG(1) << __func__ << ": writing to data pipe failed. result=" << result + << ", buffer size=" << current_buffer_size_ + << ", num_bytes(written)=" << bytes_written_; + current_buffer_ = nullptr; + current_buffer_size_ = 0; + bytes_written_ = 0; + DCHECK(!done_cb_.is_null()); + std::move(done_cb_).Run(false); + } +} + +bool MojoDataPipeWriter::IsPipeValid() const { + return producer_handle_.is_valid(); +} + +} // namespace media
diff --git a/media/mojo/common/mojo_data_pipe_read_write.h b/media/mojo/common/mojo_data_pipe_read_write.h new file mode 100644 index 0000000..bfacacf --- /dev/null +++ b/media/mojo/common/mojo_data_pipe_read_write.h
@@ -0,0 +1,114 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MOJO_COMMON_MOJO_DATA_PIPE_READ_WRITE_H_ +#define MEDIA_MOJO_COMMON_MOJO_DATA_PIPE_READ_WRITE_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "mojo/public/cpp/system/data_pipe.h" +#include "mojo/public/cpp/system/simple_watcher.h" + +namespace media { + +// An async reader to read a certain amount of bytes from a mojo data pipe by +// request. +class MojoDataPipeReader { + public: + explicit MojoDataPipeReader( + mojo::ScopedDataPipeConsumerHandle consumer_handle); + + ~MojoDataPipeReader(); + + using DoneCB = base::OnceCallback<void(bool)>; + // Reads |num_bytes| data from the mojo data pipe into |buffer|. When the + // operation completes, |done_cb| is called and indicates whether the reading + // succeeded. This is not allowed to be called when another reading is + // ongoing. When |buffer| is null, the data will be discarded. Otherwise, + // |buffer| needs to be valid for writing during the entire reading process. + // |done_cb| will be called immediately if |num_bytes| is zero or the data + // pipe is closed without doing anything. + void Read(uint8_t* buffer, uint32_t num_bytes, DoneCB done_cb); + + bool IsPipeValid() const; + + private: + void CompleteCurrentRead(); + void OnPipeReadable(MojoResult result, const mojo::HandleSignalsState& state); + void OnPipeError(MojoResult result); + + // Read side of the data pipe. + mojo::ScopedDataPipeConsumerHandle consumer_handle_; + + // Provides notification about |consumer_handle_| readiness. + mojo::SimpleWatcher pipe_watcher_; + + // The current buffer to be read. It is provided by Read() and should be + // guaranteed to be valid until the current read completes. + uint8_t* current_buffer_ = nullptr; + + // The number of bytes to be read for the current read request. + uint32_t current_buffer_size_ = 0; + + // The current once callback to be called when read completes. + DoneCB done_cb_; + + // Number of bytes already read into the current buffer. + uint32_t bytes_read_ = 0; + + DISALLOW_COPY_AND_ASSIGN(MojoDataPipeReader); +}; + +// An async writer to write a certain amount of data into a mojo data pipe by +// request. +class MojoDataPipeWriter { + public: + explicit MojoDataPipeWriter( + mojo::ScopedDataPipeProducerHandle producer_handle); + + ~MojoDataPipeWriter(); + + using DoneCB = base::OnceCallback<void(bool)>; + // Writes |num_bytes| data from |buffer| into the mojo data pipe. When the + // operation completes, |done_cb| is called and indicates whether the writing + // succeeded. This is not allowed to be called when another writing is + // ongoing. |buffer| needs to be valid for reading during the entire writing + // process. |done_cb| will be called immediately if |num_bytes| is zero or + // the data pipe is closed without doing anything. + void Write(const uint8_t* buffer, uint32_t num_bytes, DoneCB done_cb); + + bool IsPipeValid() const; + + private: + void OnPipeWritable(MojoResult result, const mojo::HandleSignalsState& state); + void OnPipeError(MojoResult result); + void CompleteCurrentWrite(); + + // Write side of the data pipe. + mojo::ScopedDataPipeProducerHandle producer_handle_; + + // Provides notifications about |producer_handle_| readiness. + mojo::SimpleWatcher pipe_watcher_; + + // The current buffer to be written. It is provided by Write() and should be + // guaranteed to be valid until the current write completes. + const uint8_t* current_buffer_ = nullptr; + + // The number of bytes to be written for the current write request. + uint32_t current_buffer_size_ = 0; + + // The current once callback to be called when write completes. + DoneCB done_cb_; + + // Number of bytes already written from the current buffer. + uint32_t bytes_written_ = 0; + + DISALLOW_COPY_AND_ASSIGN(MojoDataPipeWriter); +}; + +} // namespace media + +#endif // MEDIA_MOJO_COMMON_MOJO_DATA_PIPE_READ_WRITE_H_
diff --git a/media/mojo/common/mojo_data_pipe_read_write_unittest.cc b/media/mojo/common/mojo_data_pipe_read_write_unittest.cc new file mode 100644 index 0000000..e4a2487 --- /dev/null +++ b/media/mojo/common/mojo_data_pipe_read_write_unittest.cc
@@ -0,0 +1,108 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/mojo/common/mojo_data_pipe_read_write.h" + +#include <stdint.h> + +#include <memory> + +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/test/mock_callback.h" +#include "media/base/decoder_buffer.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +namespace { + +uint32_t kDefaultDataPipeCapacityBytes = 512; + +class MojoDataPipeReadWrite { + public: + MojoDataPipeReadWrite( + uint32_t data_pipe_capacity_bytes = kDefaultDataPipeCapacityBytes) { + mojo::DataPipe data_pipe(data_pipe_capacity_bytes); + + writer_ = base::MakeUnique<MojoDataPipeWriter>( + std::move(data_pipe.producer_handle)); + reader_ = base::MakeUnique<MojoDataPipeReader>( + std::move(data_pipe.consumer_handle)); + } + + void WriteAndRead(const uint8_t* buffer, + uint32_t buffer_size, + bool discard_data = false) { + base::RunLoop run_loop; + base::MockCallback<MojoDataPipeWriter::DoneCB> mock_write_cb; + base::MockCallback<MojoDataPipeReader::DoneCB> mock_read_cb; + EXPECT_TRUE(reader_->IsPipeValid()); + EXPECT_TRUE(writer_->IsPipeValid()); + EXPECT_CALL(mock_write_cb, Run(true)).Times(1); + EXPECT_CALL(mock_read_cb, Run(true)).Times(1); + + writer_->Write(buffer, buffer_size, mock_write_cb.Get()); + EXPECT_TRUE(read_buffer_.empty()); + if (discard_data) { + reader_->Read(nullptr, buffer_size, mock_read_cb.Get()); + run_loop.RunUntilIdle(); + } else { + read_buffer_.resize(buffer_size); + reader_->Read(read_buffer_.data(), buffer_size, mock_read_cb.Get()); + run_loop.RunUntilIdle(); + EXPECT_EQ(0, std::memcmp(buffer, read_buffer_.data(), buffer_size)); + read_buffer_.clear(); + } + } + + std::unique_ptr<MojoDataPipeWriter> writer_; + std::unique_ptr<MojoDataPipeReader> reader_; + std::vector<uint8_t> read_buffer_; +}; + +} // namespace + +TEST(MojoDataPipeReadWriteTest, Normal) { + base::MessageLoop message_loop; + std::string kData = "hello, world"; + MojoDataPipeReadWrite pipe_read_write_; + pipe_read_write_.WriteAndRead(reinterpret_cast<const uint8_t*>(kData.data()), + kData.size()); +} + +TEST(MojoDataPipeReadWriteTest, SequentialReading) { + base::MessageLoop message_loop; + std::string kData1 = "hello, world"; + std::string kData2 = "Bye!"; + MojoDataPipeReadWrite pipe_read_write_; + pipe_read_write_.WriteAndRead(reinterpret_cast<const uint8_t*>(kData1.data()), + kData1.size()); + pipe_read_write_.WriteAndRead(reinterpret_cast<const uint8_t*>(kData2.data()), + kData2.size()); +} + +TEST(MojoDataPipeReadWriteTest, LongerThanCapacity) { + base::MessageLoop message_loop; + std::string kData = "hello, world, hello, world, hello, world"; + MojoDataPipeReadWrite pipe_read_write_(10); + pipe_read_write_.WriteAndRead(reinterpret_cast<const uint8_t*>(kData.data()), + kData.size()); +} + +TEST(MojoDataPipeReadWriteTest, DiscardDataInPipe) { + base::MessageLoop message_loop; + std::string kData1 = "to be discarded"; + std::string kData2 = "hello, world, hello, world, hello, world"; + MojoDataPipeReadWrite pipe_read_write_(10); + pipe_read_write_.WriteAndRead(reinterpret_cast<const uint8_t*>(kData1.data()), + kData1.size(), true); + pipe_read_write_.WriteAndRead(reinterpret_cast<const uint8_t*>(kData2.data()), + kData2.size()); +} + +} // namespace media
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index ec89f78..9f7d1846 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc
@@ -114,24 +114,24 @@ const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\""; const char kOpusAudioOnlyWebM[] = "video/webm; codecs=\"opus\""; const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\""; -#if BUILDFLAG(USE_PROPRIETARY_CODECS) -const char kADTS[] = "audio/aac"; -const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\""; -const char kMP4VideoAVC3[] = "video/mp4; codecs=\"avc3.64001f\""; const char kMP4VideoVP9[] = "video/mp4; codecs=\"vp09.00.10.08.01.02.02.02.00\""; -const char kMP4VideoHEVC1[] = "video/mp4; codecs=\"hvc1.1.6.L93.B0\""; -const char kMP4VideoHEVC2[] = "video/mp4; codecs=\"hev1.1.6.L93.B0\""; -const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\""; -const char kMP4Audio[] = "audio/mp4; codecs=\"mp4a.40.2\""; const char kMP4AudioFlac[] = "audio/mp4; codecs=\"flac\""; const char kMP3[] = "audio/mpeg"; -const char kMP2AudioSBR[] = "video/mp2t; codecs=\"avc1.4D4041,mp4a.40.5\""; #if BUILDFLAG(ENABLE_AV1_DECODER) // TODO(dalecurtis): This is not the correct final string. Fix before enabling // by default. http://crbug.com/784607 const char kMP4AV1[] = "video/mp4; codecs=\"av1\""; #endif // BUILDFLAG(ENABLE_AV1_DECODER) +#if BUILDFLAG(USE_PROPRIETARY_CODECS) +const char kADTS[] = "audio/aac"; +const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\""; +const char kMP4VideoAVC3[] = "video/mp4; codecs=\"avc3.64001f\""; +const char kMP4VideoHEVC1[] = "video/mp4; codecs=\"hvc1.1.6.L93.B0\""; +const char kMP4VideoHEVC2[] = "video/mp4; codecs=\"hev1.1.6.L93.B0\""; +const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\""; +const char kMP4Audio[] = "audio/mp4; codecs=\"mp4a.40.2\""; +const char kMP2AudioSBR[] = "video/mp2t; codecs=\"avc1.4D4041,mp4a.40.5\""; #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) // Constants for the Media Source config change tests. @@ -1537,31 +1537,6 @@ } #endif -#if BUILDFLAG(USE_PROPRIETARY_CODECS) - -TEST_F(PipelineIntegrationTest, BasicPlaybackHi10P) { - ASSERT_EQ(PIPELINE_OK, Start("bear-320x180-hi10p.mp4")); - - Play(); - - ASSERT_TRUE(WaitUntilOnEnded()); -} - -std::vector<std::unique_ptr<VideoDecoder>> CreateFailingVideoDecoder() { - std::vector<std::unique_ptr<VideoDecoder>> failing_video_decoder; - failing_video_decoder.push_back(base::MakeUnique<FailingVideoDecoder>()); - return failing_video_decoder; -} - -TEST_F(PipelineIntegrationTest, BasicFallback) { - ASSERT_EQ(PIPELINE_OK, - Start("bear.mp4", kNormal, base::Bind(&CreateFailingVideoDecoder))); - - Play(); - - ASSERT_TRUE(WaitUntilOnEnded()); -}; - #if BUILDFLAG(ENABLE_AV1_DECODER) TEST_P(MSEPipelineIntegrationTest, BasicPlayback_AV1_MP4) { base::test::ScopedFeatureList scoped_feature_list_; @@ -1603,55 +1578,6 @@ EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash()); } -TEST_P(MSEPipelineIntegrationTest, ADTS) { - MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile); - EXPECT_EQ(PIPELINE_OK, - StartPipelineWithMediaSource(&source, kHashed, nullptr)); - source.EndOfStream(); - - EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); - EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); - EXPECT_EQ(325, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); - - Play(); - - EXPECT_TRUE(WaitUntilOnEnded()); - - // Verify that nothing was stripped. - EXPECT_HASH_EQ("0.46,1.72,4.26,4.57,3.39,1.53,", GetAudioHash()); -} - -TEST_P(MSEPipelineIntegrationTest, ADTS_TimestampOffset) { - MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile); - EXPECT_EQ(PIPELINE_OK, - StartPipelineWithMediaSource(&source, kHashed, nullptr)); - EXPECT_EQ(325, source.last_timestamp_offset().InMilliseconds()); - - // Trim off multiple frames off the beginning of the segment which will cause - // the first decoded frame to be incorrect if preroll isn't implemented. - const base::TimeDelta adts_preroll_duration = - base::TimeDelta::FromSecondsD(2.5 * 1024 / 44100); - const base::TimeDelta append_time = - source.last_timestamp_offset() - adts_preroll_duration; - - scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.adts"); - source.AppendAtTimeWithWindow( - append_time, append_time + adts_preroll_duration, kInfiniteDuration, - second_file->data(), second_file->data_size()); - source.EndOfStream(); - - Play(); - EXPECT_TRUE(WaitUntilOnEnded()); - - EXPECT_EQ(592, source.last_timestamp_offset().InMilliseconds()); - EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); - EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); - EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); - - // Verify preroll is stripped. - EXPECT_HASH_EQ("-1.76,-1.35,-0.72,0.70,1.24,0.52,", GetAudioHash()); -} - TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) { ASSERT_EQ(PIPELINE_OK, Start("sfx.mp3", kHashed)); @@ -1663,17 +1589,6 @@ EXPECT_HASH_EQ("1.30,2.72,4.56,5.08,3.74,2.03,", GetAudioHash()); } -TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_ADTS) { - ASSERT_EQ(PIPELINE_OK, Start("sfx.adts", kHashed)); - - Play(); - - ASSERT_TRUE(WaitUntilOnEnded()); - - // Verify codec delay and preroll are stripped. - EXPECT_HASH_EQ("1.80,1.66,2.31,3.26,4.46,3.36,", GetAudioHash()); -} - TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_FlacInMp4) { ASSERT_EQ(PIPELINE_OK, Start("sfx-flac.mp4", kHashed)); Play(); @@ -1814,6 +1729,91 @@ EXPECT_TRUE(WaitUntilOnEnded()); } +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + +TEST_P(MSEPipelineIntegrationTest, ADTS) { + MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile); + EXPECT_EQ(PIPELINE_OK, + StartPipelineWithMediaSource(&source, kHashed, nullptr)); + source.EndOfStream(); + + EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); + EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); + EXPECT_EQ(325, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); + + Play(); + + EXPECT_TRUE(WaitUntilOnEnded()); + + // Verify that nothing was stripped. + EXPECT_HASH_EQ("0.46,1.72,4.26,4.57,3.39,1.53,", GetAudioHash()); +} + +TEST_P(MSEPipelineIntegrationTest, ADTS_TimestampOffset) { + MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile); + EXPECT_EQ(PIPELINE_OK, + StartPipelineWithMediaSource(&source, kHashed, nullptr)); + EXPECT_EQ(325, source.last_timestamp_offset().InMilliseconds()); + + // Trim off multiple frames off the beginning of the segment which will cause + // the first decoded frame to be incorrect if preroll isn't implemented. + const base::TimeDelta adts_preroll_duration = + base::TimeDelta::FromSecondsD(2.5 * 1024 / 44100); + const base::TimeDelta append_time = + source.last_timestamp_offset() - adts_preroll_duration; + + scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.adts"); + source.AppendAtTimeWithWindow( + append_time, append_time + adts_preroll_duration, kInfiniteDuration, + second_file->data(), second_file->data_size()); + source.EndOfStream(); + + Play(); + EXPECT_TRUE(WaitUntilOnEnded()); + + EXPECT_EQ(592, source.last_timestamp_offset().InMilliseconds()); + EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); + EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds()); + EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds()); + + // Verify preroll is stripped. + EXPECT_HASH_EQ("-1.76,-1.35,-0.72,0.70,1.24,0.52,", GetAudioHash()); +} + +TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_ADTS) { + ASSERT_EQ(PIPELINE_OK, Start("sfx.adts", kHashed)); + + Play(); + + ASSERT_TRUE(WaitUntilOnEnded()); + + // Verify codec delay and preroll are stripped. + EXPECT_HASH_EQ("1.80,1.66,2.31,3.26,4.46,3.36,", GetAudioHash()); +} + +TEST_F(PipelineIntegrationTest, BasicPlaybackHi10P) { + ASSERT_EQ(PIPELINE_OK, Start("bear-320x180-hi10p.mp4")); + + Play(); + + ASSERT_TRUE(WaitUntilOnEnded()); +} + +std::vector<std::unique_ptr<VideoDecoder>> CreateFailingVideoDecoder() { + std::vector<std::unique_ptr<VideoDecoder>> failing_video_decoder; + failing_video_decoder.push_back(base::MakeUnique<FailingVideoDecoder>()); + return failing_video_decoder; +} + +TEST_F(PipelineIntegrationTest, BasicFallback) { + ASSERT_EQ(PIPELINE_OK, + Start("bear.mp4", kNormal, base::Bind(&CreateFailingVideoDecoder))); + + Play(); + + ASSERT_TRUE(WaitUntilOnEnded()); +}; + TEST_P(MSEPipelineIntegrationTest, ConfigChange_MP4) { MockMediaSource source("bear-640x360-av_frag.mp4", kMP4, kAppendWholeFile); EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source)); @@ -2051,6 +2051,37 @@ Stop(); } +MAYBE_EME_TEST_P(MSEPipelineIntegrationTest, + MAYBE_EME(EncryptedPlayback_MP4_VP9_CENC_VideoOnly)) { + MockMediaSource source("bear-320x240-v_frag-vp9-cenc.mp4", kMP4VideoVP9, + kAppendWholeFile); + FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); + EXPECT_EQ(PIPELINE_OK, + StartPipelineWithEncryptedMedia(&source, &encrypted_media)); + + source.EndOfStream(); + + Play(); + + ASSERT_TRUE(WaitUntilOnEnded()); + source.Shutdown(); + Stop(); +} + +TEST_P(MSEPipelineIntegrationTest, BasicPlayback_VideoOnly_MP4_VP9) { + MockMediaSource source("bear-320x240-v_frag-vp9.mp4", kMP4VideoVP9, + kAppendWholeFile); + EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source)); + source.EndOfStream(); + ASSERT_EQ(PIPELINE_OK, pipeline_status_); + + Play(); + + ASSERT_TRUE(WaitUntilOnEnded()); + source.Shutdown(); + Stop(); +} + #if BUILDFLAG(USE_PROPRIETARY_CODECS) MAYBE_EME_TEST_P(MSEPipelineIntegrationTest, MAYBE_EME(EncryptedPlayback_MP4_CENC_VideoOnly)) { @@ -2246,23 +2277,6 @@ Stop(); } -MAYBE_EME_TEST_P(MSEPipelineIntegrationTest, - MAYBE_EME(EncryptedPlayback_MP4_VP9_CENC_VideoOnly)) { - MockMediaSource source("bear-320x240-v_frag-vp9-cenc.mp4", kMP4VideoVP9, - kAppendWholeFile); - FakeEncryptedMedia encrypted_media(new KeyProvidingApp()); - EXPECT_EQ(PIPELINE_OK, - StartPipelineWithEncryptedMedia(&source, &encrypted_media)); - - source.EndOfStream(); - - Play(); - - ASSERT_TRUE(WaitUntilOnEnded()); - source.Shutdown(); - Stop(); -} - TEST_P(MSEPipelineIntegrationTest, BasicPlayback_VideoOnly_MP4_AVC3) { MockMediaSource source("bear-1280x720-v_frag-avc3.mp4", kMP4VideoAVC3, kAppendWholeFile); @@ -2281,20 +2295,6 @@ Stop(); } -TEST_P(MSEPipelineIntegrationTest, BasicPlayback_VideoOnly_MP4_VP9) { - MockMediaSource source("bear-320x240-v_frag-vp9.mp4", kMP4VideoVP9, - kAppendWholeFile); - EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source)); - source.EndOfStream(); - ASSERT_EQ(PIPELINE_OK, pipeline_status_); - - Play(); - - ASSERT_TRUE(WaitUntilOnEnded()); - source.Shutdown(); - Stop(); -} - TEST_P(MSEPipelineIntegrationTest, BasicPlayback_VideoOnly_MP4_HEVC1) { // HEVC demuxing might be enabled even on platforms that don't support HEVC // decoding. For those cases we'll get DECODER_ERROR_NOT_SUPPORTED, which
diff --git a/remoting/client/gesture_interpreter.cc b/remoting/client/gesture_interpreter.cc index 638d2c2..32365b5 100644 --- a/remoting/client/gesture_interpreter.cc +++ b/remoting/client/gesture_interpreter.cc
@@ -105,14 +105,25 @@ } ViewMatrix::Point cursor_position = input_strategy_->GetCursorPosition(); - if (state == GESTURE_BEGAN) { - StartInputFeedback(cursor_position.x, cursor_position.y, - TouchInputStrategy::DRAG_FEEDBACK); + switch (state) { + case GESTURE_BEGAN: + StartInputFeedback(cursor_position.x, cursor_position.y, + TouchInputStrategy::DRAG_FEEDBACK); + input_stub_->SendMouseEvent(cursor_position.x, cursor_position.y, + protocol::MouseEvent_MouseButton_BUTTON_LEFT, + true); + break; + case GESTURE_CHANGED: + InjectCursorPosition(cursor_position.x, cursor_position.y); + break; + case GESTURE_ENDED: + input_stub_->SendMouseEvent(cursor_position.x, cursor_position.y, + protocol::MouseEvent_MouseButton_BUTTON_LEFT, + false); + break; + default: + NOTREACHED(); } - - input_stub_->SendMouseEvent(cursor_position.x, cursor_position.y, - protocol::MouseEvent_MouseButton_BUTTON_LEFT, - is_dragging_mode); } void GestureInterpreter::OneFingerFling(float velocity_x, float velocity_y) {
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json index 77164e3b..52bff4d 100644 --- a/testing/buildbot/chromium.clang.json +++ b/testing/buildbot/chromium.clang.json
@@ -1,4 +1,6 @@ { + "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, + "AAAAA2 See generate_buildbot_json.py to make changes": {}, "CFI Linux (icall)": { "gtest_tests": [ { @@ -7025,8 +7027,7 @@ "--gtest_filter=-SaveType/SavePageMultiFrameBrowserTest.ObjectElements/0" ], "swarming": { - "can_use_on_swarming_builders": false, - "shards": 10 + "can_use_on_swarming_builders": false }, "test": "browser_tests" }, @@ -7909,11 +7910,14 @@ } }, { + "args": [ + "--jobs=1" + ], "isolate_name": "telemetry_unittests", "name": "telemetry_unittests", "swarming": { "can_use_on_swarming_builders": true, - "shards": 2 + "shards": 4 } } ]
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py index f70b30ad..c7d55d7 100755 --- a/testing/buildbot/generate_buildbot_json.py +++ b/testing/buildbot/generate_buildbot_json.py
@@ -295,6 +295,9 @@ if 'shards' in swarming_dict: if swarming_dict['shards'] == 1: # pragma: no cover del swarming_dict['shards'] # pragma: no cover + if 'hard_timeout' in swarming_dict: + if swarming_dict['hard_timeout'] == 0: # pragma: no cover + del swarming_dict['hard_timeout'] # pragma: no cover if not swarming_dict['can_use_on_swarming_builders']: # Remove all other keys. for k in swarming_dict.keys(): # pragma: no cover
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index eeab245..848bdb7 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -23,6 +23,8 @@ 'KitKat Phone Tester (rel)', 'KitKat Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroid x64', ], 'modifications': { 'Lollipop Tablet Tester': { @@ -42,8 +44,75 @@ }, }, }, + 'angle_unittests': { + 'remove_from': [ + # chromium.clang + 'ToTAndroidCFI', + 'ToTLinuxMSan', + ], + }, + 'app_shell_unittests': { + 'remove_from': [ + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'CrWinClang', + 'CrWinClang(dbg)', + 'CrWinClang(shared)', + 'CrWinClang64', + 'CrWinClang64(dbg)', + 'CrWinClang64(dll)', + 'CrWinClangLLD', + 'CrWinClangLLD64', + 'CrWinClngLLD64dbg', + 'CrWinClngLLDdbg', + 'ToTLinuxASan', + 'ToTLinuxMSan', + 'ToTLinuxUBSanVptr', + 'ToTWin', + 'ToTWin(dbg)', + 'ToTWin(dll)', + 'ToTWin64', + 'ToTWin64(dbg)', + 'ToTWin64(dll)', + 'ToTWinCFI', + 'ToTWinCFI64', + 'ToTWinThinLTO64', + ], + }, + 'aura_unittests': { + 'remove_from': [ + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'CrWinClang', + 'CrWinClang(dbg)', + 'CrWinClang(shared)', + 'CrWinClang64', + 'CrWinClang64(dbg)', + 'CrWinClang64(dll)', + 'CrWinClangLLD', + 'CrWinClangLLD64', + 'CrWinClngLLD64dbg', + 'CrWinClngLLDdbg', + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', + 'ToTWin', + 'ToTWin(dbg)', + 'ToTWin(dll)', + 'ToTWin64', + 'ToTWin64(dbg)', + 'ToTWin64(dll)', + 'ToTWinCFI', + 'ToTWinCFI64', + 'ToTWinThinLTO64', + ], + }, 'base_unittests': { 'modifications': { + # chromium.android 'KitKat Tablet Tester': { 'swarming': { 'hard_timeout': 300, @@ -69,6 +138,12 @@ 'hard_timeout': 600, }, }, + # chromium.clang + 'ToTMac': { + 'swarming': { + 'shards': 5, + }, + }, }, }, 'breakpad_unittests': { @@ -91,6 +166,11 @@ }, }, 'browser_tests': { + 'remove_from': [ + # chromium.clang + 'CrWinAsanCov', + 'ToTLinuxUBSanVptr', + ], 'modifications': { 'Win7 Tests (dbg)(1)': { 'swarming': { @@ -122,6 +202,56 @@ 'shards': 5, }, }, + # chromium.clang + 'CFI Linux (icall)': { + 'swarming': { + 'shards': 5, + }, + }, + 'CrWinClang(dbg)': { + 'swarming': { + 'shards': 20, + }, + }, + 'CrWinClang64(dbg)': { + 'swarming': { + 'shards': 20, + }, + }, + 'ToTLinux': { + 'swarming': { + 'shards': 5, + }, + }, + 'ToTLinuxASan': { + 'swarming': { + 'shards': 5, + }, + }, + 'ToTLinuxLLD': { + 'swarming': { + 'shards': 5, + }, + }, + 'ToTWin(dbg)': { + 'swarming': { + 'shards': 20, + }, + }, + 'ToTWin64(dbg)': { + 'swarming': { + 'shards': 20, + }, + }, + 'ToTLinuxThinLTO': { + # TODO(kbr): remove this spurious filter. + 'args': [ + '--gtest_filter=-SaveType/SavePageMultiFrameBrowserTest.ObjectElements/0', + ], + 'swarming': { + 'shards': 10, + }, + }, }, }, 'blink_heap_unittests': { @@ -136,6 +266,11 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'ToTLinuxMSan', # On chromium.linux, unclear why these only run on "Linux Tests". 'Cast Audio Linux', 'Cast Linux', @@ -171,6 +306,11 @@ }, 'blink_platform_unittests': { 'remove_from': [ + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'ToTLinuxMSan', # On chromium.linux, unclear why these only run on "Linux Tests". 'Linux Tests (dbg)(1)', 'Linux Tests (dbg)(1)(32)', @@ -234,9 +374,15 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroidCFI', ], }, 'capture_unittests': { + 'remove_from': [ + # chromium.clang + 'ToTLinuxUBSanVptr', + ], 'modifications': { 'KitKat Tablet Tester': { 'swarming': { @@ -286,6 +432,9 @@ # TODO(kbr): why are the cast unit tests not run on the Cast bots?! 'Cast Audio Linux', 'Cast Linux', + # chromium.clang + 'ToTAndroidCFI', + 'ToTLinuxThinLTO', ], }, 'cc_unittests': { @@ -331,11 +480,43 @@ 'Mac', ], }, + 'chrome_elf_import_unittests': { + 'remove_from': [ + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'CrWinClang', + 'CrWinClang(dbg)', + 'CrWinClang(shared)', + 'CrWinClang64', + 'CrWinClang64(dbg)', + 'CrWinClang64(dll)', + 'CrWinClangLLD', + 'CrWinClangLLD64', + 'CrWinClngLLD64dbg', + 'CrWinClngLLDdbg', + 'ToTWin(dll)', + 'ToTWin64', + 'ToTWin64(dbg)', + 'ToTWin64(dll)', + 'ToTWinCFI', + 'ToTWinCFI64', + 'ToTWinThinLTO64', + ], + }, 'chrome_public_test_apk': { 'remove_from': [ # TODO(kbr): on chromium.android this removal looks like an accident. 'Marshmallow Phone Tester (rel)', + # chromium.clang + 'ToTAndroidCFI', ], + 'key_removals': { + 'ToTAndroid x64': [ + 'args', + ], + }, 'modifications': { 'KitKat Phone Tester (dbg)': { 'swarming': { @@ -373,15 +554,25 @@ 'hard_timeout': 1800, }, }, + # chromium.clang + 'ToTAndroid x64': { + 'swarming': { + 'shards': 1, + 'hard_timeout': 0, + }, + }, }, }, 'chrome_public_test_vr_apk': { 'remove_from': [ + # chromium.android 'KitKat Phone Tester (dbg)', 'KitKat Phone Tester (rel)', 'KitKat Tablet Tester', 'Lollipop Tablet Tester', 'Marshmallow Tablet Tester', + # chromium.clang + 'ToTAndroid x64', ], 'modifications': { 'Lollipop Phone Tester': { @@ -412,7 +603,16 @@ }, }, 'chrome_sync_shell_test_apk': { + 'key_removals': { + 'ToTAndroid x64': [ + 'args', + ], + 'ToTAndroidCFI': [ + 'args', + ], + }, 'modifications': { + # chromium.android 'KitKat Phone Tester (dbg)': { 'swarming': { 'shards': 2, @@ -433,6 +633,17 @@ 'hard_timeout': 1200, }, }, + # chromium.clang + 'ToTAndroid x64': { + 'swarming': { + 'hard_timeout': 0, + }, + }, + 'ToTAndroidCFI': { + 'swarming': { + 'hard_timeout': 0, + }, + }, }, }, 'chromedriver_unittests': { @@ -441,6 +652,9 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', ], }, 'components_background_task_scheduler_junit_tests': { @@ -462,6 +676,14 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'ToTLinux', + 'ToTLinuxASan', + 'ToTLinuxLLD', + 'ToTLinuxMSan', + 'ToTLinuxUBSanVptr', + 'ToTMac', + 'ToTMacASan', # On chromium.linux, unclear why these aren't run on the Cast bots. 'Cast Audio Linux', 'Cast Linux', @@ -494,6 +716,8 @@ }, 'components_unittests': { 'remove_from': [ + # chromium.clang + 'ToTLinuxUBSanVptr', # On chromium.linux, unclear why these aren't run on the Cast bots. 'Cast Audio Linux', 'Cast Linux', @@ -531,24 +755,38 @@ }, }, }, + 'compositor_unittests': { + 'remove_from': [ + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'CrWinClang', + 'CrWinClang(dbg)', + 'CrWinClang(shared)', + 'CrWinClang64', + 'CrWinClang64(dbg)', + 'CrWinClang64(dll)', + 'CrWinClangLLD', + 'CrWinClangLLD64', + 'CrWinClngLLD64dbg', + 'CrWinClngLLDdbg', + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', + 'ToTWin', + 'ToTWin(dbg)', + 'ToTWin(dll)', + 'ToTWin64', + 'ToTWin64(dbg)', + 'ToTWin64(dll)', + 'ToTWinCFI', + 'ToTWinCFI64', + 'ToTWinThinLTO64', + ], + }, 'content_browsertests': { 'modifications': { - 'Cast Audio Linux': { - 'args': [ - '--test-launcher-filter-file=src/testing/buildbot/filters/cast-linux.content_browsertests.filter', - ], - 'swarming': { - 'can_use_on_swarming_builders': False, - }, - }, - 'Cast Linux': { - 'args': [ - '--test-launcher-filter-file=src/testing/buildbot/filters/cast-linux.content_browsertests.filter', - ], - 'swarming': { - 'can_use_on_swarming_builders': False, - }, - }, + # chromium.android 'KitKat Tablet Tester': { 'swarming': { 'hard_timeout': 1800, @@ -605,10 +843,35 @@ 'shards': 2, }, }, + # chromium.clang + 'ToTLinuxUBSanVptr': { + 'swarming': { + 'shards': 5, + }, + }, + # chromium.linux + 'Cast Audio Linux': { + 'args': [ + '--test-launcher-filter-file=src/testing/buildbot/filters/cast-linux.content_browsertests.filter', + ], + 'swarming': { + 'can_use_on_swarming_builders': False, + }, + }, + 'Cast Linux': { + 'args': [ + '--test-launcher-filter-file=src/testing/buildbot/filters/cast-linux.content_browsertests.filter', + ], + 'swarming': { + 'can_use_on_swarming_builders': False, + }, + }, }, }, 'content_shell_crash_test': { 'remove_from': [ + # chromium.clang + 'ToTMac', # On chromium.linux, unclear why these only run on "Linux Tests". 'Linux Tests (dbg)(1)', 'Linux Tests (dbg)(1)(32)', @@ -624,7 +887,17 @@ ], }, 'content_shell_test_apk': { + 'key_removals': { + # chromium.clang + 'ToTAndroid x64': [ + 'args', + ], + 'ToTAndroidCFI': [ + 'args', + ], + }, 'modifications': { + # chromium.android 'KitKat Tablet Tester': { 'swarming': { 'hard_timeout': 1200, @@ -648,6 +921,19 @@ 'shards': 2, }, }, + # chromium.clang + 'ToTAndroid x64': { + 'swarming': { + 'hard_timeout': 0, + 'shards': 1, + }, + }, + 'ToTAndroidCFI': { + 'swarming': { + 'hard_timeout': 0, + 'shards': 1, + }, + }, }, }, 'content_unittests': { @@ -673,6 +959,15 @@ }, }, }, + 'crashpad_tests': { + 'remove_from': [ + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'ToTMacASan', + ], + }, 'crypto_unittests': { 'remove_from': [ # TODO(dpranke) - remove this exception. @@ -689,6 +984,8 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroidCFI', # TODO(kbr): on chromium.linux, it's unclear why these show up on "Cast # Audio Linux" at all, since they're supposed to be compiled out for # Chromecast. @@ -696,11 +993,19 @@ }, 'dbus_unittests': { 'remove_from': [ + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', + # chromium.linux 'Linux Tests (dbg)(1)(32)', ], }, 'device_unittests': { 'remove_from': [ + # chromium.clang + 'ToTMac', + 'ToTMacASan', + # chromium.win 'Win7 Tests (dbg)(1)', ], 'modifications': { @@ -747,16 +1052,18 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroidCFI', # chromium.win 'Win7 Tests (dbg)(1)', ], }, - 'dbus_unittests': { - 'remove_from': [ - 'Linux Tests (dbg)(1)(32)', - ], - }, 'events_unittests': { + 'remove_from': [ + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', + ], 'modifications': { 'KitKat Tablet Tester': { 'swarming': { @@ -777,6 +1084,11 @@ }, 'extensions_browsertests': { 'remove_from': [ + # chromium.clang + 'ToTLinux', + 'ToTLinuxLLD', + 'ToTMac', + 'ToTMacASan', # On chromium.mac, unclear why these aren't run. 'Mac10.10 Tests', 'Mac10.11 Tests', @@ -790,6 +1102,12 @@ 'Linux Tests (dbg)(1)(32)', ], }, + 'gcm_unit_tests': { + 'remove_from': [ + # chromium.clang + 'ToTAndroidCFI', + ], + }, 'gfx_unittests': { 'remove_from': [ # On chromium.android, unclear why these aren't run on all bots. @@ -838,6 +1156,12 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'ToTLinux', + 'ToTLinuxASan', + 'ToTLinuxLLD', + 'ToTLinuxMSan', + 'ToTLinuxUBSanVptr', # On chromium.linux, unclear why these aren't run on Cast. 'Cast Audio Linux', 'Cast Linux', @@ -870,6 +1194,48 @@ }, 'gl_unittests': { 'modifications': { + 'CFI Linux (icall)': { + 'args': [ + '--use-gpu-in-tests', + '--no-xvfb', + ], + 'swarming': { + 'dimension_sets': [ + { + 'gpu': '10de:1cb3', + 'os': 'Ubuntu', + 'pool': 'Chrome-GPU', + }, + ], + }, + 'use_xvfb': False, + }, + 'CFI Linux ToT': { + 'args': [ + '--use-gpu-in-tests', + '--no-xvfb', + ], + 'swarming': { + 'dimension_sets': [ + { + 'gpu': '10de:1cb3', + 'os': 'Ubuntu', + 'pool': 'Chrome-GPU', + }, + ], + }, + 'use_xvfb': False, + }, + 'ToTAndroidCFI': { + 'swarming': { + 'dimension_sets': [ + { + 'device_os': 'MMB29Q', + 'device_type': 'bullhead', + }, + ], + }, + }, 'Lollipop Phone Tester': { 'swarming': { 'hard_timeout': 960, @@ -887,6 +1253,16 @@ }, }, }, + 'gn_unittests': { + 'remove_from': [ + # chromium.clang + 'ToTLinux', + 'ToTLinuxASan', + 'ToTLinuxLLD', + 'ToTLinuxMSan', + 'ToTLinuxUBSanVptr', + ], + }, 'google_apis_unittests': { 'remove_from': [ # On chromium.android, unclear why these aren't run. @@ -899,6 +1275,8 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroidCFI', # On chromium.linux, unclear why these aren't run on Cast. 'Cast Audio Linux', 'Cast Linux', @@ -908,6 +1286,10 @@ }, 'gpu_ipc_service_unittests': { 'remove_from': [ + # chromium.clang + 'CrWinClngLLD64dbg', + 'ToTLinuxLLD', + # chromium.linux 'Linux Tests (dbg)(1)(32)', ], 'modifications': { @@ -961,8 +1343,43 @@ 'Mac10.11 Tests', ], }, + 'install_static_unittests': { + 'remove_from': [ + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'CrWinClang', + 'CrWinClang(dbg)', + 'CrWinClang(shared)', + 'CrWinClang64', + 'CrWinClang64(dbg)', + 'CrWinClang64(dll)', + 'CrWinClangLLD', + 'CrWinClangLLD64', + 'CrWinClngLLD64dbg', + 'CrWinClngLLDdbg', + 'ToTWin(dbg)', + 'ToTWin(dll)', + 'ToTWin64', + 'ToTWin64(dbg)', + 'ToTWin64(dll)', + 'ToTWinCFI', + 'ToTWinCFI64', + 'ToTWinThinLTO64', + ], + }, 'interactive_ui_tests': { + 'remove_from': [ + # chromium.clang + 'ToTLinuxUBSanVptr', + ], 'modifications': { + 'CFI Linux (icall)': { + 'swarming': { + 'shards': 1, + }, + }, # Unclear why this isn't sharded. 'Linux Tests': { 'swarming': { @@ -1055,6 +1472,8 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroidCFI', ], }, 'keyboard_unittests': { @@ -1079,6 +1498,13 @@ 'Marshmallow 64 bit Tester', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroid x64', + 'ToTLinux', + 'ToTLinuxASan', + 'ToTLinuxLLD', + 'ToTLinuxThinLTO', + 'ToTLinuxUBSanVptr', # On chromium.linux, unclear why these aren't run. 'Linux Tests', 'Linux Tests (dbg)(1)', @@ -1108,6 +1534,13 @@ 'linux-chromeos-rel', ], }, + 'mac_installer_unittests': { + 'remove_from': [ + # chromium.clang + 'ToTMac', + 'ToTMacASan', + ], + }, 'media_blink_unittests': { 'remove_from': [ # On chromium.android, unclear why these aren't run on all bots. @@ -1115,6 +1548,8 @@ 'KitKat Phone Tester (rel)', 'KitKat Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroid x64', ], 'modifications': { 'Lollipop Tablet Tester': { @@ -1137,6 +1572,10 @@ ], }, 'media_unittests': { + 'remove_from': [ + # chromium.clang + 'ToTLinuxUBSanVptr', + ], 'modifications': { 'KitKat Tablet Tester': { 'swarming': { @@ -1186,12 +1625,15 @@ # TODO(dpranke) - remove this exception. 'Linux Tests SANDBOX', - 'Win7 Tests (dbg)(1)', + # chromium.clang + 'ToTMac', # On chromium.mac, unclear why these only run on "Mac10.9 Tests". 'Mac10.10 Tests', 'Mac10.11 Tests', 'Mac10.12 Tests', 'Mac10.9 Tests (dbg)', + # chromium.win + 'Win7 Tests (dbg)(1)', ], }, 'midi_unittests': { @@ -1206,6 +1648,8 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroidCFI', ], }, 'mojo_common_unittests': { @@ -1221,6 +1665,9 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', # On chromium.linux, unclear why these aren't run on Cast. 'Cast Audio Linux', 'Cast Linux', @@ -1246,6 +1693,9 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', # On chromium.linux, unclear why these aren't run on Cast. 'Cast Audio Linux', 'Cast Linux', @@ -1271,6 +1721,9 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', # On chromium.linux, unclear why these aren't run on Cast. 'Cast Audio Linux', 'Cast Linux', @@ -1296,6 +1749,9 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', # On chromium.linux, unclear why these aren't run on Cast. 'Cast Audio Linux', 'Cast Linux', @@ -1317,8 +1773,11 @@ 'Marshmallow 64 bit Tester', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroid x64', ], 'modifications': { + # chromium.android 'KitKat Phone Tester (dbg)': { 'args': [ '--gs-results-bucket=chromium-result-details', @@ -1334,15 +1793,48 @@ '--gs-results-bucket=chromium-result-details', ], }, + # chromium.clang + 'ToTAndroidCFI': { + 'swarming': { + 'hard_timeout': 0, + }, + }, }, }, + 'nacl_helper_nonsfi_unittests': { + 'remove_from': [ + # chromium.clang + 'CFI Linux (icall)', + 'CFI Linux ToT', + 'ToTLinux (dbg)', + 'ToTLinuxASan', + 'ToTLinuxMSan', + 'ToTLinuxThinLTO', + 'ToTLinuxUBSanVptr', + ], + }, + 'nacl_loader_unittests': { + 'remove_from': [ + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', + ], + }, 'native_theme_unittests': { 'remove_from': [ + # chromium.clang + 'ToTLinuxASan', + 'ToTMacASan', + # chromium.linux 'Linux Tests (dbg)(1)(32)', ], }, 'net_unittests': { + 'remove_from': [ + 'CrWinAsanCov', + ], 'modifications': { + # chromium.android 'KitKat Tablet Tester': { 'swarming': { 'hard_timeout': 1800, @@ -1376,6 +1868,12 @@ 'hard_timeout': 1800, }, }, + # chromium.clang + 'ToTLinuxASan': { + 'swarming': { + 'shards': 4, + }, + }, }, }, 'printing_unittests': { @@ -1397,6 +1895,8 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroidCFI', # On chromium.linux, unclear why these aren't run on 32-bit. 'Linux Tests (dbg)(1)(32)', ], @@ -1419,6 +1919,9 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'ToTAndroid x64', + 'ToTAndroidCFI', # On chromium.linux, unclear why these aren't run on 32-bit. 'Linux Tests (dbg)(1)(32)', ], @@ -1442,6 +1945,9 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroid x64', + 'ToTAndroidCFI', ], 'modifications': { 'Marshmallow 64 bit Tester': { @@ -1470,6 +1976,9 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'ToTAndroid x64', + 'ToTAndroidCFI', # On chromium.linux, unclear why these aren't run on 32-bit. 'Linux Tests (dbg)(1)(32)', ], @@ -1485,6 +1994,9 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroid x64', + 'ToTAndroidCFI', ], 'modifications': { 'Marshmallow 64 bit Tester': { @@ -1578,6 +2090,15 @@ 'Marshmallow 64 bit Tester', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'CFI Linux (icall)', + 'CFI Linux ToT', + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'ToTAndroidASan', + 'ToTLinuxMSan', + 'ToTLinuxThinLTO', # On chromium.linux, unclear why these aren't run on Cast. 'Cast Audio Linux', 'Cast Linux', @@ -1661,6 +2182,8 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroidCFI', # On chromium.linux, unclear why these aren't run on Cast. 'Cast Audio Linux', 'Cast Linux', @@ -1704,6 +2227,13 @@ }, }, 'storage_unittests': { + 'remove_from': [ + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxLLD', + 'ToTLinuxThinLTO', + 'ToTLinuxUBSanVptr', + ], 'modifications': { # chromium.android 'KitKat Phone Tester (dbg)': { @@ -1912,6 +2442,11 @@ }, }, 'ui_touch_selection_unittests': { + 'remove_from': [ + # chromium.clang + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', + ], 'modifications': { 'KitKat Tablet Tester': { 'swarming': { @@ -1927,11 +2462,14 @@ }, 'unit_tests': { 'remove_from': [ + # chromium.clang + 'CrWinAsanCov', # On chromium.linux, unclear why these aren't run on Cast. 'Cast Audio Linux', 'Cast Linux', ], 'modifications': { + # chromium.android 'KitKat Tablet Tester': { 'swarming': { 'hard_timeout': 1200, @@ -1968,6 +2506,12 @@ 'shards': 2, }, }, + # chromium.clang + 'ToTLinuxASan': { + 'swarming': { + 'shards': 2, + }, + } }, }, 'url_unittests': { @@ -1982,10 +2526,16 @@ 'Marshmallow Phone Tester (rel)', 'Marshmallow Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroidCFI', ], }, 'views_unittests': { 'remove_from': [ + # chromium.clang + 'ToTLinuxASan', + 'ToTMacASan', + # chromium.linux 'Linux Tests (dbg)(1)(32)', ], }, @@ -2003,6 +2553,16 @@ 'remove_from': [ # On chromium.android, unclear why these aren't run on all bots. 'Nougat Phone Tester', + # chromium.clang + 'CFI Linux (icall)', + 'CFI Linux ToT', + 'ToTAndroid x64', + 'ToTAndroidASan', + 'ToTLinux', + 'ToTLinuxASan', + 'ToTLinuxLLD', + 'ToTLinuxThinLTO', + 'ToTLinuxUBSanVptr', # chromium.win 'Win10 Tests x64', ], @@ -2048,6 +2608,8 @@ 'KitKat Phone Tester (dbg)', 'KitKat Phone Tester (rel)', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroid x64', # chromium.win 'Win 7 Tests x64 (1)', 'Win10 Tests x64', @@ -2075,12 +2637,37 @@ }, }, }, + 'vr_pixeltests': { + 'remove_from': [ + # chromium.android + 'KitKat Phone Tester (dbg)', + 'KitKat Phone Tester (rel)', + 'KitKat Tablet Tester', + 'Lollipop Phone Tester', + 'Lollipop Tablet Tester', + 'Marshmallow 64 bit Tester', + 'Marshmallow Phone Tester (rel)', + 'Marshmallow Tablet Tester', + # chromium.clang + 'ToTAndroid x64', + # chromium.win + 'Win 7 Tests x64 (1)', + 'Win10 Tests x64', + 'Win7 Tests (1)', + 'Win7 Tests (dbg)(1)', + ], + }, 'webkit_layout_tests': { 'remove_from': [ + # chromium.clang + 'ToTMac', + # chromium.linux 'Linux Tests (dbg)(1)', 'Linux Tests (dbg)(1)(32)', + # chromium.mac 'Mac10.9 Tests', 'Mac10.9 Tests (dbg)', + # chromium.win 'Win 7 Tests x64 (1)', 'Win10 Tests x64', 'Win7 Tests (1)', @@ -2174,6 +2761,8 @@ }, 'webkit_python_tests': { 'remove_from': [ + # chromium.clang + 'ToTMac', # On chromium.linux, unclear why these only run on "Linux Tests". 'Linux Tests (dbg)(1)', 'Linux Tests (dbg)(1)(32)', @@ -2202,6 +2791,13 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'ToTAndroidCFI', + 'ToTLinuxMSan', + 'ToTLinuxThinLTO', # On chromium.linux, unclear why these only run on "Linux Tests". 'Cast Audio Linux', 'Cast Linux', @@ -2224,8 +2820,17 @@ 'KitKat Phone Tester (rel)', 'KitKat Tablet Tester', 'Nougat Phone Tester', + # chromium.clang + 'ToTAndroid x64', ], + 'key_removals': { + # chromium.clang + 'ToTAndroidCFI': [ + 'args', + ], + }, 'modifications': { + # chromium.android 'Lollipop Phone Tester': { 'swarming': { 'shards': 6, @@ -2257,6 +2862,35 @@ }, }, }, + 'wm_unittests': { + 'remove_from': [ + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'CrWinClang', + 'CrWinClang(dbg)', + 'CrWinClang(shared)', + 'CrWinClang64', + 'CrWinClang64(dbg)', + 'CrWinClang64(dll)', + 'CrWinClangLLD', + 'CrWinClangLLD64', + 'CrWinClngLLD64dbg', + 'CrWinClngLLDdbg', + 'ToTLinuxASan', + 'ToTLinuxUBSanVptr', + 'ToTWin', + 'ToTWin(dbg)', + 'ToTWin(dll)', + 'ToTWin64', + 'ToTWin64(dbg)', + 'ToTWin64(dll)', + 'ToTWinCFI', + 'ToTWinCFI64', + 'ToTWinThinLTO64', + ], + }, 'wtf_unittests': { 'remove_from': [ # On chromium.android, unclear why these aren't run. @@ -2273,6 +2907,12 @@ 'Linux ChromiumOS Tests (dbg)(1)', 'linux-chromeos-dbg', 'linux-chromeos-rel', + # chromium.clang + 'CrWinAsan', + 'CrWinAsan(dll)', + 'CrWinAsanCov', + 'ToTAndroidCFI', + 'ToTLinuxMSan', # On chromium.linux, unclear why these only run on "Linux Tests". 'Cast Audio Linux', 'Cast Linux',
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 21e9ccd..12b11e9 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -16,6 +16,13 @@ { # Test suites. + + 'android_clang_and_fyi_specific_gtests': { + # TODO(kbr): this entire test suite should probably be removed. + 'cast_unittests': {}, + 'gcm_unit_tests': {}, + }, + 'android_l_cts_tests': { 'arch': 'arm64', 'platform': 'L', @@ -130,14 +137,22 @@ }, }, + 'angle_gtests': { + 'angle_unittests': {}, + }, + 'aura_gtests': { 'app_shell_unittests': {}, 'aura_unittests': {}, 'compositor_unittests': {}, - 'keyboard_unittests': {}, 'wm_unittests': {}, }, + 'aura_non_clang_gtests': { + # TODO(kbr): merge back into 'aura_gtests'. + 'keyboard_unittests': {}, + }, + 'cast_audio_specific_chromium_gtests': { 'cast_audio_backend_unittests': {}, 'cast_base_unittests': {}, @@ -151,20 +166,42 @@ 'cast_graphics_unittests': {}, }, + 'check_gn_headers_script': { + 'check_gn_headers': { + 'script': 'check_gn_headers.py', + } + }, + 'check_network_annotations_script': { 'check_network_annotations': { 'script': 'check_network_annotations.py', }, }, + 'chromium_android_asan_gtests': { + # TODO(kbr): reduce duplication among these tests, and with other + # test suites. + 'base_unittests': { + 'args': [ + '--tool=asan', + ], + }, + 'components_browsertests': { + 'args': [ + '--tool=asan', + ], + }, + }, + + 'chromium_android_asan_junit_tests': { + 'base_junit_tests': {}, + }, + 'chromium_gtests': { 'base_unittests': {}, 'blink_heap_unittests': {}, - 'boringssl_crypto_tests': {}, - 'boringssl_ssl_tests': {}, 'cacheinvalidation_unittests': {}, 'capture_unittests': {}, - 'components_browsertests': {}, 'components_unittests': { 'android_swarming': { 'hard_timeout': 900, @@ -183,43 +220,20 @@ }, }, 'crypto_unittests': {}, - 'gin_unittests': {}, 'google_apis_unittests': {}, 'gpu_ipc_service_unittests': {}, 'gpu_unittests': {}, 'ipc_tests': {}, 'jingle_unittests': {}, - 'libjingle_xmpp_unittests': {}, 'media_blink_unittests': {}, 'media_unittests': {}, 'midi_unittests': {}, - 'mojo_common_unittests': { - 'android_swarming': { - 'hard_timeout': 60, - }, - }, - 'mojo_public_bindings_unittests': { - 'android_swarming': { - 'hard_timeout': 60, - }, - }, - 'mojo_public_system_unittests': { - 'android_swarming': { - 'hard_timeout': 60, - }, - }, - 'mojo_system_unittests': { - 'android_swarming': { - 'hard_timeout': 180, - }, - }, 'net_unittests': { 'android_swarming': { 'hard_timeout': 900, 'shards': 3, }, }, - 'service_manager_unittests': {}, 'services_unittests': { 'android_swarming': { 'hard_timeout': 120, @@ -227,7 +241,6 @@ }, 'skia_unittests': {}, 'sql_unittests': {}, - 'storage_unittests': {}, 'ui_base_unittests': {}, 'unit_tests': { 'android_swarming': { @@ -240,12 +253,18 @@ }, 'chromium_gtests_for_devices_with_graphical_output': { - 'cc_unittests': {}, 'device_unittests': {}, + 'remoting_unittests': {}, + }, + + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output': { + 'viz_unittests': {}, + }, + + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output': { + 'cc_unittests': {}, 'display_unittests': {}, 'gfx_unittests': {}, - 'remoting_unittests': {}, - 'viz_unittests': {}, }, 'chromium_junit_tests': { @@ -285,6 +304,15 @@ } }, + 'clang_gl_gtests': { + 'gl_unittests': {}, + }, + + 'clang_linux_and_mac_gtests': { + # TODO: merge back into non_android_chromium_gtests. + 'interactive_ui_tests': {}, + }, + 'cronet_gtests': { 'cronet_sample_test_apk': { 'swarming': { @@ -375,11 +403,13 @@ }, }, - 'linux_and_chromeos_specific_chromium_gtests': { + 'linux_and_chromeos_non_clang_specific_chromium_gtests': { + # TOOD(kbr): rename back to linux_and_chromeos_specific_chromium_gtests. 'media_service_unittests': {}, }, - 'linux_and_mac_specific_chromium_gtests': { + 'linux_and_mac_non_clang_specific_chromium_gtests': { + # TODO(kbr): merge back into linux_and_mac_specific_chromium_gtests. 'snapshot_unittests': {}, }, @@ -509,14 +539,22 @@ 'ui_chromeos_unittests': {}, }, + 'linux_clang_and_fyi_specific_chromium_gtests': { + # TODO(kbr): needs to be merged with linux_chromeos_specific_gtests. + 'nacl_helper_nonsfi_unittests': {}, + }, + 'linux_flavor_specific_chromium_gtests': { # Android, Chrome OS and Linux 'sandbox_linux_unittests': {}, }, + 'linux_incl_clang_specific_chromium_gtests': { + 'dbus_unittests': {}, + }, + 'linux_specific_chromium_gtests': { # TODO(kbr): unclear why some of these aren't run more broadly. - 'dbus_unittests': {}, 'filesystem_service_unittests': {}, 'leveldb_service_unittests': {}, 'site_per_process_browser_tests': { @@ -572,31 +610,16 @@ }, 'non_android_chromium_gtests': { - 'accessibility_unittests': {}, 'browser_tests': { 'swarming': { 'shards': 10, }, }, - # TODO(kbr): cast_unittests is run on Android x86 testers on - # chromium.android.fyi. - 'cast_unittests': {}, - 'chrome_app_unittests': {}, - 'chromedriver_unittests': {}, - 'extensions_browsertests': {}, 'extensions_unittests': {}, - 'interactive_ui_tests': { - 'swarming': { - 'shards': 2, - }, - }, - 'message_center_unittests': {}, - 'nacl_loader_unittests': {}, 'native_theme_unittests': {}, 'pdf_unittests': {}, 'ppapi_unittests': {}, 'printing_unittests': {}, - 'sync_integration_tests': {}, 'views_unittests': {}, }, @@ -605,19 +628,105 @@ }, 'non_android_and_cast_and_chromeos_chromium_gtests': { - 'battor_agent_unittests': {}, 'blink_platform_unittests': {}, - 'gn_unittests': {}, + }, + + 'non_android_and_cast_and_chromeos_and_clang_chromium_gtests': { + 'battor_agent_unittests': {}, 'headless_browsertests': {}, 'headless_unittests': {}, }, + 'non_android_and_cast_and_chromeos_and_clang_android_mac_win_chromium_gtests': { + # TODO(kbr): merge back into non_android_and_cast_and_chromeos_chromium_gtests. + 'gn_unittests': {}, + }, + + 'non_android_and_clang_linux_mac_chromium_gtests': { + # TODO(kbr): merge back into non_android_chromium_gtests. + 'chrome_app_unittests': {}, + }, + + 'non_android_and_clang_linux_mac_win_chromium_gtests': { + # TODO(kbr): merge back into non_android_chromium_gtests. + 'interactive_ui_tests': { + 'swarming': { + 'shards': 2, + }, + }, + 'message_center_unittests': {}, + }, + + 'non_android_and_clang_linux_win_chromium_gtests': { + 'sync_integration_tests': {}, + }, + + 'non_android_and_clang_mac_win_chromium_gtests': { + # TODO(kbr): merge back into non_android_chromium_gtests. + 'nacl_loader_unittests': {}, + }, + + 'non_android_and_clang_win_chromium_gtests': { + # TODO(kbr): merge back into non_android_chromium_gtests. + 'accessibility_unittests': {}, + # TODO(kbr): cast_unittests is run on Android x86 testers on + # chromium.android.fyi and chromuim.clang. Figure out whether this + # is correct. + 'cast_unittests': {}, + 'chromedriver_unittests': {}, + 'extensions_browsertests': {}, + }, + + 'non_clang_chromium_gtests': { + # TODO(kbr): merge back into chromium_gtests. + 'boringssl_crypto_tests': {}, + 'boringssl_ssl_tests': {}, + 'libjingle_xmpp_unittests': {}, + 'service_manager_unittests': {}, + }, + + 'non_clang_android_mac_win_chromium_gtests': { + # TODO(kbr): merge back into chromium_gtests. + 'gin_unittests': {}, + }, + + 'non_clang_mac_win_chromium_gtests': { + # TODO(kbr): merge back into chromium_gtests. + 'storage_unittests': {}, + }, + + 'non_clang_win_chromium_gtests': { + # TODO(kbr): merge back into chromium_gtests. + 'components_browsertests': {}, + 'mojo_common_unittests': { + 'android_swarming': { + 'hard_timeout': 60, + }, + }, + 'mojo_public_bindings_unittests': { + 'android_swarming': { + 'hard_timeout': 60, + }, + }, + 'mojo_public_system_unittests': { + 'android_swarming': { + 'hard_timeout': 60, + }, + }, + 'mojo_system_unittests': { + 'android_swarming': { + 'hard_timeout': 180, + }, + }, + }, + 'non_linux_chromium_gtests': { 'crashpad_tests': {}, }, - 'non_mac_chromium_gtests': { + 'non_mac_non_clang_win_chromium_gtests': { # It's unclear why at least some of these aren't run on macOS. + # TODO(kbr): rename this back to non_mac_chromium_gtests. 'events_unittests': {}, 'latency_unittests': {}, 'ui_touch_selection_unittests': {}, @@ -648,10 +757,26 @@ }, }, - 'vr_platform_specific_chromium_gtests': { + 'viz_gtests': { + 'viz_content_browsertests': { + 'args': [ + '--enable-viz', + '--test-launcher-filter-file=../../testing/buildbot/filters/viz.content_browsertests.filter' + ], + 'swarming': { + 'shards': 2, + }, + 'test': 'content_browsertests', + }, + }, + + # TODO(kbr): rename this back to vr_platform_specific_chromium_gtests and + # run it on Win/Clang. + 'vr_platform_specific_non_clang_win_chromium_gtests': { # Only run on platforms that intend to support WebVR in the near # future. 'vr_common_unittests': {}, + 'vr_pixeltests': {}, }, 'webview_ui_instrumentation_tests': { @@ -717,14 +842,37 @@ }, # Composition test suites. + 'chromium_android_clang_and_gl_gtests': [ + 'android_clang_and_fyi_specific_gtests', + 'android_specific_chromium_gtests', + 'angle_gtests', + 'chromium_gtests', + 'chromium_gtests_for_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', + 'clang_gl_gtests', + 'linux_and_android_specific_chromium_gtests', + 'linux_flavor_specific_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_clang_win_chromium_gtests', + 'non_mac_non_clang_win_chromium_gtests', + 'vr_platform_specific_non_clang_win_chromium_gtests', + ], + 'chromium_android_gtests': [ 'android_specific_chromium_gtests', 'chromium_gtests', 'chromium_gtests_for_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', 'linux_and_android_specific_chromium_gtests', 'linux_flavor_specific_chromium_gtests', - 'non_mac_chromium_gtests', - 'vr_platform_specific_chromium_gtests', + 'non_clang_android_mac_win_chromium_gtests', + 'non_clang_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_clang_win_chromium_gtests', + 'non_mac_non_clang_win_chromium_gtests', + 'vr_platform_specific_non_clang_win_chromium_gtests', ], 'chromium_isolated_scripts': [ @@ -736,6 +884,10 @@ 'cast_audio_specific_chromium_gtests', 'chromium_gtests', 'linux_flavor_specific_chromium_gtests', + 'non_clang_android_mac_win_chromium_gtests', + 'non_clang_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_clang_win_chromium_gtests', ], 'chromium_linux_cast_video_gtests': [ @@ -743,21 +895,88 @@ 'cast_video_specific_chromium_gtests', 'chromium_gtests', 'linux_flavor_specific_chromium_gtests', + 'non_clang_android_mac_win_chromium_gtests', + 'non_clang_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_clang_win_chromium_gtests', + ], + + 'chromium_linux_clang_gtests': [ + 'angle_gtests', + 'aura_gtests', + 'chromium_gtests', + 'chromium_gtests_for_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', + 'clang_linux_and_mac_gtests', + 'linux_clang_and_fyi_specific_chromium_gtests', + 'linux_flavor_specific_chromium_gtests', + 'linux_incl_clang_specific_chromium_gtests', + 'non_android_chromium_gtests', + 'non_android_and_cast_chromium_gtests', + 'non_android_and_cast_and_chromeos_and_clang_android_mac_win_chromium_gtests', + 'non_android_and_cast_and_chromeos_chromium_gtests', + 'non_android_and_clang_mac_win_chromium_gtests', + 'non_android_and_clang_win_chromium_gtests', + 'non_clang_android_mac_win_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_clang_win_chromium_gtests', + 'non_mac_non_clang_win_chromium_gtests', + ], + + 'chromium_linux_clang_and_gl_gtests': [ + 'angle_gtests', + 'aura_gtests', + 'chromium_gtests', + 'chromium_gtests_for_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', + 'clang_gl_gtests', + 'clang_linux_and_mac_gtests', + 'linux_clang_and_fyi_specific_chromium_gtests', + 'linux_flavor_specific_chromium_gtests', + 'linux_incl_clang_specific_chromium_gtests', + 'non_android_chromium_gtests', + 'non_android_and_cast_chromium_gtests', + 'non_android_and_cast_and_chromeos_and_clang_android_mac_win_chromium_gtests', + 'non_android_and_cast_and_chromeos_chromium_gtests', + 'non_android_and_clang_mac_win_chromium_gtests', + 'non_android_and_clang_win_chromium_gtests', + 'non_clang_android_mac_win_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_clang_win_chromium_gtests', + 'non_mac_non_clang_win_chromium_gtests', ], 'chromium_linux_gtests': [ 'aura_gtests', + 'aura_non_clang_gtests', 'chromium_gtests', 'chromium_gtests_for_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', 'linux_and_android_specific_chromium_gtests', - 'linux_and_chromeos_specific_chromium_gtests', - 'linux_and_mac_specific_chromium_gtests', + 'linux_and_chromeos_non_clang_specific_chromium_gtests', + 'linux_and_mac_non_clang_specific_chromium_gtests', 'linux_flavor_specific_chromium_gtests', + 'linux_incl_clang_specific_chromium_gtests', 'linux_specific_chromium_gtests', 'non_android_chromium_gtests', 'non_android_and_cast_chromium_gtests', + 'non_android_and_cast_and_chromeos_and_clang_android_mac_win_chromium_gtests', 'non_android_and_cast_and_chromeos_chromium_gtests', - 'non_mac_chromium_gtests', + 'non_android_and_cast_and_chromeos_and_clang_chromium_gtests', + 'non_android_and_clang_linux_mac_chromium_gtests', + 'non_android_and_clang_linux_mac_win_chromium_gtests', + 'non_android_and_clang_linux_win_chromium_gtests', + 'non_android_and_clang_mac_win_chromium_gtests', + 'non_android_and_clang_win_chromium_gtests', + 'non_clang_android_mac_win_chromium_gtests', + 'non_clang_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_clang_win_chromium_gtests', + 'non_mac_non_clang_win_chromium_gtests', + 'viz_gtests', ], 'linux_chromeos_dbg_gtests': [ @@ -767,16 +986,25 @@ # - non_android_and_cast_and_chromeos_chromium_gtests # + linux_chromeos_specific_gtests 'aura_gtests', + 'aura_non_clang_gtests', 'chromium_gtests', 'chromium_gtests_for_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', 'linux_and_android_specific_chromium_gtests', - 'linux_and_chromeos_specific_chromium_gtests', - 'linux_and_mac_specific_chromium_gtests', + 'linux_and_chromeos_non_clang_specific_chromium_gtests', + 'linux_and_mac_non_clang_specific_chromium_gtests', 'linux_chromeos_specific_gtests', 'linux_flavor_specific_chromium_gtests', 'non_android_chromium_gtests', 'non_android_and_cast_chromium_gtests', - 'non_mac_chromium_gtests', + 'non_android_and_clang_linux_mac_win_chromium_gtests', + 'non_android_and_clang_linux_mac_chromium_gtests', + 'non_android_and_clang_linux_win_chromium_gtests', + 'non_android_and_clang_mac_win_chromium_gtests', + 'non_android_and_clang_win_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_mac_non_clang_win_chromium_gtests', ], 'linux_chromeos_rel_gtests': [ @@ -784,17 +1012,26 @@ # linux_chromeos_dbg_gtests # + linux_chromeos_rel_specific_gtests 'aura_gtests', + 'aura_non_clang_gtests', 'chromium_gtests', 'chromium_gtests_for_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', 'linux_and_android_specific_chromium_gtests', - 'linux_and_chromeos_specific_chromium_gtests', - 'linux_and_mac_specific_chromium_gtests', + 'linux_and_chromeos_non_clang_specific_chromium_gtests', + 'linux_and_mac_non_clang_specific_chromium_gtests', 'linux_chromeos_specific_gtests', 'linux_chromeos_rel_specific_gtests', 'linux_flavor_specific_chromium_gtests', 'non_android_chromium_gtests', 'non_android_and_cast_chromium_gtests', - 'non_mac_chromium_gtests', + 'non_android_and_clang_linux_mac_win_chromium_gtests', + 'non_android_and_clang_linux_mac_chromium_gtests', + 'non_android_and_clang_linux_win_chromium_gtests', + 'non_android_and_clang_mac_win_chromium_gtests', + 'non_android_and_clang_win_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_mac_non_clang_win_chromium_gtests', ], 'chromium_linux_isolated_scripts': [ @@ -803,27 +1040,83 @@ 'telemetry_perf_unittests_isolated_scripts', ], - 'chromium_mac_gtests': [ + 'chromium_mac_clang_gtests': [ + 'angle_gtests', 'chromium_gtests', 'chromium_gtests_for_devices_with_graphical_output', - 'linux_and_mac_specific_chromium_gtests', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', + 'clang_linux_and_mac_gtests', 'mac_specific_chromium_gtests', 'non_android_chromium_gtests', 'non_android_and_cast_chromium_gtests', 'non_android_and_cast_and_chromeos_chromium_gtests', + 'non_android_and_clang_linux_win_chromium_gtests', + 'non_android_and_clang_win_chromium_gtests', + 'non_clang_win_chromium_gtests', 'non_linux_chromium_gtests', ], - 'chromium_win_gtests': [ + 'chromium_mac_gtests': [ + 'chromium_gtests', + 'chromium_gtests_for_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', + 'linux_and_mac_non_clang_specific_chromium_gtests', + 'mac_specific_chromium_gtests', + 'non_android_chromium_gtests', + 'non_android_and_cast_chromium_gtests', + 'non_android_and_cast_and_chromeos_and_clang_android_mac_win_chromium_gtests', + 'non_android_and_cast_and_chromeos_chromium_gtests', + 'non_android_and_cast_and_chromeos_and_clang_chromium_gtests', + 'non_android_and_clang_linux_mac_chromium_gtests', + 'non_android_and_clang_linux_mac_win_chromium_gtests', + 'non_android_and_clang_linux_win_chromium_gtests', + 'non_android_and_clang_mac_win_chromium_gtests', + 'non_android_and_clang_win_chromium_gtests', + 'non_clang_android_mac_win_chromium_gtests', + 'non_clang_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_clang_win_chromium_gtests', + 'non_linux_chromium_gtests', + ], + + 'chromium_win_clang_gtests': [ + 'angle_gtests', 'aura_gtests', 'chromium_gtests', 'chromium_gtests_for_devices_with_graphical_output', 'non_android_chromium_gtests', 'non_android_and_cast_chromium_gtests', 'non_android_and_cast_and_chromeos_chromium_gtests', + 'non_android_and_clang_linux_mac_chromium_gtests', 'non_linux_chromium_gtests', - 'non_mac_chromium_gtests', - 'vr_platform_specific_chromium_gtests', + 'win_specific_chromium_gtests', + ], + + 'chromium_win_gtests': [ + 'aura_gtests', + 'aura_non_clang_gtests', + 'chromium_gtests', + 'chromium_gtests_for_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_mac_win_devices_with_graphical_output', + 'chromium_gtests_for_non_clang_win_devices_with_graphical_output', + 'non_android_chromium_gtests', + 'non_android_and_cast_chromium_gtests', + 'non_android_and_cast_and_chromeos_and_clang_android_mac_win_chromium_gtests', + 'non_android_and_cast_and_chromeos_chromium_gtests', + 'non_android_and_cast_and_chromeos_and_clang_chromium_gtests', + 'non_android_and_clang_linux_mac_chromium_gtests', + 'non_android_and_clang_linux_mac_win_chromium_gtests', + 'non_android_and_clang_linux_win_chromium_gtests', + 'non_android_and_clang_mac_win_chromium_gtests', + 'non_android_and_clang_win_chromium_gtests', + 'non_clang_android_mac_win_chromium_gtests', + 'non_clang_chromium_gtests', + 'non_clang_mac_win_chromium_gtests', + 'non_clang_win_chromium_gtests', + 'non_linux_chromium_gtests', + 'non_mac_non_clang_win_chromium_gtests', + 'vr_platform_specific_non_clang_win_chromium_gtests', 'win_specific_chromium_gtests', ],
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index f64067c1f..e0b6a81 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -369,6 +369,230 @@ }, }, { + 'name': 'chromium.clang', + 'machines': { + 'CFI Linux (icall)': { + 'test_suites': { + 'gtest_tests': 'chromium_linux_clang_and_gl_gtests', + }, + }, + 'CFI Linux ToT': { + 'test_suites': { + 'gtest_tests': 'chromium_linux_clang_and_gl_gtests', + }, + }, + 'CrWinAsan': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinAsan(dll)': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinAsanCov': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClang': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClang(dbg)': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClang(shared)': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClang64': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClang64(dbg)': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClang64(dll)': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClangLLD': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClangLLD64': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClngLLD64dbg': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'CrWinClngLLDdbg': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'ToTAndroid': { + 'additional_compile_targets': [ + 'all', + ], + }, + 'ToTAndroid x64': { + 'swarming': { + 'dimension_sets': [ + { + 'device_type': 'coho', + }, + ], + }, + 'test_suites': { + 'gtest_tests': 'chromium_android_clang_and_gl_gtests', + }, + }, + 'ToTAndroid64': { + 'additional_compile_targets': [ + 'all', + ], + }, + 'ToTAndroidASan': { + 'test_suites': { + 'gtest_tests': 'chromium_android_asan_gtests', + 'junit_tests': 'chromium_android_asan_junit_tests', + }, + 'use_swarming': False, + }, + 'ToTAndroidCFI': { + 'swarming': { + 'dimension_sets': [ + { + 'device_os': 'MMB29Q', + 'device_type': 'bullhead', + }, + ], + }, + 'test_suites': { + 'gtest_tests': 'chromium_android_clang_and_gl_gtests', + }, + }, + 'ToTLinux': { + 'test_suites': { + 'gtest_tests': 'chromium_linux_clang_gtests', + 'scripts': 'check_gn_headers_script', + }, + }, + 'ToTLinux (dbg)': { + 'additional_compile_targets': [ + 'all', + ], + }, + 'ToTLinuxASan': { + 'additional_compile_targets': [ + 'all', + ], + 'test_suites': { + 'gtest_tests': 'chromium_linux_clang_gtests', + }, + }, + 'ToTLinuxLLD': { + 'additional_compile_targets': [ + 'all', + ], + 'test_suites': { + 'gtest_tests': 'chromium_linux_clang_gtests', + }, + }, + 'ToTLinuxMSan': { + 'test_suites': { + 'gtest_tests': 'chromium_linux_clang_gtests', + }, + }, + 'ToTLinuxThinLTO': { + 'test_suites': { + 'gtest_tests': 'chromium_linux_clang_and_gl_gtests', + }, + 'use_swarming': False, + }, + 'ToTLinuxUBSanVptr': { + 'additional_compile_targets': [ + 'all', + ], + 'test_suites': { + 'gtest_tests': 'chromium_linux_clang_gtests', + }, + }, + 'ToTMac': { + 'test_suites': { + 'gtest_tests': 'chromium_mac_clang_gtests', + 'isolated_scripts': 'chromium_isolated_scripts', + }, + }, + 'ToTMacASan': { + 'test_suites': { + 'gtest_tests': 'chromium_mac_clang_gtests', + }, + }, + 'ToTWin': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'ToTWin(dbg)': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'ToTWin(dll)': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'ToTWin64': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'ToTWin64(dbg)': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'ToTWin64(dll)': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'ToTWinCFI': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'ToTWinCFI64': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + 'ToTWinThinLTO64': { + 'test_suites': { + 'gtest_tests': 'chromium_win_clang_gtests', + }, + }, + }, + }, + { 'name': 'chromium.linux', 'machines': { 'Fuchsia ARM64': {
diff --git a/third_party/WebKit/API_OWNERS b/third_party/WebKit/API_OWNERS index 13300c6..72f5306 100644 --- a/third_party/WebKit/API_OWNERS +++ b/third_party/WebKit/API_OWNERS
@@ -5,7 +5,6 @@ bratell@opera.com chrishtr@chromium.org darin@chromium.org -dglazkov@chromium.org foolip@chromium.org jochen@chromium.org mkwst@chromium.org
diff --git a/third_party/WebKit/LayoutTests/fast/table/collapsed-border-overflow-hidden-expected.html b/third_party/WebKit/LayoutTests/fast/table/collapsed-border-overflow-hidden-expected.html new file mode 100644 index 0000000..10d5307 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/table/collapsed-border-overflow-hidden-expected.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<style> +table { + border-collapse: collapse; + border: 20px solid green; +} +td { + width: 100px; + height: 100px; +} +</style> +Table with overflow: hidden should not clip off outer halves of collapsed borders. Passes if no red. +<table> + <tr><td></td></tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/fast/table/collapsed-border-overflow-hidden.html b/third_party/WebKit/LayoutTests/fast/table/collapsed-border-overflow-hidden.html new file mode 100644 index 0000000..b4d5daa --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/table/collapsed-border-overflow-hidden.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<style> +table { + border-collapse: collapse; + position: absolute; + border-width: 20px; + border-style: solid; +} +td { + width: 100px; + height: 100px; +} +</style> +Table with overflow: hidden should not clip off outer halves of collapsed borders. Passes if no red. +<table style="border-color: red"> +<tr><td></td></tr> +</table> +<table style="border-color: green; overflow: hidden"> +<tr><td></td></tr> +</table>
diff --git a/third_party/WebKit/Source/core/OWNERS b/third_party/WebKit/Source/core/OWNERS index d7ed9ecd..c890acc 100644 --- a/third_party/WebKit/Source/core/OWNERS +++ b/third_party/WebKit/Source/core/OWNERS
@@ -11,7 +11,6 @@ cbiesinger@chromium.org chrishtr@chromium.org dcheng@chromium.org -dglazkov@chromium.org # dtapuska reviews input-related changes dtapuska@chromium.org dgozman@chromium.org
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp index c67178c..3196188 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
@@ -1475,6 +1475,14 @@ LayoutRect LayoutTable::OverflowClipRect( const LayoutPoint& location, OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const { + if (ShouldCollapseBorders()) { + // Though the outer halves of the collapsed borders are considered as the + // the border area of the table by means of the box model, they are actually + // contents of the table and should not be clipped off. The overflow clip + // rect is BorderBoxRect() + location. + return LayoutRect(location, Size()); + } + LayoutRect rect = LayoutBlock::OverflowClipRect(location, overlay_scrollbar_clip_behavior);
diff --git a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.cpp index 89c84ed1..1b8176e0 100644 --- a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.cpp
@@ -260,9 +260,15 @@ const ComputedStyle* container_style = snap_container.Style(); const ComputedStyle* area_style = snap_area.Style(); SnapAreaData snap_area_data; - LayoutRect container( - LayoutPoint(), - LayoutSize(snap_container.OffsetWidth(), snap_container.OffsetHeight())); + + // Scroll-padding represents inward offsets from the corresponding edge of the + // scrollport. https://drafts.csswg.org/css-scroll-snap-1/#scroll-padding + // Scrollport is the visual vieport of the scroll container (through which the + // scrollable overflow region can be viewed) coincides with its padding box. + // https://drafts.csswg.org/css-scroll-snap-1/#scroll-padding + // So we use the size of the padding box here. + LayoutRect container(LayoutPoint(), snap_container.PaddingBoxRect().Size()); + // We assume that the snap_container is the snap_area's ancestor in layout // tree, as the snap_container is found by walking up the layout tree in // FindSnapContainer(). Under this assumption,
diff --git a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinatorTest.cpp b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinatorTest.cpp index 7c5bf441..8b945314 100644 --- a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinatorTest.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinatorTest.cpp
@@ -418,10 +418,12 @@ ->MaximumScrollOffset() .Height(); - // (#area.left + #area.right) / 2 - (#scroller.left + #scroller.right) / 2 - double snap_offset_x = (200 + (200 + 100)) / 2 - 140 / 2; - // (#area.top + #area.bottom) / 2 - (#scroller.top + #scroller.bottom) / 2 - double snap_offset_y = (200 + (200 + 100)) / 2 - 160 / 2; + // (#area.left + #area.right) / 2 - #scroller.width / 2 + double snap_offset_x = + (200 + (200 + 100)) / 2 - float(scroller_element->clientWidth()) / 2; + // (#area.top + #area.bottom) / 2 - #scroller.height / 2 + double snap_offset_y = + (200 + (200 + 100)) / 2 - float(scroller_element->clientHeight()) / 2; bool must_snap = false; @@ -475,14 +477,16 @@ // (#scroller.left + #scroller.scroll-padding-left + // #scroller.right - #scroller.scroll-padding-right) / 2 double snap_offset_x = - (200 - 8 + (200 + 100 + 4)) / 2 - (0 + 16 + 140 - 12) / 2; + (200 - 8 + (200 + 100 + 4)) / 2 - + (0 + 16 + float(scroller_element->clientWidth()) - 12) / 2; // (#area.top - #area.scroll-snap-margin-top + // #area.bottom + #area.scroll-snap-margin-bottom) / 2 - // (#scroller.top + #scroller.scroll-padding-top + // #scroller.bottom - #scroller.scroll-padding-bottom) / 2 double snap_offset_y = - (200 - 2 + (200 + 100 + 6)) / 2 - (0 + 10 + 160 - 14) / 2; + (200 - 2 + (200 + 100 + 6)) / 2 - + (0 + 10 + float(scroller_element->clientHeight()) - 14) / 2; bool must_snap = false; @@ -519,11 +523,13 @@ // (#area.right + #area.scroll-snap-margin) // - (#scroller.right - #scroller.scroll-padding) - double snap_offset_x = (200 + 100 + 8) - (140 - 10); + double snap_offset_x = + (200 + 100 + 8) - (scroller_element->clientWidth() - 10); // (#area.bottom + #area.scroll-snap-margin) // - (#scroller.bottom - #scroller.scroll-padding) - double snap_offset_y = (200 + 100 + 8) - (160 - 10); + double snap_offset_y = + (200 + 100 + 8) - (scroller_element->clientHeight() - 10); bool must_snap = false; @@ -561,14 +567,14 @@ // (#area.right + #area.scroll-snap-margin) // - (#scroller.right - #scroller.scroll-padding) - // = (100 + 8) - (140 - 10) - // As scrollOffset cannot be set to -22, we set it to 0. + // = (100 + 8) - (clientWidth - 10) < 0 + // As scrollOffset cannot be set to a negative number, we set it to 0. double snap_offset_x = 0; // (#area.bottom + #area.scroll-snap-margin) // - (#scroller.bottom - #scroller.scroll-padding) - // = (100 + 8) - (160 - 10) - // As scrollOffset cannot be set to -42, we set it to 0. + // = (100 + 8) - (clientHeight - 10) < 0 + // As scrollOffset cannot be set to a negative number, we set it to 0. double snap_offset_y = 0; bool must_snap = false;
diff --git a/third_party/WebKit/Source/platform/OWNERS b/third_party/WebKit/Source/platform/OWNERS index f4397b3..3785f08 100644 --- a/third_party/WebKit/Source/platform/OWNERS +++ b/third_party/WebKit/Source/platform/OWNERS
@@ -1,4 +1,3 @@ -dglazkov@chromium.org drott@chromium.org eae@chromium.org fmalita@chromium.org
diff --git a/third_party/WebKit/public/OWNERS b/third_party/WebKit/public/OWNERS index 08f313b..69861f5 100644 --- a/third_party/WebKit/public/OWNERS +++ b/third_party/WebKit/public/OWNERS
@@ -1,6 +1,5 @@ chrishtr@chromium.org dcheng@chromium.org -dglazkov@chromium.org dstockwell@chromium.org foolip@chromium.org haraken@chromium.org
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index ec085780..b17e65b1 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -25030,6 +25030,7 @@ <int value="-790036192" label="overscroll-start-threshold"/> <int value="-787426248" label="ChromeHomeSurvey:disabled"/> <int value="-780798969" label="disable-single-click-autofill"/> + <int value="-780599934" label="AutofillUpstreamSendPanFirstSix:enabled"/> <int value="-778126349" label="DownloadsLocationChange:enabled"/> <int value="-776686417" label="SiteExplorationUi:disabled"/> <int value="-775321548" label="UseNewDoodleApi:disabled"/> @@ -25296,6 +25297,7 @@ <int value="-29847483" label="MemoryAblation:enabled"/> <int value="-23090520" label="disable-search-button-in-omnibox"/> <int value="-22544408" label="enable-video-player-chromecast-support"/> + <int value="-19354048" label="AutofillUpstreamSendPanFirstSix:disabled"/> <int value="-16824589" label="ash-shelf-color"/> <int value="-13918890" label="disable-download-notification"/> <int value="-11260186" label="enable-offline-pages-as-saved-pages"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 4941789..d2401d3 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -13518,15 +13518,6 @@ </summary> </histogram> -<histogram name="DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch" - enum="BooleanSuccess"> - <owner>tbansal@chromium.org</owner> - <summary> - Whether the warmup (or probe) URL was successfully fetched over a data saver - proxy. - </summary> -</histogram> - <histogram name="DataUsage.MatchingRulesCount.Invalid" units="count"> <owner>bengr@chromium.org</owner> <owner>rajendrant@chromium.org</owner> @@ -101144,20 +101135,6 @@ <affected-histogram name="Previews.OriginalContentLength"/> </histogram_suffixes> -<histogram_suffixes name="DataSaverProxyTypes" separator="."> - <owner>tbansal@chromium.org</owner> - <suffix name="SecureProxy.Core" - label="Over a secure, core data saver proxy."/> - <suffix name="SecureProxy.NonCore" - label="Over a secure, non-core data saver proxy."/> - <suffix name="InsecureProxy.Core" - label="Over an insecure, core data saver proxy."/> - <suffix name="InsecureProxy.NonCore" - label="Over an insecure, non-core data saver proxy."/> - <affected-histogram - name="DataReductionProxy.WarmupURLFetcherCallback.SuccessfulFetch"/> -</histogram_suffixes> - <histogram_suffixes name="DataUsageReportSubmissionBytes" separator="."> <suffix name="Failed" label="Platform external data use observer reported the submission as
diff --git a/ui/accessibility/platform/atk_util_auralinux_gtk2.cc b/ui/accessibility/platform/atk_util_auralinux_gtk2.cc index 9c50ead8..ac11b56 100644 --- a/ui/accessibility/platform/atk_util_auralinux_gtk2.cc +++ b/ui/accessibility/platform/atk_util_auralinux_gtk2.cc
@@ -20,6 +20,8 @@ const char kAtkBridgeSymbolName[] = "gnome_accessibility_module_init"; const char kGtkModules[] = "GTK_MODULES"; +namespace ui { + // Returns a function pointer to be invoked on the main thread to init // the gnome accessibility module if it's enabled (nullptr otherwise). GnomeAccessibilityModuleInitFunc GetAccessibilityModuleInitFunc() { @@ -78,3 +80,5 @@ base::Bind(&GetAccessibilityModuleInitFunc), base::Bind(&FinishAccessibilityInitOnMainThread)); } + +} // namespace ui
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 04840b9f..3645718 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -288,6 +288,8 @@ context_factory_private_->SetDisplayVisible(this, host_->IsVisible()); context_factory_private_->SetDisplayColorSpace(this, blending_color_space_, output_color_space_); + context_factory_private_->SetDisplayColorMatrix(this, + display_color_matrix_); } } @@ -315,6 +317,12 @@ return animation_timeline_.get(); } +void Compositor::SetDisplayColorMatrix(const SkMatrix44& matrix) { + display_color_matrix_ = matrix; + if (context_factory_private_) + context_factory_private_->SetDisplayColorMatrix(this, matrix); +} + void Compositor::ScheduleFullRedraw() { // TODO(enne): Some callers (mac) call this function expecting that it // will also commit. This should probably just redraw the screen
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 981727c5..5e54899a 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -25,6 +25,7 @@ #include "components/viz/common/surfaces/surface_sequence.h" #include "components/viz/host/host_frame_sink_client.h" #include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkMatrix44.h" #include "ui/compositor/compositor_animation_observer.h" #include "ui/compositor/compositor_export.h" #include "ui/compositor/compositor_lock.h" @@ -124,6 +125,11 @@ virtual void ResizeDisplay(ui::Compositor* compositor, const gfx::Size& size) = 0; + // Sets the color matrix used to transform how all output is drawn to the + // display underlying this ui::Compositor. + virtual void SetDisplayColorMatrix(ui::Compositor* compositor, + const SkMatrix44& matrix) = 0; + // Set the output color profile into which this compositor should render. virtual void SetDisplayColorSpace( ui::Compositor* compositor, @@ -239,6 +245,13 @@ return output_color_space_; } + // Gets and sets the color matrix used to transform the output colors of what + // this compositor renders. + const SkMatrix44& display_color_matrix() const { + return display_color_matrix_; + } + void SetDisplayColorMatrix(const SkMatrix44& matrix); + // Where possible, draws are scissored to a damage region calculated from // changes to layer properties. This bypasses that and indicates that // the whole frame needs to be drawn. @@ -479,6 +492,8 @@ scoped_refptr<cc::AnimationTimeline> animation_timeline_; std::unique_ptr<ScopedAnimationDurationScaleMode> slow_animations_; + SkMatrix44 display_color_matrix_; + gfx::ColorSpace output_color_space_; gfx::ColorSpace blending_color_space_;
diff --git a/ui/compositor/compositor_unittest.cc b/ui/compositor/compositor_unittest.cc index 08ce8b9..eccd07a 100644 --- a/ui/compositor/compositor_unittest.cc +++ b/ui/compositor/compositor_unittest.cc
@@ -19,6 +19,7 @@ #include "ui/compositor/layer.h" #include "ui/compositor/test/context_factories_for_test.h" #include "ui/compositor/test/draw_waiter_for_test.h" +#include "ui/compositor/test/in_process_context_factory.h" using testing::Mock; using testing::_; @@ -124,6 +125,43 @@ } // namespace +TEST_F(CompositorTestWithMessageLoop, OutputColorMatrix) { + auto root_layer = std::make_unique<Layer>(ui::LAYER_SOLID_COLOR); + root_layer->SetBounds(gfx::Rect(10, 10)); + compositor()->SetRootLayer(root_layer.get()); + compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10)); + DCHECK(compositor()->IsVisible()); + + // Set a non-identity color matrix on the compistor display, and expect it to + // be set on the context factory. + SkMatrix44 color_matrix(SkMatrix44::kIdentity_Constructor); + color_matrix.set(1, 1, 0.7f); + color_matrix.set(2, 2, 0.4f); + compositor()->SetDisplayColorMatrix(color_matrix); + InProcessContextFactory* context_factory_private = + static_cast<InProcessContextFactory*>( + compositor()->context_factory_private()); + compositor()->ScheduleDraw(); + DrawWaiterForTest::WaitForCompositingEnded(compositor()); + EXPECT_EQ(color_matrix, + context_factory_private->GetOutputColorMatrix(compositor())); + + // Simulate a lost context by releasing the output surface and setting it on + // the compositor again. Expect that the same color matrix will be set again + // on the context factory. + context_factory_private->ResetOutputColorMatrixToIdentity(compositor()); + compositor()->SetVisible(false); + EXPECT_EQ(gfx::kNullAcceleratedWidget, + compositor()->ReleaseAcceleratedWidget()); + compositor()->SetAcceleratedWidget(gfx::kNullAcceleratedWidget); + compositor()->SetVisible(true); + compositor()->ScheduleDraw(); + DrawWaiterForTest::WaitForCompositingEnded(compositor()); + EXPECT_EQ(color_matrix, + context_factory_private->GetOutputColorMatrix(compositor())); + compositor()->SetRootLayer(nullptr); +} + TEST_F(CompositorTestWithMockedTime, LocksAreObserved) { std::unique_ptr<CompositorLock> lock;
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc index b6cd30de..b9c5d1bd 100644 --- a/ui/compositor/test/in_process_context_factory.cc +++ b/ui/compositor/test/in_process_context_factory.cc
@@ -147,6 +147,7 @@ gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle; std::unique_ptr<viz::BeginFrameSource> begin_frame_source; std::unique_ptr<viz::Display> display; + SkMatrix44 output_color_matrix; }; InProcessContextFactory::InProcessContextFactory( @@ -352,6 +353,16 @@ per_compositor_data_[compositor]->display->Resize(size); } +void InProcessContextFactory::SetDisplayColorMatrix(ui::Compositor* compositor, + const SkMatrix44& matrix) { + auto iter = per_compositor_data_.find(compositor); + if (iter == per_compositor_data_.end()) + return; + + iter->second->output_color_matrix = matrix; + iter->second->display->SetColorMatrix(matrix); +} + const viz::ResourceSettings& InProcessContextFactory::GetResourceSettings() const { return renderer_settings_.resource_settings; @@ -369,6 +380,24 @@ return frame_sink_manager_; } +SkMatrix44 InProcessContextFactory::GetOutputColorMatrix( + Compositor* compositor) const { + auto iter = per_compositor_data_.find(compositor); + if (iter == per_compositor_data_.end()) + return SkMatrix44(SkMatrix44::kIdentity_Constructor); + + return iter->second->output_color_matrix; +} + +void InProcessContextFactory::ResetOutputColorMatrixToIdentity( + ui::Compositor* compositor) { + auto iter = per_compositor_data_.find(compositor); + if (iter == per_compositor_data_.end()) + return; + + iter->second->output_color_matrix.setIdentity(); +} + InProcessContextFactory::PerCompositorData* InProcessContextFactory::CreatePerCompositorData(ui::Compositor* compositor) { DCHECK(!per_compositor_data_[compositor]);
diff --git a/ui/compositor/test/in_process_context_factory.h b/ui/compositor/test/in_process_context_factory.h index e059fd9..85cd49ca 100644 --- a/ui/compositor/test/in_process_context_factory.h +++ b/ui/compositor/test/in_process_context_factory.h
@@ -74,6 +74,8 @@ void SetDisplayVisible(ui::Compositor* compositor, bool visible) override; void ResizeDisplay(ui::Compositor* compositor, const gfx::Size& size) override; + void SetDisplayColorMatrix(ui::Compositor* compositor, + const SkMatrix44& matrix) override; void SetDisplayColorSpace( ui::Compositor* compositor, const gfx::ColorSpace& blending_color_space, @@ -91,6 +93,9 @@ void RemoveObserver(ContextFactoryObserver* observer) override; viz::FrameSinkManagerImpl* GetFrameSinkManager() override; + SkMatrix44 GetOutputColorMatrix(Compositor* compositor) const; + void ResetOutputColorMatrixToIdentity(ui::Compositor* compositor); + private: struct PerCompositorData;
diff --git a/ui/message_center/views/message_view_context_menu_controller.cc b/ui/message_center/views/message_view_context_menu_controller.cc index fb871b6..6d363c4 100644 --- a/ui/message_center/views/message_view_context_menu_controller.cc +++ b/ui/message_center/views/message_view_context_menu_controller.cc
@@ -33,13 +33,10 @@ if (!menu_model_ || menu_model_->GetItemCount() == 0) return; - menu_model_adapter_.reset(new views::MenuModelAdapter( - menu_model_.get(), + menu_runner_ = std::make_unique<views::MenuRunner>( + menu_model_.get(), views::MenuRunner::HAS_MNEMONICS, base::Bind(&MessageViewContextMenuController::OnMenuClosed, - base::Unretained(this)))); - - menu_runner_.reset(new views::MenuRunner(menu_model_adapter_->CreateMenu(), - views::MenuRunner::HAS_MNEMONICS)); + base::Unretained(this))); menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(), NULL, gfx::Rect(point, gfx::Size()), @@ -48,7 +45,6 @@ void MessageViewContextMenuController::OnMenuClosed() { menu_runner_.reset(); - menu_model_adapter_.reset(); menu_model_.reset(); }
diff --git a/ui/message_center/views/message_view_context_menu_controller.h b/ui/message_center/views/message_view_context_menu_controller.h index 49596008..8ee27f0 100644 --- a/ui/message_center/views/message_view_context_menu_controller.h +++ b/ui/message_center/views/message_view_context_menu_controller.h
@@ -17,7 +17,6 @@ } // namespace ui namespace views { -class MenuModelAdapter; class MenuRunner; } // namespace views @@ -35,11 +34,10 @@ const gfx::Point& point, ui::MenuSourceType source_type) override; - // Callback for MenuModelAdapter + // Callback for MenuRunner void OnMenuClosed(); std::unique_ptr<ui::MenuModel> menu_model_; - std::unique_ptr<views::MenuModelAdapter> menu_model_adapter_; std::unique_ptr<views::MenuRunner> menu_runner_; DISALLOW_COPY_AND_ASSIGN(MessageViewContextMenuController);