diff --git a/DEPS b/DEPS index 69a1948..224182dd 100644 --- a/DEPS +++ b/DEPS
@@ -103,6 +103,14 @@ # privately accessible. 'checkout_telemetry_dependencies': False, + # Bots that don't consume render test goldens can skip downloading + # them. + 'skip_render_test_goldens_download': False, + + # Bots that don't consume WPR archives can skip downloading + # them. + 'skip_wpr_archives_download': False, + # Fetch the prebuilt binaries for llvm-cov and llvm-profdata. Needed to # process the raw profiles produced by instrumented targets (built with # the gn arg 'use_clang_coverage'). @@ -262,7 +270,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '4159ffc366a3ef0ae8fed8a1f573bc0017045f63', + 'devtools_frontend_revision': '320cf85131725a74729695c729f6da3721c98811', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -314,7 +322,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'd1bca09f4ab36bdc8d413bf2642460b0721267f5', + 'dawn_revision': 'ccaef8525710f27db60adcc7e9778c2caac1bada', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -338,7 +346,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libavif # and whatever else without interference from each other. - 'libavif_revision': '0265cd7a10d1425cf42908458a0807e919195914', + 'libavif_revision': 'e67f9369d50e00c59b504abf52655b3c0f304430', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. @@ -877,7 +885,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '4fe1d403a22dfa80541234f4553a2d432772d81f', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7c9f31beb6db418aa5f7067eca9051691d67efd5', 'condition': 'checkout_chromeos', }, @@ -1554,7 +1562,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8567edac4fdfa5b428c14b9ed51e767ae60a4abe', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c0568abaca2da0d11367ba5a6742c7722c5640bc', 'condition': 'checkout_src_internal', }, @@ -1562,7 +1570,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'IzAbSag8-IGOAkL2GSMql94a4unzsZtFfkhskHgLSCkC', + 'version': 'T-N5zwsSNhguTsU3uUhXyI74IImSdHGJ-z8uc9QLdUsC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -1573,7 +1581,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'tdIYOywbT-7Ua5VwVKvfLfPLbfSGfLAQ2PzHie1qBhsC', + 'version': 'fMicjS5JtS2sakj0BWcnD-WvPzJtgucl2EnBXFOBEnQC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -4628,7 +4636,7 @@ # Download Telemetry's benchmark binary dependencies via conditionals { 'name': 'checkout_telemetry_benchmark_deps', - 'condition': 'checkout_telemetry_dependencies and checkout_linux and not checkout_android', + 'condition': 'checkout_telemetry_dependencies and checkout_linux and not checkout_android and not skip_wpr_archives_download', 'pattern': '.', 'action': [ 'vpython', 'src/tools/perf/fetch_benchmark_deps.py', @@ -4639,7 +4647,7 @@ }, { 'name': 'checkout_telemetry_benchmark_deps', - 'condition': 'checkout_telemetry_dependencies and checkout_win', + 'condition': 'checkout_telemetry_dependencies and checkout_win and not skip_wpr_archives_download', 'pattern': '.', 'action': [ 'vpython', 'src/tools/perf/fetch_benchmark_deps.py', @@ -4650,7 +4658,7 @@ }, { 'name': 'checkout_telemetry_benchmark_deps', - 'condition': 'checkout_telemetry_dependencies and checkout_mac', + 'condition': 'checkout_telemetry_dependencies and checkout_mac and not skip_wpr_archives_download', 'pattern': '.', 'action': [ 'vpython', 'src/tools/perf/fetch_benchmark_deps.py', @@ -4661,7 +4669,7 @@ }, { 'name': 'checkout_telemetry_benchmark_deps', - 'condition': 'checkout_telemetry_dependencies and checkout_android', + 'condition': 'checkout_telemetry_dependencies and checkout_android and not skip_wpr_archives_download', 'pattern': '.', 'action': [ 'vpython', 'src/tools/perf/fetch_benchmark_deps.py', @@ -4722,7 +4730,7 @@ { 'name': 'Fetch Android RenderTest goldens', 'pattern': '.', - 'condition': 'checkout_android', + 'condition': 'checkout_android and not skip_render_test_goldens_download', 'action': [ 'python', 'src/chrome/test/data/android/manage_render_test_goldens.py', 'download', @@ -4908,7 +4916,7 @@ 'pattern': '.', 'condition': 'checkout_chromeos or checkout_simplechrome', 'action': [ 'vpython', - 'src/tools/download_optimization_profile.py', + 'src/tools/download_optimization_profile.py', '--newest_state=src/chromeos/profiles/atom.afdo.newest.txt', '--local_state=src/chromeos/profiles/atom.afdo.local.txt', '--output_name=src/chromeos/profiles/atom.afdo.prof',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 9e0586b3..876fad0c 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -279,6 +279,8 @@ "capture_mode/capture_mode_type_view.cc", "capture_mode/capture_mode_type_view.h", "capture_mode/capture_mode_types.h", + "capture_mode/capture_mode_util.cc", + "capture_mode/capture_mode_util.h", "capture_mode/capture_window_observer.cc", "capture_mode/capture_window_observer.h", "capture_mode/stop_recording_button_tray.cc", @@ -449,6 +451,7 @@ "frame/wide_frame_view.cc", "frame_throttler/frame_throttling_controller.cc", "frame_throttler/frame_throttling_controller.h", + "frame_throttler/frame_throttling_observer.h", "high_contrast/high_contrast_controller.cc", "high_contrast/high_contrast_controller.h", "highlighter/highlighter_controller.cc", @@ -1324,8 +1327,6 @@ "system/unified/ime_mode_view.h", "system/unified/managed_device_tray_item_view.cc", "system/unified/managed_device_tray_item_view.h", - "system/unified/media_controls_chip_view.cc", - "system/unified/media_controls_chip_view.h", "system/unified/notification_counter_view.cc", "system/unified/notification_counter_view.h", "system/unified/notification_hidden_view.cc", @@ -1725,6 +1726,7 @@ "//chromeos/components/quick_answers", "//chromeos/components/quick_answers/public/cpp:prefs", "//chromeos/ui/base", + "//chromeos/ui/frame", "//services/viz/public/mojom", # TODO(https://crbug.com/644336): Make CrasAudioHandler Chrome or Ash only. @@ -2325,6 +2327,7 @@ "//chromeos:test_support", "//chromeos/strings:strings_grit", "//chromeos/ui/base", + "//chromeos/ui/frame", "//chromeos/ui/vector_icons", # TODO(https://crbug.com/644336): Make CrasAudioHandler Chrome or Ash only.
diff --git a/ash/app_list/views/page_switcher.cc b/ash/app_list/views/page_switcher.cc index 0c60f3f..63661ee 100644 --- a/ash/app_list/views/page_switcher.cc +++ b/ash/app_list/views/page_switcher.cc
@@ -11,6 +11,7 @@ #include "ash/app_list/app_list_metrics.h" #include "ash/public/cpp/app_list/app_list_color_provider.h" #include "ash/public/cpp/pagination/pagination_model.h" +#include "base/bind.h" #include "base/i18n/number_formatting.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" @@ -49,15 +50,15 @@ class PageSwitcherButton : public views::Button { public: - PageSwitcherButton(views::ButtonListener* listener, - bool is_root_app_grid_page_switcher) - : views::Button(listener), - is_root_app_grid_page_switcher_(is_root_app_grid_page_switcher) { + explicit PageSwitcherButton(bool is_root_app_grid_page_switcher) + : is_root_app_grid_page_switcher_(is_root_app_grid_page_switcher) { SetInkDropMode(InkDropMode::ON); views::InstallFixedSizeCircleHighlightPathGenerator( this, is_root_app_grid_page_switcher ? kInkDropRadiusForRootGrid : kInkDropRadiusForFolderGrid); } + PageSwitcherButton(const PageSwitcherButton&) = delete; + PageSwitcherButton& operator=(const PageSwitcherButton&) = delete; ~PageSwitcherButton() override {} @@ -167,8 +168,6 @@ // True if the page switcher root is the app grid. const bool is_root_app_grid_page_switcher_; - - DISALLOW_COPY_AND_ASSIGN(PageSwitcherButton); }; // Gets PageSwitcherButton at |index| in |buttons|. @@ -234,8 +233,8 @@ return "PageSwitcher"; } -void PageSwitcher::ButtonPressed(views::Button* sender, - const ui::Event& event) { +void PageSwitcher::OnButtonPressed(views::Button* sender, + const ui::Event& event) { if (!model_ || ignore_button_press_) return; @@ -260,13 +259,15 @@ buttons_->RemoveAllChildViews(true); for (int i = 0; i < model_->total_pages(); ++i) { - PageSwitcherButton* button = - new PageSwitcherButton(this, is_root_app_grid_page_switcher_); + PageSwitcherButton* button = buttons_->AddChildView( + std::make_unique<PageSwitcherButton>(is_root_app_grid_page_switcher_)); + button->set_callback(base::BindRepeating(&PageSwitcher::OnButtonPressed, + base::Unretained(this), + base::Unretained(button))); button->SetAccessibleName(l10n_util::GetStringFUTF16( IDS_APP_LIST_PAGE_SWITCHER, base::FormatNumber(i + 1), base::FormatNumber(model_->total_pages()))); button->SetSelected(i == model_->selected_page() ? true : false); - buttons_->AddChildView(button); } buttons_->SetVisible(model_->total_pages() > 1); Layout();
diff --git a/ash/app_list/views/page_switcher.h b/ash/app_list/views/page_switcher.h index 7c090b3d..76e3304 100644 --- a/ash/app_list/views/page_switcher.h +++ b/ash/app_list/views/page_switcher.h
@@ -7,7 +7,11 @@ #include "ash/public/cpp/pagination/pagination_model_observer.h" #include "base/macros.h" -#include "ui/views/controls/button/button.h" +#include "ui/views/view.h" + +namespace views { +class Button; +} namespace ash { class PaginationModel; @@ -16,7 +20,6 @@ // strip. Each page in the PageinationModel has a button in the strip and // when the button is clicked, the corresponding page becomes selected. class PageSwitcher : public views::View, - public views::ButtonListener, public PaginationModelObserver { public: static constexpr int kMaxButtonRadiusForRootGrid = 16; @@ -25,6 +28,8 @@ PageSwitcher(PaginationModel* model, bool is_root_app_grid_page_switcher, bool is_tablet_mode); + PageSwitcher(const PageSwitcher&) = delete; + PageSwitcher& operator=(const PageSwitcher&) = delete; ~PageSwitcher() override; // Overridden from views::View: @@ -36,8 +41,8 @@ void set_is_tablet_mode(bool started) { is_tablet_mode_ = started; } private: - // Overridden from views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; + // Button pressed callback. + void OnButtonPressed(views::Button* sender, const ui::Event& event); // Overridden from PaginationModelObserver: void TotalPagesChanged(int previous_page_count, int new_page_count) override; @@ -54,8 +59,6 @@ // Whether tablet mode is enabled. bool is_tablet_mode_; - - DISALLOW_COPY_AND_ASSIGN(PageSwitcher); }; } // namespace ash
diff --git a/ash/app_list/views/privacy_info_view.cc b/ash/app_list/views/privacy_info_view.cc index e18b284..fa2803e 100644 --- a/ash/app_list/views/privacy_info_view.cc +++ b/ash/app_list/views/privacy_info_view.cc
@@ -210,10 +210,8 @@ } } -void PrivacyInfoView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - if (sender == close_button_) - CloseButtonPressed(); +void PrivacyInfoView::OnButtonPressed() { + CloseButtonPressed(); } void PrivacyInfoView::InitLayout() { @@ -284,7 +282,9 @@ } void PrivacyInfoView::InitCloseButton() { - auto close_button = std::make_unique<views::ImageButton>(this); + auto close_button = std::make_unique<views::ImageButton>(); + close_button->set_callback(base::BindRepeating( + &PrivacyInfoView::OnButtonPressed, base::Unretained(this))); close_button->SetImage(views::ImageButton::STATE_NORMAL, gfx::CreateVectorIcon(views::kCloseIcon, kIconSizeDip, gfx::kGoogleGrey700));
diff --git a/ash/app_list/views/privacy_info_view.h b/ash/app_list/views/privacy_info_view.h index 49c814a9..b534631b 100644 --- a/ash/app_list/views/privacy_info_view.h +++ b/ash/app_list/views/privacy_info_view.h
@@ -35,9 +35,6 @@ void OnGestureEvent(ui::GestureEvent* event) override; void OnKeyEvent(ui::KeyEvent* event) override; - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - // SearchResultBaseView: void SelectInitialResultAction(bool reverse_tab_order) override; bool SelectNextResultAction(bool reverse_tab_order) override; @@ -52,6 +49,9 @@ private: enum class Action { kNone, kTextLink, kCloseButton }; + // Button pressed callback. + void OnButtonPressed(); + void InitLayout(); void InitInfoIcon(); void InitText();
diff --git a/ash/app_list/views/result_selection_controller_unittest.cc b/ash/app_list/views/result_selection_controller_unittest.cc index 3e30c65..7838a4c71 100644 --- a/ash/app_list/views/result_selection_controller_unittest.cc +++ b/ash/app_list/views/result_selection_controller_unittest.cc
@@ -36,10 +36,6 @@ return nullptr; } - void ButtonPressed(Button* sender, const ui::Event& event) override { - // Do nothing for test. - } - private: DISALLOW_COPY_AND_ASSIGN(TestResultView); };
diff --git a/ash/app_list/views/search_result_base_view.cc b/ash/app_list/views/search_result_base_view.cc index 3a23ce9..e8472fde 100644 --- a/ash/app_list/views/search_result_base_view.cc +++ b/ash/app_list/views/search_result_base_view.cc
@@ -12,7 +12,7 @@ namespace ash { -SearchResultBaseView::SearchResultBaseView() : Button(this) { +SearchResultBaseView::SearchResultBaseView() { SetInstallFocusRingOnFocus(false); }
diff --git a/ash/app_list/views/search_result_base_view.h b/ash/app_list/views/search_result_base_view.h index 7dc5640e..c2e106f 100644 --- a/ash/app_list/views/search_result_base_view.h +++ b/ash/app_list/views/search_result_base_view.h
@@ -17,7 +17,6 @@ // Base class for views that observe and display a search result class APP_LIST_EXPORT SearchResultBaseView : public views::Button, - public views::ButtonListener, public SearchResultObserver { public: SearchResultBaseView();
diff --git a/ash/app_list/views/search_result_suggestion_chip_view.cc b/ash/app_list/views/search_result_suggestion_chip_view.cc index b7f1d71..7964573 100644 --- a/ash/app_list/views/search_result_suggestion_chip_view.cc +++ b/ash/app_list/views/search_result_suggestion_chip_view.cc
@@ -54,10 +54,11 @@ SearchResultSuggestionChipView::SearchResultSuggestionChipView( AppListViewDelegate* view_delegate) - : view_delegate_(view_delegate), - icon_view_(new views::ImageView()), - text_view_(new views::Label()) { + : view_delegate_(view_delegate) { SetFocusBehavior(FocusBehavior::ALWAYS); + set_callback( + base::BindRepeating(&SearchResultSuggestionChipView::OnButtonPressed, + base::Unretained(this))); SetInstallFocusRingOnFocus(true); focus_ring()->SetColor(kFocusRingColor); @@ -96,19 +97,6 @@ UpdateSuggestionChipView(); } -void SearchResultSuggestionChipView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - DCHECK(result()); - LogAppLaunch(index_in_container()); - RecordSearchResultOpenSource(result(), view_delegate_->GetModel(), - view_delegate_->GetSearchModel()); - view_delegate_->OpenSearchResult( - result()->id(), event.flags(), - AppListLaunchedFrom::kLaunchedFromSuggestionChip, - AppListLaunchType::kAppSearchResult, index_in_container(), - false /* launch_as_default */); -} - const char* SearchResultSuggestionChipView::GetClassName() const { return "SearchResultSuggestionChipView"; } @@ -232,20 +220,32 @@ // Icon. const int icon_size = AppListConfig::instance().suggestion_chip_icon_dimension(); + icon_view_ = AddChildView(std::make_unique<views::ImageView>()); icon_view_->SetImageSize(gfx::Size(icon_size, icon_size)); icon_view_->SetPreferredSize(gfx::Size(icon_size, icon_size)); icon_view_->SetVisible(false); - AddChildView(icon_view_); // Text. + text_view_ = AddChildView(std::make_unique<views::Label>()); text_view_->SetAutoColorReadabilityEnabled(false); text_view_->SetSubpixelRenderingEnabled(false); text_view_->SetFontList(AppListConfig::instance().app_title_font()); SetText(base::string16()); text_view_->SetEnabledColor( AppListColorProvider::Get()->GetSuggestionChipTextColor()); - AddChildView(text_view_); +} + +void SearchResultSuggestionChipView::OnButtonPressed(const ui::Event& event) { + DCHECK(result()); + LogAppLaunch(index_in_container()); + RecordSearchResultOpenSource(result(), view_delegate_->GetModel(), + view_delegate_->GetSearchModel()); + view_delegate_->OpenSearchResult( + result()->id(), event.flags(), + AppListLaunchedFrom::kLaunchedFromSuggestionChip, + AppListLaunchType::kAppSearchResult, index_in_container(), + false /* launch_as_default */); } void SearchResultSuggestionChipView::SetRoundedCornersForLayer(
diff --git a/ash/app_list/views/search_result_suggestion_chip_view.h b/ash/app_list/views/search_result_suggestion_chip_view.h index d73b7065..5f3eba4 100644 --- a/ash/app_list/views/search_result_suggestion_chip_view.h +++ b/ash/app_list/views/search_result_suggestion_chip_view.h
@@ -28,6 +28,10 @@ : public SearchResultBaseView { public: explicit SearchResultSuggestionChipView(AppListViewDelegate* view_delegate); + SearchResultSuggestionChipView(const SearchResultSuggestionChipView&) = + delete; + SearchResultSuggestionChipView& operator=( + const SearchResultSuggestionChipView&) = delete; ~SearchResultSuggestionChipView() override; // Enables background blur for folder icon if |enabled| is true. @@ -38,9 +42,6 @@ // SearchResultObserver: void OnMetadataChanged() override; - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - // views::View: const char* GetClassName() const override; void ChildVisibilityChanged(views::View* child) override; @@ -67,19 +68,19 @@ void InitLayout(); + void OnButtonPressed(const ui::Event& event); + // Sets rounded corners for the layer with |corner_radius| to clip the chip. void SetRoundedCornersForLayer(int corner_radius); AppListViewDelegate* const view_delegate_; // Owned by AppListView. - views::ImageView* icon_view_; // Owned by view hierarchy. - views::Label* text_view_; // Owned by view hierarchy. + views::ImageView* icon_view_ = nullptr; // Owned by view hierarchy. + views::Label* text_view_ = nullptr; // Owned by view hierarchy. views::BoxLayout* layout_manager_; // Owned by view hierarchy. base::WeakPtrFactory<SearchResultSuggestionChipView> weak_ptr_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(SearchResultSuggestionChipView); }; } // namespace ash
diff --git a/ash/app_list/views/search_result_tile_item_list_view.h b/ash/app_list/views/search_result_tile_item_list_view.h index 753a1e1..8fc2b17 100644 --- a/ash/app_list/views/search_result_tile_item_list_view.h +++ b/ash/app_list/views/search_result_tile_item_list_view.h
@@ -28,6 +28,9 @@ public: SearchResultTileItemListView(views::Textfield* search_box, AppListViewDelegate* view_delegate); + SearchResultTileItemListView(const SearchResultTileItemListView&) = delete; + SearchResultTileItemListView& operator=(const SearchResultTileItemListView&) = + delete; ~SearchResultTileItemListView() override; // Overridden from SearchResultContainerView: @@ -77,8 +80,6 @@ const bool is_app_reinstall_recommendation_enabled_; const size_t max_search_result_tiles_; - - DISALLOW_COPY_AND_ASSIGN(SearchResultTileItemListView); }; } // namespace ash
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc index 5ff59977cb..44d82ad 100644 --- a/ash/app_list/views/search_result_tile_item_view.cc +++ b/ash/app_list/views/search_result_tile_item_view.cc
@@ -74,6 +74,8 @@ is_app_reinstall_recommendation_enabled_( app_list_features::IsAppReinstallZeroStateEnabled()), show_in_apps_page_(show_in_apps_page) { + set_callback(base::BindRepeating(&SearchResultTileItemView::OnButtonPressed, + base::Unretained(this))); SetFocusBehavior(FocusBehavior::ALWAYS); // When |result_| is null, the tile is invisible. Calling SetSearchResult with @@ -83,50 +85,44 @@ GetViewAccessibility().OverrideIsLeaf(true); // Prevent the icon view from interfering with our mouse events. - icon_ = new views::ImageView; + icon_ = AddChildView(std::make_unique<views::ImageView>()); icon_->SetCanProcessEventsWithinSubtree(false); icon_->SetVerticalAlignment(views::ImageView::Alignment::kLeading); - AddChildView(icon_); - badge_ = new views::ImageView; + badge_ = AddChildView(std::make_unique<views::ImageView>()); badge_->SetCanProcessEventsWithinSubtree(false); badge_->SetVerticalAlignment(views::ImageView::Alignment::kLeading); badge_->SetVisible(false); - AddChildView(badge_); - title_ = new views::Label; + title_ = AddChildView(std::make_unique<views::Label>()); title_->SetAutoColorReadabilityEnabled(false); title_->SetEnabledColor(AppListColorProvider::Get()->GetSearchBoxTextColor()); title_->SetLineHeight(kTileTextLineHeight); title_->SetHorizontalAlignment(gfx::ALIGN_CENTER); title_->SetHandlesTooltips(false); title_->SetAllowCharacterBreak(true); - AddChildView(title_); - rating_ = new views::Label; + rating_ = AddChildView(std::make_unique<views::Label>()); rating_->SetEnabledColor( AppListColorProvider::Get()->GetSearchBoxSecondaryTextColor()); rating_->SetLineHeight(kTileTextLineHeight); rating_->SetHorizontalAlignment(gfx::ALIGN_RIGHT); rating_->SetVisible(false); - AddChildView(rating_); - rating_star_ = new views::ImageView; + rating_star_ = AddChildView(std::make_unique<views::ImageView>()); rating_star_->SetCanProcessEventsWithinSubtree(false); rating_star_->SetVerticalAlignment(views::ImageView::Alignment::kLeading); rating_star_->SetImage(gfx::CreateVectorIcon( kBadgeRatingIcon, kSearchRatingStarSize, AppListColorProvider::Get()->GetSearchBoxSecondaryTextColor())); rating_star_->SetVisible(false); - AddChildView(rating_star_); - price_ = new views::Label; + price_ = AddChildView(std::make_unique<views::Label>()); price_->SetEnabledColor( AppListColorProvider::Get()->GetSearchBoxSecondaryTextColor()); price_->SetLineHeight(kTileTextLineHeight); price_->SetHorizontalAlignment(gfx::ALIGN_LEFT); price_->SetVisible(false); - AddChildView(price_); set_context_menu_controller(this); } @@ -249,11 +245,6 @@ UpdateBackgroundColor(); } -void SearchResultTileItemView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - ActivateResult(event.flags(), true /* by_button_press */); -} - void SearchResultTileItemView::GetAccessibleNodeData( ui::AXNodeData* node_data) { views::Button::GetAccessibleNodeData(node_data); @@ -389,6 +380,10 @@ } } +void SearchResultTileItemView::OnButtonPressed(const ui::Event& event) { + ActivateResult(event.flags(), true /* by_button_press */); +} + void SearchResultTileItemView::ActivateResult(int event_flags, bool by_button_press) { const bool launch_as_default = is_default_result() && !by_button_press;
diff --git a/ash/app_list/views/search_result_tile_item_view.h b/ash/app_list/views/search_result_tile_item_view.h index 81014777a..5f787ce 100644 --- a/ash/app_list/views/search_result_tile_item_view.h +++ b/ash/app_list/views/search_result_tile_item_view.h
@@ -51,9 +51,6 @@ return group_index_in_container_view_; } - // Overridden from views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - // Overridden from views::Button: void GetAccessibleNodeData(ui::AXNodeData* node_data) override; bool OnKeyPressed(const ui::KeyEvent& event) override; @@ -83,6 +80,8 @@ // The callback used when a menu closes. void OnMenuClosed(); + void OnButtonPressed(const ui::Event& event); + void SetIcon(const gfx::ImageSkia& icon); void SetBadgeIcon(const gfx::ImageSkia& badge_icon); void SetTitle(const base::string16& title);
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc index 7d8897c1..d5d70ab 100644 --- a/ash/app_list/views/search_result_view.cc +++ b/ash/app_list/views/search_result_view.cc
@@ -62,6 +62,8 @@ AppListViewDelegate* view_delegate) : list_view_(list_view), view_delegate_(view_delegate) { SetFocusBehavior(FocusBehavior::ALWAYS); + set_callback(base::BindRepeating(&SearchResultView::OnButtonPressed, + base::Unretained(this))); icon_ = AddChildView(std::make_unique<views::ImageView>()); display_icon_ = AddChildView(std::make_unique<views::ImageView>()); @@ -350,13 +352,6 @@ Button::OnGestureEvent(event); } -void SearchResultView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - DCHECK(sender == this); - list_view_->SearchResultActivated(this, event.flags(), - true /* by_button_press */); -} - void SearchResultView::OnMetadataChanged() { // Updates |icon_|. // Note: this might leave the view with an old icon. But it is needed to avoid @@ -385,6 +380,11 @@ : SearchResult::Actions()); } +void SearchResultView::OnButtonPressed(const ui::Event& event) { + list_view_->SearchResultActivated(this, event.flags(), + true /* by_button_press */); +} + void SearchResultView::SetIconImage(const gfx::ImageSkia& source, views::ImageView* const icon, const int icon_dimension) {
diff --git a/ash/app_list/views/search_result_view.h b/ash/app_list/views/search_result_view.h index e90a7a3..077ea44 100644 --- a/ash/app_list/views/search_result_view.h +++ b/ash/app_list/views/search_result_view.h
@@ -83,9 +83,6 @@ // ui::EventHandler overrides: void OnGestureEvent(ui::GestureEvent* event) override; - // views::ButtonListener overrides: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - // views::ContextMenuController overrides: void ShowContextMenuForViewImpl(views::View* source, const gfx::Point& point, @@ -100,6 +97,8 @@ // SearchResultObserver overrides: void OnMetadataChanged() override; + void OnButtonPressed(const ui::Event& event); + void SetIconImage(const gfx::ImageSkia& source, views::ImageView* const icon, const int icon_dimension);
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 2365b72b..f99310c 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1100,6 +1100,9 @@ <message name="IDS_ASH_PHONE_HUB_BLUETOOTH_DISABLED_DIALOG_LEARN_MORE_BUTTON" desc="Learn more button on the bluetooth disabled dialog to show more related information."> Learn more </message> + <message name="IDS_ASH_PHONE_HUB_NOTIFICATION_FROM_PHONE_TITLE" desc="The title at the header of PhoneHub notification, indicating that this notification was coming from the connected phone."> + From Phone + </message> <message name="IDS_ASH_PHONE_HUB_NOTIFICATION_INLINE_REPLY_BUTTON" desc="Label for the inline reply button inside a PhoneHub notification."> Reply </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_NOTIFICATION_FROM_PHONE_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_NOTIFICATION_FROM_PHONE_TITLE.png.sha1 new file mode 100644 index 0000000..6938ac3c --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_NOTIFICATION_FROM_PHONE_TITLE.png.sha1
@@ -0,0 +1 @@ +9cc1f57092e64a415e36c5a377cdba7216e3a31b \ No newline at end of file
diff --git a/ash/assistant/assistant_web_view_delegate_impl.cc b/ash/assistant/assistant_web_view_delegate_impl.cc index b739f5c..f91255f 100644 --- a/ash/assistant/assistant_web_view_delegate_impl.cc +++ b/ash/assistant/assistant_web_view_delegate_impl.cc
@@ -5,7 +5,7 @@ #include "ash/assistant/assistant_web_view_delegate_impl.h" #include "ash/frame/non_client_frame_view_ash.h" -#include "ash/public/cpp/caption_buttons/caption_button_model.h" +#include "chromeos/ui/frame/caption_buttons/caption_button_model.h" #include "ui/views/widget/widget.h" #include "ui/views/window/caption_button_types.h" #include "ui/views/window/non_client_view.h" @@ -14,7 +14,8 @@ namespace { -class AssistantWebContainerCaptionButtonModel : public CaptionButtonModel { +class AssistantWebContainerCaptionButtonModel + : public chromeos::CaptionButtonModel { public: AssistantWebContainerCaptionButtonModel() = default; ~AssistantWebContainerCaptionButtonModel() override = default;
diff --git a/ash/capture_mode/capture_mode_session.cc b/ash/capture_mode/capture_mode_session.cc index a61b0fdb..2b35f571 100644 --- a/ash/capture_mode/capture_mode_session.cc +++ b/ash/capture_mode/capture_mode_session.cc
@@ -7,8 +7,10 @@ #include "ash/capture_mode/capture_label_view.h" #include "ash/capture_mode/capture_mode_bar_view.h" #include "ash/capture_mode/capture_mode_controller.h" +#include "ash/capture_mode/capture_mode_util.h" #include "ash/capture_mode/capture_window_observer.h" #include "ash/display/mouse_cursor_event_filter.h" +#include "ash/magnifier/magnifier_glass.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" @@ -49,6 +51,23 @@ // The hit radius of the drag affordance circles touch events. constexpr int kAffordanceCircleTouchHitRadiusDp = 16; +// Capture region magnifier parameters. +constexpr MagnifierGlass::Params kMagnifierParams{ + /*scale=*/2.f, + /*radius=*/60, + /*border_size=*/2, + /*border_outline_thickness=*/0, + /*border_color=*/SK_ColorWHITE, + /*border_outline_color=*/SK_ColorTRANSPARENT, + /*bottom_shadow=*/ + gfx::ShadowValue(gfx::Vector2d(0, 1), + 2, + SkColorSetARGB(0x4C, 0x00, 0x00, 0x00)), + /*top_shadow=*/ + gfx::ShadowValue(gfx::Vector2d(0, 1), + 3, + SkColorSetARGB(0x26, 0x00, 0x00, 0x00))}; + constexpr int kSizeLabelBorderRadius = 4; constexpr int kSizeLabelHorizontalPadding = 8; @@ -92,34 +111,6 @@ return root->GetChildById(kShellWindowId_OverlayContainer); } -// Retrieves the point on the |rect| associated with |position|. -gfx::Point GetLocationForPosition(const gfx::Rect& rect, - FineTunePosition position) { - switch (position) { - case FineTunePosition::kTopLeft: - return rect.origin(); - case FineTunePosition::kTopCenter: - return rect.top_center(); - case FineTunePosition::kTopRight: - return rect.top_right(); - case FineTunePosition::kRightCenter: - return rect.right_center(); - case FineTunePosition::kBottomRight: - return rect.bottom_right(); - case FineTunePosition::kBottomCenter: - return rect.bottom_center(); - case FineTunePosition::kBottomLeft: - return rect.bottom_left(); - case FineTunePosition::kLeftCenter: - return rect.left_center(); - default: - break; - } - - NOTREACHED(); - return gfx::Point(); -} - // Returns the smallest rect that contains all of |points|. gfx::Rect GetRectEnclosingPoints(const std::vector<gfx::Point>& points) { DCHECK_GE(points.size(), 2u); @@ -160,6 +151,7 @@ : controller_(controller), current_root_(root), capture_mode_bar_view_(new CaptureModeBarView()), + magnifier_glass_(kMagnifierParams), old_mouse_warp_status_(SetMouseWarpEnabled(controller_->source() != CaptureModeSource::kRegion)) { Shell::Get()->AddPreTargetHandler(this); @@ -443,7 +435,7 @@ // Calculate the position and anchor points of the current pressed event. fine_tune_position_ = FineTunePosition::kNone; - // In the case of overlapping affordances, prioritize the bottomm right + // In the case of overlapping affordances, prioritize the bottom right // corner, then the rest of the corners, then the edges. static const std::vector<FineTunePosition> drag_positions = { FineTunePosition::kBottomRight, FineTunePosition::kBottomLeft, @@ -456,12 +448,14 @@ const int hit_radius_squared = hit_radius * hit_radius; for (FineTunePosition position : drag_positions) { const gfx::Point position_location = - GetLocationForPosition(controller_->user_capture_region(), position); + capture_mode_util::GetLocationForFineTunePosition( + controller_->user_capture_region(), position); // If |location_in_root| is within |hit_radius| of |position_location| for // both x and y, then |position| is the current pressed down affordance. if ((position_location - location_in_root).LengthSquared() <= hit_radius_squared) { fine_tune_position_ = position; + MaybeShowMagnifierGlassAtPoint(position_location); break; } } @@ -516,6 +510,7 @@ DCHECK(!points.empty()); points.push_back(location_in_root); UpdateCaptureRegion(GetRectEnclosingPoints(points), /*is_resizing=*/true); + MaybeShowMagnifierGlassAtPoint(location_in_root); } void CaptureModeSession::OnLocatedEventReleased( @@ -531,6 +526,7 @@ layer()->SchedulePaint(damage_region); UpdateDimensionsLabelWidget(/*is_resizing=*/false); + CloseMagnifierGlass(); if (!is_selecting_region_) return; @@ -624,6 +620,20 @@ dimensions_label_widget_->SetBounds(bounds); } +void CaptureModeSession::MaybeShowMagnifierGlassAtPoint( + const gfx::Point& location_in_root) { + if (!capture_mode_util::IsCornerFineTunePosition(fine_tune_position_)) + return; + + // TODO(richui): Hide cursor here. + magnifier_glass_.ShowFor(current_root_, location_in_root); +} + +void CaptureModeSession::CloseMagnifierGlass() { + magnifier_glass_.Close(); + // TODO(richui): Show cursor here. +} + std::vector<gfx::Point> CaptureModeSession::GetAnchorPointsForPosition( FineTunePosition position) { std::vector<gfx::Point> anchor_points;
diff --git a/ash/capture_mode/capture_mode_session.h b/ash/capture_mode/capture_mode_session.h index 9ef22bd..d5096925 100644 --- a/ash/capture_mode/capture_mode_session.h +++ b/ash/capture_mode/capture_mode_session.h
@@ -9,6 +9,7 @@ #include "ash/ash_export.h" #include "ash/capture_mode/capture_mode_types.h" +#include "ash/magnifier/magnifier_glass.h" #include "ash/public/cpp/tablet_mode_observer.h" #include "ui/compositor/layer_delegate.h" #include "ui/compositor/layer_owner.h" @@ -56,9 +57,6 @@ CaptureModeBarView* capture_mode_bar_view() const { return capture_mode_bar_view_; } - views::Widget* dimensions_label_widget() { - return dimensions_label_widget_.get(); - } bool is_selecting_region() const { return is_selecting_region_; } // Gets the current window selected for |kWindow| capture source. Returns @@ -89,6 +87,12 @@ views::Widget* capture_label_widget_for_testing() const { return capture_label_widget_.get(); } + views::Widget* dimensions_label_widget_for_testing() const { + return dimensions_label_widget_.get(); + } + const MagnifierGlass& magnifier_glass_for_testing() const { + return magnifier_glass_; + } private: // Gets the bounds of current window selected for |kWindow| capture source. @@ -130,6 +134,14 @@ // exist. void UpdateDimensionsLabelBounds(); + // If |fine_tune_position_| is not a corner, do nothing. Otherwise show + // |magnifier_glass_| at |location_in_root| in the current root window and + // hide the cursor. + void MaybeShowMagnifierGlassAtPoint(const gfx::Point& location_in_root); + + // Closes |magnifier_glass_| and shows the cursor. + void CloseMagnifierGlass(); + // Retrieves the anchor points on the current selected region associated with // |position|. The anchor points are described as the points that do not // change when resizing the capture region while dragging one of the drag @@ -169,6 +181,9 @@ // timer. std::unique_ptr<views::Widget> capture_label_widget_; + // Magnifier glass used during a region capture session. + MagnifierGlass magnifier_glass_; + // Stores the data needed to select a region during a region capture session. // This variable indicates if the user is currently selecting a region to // capture, it will be true when the first mouse/touch presses down and will
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc index 39c1cad..507b86c 100644 --- a/ash/capture_mode/capture_mode_unittests.cc +++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -13,9 +13,11 @@ #include "ash/capture_mode/capture_mode_toggle_button.h" #include "ash/capture_mode/capture_mode_type_view.h" #include "ash/capture_mode/capture_mode_types.h" +#include "ash/capture_mode/capture_mode_util.h" #include "ash/capture_mode/stop_recording_button_tray.h" #include "ash/display/cursor_window_controller.h" #include "ash/display/window_tree_host_manager.h" +#include "ash/magnifier/magnifier_glass.h" #include "ash/public/cpp/ash_features.h" #include "ash/root_window_controller.h" #include "ash/shell.h" @@ -125,6 +127,27 @@ ->close_button(); } + aura::Window* GetDimensionsLabelWindow() const { + auto* controller = CaptureModeController::Get(); + DCHECK(controller->IsActive()); + auto* widget = controller->capture_mode_session() + ->dimensions_label_widget_for_testing(); + return widget ? widget->GetNativeWindow() : nullptr; + } + + base::Optional<gfx::Point> GetMagnifierGlassCenterPoint() const { + auto* controller = CaptureModeController::Get(); + DCHECK(controller->IsActive()); + auto& magnifier = + controller->capture_mode_session()->magnifier_glass_for_testing(); + if (magnifier.host_widget_for_testing()) { + return magnifier.host_widget_for_testing() + ->GetWindowBoundsInScreen() + .CenterPoint(); + } + return base::nullopt; + } + // Start Capture Mode with source region and type image. CaptureModeController* StartImageRegionCapture() { auto* controller = CaptureModeController::Get(); @@ -149,14 +172,6 @@ EXPECT_EQ(region, controller->user_capture_region()); } - aura::Window* GetDimensionsLabelWindow() const { - auto* controller = CaptureModeController::Get(); - DCHECK(controller->IsActive()); - auto* widget = - controller->capture_mode_session()->dimensions_label_widget(); - return widget ? widget->GetNativeWindow() : nullptr; - } - void WaitForCountDownToFinish() { auto* controller = CaptureModeController::Get(); DCHECK(controller->IsActive()); @@ -477,7 +492,78 @@ EXPECT_FALSE(controller->IsActive()); } -TEST_F(CaptureModeTest, DimensionsLabelLocation) { +// Tests that the magnifying glass appears while fine tuning the capture region. +TEST_F(CaptureModeTest, CaptureRegionMagnifierWhenFineTuning) { + const gfx::Vector2d kDragDelta(50, 50); + UpdateDisplay("800x800"); + + // Start Capture Mode in a region in image mode. + StartImageRegionCapture(); + + // Press down and drag to select a region. The magnifier should not be + // visible yet. + gfx::Rect capture_region{200, 200, 400, 400}; + SelectRegion(capture_region); + EXPECT_EQ(base::nullopt, GetMagnifierGlassCenterPoint()); + + auto check_magnifier_shows_properly = [this](const gfx::Point& origin, + const gfx::Point& destination, + bool should_show) { + // If |should_show|, check that the magnifying glass is centered on the + // mouse after press and during drag. If not |should_show|, check that + // the magnifying glass never shows. Should always be not visible when + // mouse button is released. + auto* event_generator = GetEventGenerator(); + base::Optional<gfx::Point> expected_origin = + should_show ? base::make_optional(origin) : base::nullopt; + base::Optional<gfx::Point> expected_destination = + should_show ? base::make_optional(destination) : base::nullopt; + + // Move cursor to |origin| and click. + event_generator->set_current_screen_location(origin); + event_generator->PressLeftButton(); + EXPECT_EQ(expected_origin, GetMagnifierGlassCenterPoint()); + + // Drag to |destination| while holding left button. + event_generator->MoveMouseTo(destination); + EXPECT_EQ(expected_destination, GetMagnifierGlassCenterPoint()); + + // Drag back to |origin| while still holding left button. + event_generator->MoveMouseTo(origin); + EXPECT_EQ(expected_origin, GetMagnifierGlassCenterPoint()); + + // Release left button. + event_generator->ReleaseLeftButton(); + EXPECT_EQ(base::nullopt, GetMagnifierGlassCenterPoint()); + }; + + // Drag the capture region from within the existing selected region. The + // magnifier should not be visible at any point. + check_magnifier_shows_properly(gfx::Point(400, 250), gfx::Point(500, 350), + /*should_show=*/false); + + // Check that each corner fine tune position shows the magnifier when + // dragging. + struct { + std::string trace; + FineTunePosition position; + } kFineTunePositions[] = {{"top_left", FineTunePosition::kTopLeft}, + {"top_right", FineTunePosition::kTopRight}, + {"bottom_right", FineTunePosition::kBottomRight}, + {"bottom_left", FineTunePosition::kBottomLeft}}; + for (const auto& fine_tune_position : kFineTunePositions) { + SCOPED_TRACE(fine_tune_position.trace); + const gfx::Point drag_affordance_location = + capture_mode_util::GetLocationForFineTunePosition( + capture_region, fine_tune_position.position); + check_magnifier_shows_properly(drag_affordance_location, + drag_affordance_location + kDragDelta, + /*should_show=*/true); + } +} + +// Tests that the dimensions label properly renders for capture regions. +TEST_F(CaptureModeTest, CaptureRegionDimensionsLabelLocation) { UpdateDisplay("800x800"); // Start Capture Mode in a region in image mode.
diff --git a/ash/capture_mode/capture_mode_util.cc b/ash/capture_mode/capture_mode_util.cc new file mode 100644 index 0000000..278c39836 --- /dev/null +++ b/ash/capture_mode/capture_mode_util.cc
@@ -0,0 +1,57 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/capture_mode/capture_mode_util.h" + +#include "base/notreached.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { + +namespace capture_mode_util { + +gfx::Point GetLocationForFineTunePosition(const gfx::Rect& rect, + FineTunePosition position) { + switch (position) { + case FineTunePosition::kTopLeft: + return rect.origin(); + case FineTunePosition::kTopCenter: + return rect.top_center(); + case FineTunePosition::kTopRight: + return rect.top_right(); + case FineTunePosition::kRightCenter: + return rect.right_center(); + case FineTunePosition::kBottomRight: + return rect.bottom_right(); + case FineTunePosition::kBottomCenter: + return rect.bottom_center(); + case FineTunePosition::kBottomLeft: + return rect.bottom_left(); + case FineTunePosition::kLeftCenter: + return rect.left_center(); + default: + break; + } + + NOTREACHED(); + return gfx::Point(); +} + +bool IsCornerFineTunePosition(FineTunePosition position) { + switch (position) { + case FineTunePosition::kTopLeft: + case FineTunePosition::kTopRight: + case FineTunePosition::kBottomRight: + case FineTunePosition::kBottomLeft: + return true; + default: + break; + } + return false; +} + +} // namespace capture_mode_util + +} // namespace ash
diff --git a/ash/capture_mode/capture_mode_util.h b/ash/capture_mode/capture_mode_util.h new file mode 100644 index 0000000..6dfdf37 --- /dev/null +++ b/ash/capture_mode/capture_mode_util.h
@@ -0,0 +1,31 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_UTIL_H_ +#define ASH_CAPTURE_MODE_CAPTURE_MODE_UTIL_H_ + +#include "ash/ash_export.h" +#include "ash/capture_mode/capture_mode_types.h" + +namespace gfx { +class Point; +class Rect; +} // namespace gfx + +namespace ash { + +namespace capture_mode_util { + +// Retrieves the point on the |rect| associated with |position|. +ASH_EXPORT gfx::Point GetLocationForFineTunePosition(const gfx::Rect& rect, + FineTunePosition position); + +// Return whether |position| is a corner. +ASH_EXPORT bool IsCornerFineTunePosition(FineTunePosition position); + +} // namespace capture_mode_util + +} // namespace ash + +#endif // ASH_CAPTURE_MODE_CAPTURE_MODE_UTIL_H_
diff --git a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc index 426ffe3..4e55573 100644 --- a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc +++ b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
@@ -8,6 +8,7 @@ #include "ash/clipboard/clipboard_history_resource_manager.h" #include "ash/clipboard/clipboard_history_util.h" #include "ash/public/cpp/rounded_image_view.h" +#include "ash/style/ash_color_provider.h" #include "base/time/time.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/compositor/layer.h" @@ -44,6 +45,9 @@ // The radius of the image's rounded corners. constexpr int kRoundedCornerRadius = 4; +// The thickness of the image border. +constexpr int kBorderThickness = 1; + //////////////////////////////////////////////////////////////////////////////// // FadeImageView // An ImageView which reacts to updates from ClipboardHistoryResourceManager by @@ -236,6 +240,10 @@ auto image_view = BuildImageView(); image_view->SetPreferredSize(gfx::Size(INT_MAX, kBitmapHeight)); image_view_ = contents_view->AddChildView(std::move(image_view)); + image_view_->SetBorder(views::CreateRoundedRectBorder( + kBorderThickness, kRoundedCornerRadius, + AshColorProvider::Get()->GetControlsLayerColor( + AshColorProvider::ControlsLayerType::kHairlineBorderColor))); contents_view->InstallDeleteButton(); return contents_view; }
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc index 6260158..5325185c 100644 --- a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc +++ b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" @@ -18,6 +18,8 @@ namespace ash { +using ::chromeos::FrameCaptionButtonContainerView; + class FrameCaptionButtonContainerViewTest : public AshTestBase { public: enum MaximizeAllowed { MAXIMIZE_ALLOWED, MAXIMIZE_DISALLOWED };
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc index 6f943f4a..b787a53 100644 --- a/ash/frame/caption_buttons/frame_size_button_unittest.cc +++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/public/cpp/caption_buttons/frame_size_button.h" +#include "chromeos/ui/frame/caption_buttons/frame_size_button.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/wm/window_state.h" #include "base/i18n/rtl.h" #include "base/run_loop.h" #include "chromeos/ui/base/window_properties.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "chromeos/ui/vector_icons/vector_icons.h" #include "ui/aura/window.h" #include "ui/display/display.h" @@ -27,6 +27,8 @@ namespace { +using ::chromeos::FrameCaptionButtonContainerView; +using ::chromeos::FrameSizeButton; using ::chromeos::WindowStateType; class TestWidgetDelegate : public views::WidgetDelegateView {
diff --git a/ash/frame/default_frame_header_unittest.cc b/ash/frame/default_frame_header_unittest.cc index f41b4fb5..83b8dc2 100644 --- a/ash/frame/default_frame_header_unittest.cc +++ b/ash/frame/default_frame_header_unittest.cc
@@ -7,8 +7,6 @@ #include <memory> #include "ash/frame/non_client_frame_view_ash.h" -#include "ash/public/cpp/caption_buttons/frame_back_button.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" #include "ash/test/ash_test_base.h" @@ -16,6 +14,8 @@ #include "base/i18n/rtl.h" #include "base/stl_util.h" #include "base/test/icu_test_util.h" +#include "chromeos/ui/frame/caption_buttons/frame_back_button.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "ui/aura/window.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/gfx/animation/animation_test_api.h" @@ -25,6 +25,8 @@ #include "ui/views/window/non_client_view.h" #include "ui/wm/core/window_util.h" +using chromeos::FrameBackButton; +using chromeos::FrameCaptionButtonContainerView; using views::NonClientFrameView; using views::Widget;
diff --git a/ash/frame/header_view.cc b/ash/frame/header_view.cc index 9a62b54b..f265c9fe 100644 --- a/ash/frame/header_view.cc +++ b/ash/frame/header_view.cc
@@ -6,15 +6,15 @@ #include <memory> -#include "ash/public/cpp/caption_buttons/caption_button_model.h" -#include "ash/public/cpp/caption_buttons/frame_back_button.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/default_frame_header.h" #include "ash/public/cpp/window_properties.h" #include "ash/shell.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" #include "base/auto_reset.h" +#include "chromeos/ui/frame/caption_buttons/caption_button_model.h" +#include "chromeos/ui/frame/caption_buttons/frame_back_button.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "ui/aura/client/aura_constants.h" #include "ui/base/ui_base_features.h" #include "ui/views/controls/image_view.h" @@ -57,8 +57,9 @@ header_content_view_ = AddChildView(std::make_unique<HeaderContentView>(this)); - caption_button_container_ = AddChildView( - std::make_unique<FrameCaptionButtonContainerView>(target_widget_)); + caption_button_container_ = + AddChildView(std::make_unique<chromeos::FrameCaptionButtonContainerView>( + target_widget_)); caption_button_container_->UpdateCaptionButtonState(false /*=animate*/); aura::Window* window = target_widget->GetNativeWindow(); @@ -304,7 +305,7 @@ views::FrameCaptionButton* back_button = frame_header_->GetBackButton(); if (has_back_button) { if (!back_button) { - back_button = new FrameBackButton(); + back_button = new chromeos::FrameBackButton(); AddChildView(back_button); frame_header_->SetBackButton(back_button); }
diff --git a/ash/frame/header_view.h b/ash/frame/header_view.h index 35707b55..b15321f 100644 --- a/ash/frame/header_view.h +++ b/ash/frame/header_view.h
@@ -20,6 +20,10 @@ #include "ui/base/ui_base_types.h" #include "ui/views/view.h" +namespace chromeos { +class FrameCaptionButtonContainerView; +} + namespace gfx { class ImageSkia; } @@ -34,7 +38,6 @@ namespace ash { class DefaultFrameHeader; -class FrameCaptionButtonContainerView; enum class FrameBackButtonState; // View which paints the frame header (title, caption buttons...). It slides off @@ -98,7 +101,7 @@ intptr_t old) override; void OnWindowDestroying(aura::Window* window) override; - FrameCaptionButtonContainerView* caption_button_container() { + chromeos::FrameCaptionButtonContainerView* caption_button_container() { return caption_button_container_; } @@ -151,7 +154,8 @@ HeaderContentView* header_content_view_ = nullptr; // View which contains the window caption buttons. - FrameCaptionButtonContainerView* caption_button_container_ = nullptr; + chromeos::FrameCaptionButtonContainerView* caption_button_container_ = + nullptr; // The fraction of the header's height which is visible while in fullscreen. // This value is meaningless when not in fullscreen.
diff --git a/ash/frame/non_client_frame_view_ash.cc b/ash/frame/non_client_frame_view_ash.cc index 3485a40..553fc8f 100644 --- a/ash/frame/non_client_frame_view_ash.cc +++ b/ash/frame/non_client_frame_view_ash.cc
@@ -10,7 +10,6 @@ #include "ash/frame/header_view.h" #include "ash/public/cpp/ash_constants.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/default_frame_header.h" #include "ash/public/cpp/frame_utils.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h" @@ -24,6 +23,7 @@ #include "ash/wm/window_state_observer.h" #include "ash/wm/window_util.h" #include "base/bind.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_observer.h" @@ -257,7 +257,7 @@ } void NonClientFrameViewAsh::SetCaptionButtonModel( - std::unique_ptr<CaptionButtonModel> model) { + std::unique_ptr<chromeos::CaptionButtonModel> model) { header_view_->caption_button_container()->SetModel(std::move(model)); header_view_->UpdateCaptionButtons(); } @@ -406,7 +406,7 @@ return false; } -FrameCaptionButtonContainerView* +chromeos::FrameCaptionButtonContainerView* NonClientFrameViewAsh::GetFrameCaptionButtonContainerViewForTest() { return header_view_->caption_button_container(); }
diff --git a/ash/frame/non_client_frame_view_ash.h b/ash/frame/non_client_frame_view_ash.h index 16dab591..4f549f5 100644 --- a/ash/frame/non_client_frame_view_ash.h +++ b/ash/frame/non_client_frame_view_ash.h
@@ -17,13 +17,16 @@ #include "ui/views/widget/widget.h" #include "ui/views/window/non_client_view.h" +namespace chromeos { +class FrameCaptionButtonContainerView; +} + namespace views { class Widget; } namespace ash { -class FrameCaptionButtonContainerView; class ImmersiveFullscreenController; class NonClientFrameViewAshImmersiveHelper; @@ -48,7 +51,8 @@ static NonClientFrameViewAsh* Get(aura::Window* window); // Sets the caption button modeland updates the caption buttons. - void SetCaptionButtonModel(std::unique_ptr<CaptionButtonModel> model); + void SetCaptionButtonModel( + std::unique_ptr<chromeos::CaptionButtonModel> model); // Inits |immersive_fullscreen_controller| so that the controller reveals // and hides |header_view_| in immersive fullscreen. @@ -118,7 +122,8 @@ // Returns the container for the minimize/maximize/close buttons that is // held by the HeaderView. Used in testing. - FrameCaptionButtonContainerView* GetFrameCaptionButtonContainerViewForTest(); + chromeos::FrameCaptionButtonContainerView* + GetFrameCaptionButtonContainerViewForTest(); // Called when |frame_|'s "paint as active" state has changed. void PaintAsActiveChanged();
diff --git a/ash/frame/non_client_frame_view_ash_unittest.cc b/ash/frame/non_client_frame_view_ash_unittest.cc index c1563381..d529f590 100644 --- a/ash/frame/non_client_frame_view_ash_unittest.cc +++ b/ash/frame/non_client_frame_view_ash_unittest.cc
@@ -10,7 +10,6 @@ #include "ash/frame/header_view.h" #include "ash/frame/wide_frame_view.h" #include "ash/public/cpp/ash_switches.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/default_frame_header.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h" @@ -27,6 +26,7 @@ #include "ash/wm/wm_event.h" #include "base/command_line.h" #include "base/containers/flat_set.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "chromeos/ui/vector_icons/vector_icons.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" @@ -49,6 +49,8 @@ namespace ash { +using ::chromeos::FrameCaptionButtonContainerView; + // A views::WidgetDelegate which uses a NonClientFrameViewAsh. class NonClientFrameViewAshTestWidgetDelegate : public views::WidgetDelegateView { @@ -417,7 +419,7 @@ namespace { -class TestButtonModel : public CaptionButtonModel { +class TestButtonModel : public chromeos::CaptionButtonModel { public: TestButtonModel() = default; ~TestButtonModel() override = default;
diff --git a/ash/frame/snap_controller_impl.cc b/ash/frame/snap_controller_impl.cc index ec4b9b1..28f24c14 100644 --- a/ash/frame/snap_controller_impl.cc +++ b/ash/frame/snap_controller_impl.cc
@@ -21,8 +21,8 @@ } void SnapControllerImpl::ShowSnapPreview(aura::Window* window, - SnapDirection snap) { - if (snap == SnapDirection::kNone) { + chromeos::SnapDirection snap) { + if (snap == chromeos::SnapDirection::kNone) { phantom_window_controller_.reset(); return; } @@ -33,21 +33,23 @@ std::make_unique<PhantomWindowController>(window); } gfx::Rect phantom_bounds_in_screen = - (snap == SnapDirection::kLeft) + (snap == chromeos::SnapDirection::kLeft) ? GetDefaultLeftSnappedWindowBoundsInParent(window) : GetDefaultRightSnappedWindowBoundsInParent(window); ::wm::ConvertRectToScreen(window->parent(), &phantom_bounds_in_screen); phantom_window_controller_->Show(phantom_bounds_in_screen); } -void SnapControllerImpl::CommitSnap(aura::Window* window, SnapDirection snap) { +void SnapControllerImpl::CommitSnap(aura::Window* window, + chromeos::SnapDirection snap) { phantom_window_controller_.reset(); - if (snap == SnapDirection::kNone) + if (snap == chromeos::SnapDirection::kNone) return; WindowState* window_state = WindowState::Get(window); - const WMEvent snap_event(snap == SnapDirection::kLeft ? WM_EVENT_SNAP_LEFT - : WM_EVENT_SNAP_RIGHT); + const WMEvent snap_event(snap == chromeos::SnapDirection::kLeft + ? WM_EVENT_SNAP_LEFT + : WM_EVENT_SNAP_RIGHT); window_state->OnWMEvent(&snap_event); }
diff --git a/ash/frame/snap_controller_impl.h b/ash/frame/snap_controller_impl.h index 68bf9bc..61065979 100644 --- a/ash/frame/snap_controller_impl.h +++ b/ash/frame/snap_controller_impl.h
@@ -8,22 +8,23 @@ #include <memory> #include "ash/ash_export.h" -#include "ash/public/cpp/caption_buttons/snap_controller.h" #include "base/macros.h" +#include "chromeos/ui/frame/caption_buttons/snap_controller.h" namespace ash { class PhantomWindowController; // A controller for toplevel window actions which can only run in Ash. -class ASH_EXPORT SnapControllerImpl : public SnapController { +class ASH_EXPORT SnapControllerImpl : public chromeos::SnapController { public: SnapControllerImpl(); ~SnapControllerImpl() override; bool CanSnap(aura::Window* window) override; - void ShowSnapPreview(aura::Window* window, SnapDirection snap) override; - void CommitSnap(aura::Window* window, SnapDirection snap) override; + void ShowSnapPreview(aura::Window* window, + chromeos::SnapDirection snap) override; + void CommitSnap(aura::Window* window, chromeos::SnapDirection snap) override; private: std::unique_ptr<PhantomWindowController> phantom_window_controller_;
diff --git a/ash/frame/wide_frame_view.cc b/ash/frame/wide_frame_view.cc index 611500c..9399c90 100644 --- a/ash/frame/wide_frame_view.cc +++ b/ash/frame/wide_frame_view.cc
@@ -6,7 +6,6 @@ #include "ash/frame/header_view.h" #include "ash/frame/non_client_frame_view_ash.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/default_frame_header.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h" #include "ash/public/cpp/window_properties.h" @@ -15,6 +14,7 @@ #include "ash/wm/window_state.h" #include "ash/wm/wm_event.h" #include "base/metrics/user_metrics.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "ui/aura/window.h" #include "ui/aura/window_targeter.h" #include "ui/display/display.h" @@ -78,7 +78,7 @@ } void WideFrameView::SetCaptionButtonModel( - std::unique_ptr<CaptionButtonModel> model) { + std::unique_ptr<chromeos::CaptionButtonModel> model) { header_view_->caption_button_container()->SetModel(std::move(model)); header_view_->UpdateCaptionButtons(); }
diff --git a/ash/frame/wide_frame_view.h b/ash/frame/wide_frame_view.h index 32b684da..a843bbc6 100644 --- a/ash/frame/wide_frame_view.h +++ b/ash/frame/wide_frame_view.h
@@ -6,9 +6,9 @@ #define ASH_FRAME_WIDE_FRAME_VIEW_H_ #include "ash/ash_export.h" -#include "ash/public/cpp/caption_buttons/caption_button_model.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h" #include "ash/wm/overview/overview_observer.h" +#include "chromeos/ui/frame/caption_buttons/caption_button_model.h" #include "ui/aura/window_observer.h" #include "ui/display/display_observer.h" #include "ui/views/widget/widget_delegate.h" @@ -44,7 +44,8 @@ void Init(ImmersiveFullscreenController* controller); // Set the caption model for caption buttions on this frame. - void SetCaptionButtonModel(std::unique_ptr<CaptionButtonModel> mode); + void SetCaptionButtonModel( + std::unique_ptr<chromeos::CaptionButtonModel> mode); HeaderView* header_view() { return header_view_; }
diff --git a/ash/frame_throttler/frame_throttling_controller.cc b/ash/frame_throttler/frame_throttling_controller.cc index 979b91d..9b2d4f8 100644 --- a/ash/frame_throttler/frame_throttling_controller.cc +++ b/ash/frame_throttler/frame_throttling_controller.cc
@@ -50,7 +50,7 @@ int value; if (base::StringToInt(cl->GetSwitchValueASCII(switches::kFrameThrottleFps), &value)) { - fps_ = value; + throttled_fps_ = value; } } } @@ -69,10 +69,10 @@ frame_sink_ids.reserve(windows.size()); CollectBrowserFrameSinkIds(windows, &frame_sink_ids); if (!frame_sink_ids.empty()) - StartThrottling(frame_sink_ids, fps_); + StartThrottling(frame_sink_ids, throttled_fps_); for (auto& observer : observers_) { - observer.OnThrottlingStarted(windows); + observer.OnThrottlingStarted(windows, throttled_fps_); } } @@ -97,11 +97,12 @@ windows_throttled_ = false; } -void FrameThrottlingController::AddObserver(Observer* observer) { +void FrameThrottlingController::AddObserver(FrameThrottlingObserver* observer) { observers_.AddObserver(observer); } -void FrameThrottlingController::RemoveObserver(Observer* observer) { +void FrameThrottlingController::RemoveObserver( + FrameThrottlingObserver* observer) { observers_.RemoveObserver(observer); }
diff --git a/ash/frame_throttler/frame_throttling_controller.h b/ash/frame_throttler/frame_throttling_controller.h index 904c3aa..f22c851 100644 --- a/ash/frame_throttler/frame_throttling_controller.h +++ b/ash/frame_throttler/frame_throttling_controller.h
@@ -9,6 +9,7 @@ #include <vector> #include "ash/ash_export.h" +#include "ash/frame_throttler/frame_throttling_observer.h" #include "base/macros.h" #include "base/observer_list.h" #include "base/observer_list_types.h" @@ -28,13 +29,6 @@ class ASH_EXPORT FrameThrottlingController { public: - class Observer : public base::CheckedObserver { - public: - virtual void OnThrottlingStarted( - const std::vector<aura::Window*>& windows) {} - virtual void OnThrottlingEnded() {} - }; - explicit FrameThrottlingController(ui::ContextFactory* context_factory); FrameThrottlingController(const FrameThrottlingController&) = delete; FrameThrottlingController& operator=(const FrameThrottlingController&) = @@ -46,17 +40,19 @@ // Ends throttling of all throttled windows. void EndThrottling(); - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); + void AddObserver(FrameThrottlingObserver* observer); + void RemoveObserver(FrameThrottlingObserver* observer); + + uint8_t throttled_fps() const { return throttled_fps_; } private: void StartThrottling(const std::vector<viz::FrameSinkId>& frame_sink_ids, uint8_t fps); ui::ContextFactory* context_factory_ = nullptr; - base::ObserverList<Observer> observers_; + base::ObserverList<FrameThrottlingObserver> observers_; // The fps used for throttling. - uint8_t fps_ = kDefaultThrottleFps; + uint8_t throttled_fps_ = kDefaultThrottleFps; bool windows_throttled_ = false; };
diff --git a/ash/frame_throttler/frame_throttling_observer.h b/ash/frame_throttler/frame_throttling_observer.h new file mode 100644 index 0000000..6211913d --- /dev/null +++ b/ash/frame_throttler/frame_throttling_observer.h
@@ -0,0 +1,31 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_FRAME_THROTTLER_FRAME_THROTTLING_OBSERVER_H_ +#define ASH_FRAME_THROTTLER_FRAME_THROTTLING_OBSERVER_H_ + +#include <stdint.h> +#include <vector> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "base/observer_list_types.h" + +namespace aura { +class Window; +} + +namespace ash { + +// This class observes the start and end of frame throttling. +class ASH_EXPORT FrameThrottlingObserver : public base::CheckedObserver { + public: + virtual void OnThrottlingStarted(const std::vector<aura::Window*>& windows, + uint8_t fps) {} + virtual void OnThrottlingEnded() {} +}; + +} // namespace ash + +#endif // ASH_FRAME_THROTTLER_FRAME_THROTTLING_OBSERVER_H_
diff --git a/ash/frame_throttler/mock_frame_throttling_observer.h b/ash/frame_throttler/mock_frame_throttling_observer.h index ec1ed139..3f48d1c3 100644 --- a/ash/frame_throttler/mock_frame_throttling_observer.h +++ b/ash/frame_throttler/mock_frame_throttling_observer.h
@@ -7,20 +7,19 @@ #include <vector> -#include "ash/frame_throttler/frame_throttling_controller.h" -#include "base/memory/weak_ptr.h" +#include "ash/frame_throttler/frame_throttling_observer.h" #include "testing/gmock/include/gmock/gmock.h" namespace ash { -class MockFrameThrottlingObserver : public FrameThrottlingController::Observer { +class MockFrameThrottlingObserver : public FrameThrottlingObserver { public: MockFrameThrottlingObserver(); ~MockFrameThrottlingObserver() override; MOCK_METHOD(void, OnThrottlingStarted, - (const std::vector<aura::Window*>& windows), + (const std::vector<aura::Window*>& windows, uint8_t fps), (override)); MOCK_METHOD(void, OnThrottlingEnded, (), (override)); };
diff --git a/ash/magnifier/magnifier_glass.h b/ash/magnifier/magnifier_glass.h index 74f398a3..d465b008 100644 --- a/ash/magnifier/magnifier_glass.h +++ b/ash/magnifier/magnifier_glass.h
@@ -58,6 +58,8 @@ // Closes the magnifier glass widget. void Close(); + views::Widget* host_widget_for_testing() const { return host_widget_; } + private: friend class PartialMagnificationControllerTestApi; class BorderRenderer;
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index 8f82490..fdf9769 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -104,16 +104,6 @@ "assistant/conversation_starters_client.h", "back_gesture_contextual_nudge_controller.h", "back_gesture_contextual_nudge_delegate.h", - "caption_buttons/caption_button_model.h", - "caption_buttons/frame_back_button.cc", - "caption_buttons/frame_back_button.h", - "caption_buttons/frame_caption_button_container_view.cc", - "caption_buttons/frame_caption_button_container_view.h", - "caption_buttons/frame_size_button.cc", - "caption_buttons/frame_size_button.h", - "caption_buttons/frame_size_button_delegate.h", - "caption_buttons/snap_controller.cc", - "caption_buttons/snap_controller.h", "cast_config_controller.cc", "cast_config_controller.h", "child_accounts/parent_access_controller.cc", @@ -341,6 +331,7 @@ "//chromeos/services/cellular_setup:in_process_esim_manager", "//chromeos/services/network_config:in_process_instance", "//chromeos/ui/base", + "//chromeos/ui/frame", "//chromeos/ui/vector_icons", "//components/pref_registry", "//components/prefs",
diff --git a/ash/public/cpp/caption_buttons/frame_back_button.h b/ash/public/cpp/caption_buttons/frame_back_button.h deleted file mode 100644 index 32182eb8a..0000000 --- a/ash/public/cpp/caption_buttons/frame_back_button.h +++ /dev/null
@@ -1,30 +0,0 @@ -// 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 ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_BACK_BUTTON_H_ -#define ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_BACK_BUTTON_H_ - -#include "ash/public/cpp/ash_public_export.h" -#include "ui/views/window/frame_caption_button.h" - -namespace ash { - -// A button to send back key events. It's used in Chrome hosted app windows, -// among other places. -class ASH_PUBLIC_EXPORT FrameBackButton : public views::FrameCaptionButton, - public views::ButtonListener { - public: - FrameBackButton(); - ~FrameBackButton() override; - - // views::ButtonListener: - void ButtonPressed(Button* sender, const ui::Event& event) override; - - private: - DISALLOW_COPY_AND_ASSIGN(FrameBackButton); -}; - -} // namespace ash - -#endif // ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_BACK_BUTTON_H_
diff --git a/ash/public/cpp/default_frame_header.cc b/ash/public/cpp/default_frame_header.cc index b205f83f..9e736b4 100644 --- a/ash/public/cpp/default_frame_header.cc +++ b/ash/public/cpp/default_frame_header.cc
@@ -5,12 +5,12 @@ #include "ash/public/cpp/default_frame_header.h" #include "ash/public/cpp/ash_constants.h" -#include "ash/public/cpp/caption_buttons/caption_button_model.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/window_properties.h" #include "base/logging.h" // DCHECK #include "chromeos/ui/base/window_properties.h" #include "chromeos/ui/base/window_state_type.h" +#include "chromeos/ui/frame/caption_buttons/caption_button_model.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "third_party/skia/include/core/SkPath.h" #include "ui/gfx/canvas.h" #include "ui/gfx/color_utils.h" @@ -64,7 +64,7 @@ DefaultFrameHeader::DefaultFrameHeader( views::Widget* target_widget, views::View* header_view, - FrameCaptionButtonContainerView* caption_button_container) + chromeos::FrameCaptionButtonContainerView* caption_button_container) : FrameHeader(target_widget, header_view) { DCHECK(caption_button_container); SetCaptionButtonContainer(caption_button_container);
diff --git a/ash/public/cpp/default_frame_header.h b/ash/public/cpp/default_frame_header.h index 8bb5dba..efa8bf0 100644 --- a/ash/public/cpp/default_frame_header.h +++ b/ash/public/cpp/default_frame_header.h
@@ -21,9 +21,10 @@ class ASH_PUBLIC_EXPORT DefaultFrameHeader : public FrameHeader { public: // DefaultFrameHeader does not take ownership of any of the parameters. - DefaultFrameHeader(views::Widget* target_widget, - views::View* header_view, - FrameCaptionButtonContainerView* caption_button_container); + DefaultFrameHeader( + views::Widget* target_widget, + views::View* header_view, + chromeos::FrameCaptionButtonContainerView* caption_button_container); ~DefaultFrameHeader() override; SkColor active_frame_color_for_testing() { return active_frame_color_; }
diff --git a/ash/public/cpp/frame_header.cc b/ash/public/cpp/frame_header.cc index 09a23a16..042d86c 100644 --- a/ash/public/cpp/frame_header.cc +++ b/ash/public/cpp/frame_header.cc
@@ -4,11 +4,11 @@ #include "ash/public/cpp/frame_header.h" -#include "ash/public/cpp/caption_buttons/caption_button_model.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/frame_utils.h" #include "ash/public/cpp/window_properties.h" #include "base/logging.h" // DCHECK +#include "chromeos/ui/frame/caption_buttons/caption_button_model.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "chromeos/ui/vector_icons/vector_icons.h" #include "ui/base/class_property.h" #include "ui/compositor/layer_animation_observer.h" @@ -261,7 +261,7 @@ return back_button_; } -const CaptionButtonModel* FrameHeader::GetCaptionButtonModel() const { +const chromeos::CaptionButtonModel* FrameHeader::GetCaptionButtonModel() const { return caption_button_container_->model(); } @@ -317,7 +317,7 @@ } void FrameHeader::SetCaptionButtonContainer( - FrameCaptionButtonContainerView* caption_button_container) { + chromeos::FrameCaptionButtonContainerView* caption_button_container) { caption_button_container_ = caption_button_container; caption_button_container_->SetButtonImage(views::CAPTION_BUTTON_ICON_MINIMIZE, views::kWindowControlMinimizeIcon); @@ -365,7 +365,7 @@ : views::kWindowControlMaximizeIcon; // TODO(crbug.com/1092005): Investigate if we can move this to // CaptionButtonModel and just check the model in - // FrameCaptionButtonContainerView. + // chromeos::FrameCaptionButtonContainerView. const bool use_restore_frame = ash::ShouldUseRestoreFrame(target_widget_); caption_button_container()->SetButtonImage( views::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE,
diff --git a/ash/public/cpp/frame_header.h b/ash/public/cpp/frame_header.h index 89ce587..9f1e495 100644 --- a/ash/public/cpp/frame_header.h +++ b/ash/public/cpp/frame_header.h
@@ -6,15 +6,19 @@ #define ASH_PUBLIC_CPP_FRAME_HEADER_H_ #include "ash/public/cpp/ash_public_export.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "base/callback.h" #include "base/optional.h" #include "base/strings/string16.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/ui_base_types.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/views/window/frame_caption_button.h" +namespace chromeos { +class CaptionButtonModel; +} // namespace chromeos + namespace gfx { class Canvas; class Rect; @@ -27,7 +31,6 @@ } // namespace views namespace ash { -class CaptionButtonModel; // Helper class for managing the window header. class ASH_PUBLIC_EXPORT FrameHeader { @@ -73,7 +76,7 @@ void SetLeftHeaderView(views::View* view); void SetBackButton(views::FrameCaptionButton* view); views::FrameCaptionButton* GetBackButton() const; - const CaptionButtonModel* GetCaptionButtonModel() const; + const chromeos::CaptionButtonModel* GetCaptionButtonModel() const; // Updates the frame header painting to reflect a change in frame colors. virtual void UpdateFrameColors() = 0; @@ -86,7 +89,7 @@ views::View* view() { return view_; } - FrameCaptionButtonContainerView* caption_button_container() { + chromeos::FrameCaptionButtonContainerView* caption_button_container() { return caption_button_container_; } @@ -106,7 +109,7 @@ void PaintTitleBar(gfx::Canvas* canvas); void SetCaptionButtonContainer( - FrameCaptionButtonContainerView* caption_button_container); + chromeos::FrameCaptionButtonContainerView* caption_button_container); Mode mode() const { return mode_; } @@ -137,7 +140,8 @@ views::View* view_; views::FrameCaptionButton* back_button_ = nullptr; // May remain nullptr. views::View* left_header_view_ = nullptr; // May remain nullptr. - FrameCaptionButtonContainerView* caption_button_container_ = nullptr; + chromeos::FrameCaptionButtonContainerView* caption_button_container_ = + nullptr; FrameAnimatorView* frame_animator_ = nullptr; // owned by view tree. // The height of the header to paint.
diff --git a/ash/public/cpp/metrics_util.cc b/ash/public/cpp/metrics_util.cc index 158c67d..eb2ad06 100644 --- a/ash/public/cpp/metrics_util.cc +++ b/ash/public/cpp/metrics_util.cc
@@ -15,29 +15,27 @@ bool g_data_collection_enabled = false; -std::vector<cc::FrameSequenceMetrics::ThroughputData>& GetDataCollector() { +std::vector<cc::FrameSequenceMetrics::CustomReportData>& GetDataCollector() { static base::NoDestructor< - std::vector<cc::FrameSequenceMetrics::ThroughputData>> + std::vector<cc::FrameSequenceMetrics::CustomReportData>> data; return *data; } void CollectDataAndForwardReport( ReportCallback callback, - const cc::FrameSequenceMetrics::ThroughputData throughput) { + const cc::FrameSequenceMetrics::CustomReportData& data) { // An arbitrary cap on the maximum number of animations being collected. DCHECK_LT(GetDataCollector().size(), 1000u); - GetDataCollector().push_back(throughput); - std::move(callback).Run(throughput); + GetDataCollector().push_back(data); + std::move(callback).Run(data); } // Calculates smoothness from |throughput| and sends to |callback|. void ForwardSmoothness(SmoothnessCallback callback, - cc::FrameSequenceMetrics::ThroughputData throughput) { - const int smoothness = std::floor(100.0f * throughput.frames_produced / - throughput.frames_expected); - callback.Run(smoothness); + const cc::FrameSequenceMetrics::CustomReportData& data) { + callback.Run(CalculateSmoothness(data)); } } // namespace @@ -58,14 +56,23 @@ g_data_collection_enabled = true; } -std::vector<cc::FrameSequenceMetrics::ThroughputData> StopDataCollection() { +std::vector<cc::FrameSequenceMetrics::CustomReportData> StopDataCollection() { DCHECK(g_data_collection_enabled); g_data_collection_enabled = false; - std::vector<cc::FrameSequenceMetrics::ThroughputData> data; + std::vector<cc::FrameSequenceMetrics::CustomReportData> data; data.swap(GetDataCollector()); return data; } +int CalculateSmoothness( + const cc::FrameSequenceMetrics::CustomReportData& data) { + return std::floor(100.0f * data.frames_produced / data.frames_expected); +} + +int CalculateJank(const cc::FrameSequenceMetrics::CustomReportData& data) { + return std::floor(100.0f * data.jank_count / data.frames_expected); +} + } // namespace metrics_util } // namespace ash
diff --git a/ash/public/cpp/metrics_util.h b/ash/public/cpp/metrics_util.h index 763be081..e0e51261 100644 --- a/ash/public/cpp/metrics_util.h +++ b/ash/public/cpp/metrics_util.h
@@ -14,8 +14,8 @@ namespace ash { namespace metrics_util { -using ReportCallback = - base::RepeatingCallback<void(cc::FrameSequenceMetrics::ThroughputData)>; +using ReportCallback = base::RepeatingCallback<void( + const cc::FrameSequenceMetrics::CustomReportData&)>; using SmoothnessCallback = base::RepeatingCallback<void(int smoothness)>; // Returns a ReportCallback that could be passed to ui::ThroughputTracker @@ -31,9 +31,17 @@ ASH_PUBLIC_EXPORT void StartDataCollection(); // Stops data collection and returns the data collected since starting. -ASH_PUBLIC_EXPORT std::vector<cc::FrameSequenceMetrics::ThroughputData> +ASH_PUBLIC_EXPORT std::vector<cc::FrameSequenceMetrics::CustomReportData> StopDataCollection(); +// Returns smoothness calculated from given data. +ASH_PUBLIC_EXPORT int CalculateSmoothness( + const cc::FrameSequenceMetrics::CustomReportData& data); + +// Returns jank percentage calculated from given data. +ASH_PUBLIC_EXPORT int CalculateJank( + const cc::FrameSequenceMetrics::CustomReportData& data); + } // namespace metrics_util } // namespace ash
diff --git a/ash/public/cpp/metrics_util_unittest.cc b/ash/public/cpp/metrics_util_unittest.cc index 912b538..f62dc8c 100644 --- a/ash/public/cpp/metrics_util_unittest.cc +++ b/ash/public/cpp/metrics_util_unittest.cc
@@ -13,9 +13,9 @@ namespace metrics_util { TEST(MetricsUtilTest, ReportSmoothness) { - cc::FrameSequenceMetrics::ThroughputData throughput_data; - throughput_data.frames_produced = 30; - throughput_data.frames_expected = 60; + cc::FrameSequenceMetrics::CustomReportData report_data; + report_data.frames_produced = 30; + report_data.frames_expected = 60; constexpr int kExpectedSmoothes = 50; base::Optional<int> reported_smoothness; @@ -48,7 +48,7 @@ reported_smoothness.reset(); ReportCallback report_callback = ForSmoothness(smoothness_callback, test.exclude_from_collection); - report_callback.Run(throughput_data); + report_callback.Run(report_data); ASSERT_TRUE(reported_smoothness.has_value()); EXPECT_EQ(kExpectedSmoothes, reported_smoothness.value());
diff --git a/ash/shell.h b/ash/shell.h index cfee3fe..f47bc16d 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -32,6 +32,10 @@ class Window; } // namespace aura +namespace chromeos { +class SnapController; +} // namespace chromeos + namespace dbus { class Bus; } @@ -175,7 +179,6 @@ class ShellObserver; class ShutdownControllerImpl; class SmsObserver; -class SnapController; class StickyKeysController; class SystemGestureEventFilter; class SystemModalContainerEventFilter; @@ -829,7 +832,7 @@ std::unique_ptr<DockedMagnifierControllerImpl> docked_magnifier_controller_; - std::unique_ptr<SnapController> snap_controller_; + std::unique_ptr<chromeos::SnapController> snap_controller_; // |native_cursor_manager_| is owned by |cursor_manager_|, but we keep a // pointer to vend to test code.
diff --git a/ash/system/bluetooth/bluetooth_detailed_view.cc b/ash/system/bluetooth/bluetooth_detailed_view.cc index 0e9cbf7..24e71b9c38 100644 --- a/ash/system/bluetooth/bluetooth_detailed_view.cc +++ b/ash/system/bluetooth/bluetooth_detailed_view.cc
@@ -4,20 +4,22 @@ #include "ash/system/bluetooth/bluetooth_detailed_view.h" -#include <map> #include <memory> +#include <unordered_map> #include <utility> #include "ash/public/cpp/system_tray_client.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" +#include "ash/style/ash_color_provider.h" #include "ash/system/machine_learning/user_settings_event_logger.h" #include "ash/system/model/system_tray_model.h" #include "ash/system/tray/hover_highlight_view.h" #include "ash/system/tray/tray_info_label.h" #include "ash/system/tray/tray_popup_item_style.h" #include "ash/system/tray/tray_popup_utils.h" +#include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "services/device/public/cpp/bluetooth/bluetooth_utils.h" #include "ui/base/l10n/l10n_util.h" @@ -110,15 +112,21 @@ } } +HoverHighlightView* GetScrollListItemForDevice( + const std::unordered_map<HoverHighlightView*, BluetoothAddress>& device_map, + const BluetoothAddress& address) { + for (const auto& view_and_address : device_map) { + if (view_and_address.second == address) + return view_and_address.first; + } + return nullptr; +} + } // namespace BluetoothDetailedView::BluetoothDetailedView(DetailedViewDelegate* delegate, LoginStatus login) - : TrayDetailedView(delegate), - login_(login), - toggle_(nullptr), - settings_(nullptr), - disabled_panel_(nullptr) { + : TrayDetailedView(delegate), login_(login) { CreateItems(); } @@ -180,31 +188,50 @@ for (const auto& device : paired_not_connected_devices) paired_not_connected_devices_.push_back(device->Clone()); - base::Optional<BluetoothAddress> focused_device_address = - GetFocusedDeviceAddress(); - + // Keep track of previous device_map_ so that existing scroll list + // item views can be re-used. This is required for a11y so that + // keyboard focus and screen-reader call outs are not disrupted + // by frequent device list updates. + std::unordered_map<HoverHighlightView*, BluetoothAddress> old_device_map = + device_map_; device_map_.clear(); - scroll_content()->RemoveAllChildViews(true); // Add paired devices and their section header to the list. bool has_paired_devices = !connected_devices.empty() || !connecting_devices.empty() || !paired_not_connected_devices.empty(); + int index = 0; if (has_paired_devices) { - AddScrollListSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_DEVICES); - AppendSameTypeDevicesToScrollList(connected_devices, true, true); - AppendSameTypeDevicesToScrollList(connecting_devices, true, false); - AppendSameTypeDevicesToScrollList(paired_not_connected_devices, false, - false); + paired_devices_heading_ = + AddSubHeading(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_DEVICES, + paired_devices_heading_, index++); + index = AddSameTypeDevicesToScrollList(connected_devices, old_device_map, + index, true, true); + index = AddSameTypeDevicesToScrollList(connecting_devices, old_device_map, + index, true, false); + index = AddSameTypeDevicesToScrollList(paired_not_connected_devices, + old_device_map, index, false, false); + } else if (paired_devices_heading_) { + scroll_content()->RemoveChildView(paired_devices_heading_); + paired_devices_heading_ = nullptr; } // Add unpaired devices to the list. If at least one paired device is // present, also add a section header above the unpaired devices. if (!discovered_not_paired_devices.empty()) { - if (has_paired_devices) - AddScrollListSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_UNPAIRED_DEVICES); - AppendSameTypeDevicesToScrollList(discovered_not_paired_devices, false, - false); + if (has_paired_devices) { + unpaired_devices_heading_ = + AddSubHeading(IDS_ASH_STATUS_TRAY_BLUETOOTH_UNPAIRED_DEVICES, + unpaired_devices_heading_, index++); + } + index = AddSameTypeDevicesToScrollList(discovered_not_paired_devices, + old_device_map, index, false, false); + } + + if (unpaired_devices_heading_ && + (discovered_not_paired_devices.empty() || !has_paired_devices)) { + scroll_content()->RemoveChildView(unpaired_devices_heading_); + unpaired_devices_heading_ = nullptr; } // Show user Bluetooth state if there is no bluetooth devices in list. @@ -213,9 +240,12 @@ nullptr /* delegate */, IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING)); } - // Focus the device which was focused before the device-list update. - if (focused_device_address) - FocusDeviceByAddress(focused_device_address.value()); + // Remove views for devices from old_device_map that are not in device_map_. + for (auto& view_and_address : old_device_map) { + if (device_map_.find(view_and_address.first) == device_map_.end()) { + scroll_content()->RemoveChildView(view_and_address.first); + } + } scroll_content()->InvalidateLayout(); @@ -236,15 +266,38 @@ CreateTitleRow(IDS_ASH_STATUS_TRAY_BLUETOOTH); } -void BluetoothDetailedView::AppendSameTypeDevicesToScrollList( +TriView* BluetoothDetailedView::AddSubHeading(int text_id, + TriView* sub_heading_view, + int child_index) { + if (!sub_heading_view) { + sub_heading_view = AddScrollListSubHeader(text_id); + } + scroll_content()->ReorderChildView(sub_heading_view, child_index); + return sub_heading_view; +} + +int BluetoothDetailedView::AddSameTypeDevicesToScrollList( const BluetoothDeviceList& list, + const std::unordered_map<HoverHighlightView*, BluetoothAddress>& + old_device_list, + int child_index, bool highlight, bool checked) { for (const auto& device : list) { const gfx::VectorIcon& icon = GetBluetoothDeviceIcon(device->device_type, device->connection_state); - HoverHighlightView* container = AddScrollListItem( - icon, device::GetBluetoothDeviceNameForDisplay(device)); + base::string16 device_name = + device::GetBluetoothDeviceNameForDisplay(device); + HoverHighlightView* container = + GetScrollListItemForDevice(old_device_list, device->address); + if (!container) { + container = AddScrollListItem(icon, device_name); + } else { + container->text_label()->SetText(device_name); + container->left_icon()->SetImage(gfx::CreateVectorIcon( + icon, AshColorProvider::Get()->GetContentLayerColor( + AshColorProvider::ContentLayerType::kIconColorPrimary))); + } container->SetAccessibleName( device::GetBluetoothDeviceLabelForAccessibility(device)); switch (device->connection_state) { @@ -261,8 +314,10 @@ : base::nullopt); break; } + scroll_content()->ReorderChildView(container, child_index++); device_map_[container] = device->address; } + return child_index; } bool BluetoothDetailedView::FoundDevice( @@ -277,11 +332,9 @@ void BluetoothDetailedView::UpdateClickedDevice( const BluetoothAddress& device_address, - views::View* item_container) { + HoverHighlightView* item_container) { if (FoundDevice(device_address, paired_not_connected_devices_)) { - HoverHighlightView* container = - static_cast<HoverHighlightView*>(item_container); - SetupConnectingScrollListItem(container); + SetupConnectingScrollListItem(item_container); scroll_content()->SizeToPreferredSize(); scroller()->Layout(); } @@ -318,8 +371,9 @@ if (helper->GetBluetoothState() != BluetoothSystem::State::kPoweredOn) return; - std::map<views::View*, BluetoothAddress>::iterator find; - find = device_map_.find(view); + HoverHighlightView* container = static_cast<HoverHighlightView*>(view); + std::unordered_map<HoverHighlightView*, BluetoothAddress>::iterator find; + find = device_map_.find(container); if (find == device_map_.end()) return; @@ -327,7 +381,7 @@ if (FoundDevice(device_address, connecting_devices_)) return; - UpdateClickedDevice(device_address, view); + UpdateClickedDevice(device_address, container); LogUserBluetoothEvent(device_address); helper->ConnectToBluetoothDevice(device_address); }
diff --git a/ash/system/bluetooth/bluetooth_detailed_view.h b/ash/system/bluetooth/bluetooth_detailed_view.h index 2001148..e880925b 100644 --- a/ash/system/bluetooth/bluetooth_detailed_view.h +++ b/ash/system/bluetooth/bluetooth_detailed_view.h
@@ -5,7 +5,7 @@ #ifndef ASH_SYSTEM_BLUETOOTH_BLUETOOTH_DETAILED_VIEW_H_ #define ASH_SYSTEM_BLUETOOTH_BLUETOOTH_DETAILED_VIEW_H_ -#include <map> +#include <unordered_map> #include "ash/login_status.h" #include "ash/system/bluetooth/tray_bluetooth_helper.h" @@ -17,6 +17,9 @@ } // namespace views namespace ash { + +class TriView; + namespace tray { class BluetoothDetailedView : public TrayDetailedView { @@ -53,9 +56,23 @@ private: void CreateItems(); - void AppendSameTypeDevicesToScrollList(const BluetoothDeviceList& list, - bool highlight, - bool checked); + // Adds subheading with given |text_id| at given |child_index|. If + // |sub_heading_view| is nullptr, then a new view is created. Returns + // |sub_heading_view| or the newly created view. + TriView* AddSubHeading(int text_id, + TriView* sub_heading_view, + int child_index); + + // Adds devices from |list| into the scroll list at given |child_index|. + // To avoid disrupting a11y, list items are re-used from |old_device_list| if + // it exists. Returns index position for next scroll list item. + int AddSameTypeDevicesToScrollList( + const BluetoothDeviceList& list, + const std::unordered_map<HoverHighlightView*, BluetoothAddress>& + old_device_list, + int child_index, + bool highlight, + bool checked); // Returns true if the device with |device_id| is found in |device_list|. bool FoundDevice(const BluetoothAddress& device_id, @@ -64,7 +81,7 @@ // Updates UI of the clicked bluetooth device to show it is being connected // or disconnected if such an operation is going to be performed underway. void UpdateClickedDevice(const BluetoothAddress& device_id, - views::View* item_container); + HoverHighlightView* item_container); void ShowSettings(); @@ -80,17 +97,20 @@ // TODO(jamescook): Don't cache this. LoginStatus login_; - std::map<views::View*, BluetoothAddress> device_map_; + std::unordered_map<HoverHighlightView*, BluetoothAddress> device_map_; BluetoothDeviceList connecting_devices_; BluetoothDeviceList paired_not_connected_devices_; - views::ToggleButton* toggle_; - views::Button* settings_; + views::ToggleButton* toggle_ = nullptr; + views::Button* settings_ = nullptr; + + TriView* paired_devices_heading_ = nullptr; + TriView* unpaired_devices_heading_ = nullptr; // The container of the message "Bluetooth is disabled" and an icon. It should // be shown instead of Bluetooth device list when Bluetooth is disabled. - views::View* disabled_panel_; + views::View* disabled_panel_ = nullptr; DISALLOW_COPY_AND_ASSIGN(BluetoothDetailedView); };
diff --git a/ash/system/holding_space/holding_space_item_view.cc b/ash/system/holding_space/holding_space_item_view.cc index 669575c5..eb0fd05 100644 --- a/ash/system/holding_space/holding_space_item_view.cc +++ b/ash/system/holding_space/holding_space_item_view.cc
@@ -137,6 +137,12 @@ return AshColorProvider::Get()->GetRippleAttributes().base_color; } +bool HoldingSpaceItemView::HandleAccessibleAction( + const ui::AXActionData& action_data) { + return delegate_->OnHoldingSpaceItemViewAccessibleAction(this, action_data) || + views::InkDropHostView::HandleAccessibleAction(action_data); +} + void HoldingSpaceItemView::OnBoundsChanged(const gfx::Rect& previous_bounds) { gfx::Rect bounds = GetLocalBounds(); selected_layer_owner_->layer()->SetBounds(bounds);
diff --git a/ash/system/holding_space/holding_space_item_view.h b/ash/system/holding_space/holding_space_item_view.h index cfea1d6..a2536892 100644 --- a/ash/system/holding_space/holding_space_item_view.h +++ b/ash/system/holding_space/holding_space_item_view.h
@@ -39,6 +39,7 @@ // views::InkDropHostView: SkColor GetInkDropBaseColor() const override; + bool HandleAccessibleAction(const ui::AXActionData& action_data) override; void OnBoundsChanged(const gfx::Rect& previous_bounds) override; void OnFocus() override; void OnBlur() override;
diff --git a/ash/system/holding_space/holding_space_item_view_delegate.cc b/ash/system/holding_space/holding_space_item_view_delegate.cc index faab9b22..b185ffe 100644 --- a/ash/system/holding_space/holding_space_item_view_delegate.cc +++ b/ash/system/holding_space/holding_space_item_view_delegate.cc
@@ -4,7 +4,6 @@ #include "ash/system/holding_space/holding_space_item_view_delegate.h" -#include "ash/accessibility/accessibility_controller_impl.h" #include "ash/public/cpp/holding_space/holding_space_client.h" #include "ash/public/cpp/holding_space/holding_space_constants.h" #include "ash/public/cpp/holding_space/holding_space_controller.h" @@ -12,11 +11,12 @@ #include "ash/public/cpp/holding_space/holding_space_metrics.h" #include "ash/public/cpp/holding_space/holding_space_model.h" #include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/system/holding_space/holding_space_item_view.h" #include "base/bind.h" #include "net/base/mime_util.h" +#include "ui/accessibility/ax_action_data.h" +#include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/simple_menu_model.h" @@ -71,6 +71,21 @@ views_.push_back(view); } +bool HoldingSpaceItemViewDelegate::OnHoldingSpaceItemViewAccessibleAction( + HoldingSpaceItemView* view, + const ui::AXActionData& action_data) { + // When performing the default accessible action (e.g. Search + Space), we + // open the selected holding space items. If `view` is not part of the current + // selection it will become the entire selection. + if (action_data.action == ax::mojom::Action::kDoDefault) { + if (!view->selected()) + SetSelection(view); + OpenItems(GetSelection()); + return true; + } + return false; +} + void HoldingSpaceItemViewDelegate::OnHoldingSpaceItemViewGestureEvent( HoldingSpaceItemView* view, const ui::GestureEvent& event) { @@ -109,19 +124,6 @@ // clear any view that we had cached to ignore mouse released events for. ignore_mouse_released_ = nullptr; - // If ChromeVox is enabled, we assume this mouse `event` to be a result of - // having pressed Search + Space. In this case, we'll open the selected - // holding space items. If the "pressed" `view` is not part of the current - // selection it will become the entire selection. - const bool spoken_feedback_enabled = - Shell::Get()->accessibility_controller()->spoken_feedback().enabled(); - if (spoken_feedback_enabled) { - if (!view->selected()) - SetSelection(view); - OpenItems(GetSelection()); - return true; - } - // If the `view` is already selected, mouse press is a no-op. Actions taken on // selected views are performed on mouse released in order to give drag/drop // a chance to take effect (assuming that drag thresholds are met).
diff --git a/ash/system/holding_space/holding_space_item_view_delegate.h b/ash/system/holding_space/holding_space_item_view_delegate.h index 771e7d28..006f224 100644 --- a/ash/system/holding_space/holding_space_item_view_delegate.h +++ b/ash/system/holding_space/holding_space_item_view_delegate.h
@@ -50,6 +50,12 @@ // Invoked when `view` has been created. void OnHoldingSpaceItemViewCreated(HoldingSpaceItemView* view); + // Invoked when `view` should perform an accessible action. Returns true if + // the action is handled, otherwise false. + bool OnHoldingSpaceItemViewAccessibleAction( + HoldingSpaceItemView* view, + const ui::AXActionData& action_data); + // Invoked when `view` receives the specified gesture `event`. void OnHoldingSpaceItemViewGestureEvent(HoldingSpaceItemView* view, const ui::GestureEvent& event);
diff --git a/ash/system/holding_space/holding_space_tray.cc b/ash/system/holding_space/holding_space_tray.cc index ced25cf..e5878513 100644 --- a/ash/system/holding_space/holding_space_tray.cc +++ b/ash/system/holding_space/holding_space_tray.cc
@@ -75,7 +75,8 @@ // Activate the bubble for a11y or if it was shown via keypress. Otherwise // focus will remain on the tray when it should enter the bubble. - if (event.IsKeyEvent() || (event.flags() & ui::EF_TOUCH_ACCESSIBILITY)) { + if (event.IsKeyEvent() || + Shell::Get()->accessibility_controller()->spoken_feedback().enabled()) { DCHECK(bubble_ && bubble_->GetBubbleWidget()); bubble_->GetBubbleWidget()->widget_delegate()->SetCanActivate(true); bubble_->GetBubbleWidget()->Activate();
diff --git a/ash/system/phonehub/notification_opt_in_view.cc b/ash/system/phonehub/notification_opt_in_view.cc index 7e376e3..c75bea62 100644 --- a/ash/system/phonehub/notification_opt_in_view.cc +++ b/ash/system/phonehub/notification_opt_in_view.cc
@@ -40,11 +40,11 @@ constexpr int kDismissButtonTag = 1; constexpr int kSetUpButtonTag = 2; -// URL of the multidevice settings page. -// TODO(crbug.com/1126208): update to the direct link to the Phone Hub -// notification set up dialog. +// URL of the multidevice settings page with the URL parameter that will +// start up the opt-in-flow. constexpr char kMultideviceSettingsUrl[] = - "chrome://os-settings/multidevice/features"; + "chrome://os-settings/multidevice/" + "features?showNotificationAccessSetupDialog"; } // namespace
diff --git a/ash/system/phonehub/phone_hub_notification_controller.cc b/ash/system/phonehub/phone_hub_notification_controller.cc index 51a94a5..4a5a1567 100644 --- a/ash/system/phonehub/phone_hub_notification_controller.cc +++ b/ash/system/phonehub/phone_hub_notification_controller.cc
@@ -9,6 +9,7 @@ #include "ash/strings/grit/ash_strings.h" #include "ash/system/model/system_tray_model.h" #include "ash/system/tray/tray_popup_utils.h" +#include "base/bind.h" #include "base/logging.h" #include "base/memory/weak_ptr.h" #include "base/strings/strcat.h" @@ -19,14 +20,35 @@ #include "ui/message_center/message_center.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_delegate.h" +#include "ui/message_center/views/message_view_factory.h" +#include "ui/message_center/views/notification_header_view.h" +#include "ui/message_center/views/notification_view_md.h" namespace ash { namespace { const char kNotifierId[] = "chrome://phonehub"; const char kNotifierIdSeparator[] = "-"; +const char kNotificationCustomViewType[] = "phonehub"; const int kReplyButtonIndex = 0; const int kCancelButtonIndex = 1; + +std::unique_ptr<message_center::MessageView> CreateCustomNotificationView( + const message_center::Notification& notification) { + DCHECK_EQ(kNotificationCustomViewType, notification.custom_view_type()); + + std::unique_ptr<message_center::NotificationViewMD> notification_view = + std::make_unique<message_center::NotificationViewMD>(notification); + message_center::NotificationHeaderView* header_row = + static_cast<message_center::NotificationHeaderView*>( + notification_view->GetViewByID( + message_center::NotificationViewMD::kHeaderRow)); + header_row->SetSummaryText(l10n_util::GetStringUTF16( + IDS_ASH_PHONE_HUB_NOTIFICATION_FROM_PHONE_TITLE)); + + return notification_view; +} + } // namespace // Delegate for the displayed ChromeOS notification. @@ -101,7 +123,11 @@ base::WeakPtrFactory<NotificationDelegate> weak_ptr_factory_{this}; }; -PhoneHubNotificationController::PhoneHubNotificationController() = default; +PhoneHubNotificationController::PhoneHubNotificationController() { + message_center::MessageViewFactory::SetCustomNotificationViewFactory( + kNotificationCustomViewType, + base::BindRepeating(&CreateCustomNotificationView)); +} PhoneHubNotificationController::~PhoneHubNotificationController() { if (manager_) @@ -178,6 +204,7 @@ NotificationDelegate* delegate = notification_map_[phone_hub_id].get(); auto cros_notification = CreateNotification(notification, cros_id, delegate); + cros_notification->set_custom_view_type(kNotificationCustomViewType); auto* message_center = message_center::MessageCenter::Get(); if (notification_already_exists) @@ -194,7 +221,7 @@ message_center::NotifierId notifier_id( message_center::NotifierType::SYSTEM_COMPONENT, kNotifierId); - auto notification_type = message_center::NOTIFICATION_TYPE_SIMPLE; + auto notification_type = message_center::NOTIFICATION_TYPE_CUSTOM; base::string16 title = notification->title().value_or(base::string16()); base::string16 message = @@ -208,10 +235,8 @@ optional_fields.timestamp = notification->timestamp(); auto shared_image = notification->shared_image(); - if (shared_image.has_value()) { + if (shared_image.has_value()) optional_fields.image = shared_image.value(); - notification_type = message_center::NOTIFICATION_TYPE_IMAGE; - } const gfx::Image& icon = notification->contact_image().value_or(gfx::Image());
diff --git a/ash/system/phonehub/phone_hub_tray_unittest.cc b/ash/system/phonehub/phone_hub_tray_unittest.cc index db56ec9..0dd5ddc 100644 --- a/ash/system/phonehub/phone_hub_tray_unittest.cc +++ b/ash/system/phonehub/phone_hub_tray_unittest.cc
@@ -177,7 +177,9 @@ // for the notification set up flow. EXPECT_CALL(new_window_delegate(), NewTabWithUrl) .WillOnce([](const GURL& url, bool from_user_interaction) { - EXPECT_EQ(GURL("chrome://os-settings/multidevice/features"), url); + EXPECT_EQ(GURL("chrome://os-settings/multidevice/" + "features?showNotificationAccessSetupDialog"), + url); EXPECT_TRUE(from_user_interaction); });
diff --git a/ash/system/unified/media_controls_chip_view.cc b/ash/system/unified/media_controls_chip_view.cc deleted file mode 100644 index 3e679d7..0000000 --- a/ash/system/unified/media_controls_chip_view.cc +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/unified/media_controls_chip_view.h" - -#include "ash/style/ash_color_provider.h" -#include "ui/gfx/canvas.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" - -namespace ash { - -namespace { -constexpr int kMediaControlsChipContainerRadius = 8; -constexpr gfx::Insets kMediaControlsChipViewPadding(8, 16, 11, 16); -constexpr gfx::Insets kMediaControlsChipContainerPadding(8); -constexpr int kMediaControlsChipSpacing = 16; -} // namespace - -MediaControlsChipView::MediaControlsChipView() - : artwork_view_(new views::ImageView), - title_artist_view_(new views::View), - title_label_(new views::Label), - artist_label_(new views::Label) { - auto* container = SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal, - kMediaControlsChipViewPadding + kMediaControlsChipContainerPadding, - kMediaControlsChipSpacing)); - container->set_cross_axis_alignment( - views::BoxLayout::CrossAxisAlignment::kCenter); - - AddChildView(artwork_view_); - - auto* title_artist_container = - title_artist_view_->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, gfx::Insets(), 0)); - title_artist_container->set_main_axis_alignment( - views::BoxLayout::MainAxisAlignment::kCenter); - title_artist_container->set_cross_axis_alignment( - views::BoxLayout::CrossAxisAlignment::kStart); - - title_label_->SetAutoColorReadabilityEnabled(false); - title_label_->SetSubpixelRenderingEnabled(false); - title_label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorPrimary)); - title_artist_view_->AddChildView(title_label_); - - artist_label_->SetAutoColorReadabilityEnabled(false); - artist_label_->SetSubpixelRenderingEnabled(false); - artist_label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor( - AshColorProvider::ContentLayerType::kTextColorSecondary)); - title_artist_view_->AddChildView(artist_label_); - - AddChildView(title_artist_view_); -} - -MediaControlsChipView::~MediaControlsChipView() {} - -void MediaControlsChipView::OnPaintBackground(gfx::Canvas* canvas) { - cc::PaintFlags flags; - flags.setAntiAlias(true); - flags.setColor(AshColorProvider::Get()->GetControlsLayerColor( - AshColorProvider::ControlsLayerType::kControlBackgroundColorInactive)); - gfx::Rect bounds = GetContentsBounds(); - bounds.Inset(kMediaControlsChipViewPadding); - canvas->DrawRoundRect(bounds, kMediaControlsChipContainerRadius, flags); - views::View::OnPaintBackground(canvas); -} - -void MediaControlsChipView::SetExpandedAmount(double expanded_amount) { - DCHECK(0.0 <= expanded_amount && expanded_amount <= 1.0); - SetVisible(expanded_amount > 0.0); - InvalidateLayout(); - // TODO(leandre): add animation and opacity when collapsing/expanding the - // tray. -} - -const char* MediaControlsChipView::GetClassName() const { - return "MediaControlsChipView"; -} - -} // namespace ash
diff --git a/ash/system/unified/media_controls_chip_view.h b/ash/system/unified/media_controls_chip_view.h deleted file mode 100644 index 43c54c0..0000000 --- a/ash/system/unified/media_controls_chip_view.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_UNIFIED_MEDIA_CONTROLS_CHIP_VIEW_H_ -#define ASH_SYSTEM_UNIFIED_MEDIA_CONTROLS_CHIP_VIEW_H_ - -#include "ash/ash_export.h" -#include "services/media_session/public/mojom/media_session.mojom.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/image_button.h" -#include "ui/views/view.h" - -namespace views { -class Label; -class ImageView; -} // namespace views - -namespace ash { - -// A media controls chip in UnifiedSystemTray bubble. It shows -// information and basic controls of the media currently playing. -class ASH_EXPORT MediaControlsChipView : public views::View { - public: - MediaControlsChipView(); - ~MediaControlsChipView() override; - MediaControlsChipView(MediaControlsChipView&) = delete; - MediaControlsChipView operator=(MediaControlsChipView&) = delete; - - // views::View: - void OnPaintBackground(gfx::Canvas* canvas) override; - - // Change the expanded state. 0.0 if collapsed, and 1.0 if expanded. - // Otherwise, it shows intermediate state. If collapsed, the media controls - // are hidden. - void SetExpandedAmount(double expanded_amount); - - const char* GetClassName() const override; - - private: - views::ImageView* artwork_view_ = nullptr; - views::View* title_artist_view_ = nullptr; - - views::Label* title_label_ = nullptr; - views::Label* artist_label_ = nullptr; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_UNIFIED_MEDIA_CONTROLS_CHIP_VIEW_H_
diff --git a/ash/wm/overview/overview_controller_unittest.cc b/ash/wm/overview/overview_controller_unittest.cc index 6a870bb..4ea005f 100644 --- a/ash/wm/overview/overview_controller_unittest.cc +++ b/ash/wm/overview/overview_controller_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "ash/app_list/test/app_list_test_helper.h" +#include "ash/frame_throttler/frame_throttling_controller.h" #include "ash/frame_throttler/mock_frame_throttling_observer.h" #include "ash/keyboard/ui/keyboard_ui_controller.h" #include "ash/keyboard/ui/keyboard_util.h" @@ -689,13 +690,14 @@ std::unique_ptr<aura::Window> created_windows[window_count]; std::vector<aura::Window*> windows(window_count, nullptr); for (int i = 0; i < window_count; ++i) { - created_windows[i] = CreateTestWindow(); + created_windows[i] = CreateAppWindow(gfx::Rect(), AppType::BROWSER); windows[i] = created_windows[i].get(); } auto* controller = Shell::Get()->overview_controller(); - EXPECT_CALL(observer, - OnThrottlingStarted(testing::UnorderedElementsAreArray(windows))); + EXPECT_CALL(observer, OnThrottlingStarted( + testing::UnorderedElementsAreArray(windows), + frame_throttling_controller->throttled_fps())); controller->StartOverview(); EXPECT_CALL(observer, OnThrottlingEnded());
diff --git a/ash/wm/overview/overview_grid_unittest.cc b/ash/wm/overview/overview_grid_unittest.cc index 43c43d9..2a48b15 100644 --- a/ash/wm/overview/overview_grid_unittest.cc +++ b/ash/wm/overview/overview_grid_unittest.cc
@@ -4,6 +4,7 @@ #include "ash/wm/overview/overview_grid.h" +#include "ash/frame_throttler/frame_throttling_controller.h" #include "ash/frame_throttler/mock_frame_throttling_observer.h" #include "ash/screen_util.h" #include "ash/shell.h" @@ -295,23 +296,26 @@ testing::NiceMock<MockFrameThrottlingObserver> observer; FrameThrottlingController* frame_throttling_controller = Shell::Get()->frame_throttling_controller(); + uint8_t throttled_fps = frame_throttling_controller->throttled_fps(); frame_throttling_controller->AddObserver(&observer); const int window_count = 5; std::unique_ptr<aura::Window> created_windows[window_count]; std::vector<aura::Window*> windows(window_count, nullptr); for (int i = 0; i < window_count; ++i) { - created_windows[i] = CreateTestWindow(); + created_windows[i] = CreateAppWindow(gfx::Rect(), AppType::BROWSER); windows[i] = created_windows[i].get(); } InitializeGrid(windows); frame_throttling_controller->StartThrottling(windows); // Add a new window to overview. - std::unique_ptr<aura::Window> new_window(CreateTestWindow()); + std::unique_ptr<aura::Window> new_window( + CreateAppWindow(gfx::Rect(), AppType::BROWSER)); windows.push_back(new_window.get()); EXPECT_CALL(observer, OnThrottlingEnded()); EXPECT_CALL(observer, - OnThrottlingStarted(testing::UnorderedElementsAreArray(windows))); + OnThrottlingStarted(testing::UnorderedElementsAreArray(windows), + throttled_fps)); grid()->AppendItem(new_window.get(), /*reposition=*/false, /*animate=*/false, /*use_spawn_animation=*/false); @@ -320,8 +324,9 @@ aura::Window* window = windows[0]; windows.erase(windows.begin()); EXPECT_CALL(observer, OnThrottlingEnded()); - EXPECT_CALL(observer, OnThrottlingStarted( - testing::UnorderedElementsAreArray(windows))); + EXPECT_CALL(observer, + OnThrottlingStarted(testing::UnorderedElementsAreArray(windows), + throttled_fps)); OverviewItem* item = grid()->GetOverviewItemContaining(window); grid()->RemoveItem(item, /*item_destroying=*/false, /*reposition=*/false); }
diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc index 79ab60bb..aafbfef9 100644 --- a/ash/wm/window_cycle_controller_unittest.cc +++ b/ash/wm/window_cycle_controller_unittest.cc
@@ -9,6 +9,7 @@ #include "ash/app_list/test/app_list_test_helper.h" #include "ash/focus_cycler.h" +#include "ash/frame_throttler/frame_throttling_controller.h" #include "ash/frame_throttler/mock_frame_throttling_observer.h" #include "ash/home_screen/home_screen_controller.h" #include "ash/public/cpp/ash_features.h" @@ -1217,28 +1218,32 @@ MockFrameThrottlingObserver observer; FrameThrottlingController* frame_throttling_controller = Shell::Get()->frame_throttling_controller(); + uint8_t throttled_fps = frame_throttling_controller->throttled_fps(); frame_throttling_controller->AddObserver(&observer); const int window_count = 5; std::unique_ptr<aura::Window> created_windows[window_count]; std::vector<aura::Window*> windows(window_count, nullptr); for (int i = 0; i < window_count; ++i) { - created_windows[i] = CreateTestWindow(); + created_windows[i] = CreateAppWindow(gfx::Rect(), AppType::BROWSER); windows[i] = created_windows[i].get(); } WindowCycleController* controller = Shell::Get()->window_cycle_controller(); EXPECT_CALL(observer, - OnThrottlingStarted(testing::UnorderedElementsAreArray(windows))); + OnThrottlingStarted(testing::UnorderedElementsAreArray(windows), + throttled_fps)); controller->HandleCycleWindow(WindowCycleController::FORWARD); EXPECT_CALL(observer, - OnThrottlingStarted(testing::UnorderedElementsAreArray(windows))) + OnThrottlingStarted(testing::UnorderedElementsAreArray(windows), + throttled_fps)) .Times(0); controller->HandleCycleWindow(WindowCycleController::FORWARD); EXPECT_CALL(observer, OnThrottlingEnded()); controller->CompleteCycling(); EXPECT_CALL(observer, - OnThrottlingStarted(testing::UnorderedElementsAreArray(windows))); + OnThrottlingStarted(testing::UnorderedElementsAreArray(windows), + throttled_fps)); controller->HandleCycleWindow(WindowCycleController::FORWARD); EXPECT_CALL(observer, OnThrottlingEnded()); controller->CancelCycling();
diff --git a/base/BUILD.gn b/base/BUILD.gn index 053e868..31e2aa7 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1793,8 +1793,10 @@ "allocator/partition_allocator/yield_processor.h", ] if (is_win) { - sources += - [ "allocator/partition_allocator/page_allocator_internals_win.h" ] + sources += [ + "allocator/partition_allocator/page_allocator_internals_win.h", + "allocator/partition_allocator/partition_tls_win.cc", + ] } else if (is_posix) { sources += [ "allocator/partition_allocator/page_allocator_internals_posix.h" ] @@ -2141,6 +2143,7 @@ "trace_event/optional_trace_event.h", "trace_event/process_memory_dump.cc", "trace_event/process_memory_dump.h", + "trace_event/task_execution_macros.h", "trace_event/thread_instruction_count.cc", "trace_event/thread_instruction_count.h", "trace_event/trace_arguments.cc",
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc index 12ab036a8..0852843 100644 --- a/base/allocator/partition_allocator/partition_alloc.cc +++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -320,7 +320,7 @@ // this operation is idempotent, so there is no harm. InitBucketIndexLookup(this); -#if !defined(OS_POSIX) +#if !defined(PA_THREAD_CACHE_SUPPORTED) // TLS in ThreadCache not supported on other OSes. with_thread_cache = false; #else
diff --git a/base/allocator/partition_allocator/partition_tls.h b/base/allocator/partition_allocator/partition_tls.h index 2bf7af8..597443f 100644 --- a/base/allocator/partition_allocator/partition_tls.h +++ b/base/allocator/partition_allocator/partition_tls.h
@@ -6,12 +6,17 @@ #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TLS_H_ #include "base/allocator/partition_allocator/partition_alloc_check.h" +#include "base/compiler_specific.h" #include "build/build_config.h" #if defined(OS_POSIX) #include <pthread.h> #endif +#if defined(OS_WIN) +#include <windows.h> +#endif + // Barebones TLS implementation for use in PartitionAlloc. This doesn't use the // general chromium TLS handling to avoid dependencies, but more importantly // because it allocates memory. @@ -21,33 +26,48 @@ #if defined(OS_POSIX) typedef pthread_key_t PartitionTlsKey; -inline bool PartitionTlsCreate(PartitionTlsKey* key, - void (*destructor)(void*)) { +ALWAYS_INLINE bool PartitionTlsCreate(PartitionTlsKey* key, + void (*destructor)(void*)) { return !pthread_key_create(key, destructor); } -inline void* PartitionTlsGet(PartitionTlsKey key) { +ALWAYS_INLINE void* PartitionTlsGet(PartitionTlsKey key) { return pthread_getspecific(key); } -inline void PartitionTlsSet(PartitionTlsKey key, void* value) { +ALWAYS_INLINE void PartitionTlsSet(PartitionTlsKey key, void* value) { int ret = pthread_setspecific(key, value); PA_DCHECK(!ret); } -#else -// Not implemented. -typedef int PartitionTlsKey; +#elif defined(OS_WIN) +// Note: supports only a single TLS key on Windows. Not a hard constraint, may +// be lifted. +typedef unsigned long PartitionTlsKey; -inline bool PartitionTlsCreate(PartitionTlsKey* key, - void (*destructor)(void*)) { - // Cannot use NOIMPLEMENTED() as it may allocate. +BASE_EXPORT bool PartitionTlsCreate(PartitionTlsKey* key, + void (*destructor)(void*)); + +ALWAYS_INLINE void* PartitionTlsGet(PartitionTlsKey key) { + return TlsGetValue(key); +} + +ALWAYS_INLINE void PartitionTlsSet(PartitionTlsKey key, void* value) { + BOOL ret = TlsSetValue(key, value); + PA_DCHECK(ret); +} +#else +// Not supported. +typedef int PartitionTlsKey; +ALWAYS_INLINE bool PartitionTlsCreate(PartitionTlsKey* key, + void (*destructor)(void*)) { + // NOTIMPLEMENTED() may allocate, crash instead. IMMEDIATE_CRASH(); } -inline void* PartitionTlsGet(PartitionTlsKey key) { +ALWAYS_INLINE void* PartitionTlsGet(PartitionTlsKey key) { IMMEDIATE_CRASH(); } -inline void PartitionTlsSet(PartitionTlsKey key, void* value) { +ALWAYS_INLINE void PartitionTlsSet(PartitionTlsKey key, void* value) { IMMEDIATE_CRASH(); } -#endif // defined(OS_POSIX) +#endif // defined(OS_WIN) } // namespace internal } // namespace base
diff --git a/base/allocator/partition_allocator/partition_tls_win.cc b/base/allocator/partition_allocator/partition_tls_win.cc new file mode 100644 index 0000000..8ffc6da5 --- /dev/null +++ b/base/allocator/partition_allocator/partition_tls_win.cc
@@ -0,0 +1,101 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/allocator/partition_allocator/partition_tls.h" + +namespace base { +namespace internal { +namespace { + +// Store the key as the thread destruction callback doesn't get it. +PartitionTlsKey g_key; +void (*g_destructor)(void*) = nullptr; + +// Static callback function to call with each thread termination. +void NTAPI PartitionTlsOnThreadExit(PVOID module, + DWORD reason, + PVOID reserved) { + if (reason != DLL_THREAD_DETACH && reason != DLL_PROCESS_DETACH) + return; + + if (g_destructor) { + void* per_thread_data = PartitionTlsGet(g_key); + if (per_thread_data) + g_destructor(per_thread_data); + } +} + +} // namespace + +bool PartitionTlsCreate(PartitionTlsKey* key, void (*destructor)(void*)) { + PA_CHECK(g_destructor == nullptr); // Only one TLS key supported at a time. + PartitionTlsKey value = TlsAlloc(); + if (value != TLS_OUT_OF_INDEXES) { + *key = value; + + g_key = value; + g_destructor = destructor; + return true; + } + return false; +} + +} // namespace internal +} // namespace base + +// See thread_local_storage_win.cc for details and reference. +// +// The callback has to be in any section between .CRT$XLA and .CRT$XLZ, as these +// are sentinels used by the TLS code to find the callback array bounds. As we +// don't particularly care about where we are called but would prefer to be +// deinitialized towards the end (in particular after Chromium's TLS), we locate +// ourselves in .CRT$XLY. + +// Force a reference to _tls_used to make the linker create the TLS directory if +// it's not already there. (e.g. if __declspec(thread) is not used). Force a +// reference to partition_tls_thread_exit_callback to prevent whole program +// optimization from discarding the variable. +#ifdef _WIN64 + +#pragma comment(linker, "/INCLUDE:_tls_used") +#pragma comment(linker, "/INCLUDE:partition_tls_thread_exit_callback") + +#else // _WIN64 + +#pragma comment(linker, "/INCLUDE:__tls_used") +#pragma comment(linker, "/INCLUDE:_partition_tls_thread_exit_callback") + +#endif // _WIN64 + +// extern "C" suppresses C++ name mangling so we know the symbol name for the +// linker /INCLUDE:symbol pragma above. +extern "C" { +// The linker must not discard partition_tls_thread_exit_callback. (We force a +// reference to this variable with a linker /INCLUDE:symbol pragma to ensure +// that.) If this variable is discarded, PartitionTlsOnThreadExit will never be +// called. +#ifdef _WIN64 + +// .CRT section is merged with .rdata on x64 so it must be constant data. +#pragma const_seg(".CRT$XLY") +// When defining a const variable, it must have external linkage to be sure the +// linker doesn't discard it. +extern const PIMAGE_TLS_CALLBACK partition_tls_thread_exit_callback; +const PIMAGE_TLS_CALLBACK partition_tls_thread_exit_callback = + base::internal::PartitionTlsOnThreadExit; + +// Reset the default section. +#pragma const_seg() + +#else // _WIN64 + +#pragma data_seg(".CRT$XLY") +PIMAGE_TLS_CALLBACK partition_tls_thread_exit_callback = + base::internal::PartitionTlsOnThreadExit; + +// Reset the default section. +#pragma data_seg() + +#endif // _WIN64 +}
diff --git a/base/allocator/partition_allocator/spinning_futex_linux.h b/base/allocator/partition_allocator/spinning_futex_linux.h index 795040dd..d6f0b27 100644 --- a/base/allocator/partition_allocator/spinning_futex_linux.h +++ b/base/allocator/partition_allocator/spinning_futex_linux.h
@@ -5,6 +5,7 @@ #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_SPINNING_FUTEX_LINUX_H_ #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_SPINNING_FUTEX_LINUX_H_ +#include <algorithm> #include <atomic> #include "base/allocator/partition_allocator/yield_processor.h" @@ -65,13 +66,28 @@ ALWAYS_INLINE void SpinningFutex::Acquire() { int tries = 0; + int backoff = 1; // Busy-waiting is inlined, which is fine as long as we have few callers. This // is only used for the partition lock, so this is the case. do { if (LIKELY(Try())) return; - YIELD_PROCESSOR; - tries++; + // Note: Per the intel optimization manual + // (https://software.intel.com/content/dam/develop/public/us/en/documents/64-ia-32-architectures-optimization-manual.pdf), + // the "pause" instruction is more costly on Skylake Client than on previous + // (and subsequent?) architectures. The latency is found to be 141 cycles + // there. This is not a big issue here as we don't spin long enough for this + // to become a problem, as we spend a maximum of ~141k cycles ~= 47us at + // 3GHz in "pause". + // + // Also, loop several times here, following the guidelines in section 2.3.4 + // of the manual, "Pause latency in Skylake Client Microarchitecture". + for (int yields = 0; yields < backoff; yields++) { + YIELD_PROCESSOR; + tries++; + } + constexpr int kMaxBackoff = 64; + backoff = std::min(kMaxBackoff, backoff << 1); } while (tries < kSpinCount); LockSlow();
diff --git a/base/allocator/partition_allocator/thread_cache.h b/base/allocator/partition_allocator/thread_cache.h index 3e991b8..c499e87 100644 --- a/base/allocator/partition_allocator/thread_cache.h +++ b/base/allocator/partition_allocator/thread_cache.h
@@ -19,6 +19,11 @@ #include "base/partition_alloc_buildflags.h" #include "base/synchronization/lock.h" +// Need TLS support. +#if defined(OS_POSIX) || defined(OS_WIN) +#define PA_THREAD_CACHE_SUPPORTED +#endif + namespace base { namespace internal {
diff --git a/base/allocator/partition_allocator/thread_cache_unittest.cc b/base/allocator/partition_allocator/thread_cache_unittest.cc index ed7671c..3bef893 100644 --- a/base/allocator/partition_allocator/thread_cache_unittest.cc +++ b/base/allocator/partition_allocator/thread_cache_unittest.cc
@@ -28,7 +28,7 @@ // disable the cache (and tests) #if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \ !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) && \ - (defined(OS_LINUX) || defined(OS_CHROMEOS)) + defined(PA_THREAD_CACHE_SUPPORTED) namespace base { namespace internal { @@ -404,4 +404,4 @@ #endif // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) && - // (defined(OS_LINUX) || defined(OS_CHROMEOS)) + // defined(PA_THREAD_CACHE_SUPPORTED)
diff --git a/base/cpu_affinity_posix_unittest.cc b/base/cpu_affinity_posix_unittest.cc index aa476d67..15622c0 100644 --- a/base/cpu_affinity_posix_unittest.cc +++ b/base/cpu_affinity_posix_unittest.cc
@@ -75,8 +75,7 @@ } // namespace #if defined(OS_ANDROID) -// Flaky on Android. crbug.com/1113964 -#define MAYBE_SetThreadCpuAffinityMode DISABLED_SetThreadCpuAffinityMode +#define MAYBE_SetThreadCpuAffinityMode SetThreadCpuAffinityMode #else // The test only considers Android device hardware models at the moment. Some // CrOS devices on the waterfall have asymmetric CPUs that aren't covered. The @@ -102,6 +101,10 @@ } else if (device_model == "Pixel 3a" || device_model == "Pixel 3a XL") { expected_little_cores = 6; EXPECT_LT(expected_little_cores, expected_total_cores); + } else if (device_model == "Nexus 5") { + // On our Nexus 5 bots, something else in the system seems to set affinity + // for the test process, making these tests flaky (crbug.com/1113964). + return; } TestThread thread;
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h index d977a0da..50e0b34 100644 --- a/base/memory/weak_ptr.h +++ b/base/memory/weak_ptr.h
@@ -248,11 +248,11 @@ } T& operator*() const { - DCHECK(get() != nullptr); + CHECK(ref_.IsValid()); return *get(); } T* operator->() const { - DCHECK(get() != nullptr); + CHECK(ref_.IsValid()); return get(); }
diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc index 6b1e9bf..6425a88a 100644 --- a/base/memory/weak_ptr_unittest.cc +++ b/base/memory/weak_ptr_unittest.cc
@@ -798,4 +798,26 @@ ASSERT_DCHECK_DEATH(arrow.target.get()); } +TEST(WeakPtrDeathTest, ArrowOperatorChecksOnBadDereference) { + // The default style "fast" does not support multi-threaded tests + // (introduces deadlock on Linux). + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + + auto target = std::make_unique<Target>(); + WeakPtr<Target> weak = target->AsWeakPtr(); + target.reset(); + EXPECT_CHECK_DEATH(weak->AsWeakPtr()); +} + +TEST(WeakPtrDeathTest, StarOperatorChecksOnBadDereference) { + // The default style "fast" does not support multi-threaded tests + // (introduces deadlock on Linux). + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + + auto target = std::make_unique<Target>(); + WeakPtr<Target> weak = target->AsWeakPtr(); + target.reset(); + EXPECT_CHECK_DEATH((*weak).AsWeakPtr()); +} + } // namespace base
diff --git a/base/task/sequence_manager/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc index 51a4df43..d16889c 100644 --- a/base/task/sequence_manager/sequence_manager_impl.cc +++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -142,7 +142,8 @@ } // namespace -class SequenceManagerImpl::NativeWorkHandleImpl : public NativeWorkHandle { +class SequenceManagerImpl::NativeWorkHandleImpl final + : public NativeWorkHandle { public: NativeWorkHandleImpl(SequenceManagerImpl* sequence_manager, TaskQueue::QueuePriority priority)
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h index 6cb9649c..e7aa0ddb 100644 --- a/base/task/sequence_manager/task_queue_impl.h +++ b/base/task/sequence_manager/task_queue_impl.h
@@ -282,7 +282,7 @@ TaskQueueImpl* const outer_; }; - class TaskRunner : public SingleThreadTaskRunner { + class TaskRunner final : public SingleThreadTaskRunner { public: explicit TaskRunner(scoped_refptr<GuardedTaskPoster> task_poster, scoped_refptr<AssociatedThreadId> associated_thread,
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc index c87b5c0..e59e6b3 100644 --- a/base/threading/platform_thread_win.cc +++ b/base/threading/platform_thread_win.cc
@@ -142,7 +142,18 @@ // |chrome/BUILD.gn|, but keep the default stack size of other threads to // 1MB for the address space pressure. flags = STACK_SIZE_PARAM_IS_A_RESERVATION; - stack_size = 1024 * 1024; + static BOOL is_wow64 = -1; + if (is_wow64 == -1 && !IsWow64Process(GetCurrentProcess(), &is_wow64)) + is_wow64 = FALSE; + // When is_wow64 is set that means we are running on 64-bit Windows and we + // get 4 GiB of address space. In that situation we can afford to use 1 MiB + // of address space for stacks. When running on 32-bit Windows we only get + // 2 GiB of address space so we need to conserve. Typically stack usage on + // these threads is only about 100 KiB. + if (is_wow64) + stack_size = 1024 * 1024; + else + stack_size = 512 * 1024; #endif }
diff --git a/base/trace_event/base_tracing.h b/base/trace_event/base_tracing.h index c5831f237d..ae3c60e7 100644 --- a/base/trace_event/base_tracing.h +++ b/base/trace_event/base_tracing.h
@@ -16,8 +16,10 @@ // Update the check in //base/PRESUBMIT.py when adding new headers here. // TODO(crbug/1006541): Switch to perfetto for trace event implementation. #include "base/trace_event/blame_context.h" +#include "base/trace_event/heap_profiler.h" #include "base/trace_event/memory_allocator_dump_guid.h" #include "base/trace_event/memory_dump_provider.h" +#include "base/trace_event/task_execution_macros.h" #include "base/trace_event/trace_event.h" #include "base/trace_event/traced_value.h" #include "base/trace_event/typed_macros.h"
diff --git a/base/trace_event/common/trace_event_common.h b/base/trace_event/common/trace_event_common.h index 28b7275..120481f3 100644 --- a/base/trace_event/common/trace_event_common.h +++ b/base/trace_event/common/trace_event_common.h
@@ -969,6 +969,7 @@ #define TRACE_TASK_EXECUTION(run_function, task) \ INTERNAL_TRACE_TASK_EXECUTION(run_function, task) +// Special trace event macro to trace log messages. #define TRACE_LOG_MESSAGE(file, message, line) \ INTERNAL_TRACE_LOG_MESSAGE(file, message, line)
diff --git a/base/trace_event/task_execution_macros.h b/base/trace_event/task_execution_macros.h new file mode 100644 index 0000000..bb53ecc6 --- /dev/null +++ b/base/trace_event/task_execution_macros.h
@@ -0,0 +1,124 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_TRACE_EVENT_TASK_EXECUTION_MACROS_H_ +#define BASE_TRACE_EVENT_TASK_EXECUTION_MACROS_H_ + +#include "base/location.h" +#include "base/trace_event/heap_profiler.h" +#include "base/trace_event/typed_macros.h" +#include "third_party/perfetto/include/perfetto/tracing/track_event_interned_data_index.h" +#include "third_party/perfetto/protos/perfetto/trace/interned_data/interned_data.pbzero.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/log_message.pbzero.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/source_location.pbzero.h" +#include "third_party/perfetto/protos/perfetto/trace/track_event/task_execution.pbzero.h" + +namespace { + +// TrackEventInternedDataIndex expects the same data structure to be used for +// all interned fields with the same field number. We can't use base::Location +// for log event's location since base::Location uses program counter based +// location. +struct TraceSourceLocation { + const char* function_name = nullptr; + const char* file_name = nullptr; + size_t line_number = 0; + + bool operator==(const TraceSourceLocation& other) const { + return file_name == other.file_name && + function_name == other.function_name && + line_number == other.line_number; + } +}; + +} // namespace + +namespace std { + +template <> +struct ::std::hash<TraceSourceLocation> { + std::size_t operator()(const TraceSourceLocation& loc) const { + static_assert( + sizeof(TraceSourceLocation) == 2 * sizeof(const char*) + sizeof(size_t), + "Padding will cause uninitialized memory to be hashed."); + return base::FastHash(base::as_bytes(base::make_span(&loc, 1))); + } +}; + +} // namespace std + +namespace { + +struct InternedSourceLocation + : public perfetto::TrackEventInternedDataIndex< + InternedSourceLocation, + perfetto::protos::pbzero::InternedData::kSourceLocationsFieldNumber, + TraceSourceLocation> { + static void Add(perfetto::protos::pbzero::InternedData* interned_data, + size_t iid, + const TraceSourceLocation& location) { + auto* msg = interned_data->add_source_locations(); + msg->set_iid(iid); + if (location.file_name != nullptr) + msg->set_file_name(location.file_name); + if (location.function_name != nullptr) + msg->set_function_name(location.function_name); + // TODO(ssid): Add line number once it is whitelisted in internal proto. + // TODO(ssid): Add program counter to the proto fields when + // !BUILDFLAG(ENABLE_LOCATION_SOURCE). + // TODO(http://crbug.com760702) remove file name and just pass the program + // counter to the heap profiler macro. + // TODO(ssid): Consider writing the program counter of the current task + // (from the callback function pointer) instead of location that posted the + // task. + } +}; + +struct InternedLogMessage + : public perfetto::TrackEventInternedDataIndex< + InternedLogMessage, + perfetto::protos::pbzero::InternedData::kLogMessageBodyFieldNumber, + std::string> { + static void Add(perfetto::protos::pbzero::InternedData* interned_data, + size_t iid, + const std::string& log_message) { + auto* msg = interned_data->add_log_message_body(); + msg->set_iid(iid); + msg->set_body(log_message); + } +}; + +} // namespace + +// Implementation detail: internal macro to trace a task execution with the +// location where it was posted from. +#define INTERNAL_TRACE_TASK_EXECUTION(run_function, task) \ + TRACE_EVENT("toplevel", run_function, [&](perfetto::EventContext ctx) { \ + ctx.event()->set_task_execution()->set_posted_from_iid( \ + InternedSourceLocation::Get( \ + &ctx, TraceSourceLocation{(task).posted_from.function_name(), \ + (task).posted_from.file_name(), \ + (task).posted_from.line_number()})); \ + }); \ + TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION INTERNAL_TRACE_EVENT_UID( \ + task_event)((task).posted_from.file_name()); \ + TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER \ + INTERNAL_TRACE_EVENT_UID(task_pc_event) \ + ((task).posted_from.program_counter()); + +// Implementation detail: internal macro to trace a log message, with the source +// location of the log statement. +#define INTERNAL_TRACE_LOG_MESSAGE(file, message, line) \ + TRACE_EVENT_INSTANT( \ + "log", "LogMessage", TRACE_EVENT_SCOPE_THREAD, \ + [&](perfetto::EventContext ctx) { \ + perfetto::protos::pbzero::LogMessage* log = \ + ctx.event()->set_log_message(); \ + log->set_source_location_iid(InternedSourceLocation::Get( \ + &ctx, \ + TraceSourceLocation{/*function_name=*/nullptr, file, line})); \ + log->set_body_iid(InternedLogMessage::Get(&ctx, message.as_string())); \ + }); + +#endif // BASE_TRACE_EVENT_TASK_EXECUTION_MACROS_H_
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h index 6c6a6c0..a0cd28cf 100644 --- a/base/trace_event/trace_event.h +++ b/base/trace_event/trace_event.h
@@ -22,7 +22,6 @@ #include "base/time/time_override.h" #include "base/trace_event/builtin_categories.h" #include "base/trace_event/common/trace_event_common.h" -#include "base/trace_event/heap_profiler.h" #include "base/trace_event/log_message.h" #include "base/trace_event/thread_instruction_count.h" #include "base/trace_event/trace_arguments.h" @@ -390,45 +389,6 @@ } \ } while (0) -#define INTERNAL_TRACE_LOG_MESSAGE(file, message, line) \ - TRACE_EVENT_INSTANT1( \ - "log", "LogMessage", \ - TRACE_EVENT_FLAG_TYPED_PROTO_ARGS | TRACE_EVENT_SCOPE_THREAD, "message", \ - std::make_unique<base::trace_event::LogMessage>(file, message, line)) - -#if BUILDFLAG(ENABLE_LOCATION_SOURCE) - -// Implementation detail: internal macro to trace a task execution with the -// location where it was posted from. -// -// This implementation is for when location sources are available. -// TODO(ssid): The program counter of the current task should be added here. -#define INTERNAL_TRACE_TASK_EXECUTION(run_function, task) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLAGS( \ - "toplevel", run_function, TRACE_EVENT_FLAG_TYPED_PROTO_ARGS, "src_file", \ - (task).posted_from.file_name(), "src_func", \ - (task).posted_from.function_name()); \ - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION INTERNAL_TRACE_EVENT_UID( \ - task_event)((task).posted_from.file_name()); \ - TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER \ - INTERNAL_TRACE_EVENT_UID(task_pc_event)((task).posted_from.program_counter()); - -#else - -// TODO(http://crbug.com760702) remove file name and just pass the program -// counter to the heap profiler macro. -// TODO(ssid): The program counter of the current task should be added here. -#define INTERNAL_TRACE_TASK_EXECUTION(run_function, task) \ - INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLAGS( \ - "toplevel", run_function, TRACE_EVENT_FLAG_TYPED_PROTO_ARGS, "src", \ - (task).posted_from.ToString()) \ - TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION INTERNAL_TRACE_EVENT_UID( \ - task_event)((task).posted_from.file_name()); \ - TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER \ - INTERNAL_TRACE_EVENT_UID(task_pc_event)((task).posted_from.program_counter()); - -#endif - namespace trace_event_internal { // Specify these values when the corresponding argument of AddTraceEvent is not
diff --git a/base/util/type_safety/id_type.h b/base/util/type_safety/id_type.h index 918e945b..87daefae 100644 --- a/base/util/type_safety/id_type.h +++ b/base/util/type_safety/id_type.h
@@ -47,7 +47,10 @@ // - it restricts the set of available operations (i.e. no multiplication); // - it default-constructs to a null value and allows checking against the null // value via is_null method. -template <typename TypeMarker, typename WrappedType, WrappedType kInvalidValue> +template <typename TypeMarker, + typename WrappedType, + WrappedType kInvalidValue, + WrappedType kFirstGeneratedId = kInvalidValue + 1> class IdType : public StrongAlias<TypeMarker, WrappedType> { public: static_assert( @@ -55,6 +58,15 @@ "If signed, the invalid value should be negative or equal to zero to " "avoid overflow issues."); + static_assert(kFirstGeneratedId != kInvalidValue, + "The first generated ID cannot be invalid."); + + static_assert(std::is_unsigned<WrappedType>::value || + kFirstGeneratedId > kInvalidValue, + "If signed, the first generated ID must be greater than the " + "invalid value so that the monotonically increasing " + "GenerateNextId method will never return the invalid value."); + using StrongAlias<TypeMarker, WrappedType>::StrongAlias; // This class can be used to generate unique IdTypes. It keeps an internal @@ -71,7 +83,7 @@ Generator& operator=(const Generator&) = delete; private: - WrappedType next_id_ = kInvalidValue + 1; + WrappedType next_id_ = kFirstGeneratedId; }; // Default-construct in the null state.
diff --git a/base/util/type_safety/id_type_unittest.cc b/base/util/type_safety/id_type_unittest.cc index 1e07bcf2..a2dc000 100644 --- a/base/util/type_safety/id_type_unittest.cc +++ b/base/util/type_safety/id_type_unittest.cc
@@ -52,6 +52,14 @@ } } +TEST(IdType, GeneratorWithDifferentStartingValue) { + using TestId = IdType<class TestIdTag, int, -1, 1>; + + TestId::Generator test_id_generator; + for (int i = 1; i < 10; i++) + EXPECT_EQ(test_id_generator.GenerateNextId(), TestId::FromUnsafeValue(i)); +} + TEST(IdType, EnsureConstexpr) { using TestId = IdType32<class TestTag>;
diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn index 862a0db..5bf00ac 100644 --- a/build/config/ios/BUILD.gn +++ b/build/config/ios/BUILD.gn
@@ -2,7 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/config/coverage/coverage.gni") import("//build/config/ios/ios_sdk.gni") import("//build/config/sysroot.gni") import("//build/toolchain/toolchain.gni") @@ -131,10 +130,6 @@ asmflags = common_flags cflags = common_flags ldflags = common_flags - - if (use_clang_coverage) { - configs = [ "//build/config/coverage:default_coverage" ] - } } config("ios_executable_flags") {
diff --git a/build/config/linux/libva/BUILD.gn b/build/config/linux/libva/BUILD.gn index 8cbedb7..ada5d66 100644 --- a/build/config/linux/libva/BUILD.gn +++ b/build/config/linux/libva/BUILD.gn
@@ -8,6 +8,10 @@ pkg_config("libva") { packages = [ "libva" ] + # Do not use exec_script to check the version here. It is done with a # static_assert instead. + + # vaapi decoders use dlopen pre-sandbox anyway to improve startup times. + ignore_libs = true }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index ebac27d86..e974d46 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20201013.1.1 +0.20201013.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index ebac27d86..e974d46 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20201013.1.1 +0.20201013.2.1
diff --git a/build/mac_toolchain.py b/build/mac_toolchain.py index 8d138b58..705fb909 100755 --- a/build/mac_toolchain.py +++ b/build/mac_toolchain.py
@@ -31,9 +31,9 @@ # To build these packages, see comments in build/xcode_binaries.yaml MAC_BINARIES_LABEL = 'infra_internal/ios/xcode/xcode_binaries/mac-amd64' MAC_BINARIES_TAG = { - # This contains binaries from Xcode 11.2.1, along with the 10.15 SDKs (aka - # 11B53). - 'default': 'wXywrnOhzFxwLYlwO62UzRxVCjnu6DoSI2D2jrCd00gC', + # This contains binaries from Xcode 12.0.1, along with the 10.15 SDK (aka + # 12A7300). + 'default': '89j_tSMJj0_9hMbceEg-P-VmiY_4CeYwsPE1e_zzRPcC', # This contains binaries from Xcode 12.2 beta 2, along with the # 11 SDK (aka 12B5025f). 'xcode_12_beta': 'G4U9cOycs9JFzxLNSMaRuoS3NZwiB6RLwg0v4dh3Vw4C',
diff --git a/build/toolchain/clang_code_coverage_wrapper.py b/build/toolchain/clang_code_coverage_wrapper.py index 4f76a01..5b5550d 100755 --- a/build/toolchain/clang_code_coverage_wrapper.py +++ b/build/toolchain/clang_code_coverage_wrapper.py
@@ -91,7 +91,7 @@ '../../chrome/browser/media/router/providers/cast/cast_internal_message_util.cc', #pylint: disable=line-too-long '../../components/cast_channel/cast_channel_enum.cc', '../../components/cast_channel/cast_message_util.cc', - '../../components/media_router/common/providers/cast/cast_media_source.cc', + '../../components/media_router/common/providers/cast/cast_media_source.cc', #pylint: disable=line-too-long '../../ui/events/keycodes/dom/keycode_converter.cc', # TODO(crbug.com/1051561): angle_unittests affected by coverage. '../../base/message_loop/message_pump_default.cc', @@ -145,10 +145,13 @@ try: while True: idx = command.index(start_flag, start_idx) - start_idx = idx + 1 if command[idx:idx + num_flags] == _COVERAGE_FLAGS: del command[idx:idx + num_flags] - break + # There can be multiple sets of _COVERAGE_FLAGS. All of these need to be + # removed. + start_idx = idx + else: + start_idx = idx + 1 except ValueError: pass
diff --git a/cc/metrics/begin_main_frame_metrics.h b/cc/metrics/begin_main_frame_metrics.h index 66d5a6d..1f26384f 100644 --- a/cc/metrics/begin_main_frame_metrics.h +++ b/cc/metrics/begin_main_frame_metrics.h
@@ -24,7 +24,6 @@ base::TimeDelta compositing_assignments; base::TimeDelta compositing_inputs; base::TimeDelta paint; - base::TimeDelta scrolling_coordinator; base::TimeDelta composite_commit; base::TimeDelta update_layers; // True if we should measure smoothness in TotalFrameCounter and
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc index 320e9d6a..2562f2b 100644 --- a/cc/metrics/compositor_frame_reporter.cc +++ b/cc/metrics/compositor_frame_reporter.cc
@@ -162,9 +162,6 @@ return "SendBeginMainFrameToCommit.CompositingAssignments"; case static_cast<int>(BlinkBreakdown::kPaint) + kBlinkBreakdownInitialIndex: return "SendBeginMainFrameToCommit.Paint"; - case static_cast<int>(BlinkBreakdown::kScrollingCoordinator) + - kBlinkBreakdownInitialIndex: - return "SendBeginMainFrameToCommit.ScrollingCoordinator"; case static_cast<int>(BlinkBreakdown::kCompositeCommit) + kBlinkBreakdownInitialIndex: return "SendBeginMainFrameToCommit.CompositeCommit"; @@ -269,9 +266,9 @@ static_cast<size_t>(VizBreakdown::kSwapStartToBufferAvailable); \ bool has_ready_timings = !!viz_breakdown_list_[start_to_buffer_available]; \ for (size_t i = 0; i < start_to_buffer_available; i++) { \ - if (!viz_breakdown_list_[i]) \ + if (!viz_breakdown_list_[i]) { \ break; \ - \ + } \ if (i == static_cast<size_t>(VizBreakdown::kSwapStartToSwapEnd) && \ has_ready_timings) { \ size_t latch_to_swap_end = \ @@ -999,9 +996,6 @@ blink_breakdown_.compositing_assignments; blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kPaint)] = blink_breakdown_.paint; - blink_breakdown_list_[static_cast<int>( - BlinkBreakdown::kScrollingCoordinator)] = - blink_breakdown_.scrolling_coordinator; blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kCompositeCommit)] = blink_breakdown_.composite_commit; blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kUpdateLayers)] =
diff --git a/cc/metrics/compositor_frame_reporter.h b/cc/metrics/compositor_frame_reporter.h index d7abf295..3b06775 100644 --- a/cc/metrics/compositor_frame_reporter.h +++ b/cc/metrics/compositor_frame_reporter.h
@@ -115,10 +115,9 @@ kCompositingInputs = 5, kCompositingAssignments = 6, kPaint = 7, - kScrollingCoordinator = 8, - kCompositeCommit = 9, - kUpdateLayers = 10, - kBeginMainSentToStarted = 11, + kCompositeCommit = 8, + kUpdateLayers = 9, + kBeginMainSentToStarted = 10, kBreakdownCount };
diff --git a/cc/metrics/compositor_frame_reporter_unittest.cc b/cc/metrics/compositor_frame_reporter_unittest.cc index 94a2c45..eaa1db0 100644 --- a/cc/metrics/compositor_frame_reporter_unittest.cc +++ b/cc/metrics/compositor_frame_reporter_unittest.cc
@@ -49,20 +49,19 @@ std::unique_ptr<BeginMainFrameMetrics> BuildBlinkBreakdown() { auto breakdown = std::make_unique<BeginMainFrameMetrics>(); - breakdown->handle_input_events = base::TimeDelta::FromMicroseconds(11); - breakdown->animate = base::TimeDelta::FromMicroseconds(10); - breakdown->style_update = base::TimeDelta::FromMicroseconds(9); - breakdown->layout_update = base::TimeDelta::FromMicroseconds(8); - breakdown->compositing_inputs = base::TimeDelta::FromMicroseconds(7); - breakdown->prepaint = base::TimeDelta::FromMicroseconds(6); - breakdown->compositing_assignments = base::TimeDelta::FromMicroseconds(5); - breakdown->paint = base::TimeDelta::FromMicroseconds(4); - breakdown->scrolling_coordinator = base::TimeDelta::FromMicroseconds(3); + breakdown->handle_input_events = base::TimeDelta::FromMicroseconds(10); + breakdown->animate = base::TimeDelta::FromMicroseconds(9); + breakdown->style_update = base::TimeDelta::FromMicroseconds(8); + breakdown->layout_update = base::TimeDelta::FromMicroseconds(7); + breakdown->compositing_inputs = base::TimeDelta::FromMicroseconds(6); + breakdown->prepaint = base::TimeDelta::FromMicroseconds(5); + breakdown->compositing_assignments = base::TimeDelta::FromMicroseconds(4); + breakdown->paint = base::TimeDelta::FromMicroseconds(3); breakdown->composite_commit = base::TimeDelta::FromMicroseconds(2); breakdown->update_layers = base::TimeDelta::FromMicroseconds(1); // Advance now by the sum of the breakdowns. - AdvanceNowByMs(11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1); + AdvanceNowByMs(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1); return breakdown; } @@ -376,9 +375,6 @@ blink_breakdown_copy.compositing_assignments}, {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.Paint", blink_breakdown_copy.paint}, - {"EventLatency.TouchPressed.SendBeginMainFrameToCommit." - "ScrollingCoordinator", - blink_breakdown_copy.scrolling_coordinator}, {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.CompositeCommit", blink_breakdown_copy.composite_commit}, {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.UpdateLayers",
diff --git a/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/cc/metrics/compositor_frame_reporting_controller_unittest.cc index 807f839..b3d3f4a 100644 --- a/cc/metrics/compositor_frame_reporting_controller_unittest.cc +++ b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -144,20 +144,19 @@ std::unique_ptr<BeginMainFrameMetrics> BuildBlinkBreakdown() { auto breakdown = std::make_unique<BeginMainFrameMetrics>(); - breakdown->handle_input_events = base::TimeDelta::FromMicroseconds(11); - breakdown->animate = base::TimeDelta::FromMicroseconds(10); - breakdown->style_update = base::TimeDelta::FromMicroseconds(9); - breakdown->layout_update = base::TimeDelta::FromMicroseconds(8); - breakdown->compositing_inputs = base::TimeDelta::FromMicroseconds(7); - breakdown->prepaint = base::TimeDelta::FromMicroseconds(6); - breakdown->compositing_assignments = base::TimeDelta::FromMicroseconds(5); - breakdown->paint = base::TimeDelta::FromMicroseconds(4); - breakdown->scrolling_coordinator = base::TimeDelta::FromMicroseconds(3); + breakdown->handle_input_events = base::TimeDelta::FromMicroseconds(10); + breakdown->animate = base::TimeDelta::FromMicroseconds(9); + breakdown->style_update = base::TimeDelta::FromMicroseconds(8); + breakdown->layout_update = base::TimeDelta::FromMicroseconds(7); + breakdown->compositing_inputs = base::TimeDelta::FromMicroseconds(6); + breakdown->prepaint = base::TimeDelta::FromMicroseconds(5); + breakdown->compositing_assignments = base::TimeDelta::FromMicroseconds(4); + breakdown->paint = base::TimeDelta::FromMicroseconds(3); breakdown->composite_commit = base::TimeDelta::FromMicroseconds(2); breakdown->update_layers = base::TimeDelta::FromMicroseconds(1); // Advance now by the sum of the breakdowns. - AdvanceNowByMs(11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1); + AdvanceNowByMs(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1); return breakdown; } @@ -921,18 +920,15 @@ base::TimeDelta::FromMicroseconds(7).InMilliseconds(), 1); histogram_tester.ExpectUniqueSample( "CompositorLatency.SendBeginMainFrameToCommit.CompositingInputs", - base::TimeDelta::FromMicroseconds(5).InMilliseconds(), 1); - histogram_tester.ExpectUniqueSample( - "CompositorLatency.SendBeginMainFrameToCommit.Prepaint", base::TimeDelta::FromMicroseconds(6).InMilliseconds(), 1); histogram_tester.ExpectUniqueSample( - "CompositorLatency.SendBeginMainFrameToCommit.CompositingAssignments", + "CompositorLatency.SendBeginMainFrameToCommit.Prepaint", base::TimeDelta::FromMicroseconds(5).InMilliseconds(), 1); histogram_tester.ExpectUniqueSample( - "CompositorLatency.SendBeginMainFrameToCommit.Paint", + "CompositorLatency.SendBeginMainFrameToCommit.CompositingAssignments", base::TimeDelta::FromMicroseconds(4).InMilliseconds(), 1); histogram_tester.ExpectUniqueSample( - "CompositorLatency.SendBeginMainFrameToCommit.ScrollingCoordinator", + "CompositorLatency.SendBeginMainFrameToCommit.Paint", base::TimeDelta::FromMicroseconds(3).InMilliseconds(), 1); histogram_tester.ExpectUniqueSample( "CompositorLatency.SendBeginMainFrameToCommit.CompositeCommit", @@ -1153,9 +1149,6 @@ blink_breakdown_copy.compositing_assignments}, {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.Paint", blink_breakdown_copy.paint}, - {"EventLatency.TouchPressed.SendBeginMainFrameToCommit." - "ScrollingCoordinator", - blink_breakdown_copy.scrolling_coordinator}, {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.CompositeCommit", blink_breakdown_copy.composite_commit}, {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.UpdateLayers",
diff --git a/cc/metrics/frame_sequence_metrics.cc b/cc/metrics/frame_sequence_metrics.cc index d6154c69..8c73bfd 100644 --- a/cc/metrics/frame_sequence_metrics.cc +++ b/cc/metrics/frame_sequence_metrics.cc
@@ -110,10 +110,10 @@ // Only construct |jank_reporter_| if it has a valid tracker and thread type. // For scrolling tracker types, |jank_reporter_| may be constructed later in // SetScrollingThread(). - if ((thread_type == ThreadType::kCompositor || - thread_type == ThreadType::kMain) && - type != FrameSequenceTrackerType::kCustom) + if (thread_type == ThreadType::kCompositor || + thread_type == ThreadType::kMain) { jank_reporter_ = std::make_unique<JankMetrics>(type, thread_type); + } } FrameSequenceMetrics::~FrameSequenceMetrics() = default; @@ -219,7 +219,12 @@ if (type_ == FrameSequenceTrackerType::kCustom) { DCHECK(!custom_reporter_.is_null()); - std::move(custom_reporter_).Run(std::move(main_throughput_)); + std::move(custom_reporter_) + .Run({ + main_throughput_.frames_expected, + main_throughput_.frames_produced, + jank_reporter_->jank_count(), + }); main_throughput_ = {}; impl_throughput_ = {};
diff --git a/cc/metrics/frame_sequence_metrics.h b/cc/metrics/frame_sequence_metrics.h index b7a3313..3d81561 100644 --- a/cc/metrics/frame_sequence_metrics.h +++ b/cc/metrics/frame_sequence_metrics.h
@@ -116,8 +116,12 @@ void SetScrollingThread(ThreadType thread); - using CustomReporter = - base::OnceCallback<void(ThroughputData throughput_data)>; + struct CustomReportData { + uint32_t frames_expected = 0; + uint32_t frames_produced = 0; + uint32_t jank_count = 0; + }; + using CustomReporter = base::OnceCallback<void(const CustomReportData& data)>; // Sets reporter callback for kCustom typed sequence. void SetCustomReporter(CustomReporter custom_reporter);
diff --git a/cc/metrics/frame_sequence_tracker_collection.cc b/cc/metrics/frame_sequence_tracker_collection.cc index a30d44b..7d98215 100644 --- a/cc/metrics/frame_sequence_tracker_collection.cc +++ b/cc/metrics/frame_sequence_tracker_collection.cc
@@ -392,12 +392,12 @@ void FrameSequenceTrackerCollection::AddCustomTrackerResult( int custom_sequence_id, - FrameSequenceMetrics::ThroughputData throughput_data) { + const FrameSequenceMetrics::CustomReportData& data) { DCHECK(custom_tracker_results_added_callback_); CustomTrackerResults results; - results[custom_sequence_id] = std::move(throughput_data); - custom_tracker_results_added_callback_.Run(std::move(results)); + results[custom_sequence_id] = data; + custom_tracker_results_added_callback_.Run(results); } } // namespace cc
diff --git a/cc/metrics/frame_sequence_tracker_collection.h b/cc/metrics/frame_sequence_tracker_collection.h index e54f39f..d1b5fa53 100644 --- a/cc/metrics/frame_sequence_tracker_collection.h +++ b/cc/metrics/frame_sequence_tracker_collection.h
@@ -32,7 +32,7 @@ // Map of kCustom tracker results keyed by a sequence id. using CustomTrackerResults = - base::flat_map<int, FrameSequenceMetrics::ThroughputData>; + base::flat_map<int, FrameSequenceMetrics::CustomReportData>; typedef uint16_t ActiveFrameSequenceTrackers; @@ -113,7 +113,7 @@ void SetUkmManager(UkmManager* manager); using NotifyCustomerTrackerResutlsCallback = - base::RepeatingCallback<void(CustomTrackerResults)>; + base::RepeatingCallback<void(const CustomTrackerResults&)>; void set_custom_tracker_results_added_callback( NotifyCustomerTrackerResutlsCallback callback) { custom_tracker_results_added_callback_ = std::move(callback); @@ -138,7 +138,7 @@ // TakeCustomTrackerResults() below. void AddCustomTrackerResult( int custom_sequence_id, - FrameSequenceMetrics::ThroughputData throughput_data); + const FrameSequenceMetrics::CustomReportData& data); const bool is_single_threaded_; // The reporter takes throughput data and connect to UkmManager to report it.
diff --git a/cc/metrics/frame_sequence_tracker_unittest.cc b/cc/metrics/frame_sequence_tracker_unittest.cc index 4f03150..72c22ae 100644 --- a/cc/metrics/frame_sequence_tracker_unittest.cc +++ b/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -1614,7 +1614,7 @@ TEST_F(FrameSequenceTrackerTest, CustomTrackers) { CustomTrackerResults results; collection_.set_custom_tracker_results_added_callback( - base::BindLambdaForTesting([&](CustomTrackerResults reported) { + base::BindLambdaForTesting([&](const CustomTrackerResults& reported) { for (const auto& pair : reported) results[pair.first] = pair.second; }));
diff --git a/cc/metrics/jank_metrics.h b/cc/metrics/jank_metrics.h index 208ccc6..6fbf5c8 100644 --- a/cc/metrics/jank_metrics.h +++ b/cc/metrics/jank_metrics.h
@@ -41,6 +41,8 @@ return effective_thread_; } + int jank_count() const { return jank_count_; } + private: // The type of the tracker this JankMetrics object is attached to. const FrameSequenceTrackerType tracker_type_;
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc index df1e7e6..59c594dc 100644 --- a/cc/paint/paint_op_reader.cc +++ b/cc/paint/paint_op_reader.cc
@@ -265,7 +265,13 @@ ReadSimple(&flags->color_); Read(&flags->width_); Read(&flags->miter_limit_); + ReadSimple(&flags->blend_mode_); + if (flags->blend_mode_ > static_cast<uint32_t>(SkBlendMode::kLastMode)) { + SetInvalid(); + return; + } + ReadSimple(&flags->bitfields_uint_); ReadFlattenable(&flags->path_effect_);
diff --git a/cc/raster/synchronous_task_graph_runner.cc b/cc/raster/synchronous_task_graph_runner.cc index b7e0e94..03a5a46 100644 --- a/cc/raster/synchronous_task_graph_runner.cc +++ b/cc/raster/synchronous_task_graph_runner.cc
@@ -10,6 +10,7 @@ #include <utility> #include "base/threading/simple_thread.h" +#include "base/trace_event/heap_profiler.h" #include "base/trace_event/trace_event.h" namespace cc {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 67fa4e2..e2fefa0 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2024,8 +2024,8 @@ } void LayerTreeHostImpl::NotifyThroughputTrackerResults( - CustomTrackerResults results) { - client_->NotifyThroughputTrackerResults(std::move(results)); + const CustomTrackerResults& results) { + client_->NotifyThroughputTrackerResults(results); } void LayerTreeHostImpl::DidNotNeedBeginFrame() {
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 43a4fb5..318734f 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -936,7 +936,7 @@ const viz::FrameTimingDetails& details); // Notifies client about the custom tracker results. - void NotifyThroughputTrackerResults(CustomTrackerResults results); + void NotifyThroughputTrackerResults(const CustomTrackerResults& results); // Once bound, this instance owns the InputHandler. However, an InputHandler // need not be bound so this should be null-checked before dereferencing.
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index b664b69..6571383c 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -204,13 +204,13 @@ ] if (current_cpu == "x86") { - # Set the initial stack size to 1MiB, instead of the 1.5MiB needed by + # Set the initial stack size to 0.5MiB, instead of the 1.5MiB needed by # Chrome's main thread. This saves significant memory on threads (like # those in the Windows thread pool, and others) whose stack size we can # only control through this setting. Because Chrome's main thread needs # a minimum 1.5 MiB stack, the main thread (in 32-bit builds only) uses # fibers to switch to a 1.5 MiB stack before running any other code. - ldflags = [ "/STACK:0x100000" ] + ldflags = [ "/STACK:0x80000" ] } else { # Increase the initial stack size. The default is 1MB, this is 8MB. ldflags = [ "/STACK:0x800000" ]
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index a3cef354..15dd853c 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -432,6 +432,7 @@ "//components/paint_preview/player/android:java", "//components/password_manager/core/browser:password_manager_java_enums", "//components/payments/content/android:java", + "//components/payments/content/android:service_java", "//components/payments/mojom:mojom_java", "//components/permissions/android:java", "//components/policy/android:policy_java", @@ -960,6 +961,7 @@ "//chrome/browser/ui/android/appmenu:java", "//chrome/test/android:chrome_java_test_support", "//components/payments/content/android:java", + "//components/payments/content/android:service_java", "//components/payments/mojom:mojom_java", "//content/public/android:content_java", "//content/public/test/android:content_java_test_support", @@ -1133,6 +1135,7 @@ "//components/paint_preview/player/android:javatests", "//components/password_manager/core/browser:password_manager_java_enums", "//components/payments/content/android:java", + "//components/payments/content/android:service_java", "//components/payments/mojom:mojom_java", "//components/permissions/android:java", "//components/policy/android:policy_java", @@ -2085,6 +2088,7 @@ "java/src/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java", "java/src/org/chromium/chrome/browser/ChromeBackgroundService.java", "java/src/org/chromium/chrome/browser/ChromeBackupAgent.java", + "java/src/org/chromium/chrome/browser/base/MainDexApplicationImpl.java", "java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java", "java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java", "java/src/org/chromium/chrome/browser/base/SplitCompatBackupAgent.java", @@ -2136,6 +2140,7 @@ # reduce base dex size. "$google_play_services_package:google_play_services_cast_framework_java", "//components/background_task_scheduler:background_task_scheduler_java", + "//components/payments/content/android:service_java", "//third_party/android_sdk/androidx_browser:androidx_browser_java", ] srcjar_deps = [ ":chrome_product_config" ]
diff --git a/chrome/android/features/cablev2_authenticator/native/cablev2_authenticator_android.cc b/chrome/android/features/cablev2_authenticator/native/cablev2_authenticator_android.cc index ada1595..aa4b5fe 100644 --- a/chrome/android/features/cablev2_authenticator/native/cablev2_authenticator_android.cc +++ b/chrome/android/features/cablev2_authenticator/native/cablev2_authenticator_android.cc
@@ -77,6 +77,10 @@ base::span<const uint8_t> JavaByteArrayToSpan( JNIEnv* env, const JavaParamRef<jbyteArray>& data) { + if (data.is_null()) { + return base::span<const uint8_t>(); + } + const size_t data_len = env->GetArrayLength(data); const jbyte* data_bytes = env->GetByteArrayElements(data, /*iscopy=*/nullptr); return base::as_bytes(base::make_span(data_bytes, data_len));
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImpl.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImpl.java index 44dae9a..754b49b 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImpl.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImpl.java
@@ -397,8 +397,7 @@ Capability.UNDOABLE_ACTIONS); addCapabilityIfConfigEnabled(feedRequestBuilder, ConfigKey.MANAGE_INTERESTS_ENABLED, Capability.MANAGE_INTERESTS); - addCapabilityIfConfigEnabled( - feedRequestBuilder, ConfigKey.SEND_FEEDBACK_ENABLED, Capability.SEND_FEEDBACK); + feedRequestBuilder.addClientCapability(Capability.SEND_FEEDBACK); addCapabilityIfConfigEnabled( feedRequestBuilder, ConfigKey.ENABLE_CAROUSELS, Capability.CAROUSELS); if (mCardMenuTooltipWouldTrigger) {
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v1/FeedConfiguration.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v1/FeedConfiguration.java index 28dc570b..e14c6e2 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v1/FeedConfiguration.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v1/FeedConfiguration.java
@@ -304,12 +304,6 @@ MANAGE_INTERESTS_ENABLED_DEFAULT); } - /** @return Whether to show context menu option to send feedback. */ - @VisibleForTesting - static boolean getSendFeedbackEnabled() { - return ChromeFeatureList.isEnabled(ChromeFeatureList.INTEREST_FEED_FEEDBACK); - } - /** @return The maximum number of times that the GC task can re-enqueue itself. */ @VisibleForTesting static long getMaximumGcAttempts() { @@ -459,7 +453,6 @@ FeedConfiguration.getLoggingImmediateContentThresholdMs()) .put(ConfigKey.MANAGE_INTERESTS_ENABLED, FeedConfiguration.getManageInterestsEnabled()) - .put(ConfigKey.SEND_FEEDBACK_ENABLED, FeedConfiguration.getSendFeedbackEnabled()) .put(ConfigKey.MAXIMUM_GC_ATTEMPTS, FeedConfiguration.getMaximumGcAttempts()) .put(ConfigKey.NON_CACHED_MIN_PAGE_SIZE, FeedConfiguration.getNonCachedMinPageSize())
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java index 347730d..b8478fad 100644 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java +++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/library/feedrequestmanager/FeedRequestManagerImplTest.java
@@ -235,6 +235,7 @@ getTestFeedRequestBuilder() .setFeedQuery(FeedQuery.newBuilder().setReason( FeedQuery.RequestReason.SCHEDULED_REFRESH)) + .addClientCapability(Capability.SEND_FEEDBACK) .addClientCapability(Capability.BASE_UI) .build()) .build(); @@ -313,8 +314,8 @@ } @Test - public void testTriggerRefresh_sendFeedbackCapabilityAddedWhenFlagIsOn() throws Exception { - testCapabilityAdded(ConfigKey.SEND_FEEDBACK_ENABLED, Capability.SEND_FEEDBACK); + public void testTriggerRefresh_sendFeedbackCapabilityAdded() throws Exception { + testCapabilityAdded(Capability.SEND_FEEDBACK); } @Test @@ -396,6 +397,7 @@ expectedSemanticProperties) .addAllFeedActionQueryDataItem( expectedDataItems)) + .addClientCapability(Capability.SEND_FEEDBACK) .addClientCapability(Capability.BASE_UI) .build()) .build(); @@ -450,6 +452,7 @@ expectedSemanticProperties) .addAllFeedActionQueryDataItem( expectedDataItems)) + .addClientCapability(Capability.SEND_FEEDBACK) .addClientCapability(Capability.BASE_UI) .build()) .build(); @@ -504,6 +507,7 @@ expectedSemanticProperties) .addAllFeedActionQueryDataItem( expectedDataItems)) + .addClientCapability(Capability.SEND_FEEDBACK) .addClientCapability(Capability.BASE_UI) .build()) .build(); @@ -557,6 +561,7 @@ expectedSemanticProperties) .addAllFeedActionQueryDataItem( expectedDataItems)) + .addClientCapability(Capability.SEND_FEEDBACK) .addClientCapability(Capability.BASE_UI) .build()) .build(); @@ -621,6 +626,7 @@ expectedSemanticProperties) .addAllFeedActionQueryDataItem( expectedDataItems)) + .addClientCapability(Capability.SEND_FEEDBACK) .addClientCapability(Capability.BASE_UI) .build()) .build(); @@ -681,6 +687,7 @@ expectedSemanticProperties) .addAllFeedActionQueryDataItem( expectedDataItems)) + .addClientCapability(Capability.SEND_FEEDBACK) .addClientCapability(Capability.BASE_UI) .build()) .build(); @@ -740,6 +747,7 @@ expectedSemanticProperties) .addAllFeedActionQueryDataItem( expectedDataItems)) + .addClientCapability(Capability.SEND_FEEDBACK) .addClientCapability(Capability.BASE_UI) .build()) .build(); @@ -901,6 +909,7 @@ .setScreenHeightInPixels( 470)) .build()) + .addClientCapability(Capability.SEND_FEEDBACK) .addClientCapability(Capability.BASE_UI) .build()) .build(); @@ -1011,7 +1020,7 @@ HttpRequest httpRequest = mFakeNetworkClient.getLatestRequest(); assertHttpRequestFormattedCorrectly(httpRequest, mContext); - Set<Capability> expectedCap = EnumSet.of(Capability.BASE_UI); + Set<Capability> expectedCap = EnumSet.of(Capability.BASE_UI, Capability.SEND_FEEDBACK); Collections.addAll(expectedCap, capability); Request request = getRequestFromHttpRequest(httpRequest);
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/v1/FeedConfigurationTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/v1/FeedConfigurationTest.java index a78f2e3..d8a870f1 100644 --- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/v1/FeedConfigurationTest.java +++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/v1/FeedConfigurationTest.java
@@ -29,9 +29,6 @@ private static final double ASSERT_EQUALS_DOUBLE_DELTA = 0.001d; - /** Default value for whether to use menu options to send user feedback. */ - public static final boolean SEND_FEEDBACK_ENABLED_DEFAULT = true; - @Test @Feature({"Feed"}) @Features.EnableFeatures({ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS}) @@ -275,13 +272,6 @@ @Test @Feature({"Feed"}) - @CommandLineFlags.Add({"enable-features=InterestFeedFeedback"}) - public void testSendFeedbackEnabled() { - Assert.assertTrue(FeedConfiguration.getSendFeedbackEnabled()); - } - - @Test - @Feature({"Feed"}) @CommandLineFlags. Add({"enable-features=InterestFeedContentSuggestions<Trial", "force-fieldtrials=Trial/Group", "force-fieldtrial-params=Trial.Group:maximum_gc_attempts/5"})
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java index 366ad6bd..f00f41d6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -22,6 +22,7 @@ import org.chromium.base.annotations.MainDex; import org.chromium.base.memory.MemoryPressureMonitor; import org.chromium.chrome.browser.background_task_scheduler.ChromeBackgroundTaskFactory; +import org.chromium.chrome.browser.base.MainDexApplicationImpl; import org.chromium.chrome.browser.base.SplitCompatApplication; import org.chromium.chrome.browser.crash.ApplicationStatusTracker; import org.chromium.chrome.browser.crash.FirebaseConfig; @@ -63,14 +64,14 @@ private static volatile ChromeAppComponent sComponent; /** Chrome application logic. */ - public static class ChromeApplicationImpl extends Impl { + public static class ChromeApplicationImpl extends MainDexApplicationImpl { public ChromeApplicationImpl() {} // Called by the framework for ALL processes. Runs before ContentProviders are created. // Quirk: context.getApplicationContext() returns null during this method. @Override public void attachBaseContext(Context context) { - boolean isBrowserProcess = isBrowserProcess(); + boolean isBrowserProcess = SplitCompatApplication.isBrowserProcess(); if (isBrowserProcess) { UmaUtils.recordMainEntryPointTime(); @@ -204,7 +205,7 @@ public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // TODO(huayinz): Add observer pattern for application configuration changes. - if (isBrowserProcess()) { + if (SplitCompatApplication.isBrowserProcess()) { SystemNightModeMonitor.getInstance().onApplicationConfigurationChanged(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java index 29c0b37..89e8c16 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
@@ -32,7 +32,7 @@ } /** Monochrome application logic. */ - public static class MonochromeApplicationImpl extends ChromeApplication.ChromeApplicationImpl { + public static class MonochromeApplicationImpl extends ChromeApplicationImpl { public MonochromeApplicationImpl() {} @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java index b58f12bb..f0e69da3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java
@@ -60,10 +60,8 @@ mContext = viewStub.getContext(); mTracker = TrackerFactory.getTrackerForProfile(profile); - Callback<Tutorial> clickListener = this::onClickIPH; - Callback<Tutorial> dismissListener = this::onDismissIPH; mVideoIPHCoordinator = createVideoIPHCoordinator( - viewStub, createImageFetcher(profile), clickListener, dismissListener); + viewStub, createImageFetcher(profile), this::onClickIPH, this::onDismissIPH); mVideoTutorialService = VideoTutorialServiceFactory.getForProfile(profile); mVideoTutorialService.getTutorials(this::onFetchTutorials); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java index 25f0526..8b8488b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java
@@ -16,6 +16,7 @@ import org.chromium.chrome.browser.SynchronousInitializationActivity; import org.chromium.chrome.browser.WebContentsFactory; import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.video_tutorials.FeatureType; import org.chromium.chrome.browser.video_tutorials.Tutorial; import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory; @@ -50,7 +51,8 @@ this, videoTutorialService, this::createWebContents, this::tryNow, this::finish); setContentView(mCoordinator.getView()); - int featureType = IntentUtils.safeGetIntExtra(getIntent(), EXTRA_VIDEO_TUTORIAL, 0); + int featureType = + IntentUtils.safeGetIntExtra(getIntent(), EXTRA_VIDEO_TUTORIAL, FeatureType.INVALID); videoTutorialService.getTutorial(featureType, mCoordinator::playVideoTutorial); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/MainDexApplicationImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/base/MainDexApplicationImpl.java new file mode 100644 index 0000000..4180289 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/base/MainDexApplicationImpl.java
@@ -0,0 +1,80 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.base; + +import android.content.Context; + +import androidx.annotation.CallSuper; + +import org.chromium.base.BundleUtils; +import org.chromium.base.ContextUtils; +import org.chromium.base.JNIUtils; +import org.chromium.base.library_loader.LibraryLoader; +import org.chromium.base.library_loader.LibraryProcessType; +import org.chromium.base.memory.MemoryPressureMonitor; +import org.chromium.base.task.AsyncTask; +import org.chromium.chrome.browser.ProductConfig; +import org.chromium.components.embedder_support.application.FontPreloadingWorkaround; +import org.chromium.components.module_installer.util.ModuleUtil; +import org.chromium.ui.base.ResourceBundle; + +/** + * Implementation of {@link SplitCompatApplication.Impl} that will be initialized in all processes. + */ +public class MainDexApplicationImpl extends SplitCompatApplication.Impl { + @Override + @CallSuper + public void onCreate() { + // These can't go in attachBaseContext because Context.getApplicationContext() (which + // they use under-the-hood) does not work until after it returns. + FontPreloadingWorkaround.maybeInstallWorkaround(getApplication()); + MemoryPressureMonitor.INSTANCE.registerComponentCallbacks(); + } + + @Override + @CallSuper + public void attachBaseContext(Context context) { + super.attachBaseContext(context); + // Perform initialization of globals common to all processes. + ContextUtils.initApplicationContext(getApplication()); + maybeInitProcessType(); + BundleUtils.setIsBundle(ProductConfig.IS_BUNDLE); + + // Write installed modules to crash keys. This needs to be done as early as possible so + // that these values are set before any crashes are reported. + ModuleUtil.updateCrashKeys(); + + AsyncTask.takeOverAndroidThreadPool(); + JNIUtils.setClassLoader(getApplication().getClassLoader()); + ResourceBundle.setAvailablePakLocales( + ProductConfig.COMPRESSED_LOCALES, ProductConfig.UNCOMPRESSED_LOCALES); + LibraryLoader.getInstance().setLinkerImplementation( + ProductConfig.USE_CHROMIUM_LINKER, ProductConfig.USE_MODERN_LINKER); + LibraryLoader.getInstance().enableJniChecks(); + } + + public boolean isWebViewProcess() { + return false; + } + + private void maybeInitProcessType() { + if (SplitCompatApplication.isBrowserProcess()) { + LibraryLoader.getInstance().setLibraryProcessType(LibraryProcessType.PROCESS_BROWSER); + return; + } + // WebView initialization sets the correct process type. + if (isWebViewProcess()) return; + + // Child processes set their own process type when bound. + String processName = ContextUtils.getProcessName(); + if (processName.contains("privileged_process") + || processName.contains("sandboxed_process")) { + return; + } + + // We must be in an isolated service process. + LibraryLoader.getInstance().setLibraryProcessType(LibraryProcessType.PROCESS_CHILD); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java index ba472d493..46f347a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
@@ -35,7 +35,7 @@ super.attachBaseContext(context); } - protected Impl createNonBrowserApplication() { - return new Impl(); + protected MainDexApplicationImpl createNonBrowserApplication() { + return new MainDexApplicationImpl(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java index 75e8304..2c372a6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java
@@ -12,17 +12,7 @@ import androidx.annotation.CallSuper; -import org.chromium.base.BundleUtils; import org.chromium.base.ContextUtils; -import org.chromium.base.JNIUtils; -import org.chromium.base.library_loader.LibraryLoader; -import org.chromium.base.library_loader.LibraryProcessType; -import org.chromium.base.memory.MemoryPressureMonitor; -import org.chromium.base.task.AsyncTask; -import org.chromium.chrome.browser.ProductConfig; -import org.chromium.components.embedder_support.application.FontPreloadingWorkaround; -import org.chromium.components.module_installer.util.ModuleUtil; -import org.chromium.ui.base.ResourceBundle; /** * Application base class which will call through to the given {@link Impl}. Application classes @@ -36,7 +26,7 @@ * Holds the implementation of application logic. Will be called by {@link * SplitCompatApplication}. */ - protected static class Impl { + public static class Impl { private SplitCompatApplication mApplication; private final void setApplication(SplitCompatApplication application) { @@ -48,67 +38,19 @@ } @CallSuper - public void onCreate() { - // These can't go in attachBaseContext because Context.getApplicationContext() (which - // they use under-the-hood) does not work until after it returns. - FontPreloadingWorkaround.maybeInstallWorkaround(getApplication()); - MemoryPressureMonitor.INSTANCE.registerComponentCallbacks(); - } - - @CallSuper public void attachBaseContext(Context context) { mApplication.superAttachBaseContext(context); - - // Perform initialization of globals common to all processes. - ContextUtils.initApplicationContext(getApplication()); - maybeInitProcessType(); - BundleUtils.setIsBundle(ProductConfig.IS_BUNDLE); - - // Write installed modules to crash keys. This needs to be done as early as possible so - // that these values are set before any crashes are reported. - ModuleUtil.updateCrashKeys(); - - AsyncTask.takeOverAndroidThreadPool(); - JNIUtils.setClassLoader(getApplication().getClassLoader()); - ResourceBundle.setAvailablePakLocales( - ProductConfig.COMPRESSED_LOCALES, ProductConfig.UNCOMPRESSED_LOCALES); - LibraryLoader.getInstance().setLinkerImplementation( - ProductConfig.USE_CHROMIUM_LINKER, ProductConfig.USE_MODERN_LINKER); - LibraryLoader.getInstance().enableJniChecks(); } - public void onTrimMemory(int level) {} - @CallSuper public void startActivity(Intent intent, Bundle options) { mApplication.superStartActivity(intent, options); } + public void onCreate() {} + + public void onTrimMemory(int level) {} public void onConfigurationChanged(Configuration newConfig) {} - - public boolean isWebViewProcess() { - return false; - } - - private void maybeInitProcessType() { - if (isBrowserProcess()) { - LibraryLoader.getInstance().setLibraryProcessType( - LibraryProcessType.PROCESS_BROWSER); - return; - } - // WebView initialization sets the correct process type. - if (isWebViewProcess()) return; - - // Child processes set their own process type when bound. - String processName = ContextUtils.getProcessName(); - if (processName.contains("privileged_process") - || processName.contains("sandboxed_process")) { - return; - } - - // We must be in an isolated service process. - LibraryLoader.getInstance().setLibraryProcessType(LibraryProcessType.PROCESS_CHILD); - } } public final void setImpl(Impl impl) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java index 2fcebb0..978b2013 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitMonochromeApplication.java
@@ -17,7 +17,7 @@ * SplitChromeApplication} for more info. */ public class SplitMonochromeApplication extends SplitChromeApplication { - private static class NonBrowserMonochromeApplication extends Impl { + private static class NonBrowserMonochromeApplication extends MainDexApplicationImpl { @Override public void attachBaseContext(Context context) { super.attachBaseContext(context); @@ -46,7 +46,7 @@ } @Override - protected Impl createNonBrowserApplication() { + protected MainDexApplicationImpl createNonBrowserApplication() { return new NonBrowserMonochromeApplication(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityDisclosureController.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityDisclosureController.java index 2e68736..6c1c5a6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityDisclosureController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityDisclosureController.java
@@ -73,6 +73,7 @@ @Override public void onDisclosureShown() { mBrowserServicesStore.setUserSeenTwaDisclosureForPackage(mClientPackageNameProvider.get()); + mModel.set(DISCLOSURE_FIRST_TIME, false); } /** Shows the disclosure if it is not already showing and hasn't been accepted. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/promo/enhanced_protection/EnhancedProtectionPromoController.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/promo/enhanced_protection/EnhancedProtectionPromoController.java index b11099fc..b4346a4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/promo/enhanced_protection/EnhancedProtectionPromoController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/promo/enhanced_protection/EnhancedProtectionPromoController.java
@@ -50,13 +50,13 @@ private EnhancedProtectionPromoStateListener mStateListener; private PromoCardCoordinator mPromoCoordinator; private PropertyModel mModel; - private boolean mIsPromoShowing; /** * Build the EnhancedProtectionPromoController that handles the set up / tear down for the * enhanced protection promo. * @param context Context from the activity. + * @param profile Current user profile. */ public EnhancedProtectionPromoController(Context context, @Nullable Profile profile) { mContext = context;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java index e303ab8..0f67909 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
@@ -44,8 +44,6 @@ @Before public void setUp() { mActivityTestRule.startMainActivityOnBlankPage(); - mAccountManagerTestRule.addTestAccountThenSigninAndEnableSync(); - mSettingsActivityTestRule.startSettingsActivity(); } @Test @@ -53,6 +51,8 @@ @Feature("RenderTest") @Features.DisableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY) public void testAccountManagementFragmentViewLegacy() throws Exception { + mAccountManagerTestRule.addTestAccountThenSigninAndEnableSync(); + mSettingsActivityTestRule.startSettingsActivity(); mRenderTestRule.render(mSettingsActivityTestRule.getFragment().getView(), "account_management_fragment_view_legacy"); } @@ -62,7 +62,21 @@ @Feature("RenderTest") @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY) public void testAccountManagementFragmentView() throws Exception { + mAccountManagerTestRule.addTestAccountThenSigninAndEnableSync(); + mSettingsActivityTestRule.startSettingsActivity(); mRenderTestRule.render(mSettingsActivityTestRule.getFragment().getView(), "account_management_fragment_view"); } + + @Test + @MediumTest + @Feature("RenderTest") + @Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY) + public void testSignedInAccountShownOnTop() throws Exception { + mAccountManagerTestRule.addAccount("testSecondary@gmail.com"); + mAccountManagerTestRule.addTestAccountThenSigninAndEnableSync(); + mSettingsActivityTestRule.startSettingsActivity(); + mRenderTestRule.render(mSettingsActivityTestRule.getFragment().getView(), + "account_management_fragment_signed_in_account_on_top"); + } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManagerTest.java index 3879798..99d3e943 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManagerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManagerTest.java
@@ -30,8 +30,11 @@ import org.chromium.chrome.browser.video_tutorials.Tutorial; import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory; import org.chromium.chrome.browser.video_tutorials.iph.VideoIPHCoordinator; +import org.chromium.chrome.browser.video_tutorials.iph.VideoTutorialIPHUtils; import org.chromium.chrome.browser.video_tutorials.test.TestVideoTutorialService; import org.chromium.chrome.test.util.browser.Features; +import org.chromium.components.feature_engagement.EventConstants; +import org.chromium.components.feature_engagement.FeatureConstants; import org.chromium.components.feature_engagement.Tracker; import java.util.HashMap; @@ -116,15 +119,17 @@ @Test public void testShowFirstEnabledIPH() { // We have already watched the first tutorial, the second one should show up as IPH card. + Tutorial testTutorial = mTestVideoTutorialService.getTestTutorials().get(1); Mockito.when(mTracker.shouldTriggerHelpUI(Mockito.anyString())).thenReturn(false, true); mVideoIPHManager = new TestNewTabPageVideoIPHManager(mViewStub, mProfile); - Mockito.verify(mVideoIPHCoordinator) - .showVideoIPH(mTestVideoTutorialService.getTestTutorials().get(1)); + Mockito.verify(mVideoIPHCoordinator).showVideoIPH(testTutorial); - // Click on the IPH. video player should be launched. - mIPHClickListener.onResult(mTestVideoTutorialService.getTestTutorials().get(1)); + // Click on the IPH. The video player should be launched. + mIPHClickListener.onResult(testTutorial); assertThat(mVideoIPHManager.videoPlayerLaunched, equalTo(true)); assertThat(mVideoIPHManager.videoListLaunched, equalTo(false)); + Mockito.verify(mTracker, Mockito.times(1)) + .notifyEvent(VideoTutorialIPHUtils.getClickEvent(testTutorial.featureType)); } @Test @@ -143,4 +148,63 @@ assertThat(mVideoIPHManager.videoPlayerLaunched, equalTo(false)); assertThat(mVideoIPHManager.videoListLaunched, equalTo(true)); } + + @Test + public void testDismissIPH() { + // Show a tutorial IPH. + Tutorial testTutorial = mTestVideoTutorialService.getTestTutorials().get(0); + Mockito.when(mTracker.shouldTriggerHelpUI(Mockito.anyString())).thenReturn(true); + mVideoIPHManager = new TestNewTabPageVideoIPHManager(mViewStub, mProfile); + Mockito.verify(mVideoIPHCoordinator).showVideoIPH(testTutorial); + + // Dismiss the IPH. The tracker should record this event. + mIPHDismissListener.onResult(testTutorial); + Mockito.verify(mTracker, Mockito.times(1)) + .notifyEvent(VideoTutorialIPHUtils.getDismissEvent(testTutorial.featureType)); + assertThat(mVideoIPHManager.videoPlayerLaunched, equalTo(false)); + assertThat(mVideoIPHManager.videoListLaunched, equalTo(false)); + } + + @Test + public void testClickEventForFeatureTypes() { + assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.SUMMARY), + equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_SUMMARY)); + assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.CHROME_INTRO), + equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_CHROME_INTRO)); + assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.DOWNLOAD), + equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_DOWNLOAD)); + assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.SEARCH), + equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_SEARCH)); + assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.VOICE_SEARCH), + equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_VOICE_SEARCH)); + } + + @Test + public void testDismissEventForFeatureTypes() { + assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.SUMMARY), + equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_SUMMARY)); + assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.CHROME_INTRO), + equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_CHROME_INTRO)); + assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.DOWNLOAD), + equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_DOWNLOAD)); + assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.SEARCH), + equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_SEARCH)); + assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.VOICE_SEARCH), + equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_VOICE_SEARCH)); + } + + @Test + public void testNTPFeatureNameForFeatureTypes() { + assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.SUMMARY), + equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_SUMMARY_FEATURE)); + assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.CHROME_INTRO), + equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_CHROME_INTRO_FEATURE)); + assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.DOWNLOAD), + equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_DOWNLOAD_FEATURE)); + assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.SEARCH), + equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_SEARCH_FEATURE)); + assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.VOICE_SEARCH), + equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_VOICE_SEARCH_FEATURE)); + assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.INVALID), equalTo(null)); + } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/OWNERS new file mode 100644 index 0000000..b7d1289 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/OWNERS
@@ -0,0 +1,5 @@ +file://chrome/browser/video_tutorials/OWNERS + +# TEAM: chrome-upboarding@chromium.org +# COMPONENT: Upboarding>VideoTutorials +# OS: Android
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityDisclosureControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityDisclosureControllerTest.java index 96c21b19..bf7df2a 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityDisclosureControllerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/ui/controller/trustedwebactivity/TrustedWebActivityDisclosureControllerTest.java
@@ -137,6 +137,16 @@ @Test @Feature("TrustedWebActivities") + public void reportsFirstTime_reportsSeenImmediately() { + doReturn(false).when(mStore).hasUserSeenTwaDisclosureForPackage(anyString()); + enterVerifiedOrigin(); + assertTrue(mModel.get(DISCLOSURE_FIRST_TIME)); + mModel.get(DISCLOSURE_EVENTS_CALLBACK).onDisclosureShown(); + assertFalse(mModel.get(DISCLOSURE_FIRST_TIME)); + } + + @Test + @Feature("TrustedWebActivities") public void recordsShown() { enterVerifiedOrigin(); mModel.get(DISCLOSURE_EVENTS_CALLBACK).onDisclosureShown();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollectorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollectorTest.java index f8ffc3e..9eb5f88 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollectorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollectorTest.java
@@ -33,7 +33,6 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Feature; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.test.util.browser.Features; @@ -114,8 +113,6 @@ @Test @Feature({"Feed"}) - @Features.EnableFeatures({ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS, - ChromeFeatureList.INTEREST_FEED_FEEDBACK}) public void testFeedSynchronousData() { @SuppressWarnings("unchecked")
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 85f4002..36bf3d4 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-88.0.4290.0_rc-r1-merged.afdo.bz2 +chromeos-chrome-amd64-88.0.4291.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index bf0fe29..b0bbb5a 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -6374,7 +6374,7 @@ Go to the <ph name="BEGIN_LINK1"><a href="#" id="legal-help-page-url"></ph>Legal Help page<ph name="END_LINK1"></a></ph> to request content changes for legal reasons. Some account and system information may be sent to Google. We will use the information you give us to help address technical issues and to improve our services, subject to our <ph name="BEGIN_LINK2"><a href="#" id="privacy-policy-url"></ph>Privacy Policy<ph name="END_LINK2"></a></ph> and <ph name="BEGIN_LINK3"><a href="#" id="terms-of-service-url"></ph>Terms of Service<ph name="END_LINK3"></a></ph>. </message> <message name="IDS_FEEDBACK_NO_DESCRIPTION" desc="Message shown when no text is entered before hitting send feedback"> - Please tell us what is happening before sending the feedback. + Please describe the problem before sending feedback. </message> <message name="IDS_FEEDBACK_SEND_REPORT" desc="Text for OK button of the send feedback dialog"> Send
diff --git a/chrome/app/generated_resources_grd/IDS_FEEDBACK_NO_DESCRIPTION.png.sha1 b/chrome/app/generated_resources_grd/IDS_FEEDBACK_NO_DESCRIPTION.png.sha1 new file mode 100644 index 0000000..b5f1883 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_FEEDBACK_NO_DESCRIPTION.png.sha1
@@ -0,0 +1 @@ +bcc758c32866264f6414228faa6ffdb96a5150a6 \ No newline at end of file
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index 6a97bfd..f1fe09d 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -69,6 +69,9 @@ <message name="IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_TITLE" desc="Title used for End of Life section on the About Page."> Update schedule </message> + <message name="IDS_SETTINGS_ABOUT_PAGE_DEVICE_NAME" desc="Title of the line item on the about page that allows the user to edit the device hostname."> + Device name + </message> <message name="IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS" desc="Status label: Rolling back ChromiumOS or Chrome OS."> Your administrator is rolling back this device (<ph name="PROGRESS_PERCENT">$1<ex>90%</ex></ph>) </message>
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ABOUT_PAGE_DEVICE_NAME.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ABOUT_PAGE_DEVICE_NAME.png.sha1 new file mode 100644 index 0000000..2bed6696 --- /dev/null +++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_ABOUT_PAGE_DEVICE_NAME.png.sha1
@@ -0,0 +1 @@ +cf4765ffcd1f3e4db5dadf2185e1160414102aab \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index d540fc0..cecaca74 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2115,6 +2115,7 @@ "//components/services/heap_profiling", "//components/services/language_detection/public/cpp", "//components/services/language_detection/public/mojom", + "//components/services/paint_preview_compositor/public/mojom:mojom", "//components/services/patch/content", "//components/services/quarantine", "//components/services/quarantine/public/mojom", @@ -4127,6 +4128,7 @@ "metrics/chromeos_metrics_provider.h", "metrics/cros_healthd_metrics_provider.cc", "metrics/cros_healthd_metrics_provider.h", + "metrics/enrollment_status.h", "metrics/family_user_metrics_provider.cc", "metrics/family_user_metrics_provider.h", "metrics/perf/collection_params.cc", @@ -4397,6 +4399,7 @@ "lacros/account_manager_util.h", "lacros/lacros_chrome_service_delegate_impl.cc", "lacros/lacros_chrome_service_delegate_impl.h", + "metrics/enrollment_status.h", "metrics/lacros_metrics_provider.cc", "metrics/lacros_metrics_provider.h", "notifications/notification_platform_bridge_chromeos.cc", @@ -5752,14 +5755,10 @@ if (enable_plugins) { sources += [ - "browsing_data/browsing_data_flash_lso_helper.cc", - "browsing_data/browsing_data_flash_lso_helper.h", "metrics/plugin_metrics_provider.cc", "metrics/plugin_metrics_provider.h", "pepper_broker_infobar_delegate.cc", "pepper_broker_infobar_delegate.h", - "pepper_flash_settings_manager.cc", - "pepper_flash_settings_manager.h", "plugins/chrome_content_browser_client_plugins_part.cc", "plugins/chrome_content_browser_client_plugins_part.h", "plugins/chrome_plugin_service_filter.cc", @@ -5774,8 +5773,6 @@ "plugins/flash_temporary_permission_tracker_factory.h", "plugins/hung_plugin_infobar_delegate.cc", "plugins/hung_plugin_infobar_delegate.h", - "plugins/plugin_data_remover_helper.cc", - "plugins/plugin_data_remover_helper.h", "plugins/plugin_finder.cc", "plugins/plugin_finder.h", "plugins/plugin_info_host_impl.cc", @@ -6417,8 +6414,6 @@ "autofill/mock_autofill_popup_controller.h", "autofill/mock_manual_filling_controller.cc", "autofill/mock_manual_filling_controller.h", - "browsing_data/mock_browsing_data_flash_lso_helper.cc", - "browsing_data/mock_browsing_data_flash_lso_helper.h", "browsing_data/mock_browsing_data_media_license_helper.cc", "browsing_data/mock_browsing_data_media_license_helper.h", "browsing_data/mock_browsing_data_quota_helper.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index 202397b9..edb9561 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -252,6 +252,7 @@ "+components/services/heap_profiling", "+components/services/language_detection/public/cpp", "+components/services/language_detection/public/mojom", + "+components/services/paint_preview_compositor/public/mojom", "+components/services/patch/content", "+components/services/patch/public", "+components/services/print_compositor/public",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 6e937c88..766c71c 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2335,6 +2335,20 @@ constexpr char kAmbientModeInternalName[] = "enable-ambient-mode"; #endif // OS_CHROMEOS +#if !defined(OS_WIN) && !defined(OS_FUCHSIA) +const FeatureEntry::FeatureParam + kSendWebUIJavaScriptErrorReportsVariationSendToStaging[] = { + {features::kSendWebUIJavaScriptErrorReportsSendToProductionVariation, + "false"}}; + +const FeatureEntry::FeatureVariation + kSendWebUIJavaScriptErrorReportsVariations[] = { + {"Send reports to staging server.", + kSendWebUIJavaScriptErrorReportsVariationSendToStaging, + base::size(kSendWebUIJavaScriptErrorReportsVariationSendToStaging), + nullptr}}; +#endif + #if defined(OS_ANDROID) // The variations of --metrics-settings-android. const FeatureEntry::FeatureParam kMetricsSettingsAndroidAlternativeOne[] = { @@ -2442,6 +2456,16 @@ flag_descriptions::kWebrtcPipeWireCapturerDescription, kOsLinux, FEATURE_VALUE_TYPE(features::kWebRtcPipeWireCapturer)}, #endif // defined(WEBRTC_USE_PIPEWIRE) +#if !defined(OS_WIN) && !defined(OS_FUCHSIA) + {"send-webui-javascript-error-reports", + flag_descriptions::kSendWebUIJavaScriptErrorReportsName, + flag_descriptions::kSendWebUIJavaScriptErrorReportsDescription, + kOsLinux | kOsCrOS | kOsAndroid, + FEATURE_WITH_PARAMS_VALUE_TYPE( + features::kSendWebUIJavaScriptErrorReports, + kSendWebUIJavaScriptErrorReportsVariations, + "SendWebUIJavaScriptErrorReportsVariations")}, +#endif #if !defined(OS_ANDROID) {"enable-webrtc-remote-event-log", flag_descriptions::kWebRtcRemoteEventLogName, @@ -3464,9 +3488,6 @@ flag_descriptions::kPostQuantumCECPQ2Description, kOsAll, FEATURE_VALUE_TYPE(net::features::kPostQuantumCECPQ2)}, #if defined(OS_ANDROID) - {"interest-feed-feedback", flag_descriptions::kInterestFeedFeedbackName, - flag_descriptions::kInterestFeedFeedbackDescription, kOsAndroid, - FEATURE_VALUE_TYPE(feed::kInterestFeedFeedback)}, {"interest-feed-v2", flag_descriptions::kInterestFeedV2Name, flag_descriptions::kInterestFeedV2Description, kOsAndroid, FEATURE_VALUE_TYPE(feed::kInterestFeedV2)},
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.cc b/chrome/browser/android/vr/arcore_device/fake_arcore.cc index d6476c13..1b2e10c 100644 --- a/chrome/browser/android/vr/arcore_device/fake_arcore.cc +++ b/chrome/browser/android/vr/arcore_device/fake_arcore.cc
@@ -17,6 +17,10 @@ FakeArCore::~FakeArCore() = default; +ArCore::MinMaxRange FakeArCore::GetTargetFramerateRange() { + return {30.f, 30.f}; +} + bool FakeArCore::Initialize( base::android::ScopedJavaLocalRef<jobject> application_context, const std::unordered_set<device::mojom::XRSessionFeature>&
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.h b/chrome/browser/android/vr/arcore_device/fake_arcore.h index 3d630f4..4235342 100644 --- a/chrome/browser/android/vr/arcore_device/fake_arcore.h +++ b/chrome/browser/android/vr/arcore_device/fake_arcore.h
@@ -26,6 +26,7 @@ base::android::ScopedJavaLocalRef<jobject> application_context, const std::unordered_set<device::mojom::XRSessionFeature>& enabled_features) override; + MinMaxRange GetTargetFramerateRange() override; void SetCameraTexture(uint32_t texture) override; void SetDisplayGeometry(const gfx::Size& frame_size, display::Display::Rotation display_rotation) override;
diff --git a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc b/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc deleted file mode 100644 index 3be1f6b..0000000 --- a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" - -#include <stdint.h> - -#include <limits> -#include <map> - -#include "base/callback.h" -#include "base/logging.h" -#include "base/macros.h" -#include "chrome/browser/pepper_flash_settings_manager.h" - -namespace { - -class BrowsingDataFlashLSOHelperImpl - : public BrowsingDataFlashLSOHelper, - public PepperFlashSettingsManager::Client { - public: - explicit BrowsingDataFlashLSOHelperImpl( - content::BrowserContext* browser_context); - - // BrowsingDataFlashLSOHelper implementation: - void StartFetching(GetSitesWithFlashDataCallback callback) override; - void DeleteFlashLSOsForSite(const std::string& site, - base::OnceClosure callback) override; - - // PepperFlashSettingsManager::Client overrides: - void OnGetSitesWithDataCompleted( - uint32_t request_id, - const std::vector<std::string>& sites) override; - void OnClearSiteDataCompleted(uint32_t request_id, bool success) override; - - private: - struct DeleteFlashLSOTask { - DeleteFlashLSOTask() {} - DeleteFlashLSOTask(const std::string& site, base::OnceClosure callback) - : site(site), callback(std::move(callback)) {} - - std::string site; - base::OnceClosure callback; - }; - - ~BrowsingDataFlashLSOHelperImpl() override; - - // Asynchronously fetches and deletes data and calls us back. - PepperFlashSettingsManager settings_manager_; - - // Identifies the request to fetch site data. - uint32_t get_sites_with_data_request_id_; - - // Contains the pending requests to clear site data. The key is the request - // ID, the value is the site for which to clear data and the callback to be - // called upon completion. - std::map<uint32_t, DeleteFlashLSOTask> clear_site_data_ids_; - - // Called when we have fetched the list of sites. - GetSitesWithFlashDataCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(BrowsingDataFlashLSOHelperImpl); -}; - -BrowsingDataFlashLSOHelperImpl::BrowsingDataFlashLSOHelperImpl( - content::BrowserContext* browser_context) - : settings_manager_(this, browser_context), - get_sites_with_data_request_id_(0u) { -} - -BrowsingDataFlashLSOHelperImpl::~BrowsingDataFlashLSOHelperImpl() { -} - -void BrowsingDataFlashLSOHelperImpl::StartFetching( - GetSitesWithFlashDataCallback callback) { - DCHECK(callback_.is_null()); - callback_ = std::move(callback); - get_sites_with_data_request_id_ = settings_manager_.GetSitesWithData(); -} - -void BrowsingDataFlashLSOHelperImpl::DeleteFlashLSOsForSite( - const std::string& site, - base::OnceClosure callback) { - const uint64_t kClearAllData = 0; - uint32_t id = settings_manager_.ClearSiteData( - site, kClearAllData, std::numeric_limits<uint64_t>::max()); - clear_site_data_ids_[id] = DeleteFlashLSOTask(site, std::move(callback)); -} - -void BrowsingDataFlashLSOHelperImpl::OnGetSitesWithDataCompleted( - uint32_t request_id, - const std::vector<std::string>& sites) { - DCHECK_EQ(get_sites_with_data_request_id_, request_id); - std::move(callback_).Run(sites); -} - -void BrowsingDataFlashLSOHelperImpl::OnClearSiteDataCompleted( - uint32_t request_id, - bool success) { - auto entry = clear_site_data_ids_.find(request_id); - DCHECK(entry != clear_site_data_ids_.end()); - LOG_IF(ERROR, !success) << "Couldn't clear Flash LSO data for " - << entry->second.site; - if (!entry->second.callback.is_null()) - std::move(entry->second.callback).Run(); - clear_site_data_ids_.erase(entry); -} - -} // namespace - -// static -BrowsingDataFlashLSOHelper* BrowsingDataFlashLSOHelper::Create( - content::BrowserContext* browser_context) { - return new BrowsingDataFlashLSOHelperImpl(browser_context); -}
diff --git a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.h b/chrome/browser/browsing_data/browsing_data_flash_lso_helper.h deleted file mode 100644 index 40ba100d..0000000 --- a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_BROWSING_DATA_BROWSING_DATA_FLASH_LSO_HELPER_H_ -#define CHROME_BROWSER_BROWSING_DATA_BROWSING_DATA_FLASH_LSO_HELPER_H_ - -#include <string> -#include <vector> - -#include "base/callback_forward.h" -#include "base/memory/ref_counted.h" - -namespace content { -class BrowserContext; -} - -// This class asynchronously fetches information about Flash LSOs and can delete -// them. -class BrowsingDataFlashLSOHelper - : public base::RefCounted<BrowsingDataFlashLSOHelper> { - public: - typedef base::OnceCallback<void(const std::vector<std::string>&)> - GetSitesWithFlashDataCallback; - - static BrowsingDataFlashLSOHelper* Create( - content::BrowserContext* browser_context); - - virtual void StartFetching(GetSitesWithFlashDataCallback callback) = 0; - virtual void DeleteFlashLSOsForSite(const std::string& site, - base::OnceClosure callback) = 0; - - protected: - friend class base::RefCounted<BrowsingDataFlashLSOHelper>; - virtual ~BrowsingDataFlashLSOHelper() {} -}; - -#endif // CHROME_BROWSER_BROWSING_DATA_BROWSING_DATA_FLASH_LSO_HELPER_H_
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc index 39c5cd9..91f3069 100644 --- a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc +++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
@@ -22,7 +22,6 @@ #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browsing_data/browsing_data_file_system_util.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h" #include "chrome/browser/browsing_data/cookies_tree_model.h" #include "chrome/browser/browsing_data/counters/cache_counter.h" @@ -560,7 +559,6 @@ new browsing_data::SharedWorkerHelper(storage_partition, profile->GetResourceContext()), new browsing_data::CacheStorageHelper(cache_storage_context), - BrowsingDataFlashLSOHelper::Create(profile), BrowsingDataMediaLicenseHelper::Create(file_system_context)); base::RunLoop run_loop; CookiesTreeObserver observer(run_loop.QuitClosure());
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index c84f395..305b4452 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -65,6 +65,8 @@ #include "chrome/browser/previews/previews_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" +#include "chrome/browser/spellchecker/spellcheck_factory.h" +#include "chrome/browser/spellchecker/spellcheck_service.h" #include "chrome/browser/translate/chrome_translate_client.h" #include "chrome/browser/ui/find_bar/find_bar_state.h" #include "chrome/browser/ui/find_bar/find_bar_state_factory.h" @@ -165,10 +167,6 @@ #include "device/fido/mac/credential_store.h" #endif // defined(OS_MAC) -#if BUILDFLAG(ENABLE_PLUGINS) -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" -#endif // BUILDFLAG(ENABLE_PLUGINS) - using base::UserMetricsAction; using content::BrowserContext; using content::BrowserThread; @@ -266,10 +264,6 @@ ChromeBrowsingDataRemoverDelegate::ChromeBrowsingDataRemoverDelegate( BrowserContext* browser_context) : profile_(Profile::FromBrowserContext(browser_context)) -#if BUILDFLAG(ENABLE_PLUGINS) - , - flash_lso_helper_(BrowsingDataFlashLSOHelper::Create(browser_context)) -#endif #if defined(OS_ANDROID) , webapp_registry_(new WebappRegistry()) @@ -737,6 +731,17 @@ } ////////////////////////////////////////////////////////////////////////////// + // DATA_TYPE_LOCAL_CUSTOM_DICTIONARY + if (remove_mask & DATA_TYPE_LOCAL_CUSTOM_DICTIONARY) { + auto* spellcheck = SpellcheckServiceFactory::GetForContext(profile_); + if (spellcheck) { + auto* dict = spellcheck->GetCustomDictionary(); + if (dict) + dict->Clear(); + } + } + + ////////////////////////////////////////////////////////////////////////////// // DATA_TYPE_DURABLE_PERMISSION if (remove_mask & DATA_TYPE_DURABLE_PERMISSION) { host_content_settings_map_->ClearSettingsForOneTypeWithPredicate( @@ -1025,16 +1030,6 @@ } } -////////////////////////////////////////////////////////////////////////////// -// DATA_TYPE_PLUGINS -// Plugins are known to //content and their bulk deletion is implemented in -// PluginDataRemover. However, the filtered deletion uses -// BrowsingDataFlashLSOHelper which (currently) has strong dependencies -// on //chrome. -// TODO(msramek): Investigate these dependencies and move the plugin deletion -// to BrowsingDataRemoverImpl in //content. Note that code in //content -// can simply take advantage of PluginDataRemover directly to delete plugin -// data in bulk. #if BUILDFLAG(ENABLE_PLUGINS) // Plugin is data not separated for protected and unprotected web origins. We // check the origin_type_mask_ to prevent unintended deletion. @@ -1044,25 +1039,8 @@ base::RecordAction(UserMetricsAction("ClearBrowsingData_LSOData")); if (filter_builder->MatchesAllOriginsAndDomains()) { - DCHECK(!plugin_data_remover_); - plugin_data_remover_.reset(content::PluginDataRemover::Create(profile_)); - base::WaitableEvent* event = - plugin_data_remover_->StartRemoving(delete_begin_); - - base::WaitableEventWatcher::EventCallback watcher_callback = - base::BindOnce( - &ChromeBrowsingDataRemoverDelegate::OnWaitableEventSignaled, - weak_ptr_factory_.GetWeakPtr(), - CreateTaskCompletionClosure(TracingDataType::kPluginData)); - watcher_.StartWatching(event, std::move(watcher_callback), - base::SequencedTaskRunnerHandle::Get()); - } else { - // TODO(msramek): Store filters from the currently executed task on the - // object to avoid having to copy them to callback methods. - flash_lso_helper_->StartFetching(base::BindOnce( - &ChromeBrowsingDataRemoverDelegate::OnSitesWithFlashDataFetched, - weak_ptr_factory_.GetWeakPtr(), filter_builder->BuildPluginFilter(), - CreateTaskCompletionClosure(TracingDataType::kFlashLsoHelper))); + // TODO(bbudge) Figure out how to delete Flash plugin data without a + // Flash plugin. } } #endif @@ -1074,21 +1052,6 @@ // Licenses. base::RecordAction(UserMetricsAction("ClearBrowsingData_ContentLicenses")); -#if BUILDFLAG(ENABLE_PLUGINS) - // Flash does not support filtering by domain, so skip this if clearing only - // a specified set of sites. - if (filter_builder->GetMode() != BrowsingDataFilterBuilder::Mode::kDelete) { - // Will be completed in OnDeauthorizeFlashContentLicensesCompleted() - OnTaskStarted(TracingDataType::kFlashDeauthorization); - if (!pepper_flash_settings_manager_.get()) { - pepper_flash_settings_manager_.reset( - new PepperFlashSettingsManager(this, profile_)); - } - deauthorize_flash_content_licenses_request_id_ = - pepper_flash_settings_manager_->DeauthorizeContentLicenses(prefs); - } -#endif // BUILDFLAG(ENABLE_PLUGINS) - #if defined(OS_CHROMEOS) // On Chrome OS, delete any content protection platform keys. // Platform keys do not support filtering by domain, so skip this if @@ -1305,13 +1268,6 @@ } #endif -#if BUILDFLAG(ENABLE_PLUGINS) -void ChromeBrowsingDataRemoverDelegate::OverrideFlashLSOHelperForTesting( - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper) { - flash_lso_helper_ = flash_lso_helper; -} -#endif - void ChromeBrowsingDataRemoverDelegate:: OverrideDomainReliabilityClearerForTesting( DomainReliabilityClearer clearer) { @@ -1331,40 +1287,3 @@ std::move(done).Run(); } #endif - -#if BUILDFLAG(ENABLE_PLUGINS) -void ChromeBrowsingDataRemoverDelegate::OnWaitableEventSignaled( - base::OnceClosure done, - base::WaitableEvent* waitable_event) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - plugin_data_remover_.reset(); - watcher_.StopWatching(); - std::move(done).Run(); -} - -void ChromeBrowsingDataRemoverDelegate::OnSitesWithFlashDataFetched( - base::RepeatingCallback<bool(const std::string&)> plugin_filter, - base::OnceClosure done, - const std::vector<std::string>& sites) { - std::vector<std::string> sites_to_delete; - for (const std::string& site : sites) { - if (plugin_filter.Run(site)) - sites_to_delete.push_back(site); - } - - base::RepeatingClosure barrier = - base::BarrierClosure(sites_to_delete.size(), std::move(done)); - - for (const std::string& site : sites_to_delete) { - flash_lso_helper_->DeleteFlashLSOsForSite(site, barrier); - } -} - -void ChromeBrowsingDataRemoverDelegate:: - OnDeauthorizeFlashContentLicensesCompleted(uint32_t request_id, - bool /* success */) { - DCHECK_EQ(request_id, deauthorize_flash_content_licenses_request_id_); - OnTaskComplete(TracingDataType::kFlashDeauthorization, - /*data_type_mask=*/0, /*success=*/true); -} -#endif
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h index a941467..921a08cf 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
@@ -26,17 +26,11 @@ #include "ppapi/buildflags/buildflags.h" #include "services/network/public/mojom/network_context.mojom.h" -#if BUILDFLAG(ENABLE_PLUGINS) -#include "chrome/browser/pepper_flash_settings_manager.h" -#endif - -class BrowsingDataFlashLSOHelper; class Profile; class WebappRegistry; namespace content { class BrowserContext; -class PluginDataRemover; } namespace webrtc_event_logging { @@ -48,10 +42,6 @@ class ChromeBrowsingDataRemoverDelegate : public content::BrowsingDataRemoverDelegate, public KeyedService -#if BUILDFLAG(ENABLE_PLUGINS) - , - public PepperFlashSettingsManager::Client -#endif { public: // This is an extension of content::BrowsingDataRemover::RemoveDataMask which @@ -77,6 +67,7 @@ DATA_TYPE_BOOKMARKS = DATA_TYPE_EMBEDDER_BEGIN << 10, DATA_TYPE_ISOLATED_ORIGINS = DATA_TYPE_EMBEDDER_BEGIN << 11, DATA_TYPE_ACCOUNT_PASSWORDS = DATA_TYPE_EMBEDDER_BEGIN << 12, + DATA_TYPE_LOCAL_CUSTOM_DICTIONARY = DATA_TYPE_EMBEDDER_BEGIN << 13, // Group datatypes. @@ -122,7 +113,8 @@ DATA_TYPE_HISTORY | // DATA_TYPE_PASSWORDS | // DATA_TYPE_CONTENT_SETTINGS | // - DATA_TYPE_BOOKMARKS, + DATA_TYPE_BOOKMARKS | // + DATA_TYPE_LOCAL_CUSTOM_DICTIONARY, // Includes all available remove options. Meant to be used when the Profile // is scheduled to be deleted, and all possible data should be wiped from @@ -196,12 +188,6 @@ std::unique_ptr<WebappRegistry> webapp_registry); #endif -#if BUILDFLAG(ENABLE_PLUGINS) - // Used for testing. - void OverrideFlashLSOHelperForTesting( - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper); -#endif - using DomainReliabilityClearer = base::RepeatingCallback<void( content::BrowsingDataFilterBuilder* filter_builder, network::mojom::NetworkContext_DomainReliabilityClearMode, @@ -224,7 +210,7 @@ kAutofillData = 6, kAutofillOrigins = 7, kPluginData = 8, - kFlashLsoHelper = 9, + kFlashLsoHelper = 9, // deprecated kDomainReliability = 10, kNetworkPredictor = 11, kWebrtcLogs = 12, @@ -298,16 +284,6 @@ // Called when plugin data has been cleared. Invokes NotifyIfDone. void OnWaitableEventSignaled(base::OnceClosure done, base::WaitableEvent* waitable_event); - - // Called when the list of |sites| storing Flash LSO cookies is fetched. - void OnSitesWithFlashDataFetched( - base::RepeatingCallback<bool(const std::string&)> plugin_filter, - base::OnceClosure done, - const std::vector<std::string>& sites); - - // PepperFlashSettingsManager::Client implementation. - void OnDeauthorizeFlashContentLicensesCompleted(uint32_t request_id, - bool success) override; #endif // The profile for which the data will be deleted. @@ -331,20 +307,6 @@ // are finished. base::CancelableClosure slow_pending_tasks_closure_; -#if BUILDFLAG(ENABLE_PLUGINS) - // Used to delete plugin data. - std::unique_ptr<content::PluginDataRemover> plugin_data_remover_; - base::WaitableEventWatcher watcher_; - - // Used for per-site plugin data deletion. - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper_; - - uint32_t deauthorize_flash_content_licenses_request_id_ = 0; - - // Used to deauthorize content licenses for Pepper Flash. - std::unique_ptr<PepperFlashSettingsManager> pepper_flash_settings_manager_; -#endif - DomainReliabilityClearer domain_reliability_clearer_; // Used if we need to clear history.
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index 517cd409..d081fd4 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -52,12 +52,17 @@ #include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h" #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" +#include "chrome/browser/spellchecker/spellcheck_custom_dictionary.h" +#include "chrome/browser/spellchecker/spellcheck_factory.h" +#include "chrome/browser/spellchecker/spellcheck_service.h" #include "chrome/browser/ssl/stateful_ssl_host_state_delegate_factory.h" #include "chrome/browser/storage/durable_storage_permission_context.h" #include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/translate/chrome_translate_client.h" +#include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_features.h" +#include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" @@ -154,7 +159,6 @@ #endif // BUILDFLAG(ENABLE_EXTENSIONS) #if BUILDFLAG(ENABLE_PLUGINS) -#include "chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h" #include "chrome/browser/plugins/chrome_plugin_service_filter.h" #include "chrome/browser/plugins/plugin_utils.h" #endif // BUILDFLAG(ENABLE_PLUGINS) @@ -648,91 +652,6 @@ DISALLOW_COPY_AND_ASSIGN(RemovePermissionPromptCountsTest); }; -#if BUILDFLAG(ENABLE_PLUGINS) -// A small modification to MockBrowsingDataFlashLSOHelper so that it responds -// immediately and does not wait for the Notify() call. Otherwise it would -// deadlock BrowsingDataRemoverImpl::RemoveImpl. -class TestBrowsingDataFlashLSOHelper : public MockBrowsingDataFlashLSOHelper { - public: - explicit TestBrowsingDataFlashLSOHelper(TestingProfile* profile) - : MockBrowsingDataFlashLSOHelper(profile) {} - - void StartFetching(GetSitesWithFlashDataCallback callback) override { - MockBrowsingDataFlashLSOHelper::StartFetching(std::move(callback)); - Notify(); - } - - private: - ~TestBrowsingDataFlashLSOHelper() override {} - - DISALLOW_COPY_AND_ASSIGN(TestBrowsingDataFlashLSOHelper); -}; - -class RemovePluginDataTester { - public: - explicit RemovePluginDataTester(TestingProfile* profile) - : helper_(new TestBrowsingDataFlashLSOHelper(profile)) { - static_cast<ChromeBrowsingDataRemoverDelegate*>( - profile->GetBrowsingDataRemoverDelegate()) - ->OverrideFlashLSOHelperForTesting(helper_); - } - - void AddDomain(const std::string& domain) { - helper_->AddFlashLSODomain(domain); - } - - const std::vector<std::string>& GetDomains() { - // TestBrowsingDataFlashLSOHelper is synchronous, so we can immediately - // return the fetched domains. - helper_->StartFetching( - base::BindOnce(&RemovePluginDataTester::OnSitesWithFlashDataFetched, - base::Unretained(this))); - return domains_; - } - - private: - void OnSitesWithFlashDataFetched(const std::vector<std::string>& sites) { - domains_ = sites; - } - - std::vector<std::string> domains_; - scoped_refptr<TestBrowsingDataFlashLSOHelper> helper_; - - DISALLOW_COPY_AND_ASSIGN(RemovePluginDataTester); -}; - -// Waits until a change is observed in content settings. -class FlashContentSettingsChangeWaiter : public content_settings::Observer { - public: - explicit FlashContentSettingsChangeWaiter(Profile* profile) - : profile_(profile) { - HostContentSettingsMapFactory::GetForProfile(profile)->AddObserver(this); - } - ~FlashContentSettingsChangeWaiter() override { - HostContentSettingsMapFactory::GetForProfile(profile_)->RemoveObserver( - this); - } - - // content_settings::Observer: - void OnContentSettingChanged( - const ContentSettingsPattern& primary_pattern, - const ContentSettingsPattern& secondary_pattern, - ContentSettingsType content_type, - const std::string& resource_identifier) override { - if (content_type == ContentSettingsType::PLUGINS) - run_loop_.Quit(); - } - - void Wait() { run_loop_.Run(); } - - private: - Profile* profile_; - base::RunLoop run_loop_; - - DISALLOW_COPY_AND_ASSIGN(FlashContentSettingsChangeWaiter); -}; -#endif - // Custom matcher to test the equivalence of two URL filters. Since those are // blackbox predicates, we can only approximate the equivalence by testing // whether the filter give the same answer for several URLs. This is currently @@ -1153,6 +1072,12 @@ profile_builder.AddTestingFactory( FaviconServiceFactory::GetInstance(), FaviconServiceFactory::GetDefaultFactory()); + profile_builder.AddTestingFactory( + SpellcheckServiceFactory::GetInstance(), + base::BindRepeating([](content::BrowserContext* profile) { + return std::unique_ptr<KeyedService>( + new SpellcheckService(static_cast<Profile*>(profile))); + })); profile_ = profile_builder.Build(); @@ -2795,84 +2720,6 @@ } } -#if BUILDFLAG(ENABLE_PLUGINS) -// Check the |ContentSettingsType::PLUGINS_DATA| content setting is cleared -// with browsing data. -TEST_F(ChromeBrowsingDataRemoverDelegateTest, ClearFlashPreviouslyChanged) { - ChromePluginServiceFilter::GetInstance()->RegisterProfile(GetProfile()); - - HostContentSettingsMap* host_content_settings_map = - HostContentSettingsMapFactory::GetForProfile(GetProfile()); - - // PLUGINS_DATA gets cleared with history OR site usage data. - for (ChromeBrowsingDataRemoverDelegate::DataType data_type : - {ChromeBrowsingDataRemoverDelegate::DATA_TYPE_SITE_USAGE_DATA, - ChromeBrowsingDataRemoverDelegate::DATA_TYPE_HISTORY}) { - FlashContentSettingsChangeWaiter waiter(GetProfile()); - host_content_settings_map->SetContentSettingDefaultScope( - Origin1(), Origin1(), ContentSettingsType::PLUGINS, std::string(), - CONTENT_SETTING_ALLOW); - host_content_settings_map->SetContentSettingDefaultScope( - Origin2(), Origin2(), ContentSettingsType::PLUGINS, std::string(), - CONTENT_SETTING_BLOCK); - waiter.Wait(); - - // Check that as a result, the PLUGINS_DATA prefs were populated. - EXPECT_NE(nullptr, - host_content_settings_map->GetWebsiteSetting( - Origin1(), Origin1(), ContentSettingsType::PLUGINS_DATA, - std::string(), nullptr)); - EXPECT_NE(nullptr, - host_content_settings_map->GetWebsiteSetting( - Origin2(), Origin2(), ContentSettingsType::PLUGINS_DATA, - std::string(), nullptr)); - - std::unique_ptr<BrowsingDataFilterBuilder> filter( - BrowsingDataFilterBuilder::Create( - BrowsingDataFilterBuilder::Mode::kPreserve)); - BlockUntilOriginDataRemoved(AnHourAgo(), base::Time::Max(), data_type, - std::move(filter)); - EXPECT_EQ(nullptr, - host_content_settings_map->GetWebsiteSetting( - Origin1(), Origin1(), ContentSettingsType::PLUGINS_DATA, - std::string(), nullptr)); - EXPECT_EQ(nullptr, - host_content_settings_map->GetWebsiteSetting( - Origin2(), Origin2(), ContentSettingsType::PLUGINS_DATA, - std::string(), nullptr)); - } -} - -TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemovePluginData) { - RemovePluginDataTester tester(GetProfile()); - - tester.AddDomain(Origin1().host()); - tester.AddDomain(Origin2().host()); - tester.AddDomain(Origin3().host()); - - std::vector<std::string> expected = {Origin1().host(), Origin2().host(), - Origin3().host()}; - EXPECT_EQ(expected, tester.GetDomains()); - - // Delete data with a filter for the registrable domain of |Origin3()|. - std::unique_ptr<BrowsingDataFilterBuilder> filter_builder( - BrowsingDataFilterBuilder::Create( - BrowsingDataFilterBuilder::Mode::kDelete)); - filter_builder->AddRegisterableDomain(kTestRegisterableDomain3); - BlockUntilOriginDataRemoved( - base::Time(), base::Time::Max(), - ChromeBrowsingDataRemoverDelegate::DATA_TYPE_PLUGIN_DATA, - std::move(filter_builder)); - - // Plugin data for |Origin3().host()| should have been removed. - expected.pop_back(); - EXPECT_EQ(expected, tester.GetDomains()); - - // TODO(msramek): Mock PluginDataRemover and test the complete deletion - // of plugin data as well. -} -#endif - // Test that the remover clears language model data (normally added by the // LanguageDetectionDriver). TEST_F(ChromeBrowsingDataRemoverDelegateTest, @@ -3197,6 +3044,39 @@ } #endif +TEST_F(ChromeBrowsingDataRemoverDelegateTest, WipeCustomDictionaryData) { + base::FilePath dict_path = + GetProfile()->GetPath().Append(chrome::kCustomDictionaryFileName); + base::FilePath backup_path = dict_path.AddExtensionASCII("backup"); + + auto* spellcheck = SpellcheckServiceFactory::GetForContext(GetProfile()); + ASSERT_NE(nullptr, spellcheck); + auto* dict = spellcheck->GetCustomDictionary(); + ASSERT_NE(nullptr, dict); + + auto change1 = std::make_unique<SpellcheckCustomDictionary::Change>(); + change1->AddWord("wug"); + dict->UpdateDictionaryFile(std::move(change1), dict_path); + + auto change2 = std::make_unique<SpellcheckCustomDictionary::Change>(); + change2->AddWord("spowing"); + dict->UpdateDictionaryFile(std::move(change2), dict_path); + + EXPECT_TRUE(base::PathExists(dict_path)); + EXPECT_TRUE(base::PathExists(backup_path)); + + BlockUntilBrowsingDataRemoved( + base::Time(), base::Time::Max(), + ChromeBrowsingDataRemoverDelegate::DATA_TYPE_LOCAL_CUSTOM_DICTIONARY, + false); + + std::string contents; + base::ReadFileToString(dict_path, &contents); + EXPECT_EQ(std::string::npos, contents.find("wug")); + EXPECT_EQ(std::string::npos, contents.find("spowing")); + EXPECT_FALSE(base::PathExists(backup_path)); +} + TEST_F(ChromeBrowsingDataRemoverDelegateTest, WipeNotificationPermissionPromptOutcomesData) { PrefService* prefs = GetProfile()->GetPrefs();
diff --git a/chrome/browser/browsing_data/cookies_tree_model.cc b/chrome/browser/browsing_data/cookies_tree_model.cc index 6e9569b..34b1a17 100644 --- a/chrome/browser/browsing_data/cookies_tree_model.cc +++ b/chrome/browser/browsing_data/cookies_tree_model.cc
@@ -21,7 +21,6 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/browsing_data/browsing_data_file_system_util.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" #include "chrome/browser/browsing_data/browsing_data_quota_helper.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/browser/profiles/profile.h" @@ -159,7 +158,6 @@ // Fall through each below cases to return false. case CookieTreeNode::DetailedInfo::TYPE_COOKIE: case CookieTreeNode::DetailedInfo::TYPE_QUOTA: - case CookieTreeNode::DetailedInfo::TYPE_FLASH_LSO: case CookieTreeNode::DetailedInfo::TYPE_MEDIA_LICENSE: return false; default: @@ -290,13 +288,6 @@ return *this; } -CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitFlashLSO( - const std::string& flash_lso_domain) { - Init(TYPE_FLASH_LSO); - this->flash_lso_domain = flash_lso_domain; - return *this; -} - CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitMediaLicense( const BrowsingDataMediaLicenseHelper::MediaLicenseInfo* media_license_info) { @@ -1164,38 +1155,6 @@ }; /////////////////////////////////////////////////////////////////////////////// -// CookieTreeFlashLSONode - -class CookieTreeFlashLSONode : public CookieTreeNode { - public: - explicit CookieTreeFlashLSONode(const std::string& domain) - : domain_(domain) {} - ~CookieTreeFlashLSONode() override = default; - - // CookieTreeNode methods: - void DeleteStoredObjects() override { - // We are one level below the host node. - CookieTreeHostNode* host = static_cast<CookieTreeHostNode*>(parent()); - CHECK_EQ(host->GetDetailedInfo().node_type, - CookieTreeNode::DetailedInfo::TYPE_HOST); - LocalDataContainer* container = GetModel()->data_container(); - container->flash_lso_helper_->DeleteFlashLSOsForSite(domain_, - base::OnceClosure()); - auto entry = std::find(container->flash_lso_domain_list_.begin(), - container->flash_lso_domain_list_.end(), domain_); - container->flash_lso_domain_list_.erase(entry); - } - DetailedInfo GetDetailedInfo() const override { - return DetailedInfo().InitFlashLSO(domain_); - } - - private: - std::string domain_; - - DISALLOW_COPY_AND_ASSIGN(CookieTreeFlashLSONode); -}; - -/////////////////////////////////////////////////////////////////////////////// // CookieTreeMediaLicensesNode class CookieTreeMediaLicensesNode : public CookieTreeCollectionNode { @@ -1345,16 +1304,6 @@ return cache_storages_child_; } -CookieTreeFlashLSONode* CookieTreeHostNode::GetOrCreateFlashLSONode( - const std::string& domain) { - DCHECK_EQ(GetHost(), domain); - if (flash_lso_child_) - return flash_lso_child_; - flash_lso_child_ = new CookieTreeFlashLSONode(domain); - AddChildSortedByTitle(base::WrapUnique(flash_lso_child_)); - return flash_lso_child_; -} - CookieTreeMediaLicensesNode* CookieTreeHostNode::GetOrCreateMediaLicensesNode() { if (media_licenses_child_) @@ -1532,7 +1481,6 @@ PopulateServiceWorkerUsageInfoWithFilter(data_container(), ¬ifier, filter); PopulateSharedWorkerInfoWithFilter(data_container(), ¬ifier, filter); PopulateCacheStorageUsageInfoWithFilter(data_container(), ¬ifier, filter); - PopulateFlashLSOInfoWithFilter(data_container(), ¬ifier, filter); PopulateMediaLicenseInfoWithFilter(data_container(), ¬ifier, filter); } @@ -1625,12 +1573,6 @@ base::string16()); } -void CookiesTreeModel::PopulateFlashLSOInfo( - LocalDataContainer* container) { - ScopedBatchUpdateNotifier notifier(this, GetRoot()); - PopulateFlashLSOInfoWithFilter(container, ¬ifier, base::string16()); -} - void CookiesTreeModel::PopulateMediaLicenseInfo(LocalDataContainer* container) { ScopedBatchUpdateNotifier notifier(this, GetRoot()); PopulateMediaLicenseInfoWithFilter(container, ¬ifier, base::string16()); @@ -1923,27 +1865,6 @@ } } -void CookiesTreeModel::PopulateFlashLSOInfoWithFilter( - LocalDataContainer* container, - ScopedBatchUpdateNotifier* notifier, - const base::string16& filter) { - CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot()); - - if (container->flash_lso_domain_list_.empty()) - return; - - std::string filter_utf8 = base::UTF16ToUTF8(filter); - notifier->StartBatchUpdate(); - for (const std::string& domain : container->flash_lso_domain_list_) { - if (filter_utf8.empty() || domain.find(filter_utf8) != std::string::npos) { - // Create a fake origin for GetOrCreateHostNode(). - GURL origin("http://" + domain); - CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin); - host_node->GetOrCreateFlashLSONode(domain); - } - } -} - void CookiesTreeModel::PopulateMediaLicenseInfoWithFilter( LocalDataContainer* container, ScopedBatchUpdateNotifier* notifier, @@ -2051,13 +1972,6 @@ profile->GetResourceContext()), new browsing_data::CacheStorageHelper( storage_partition->GetCacheStorageContext()), -#if defined(OS_ANDROID) - // Android doesn't have flash LSO hence it cannot be created for - // android build. - nullptr, -#else - BrowsingDataFlashLSOHelper::Create(profile), -#endif BrowsingDataMediaLicenseHelper::Create(file_system_context)); #if !defined(OS_ANDROID)
diff --git a/chrome/browser/browsing_data/cookies_tree_model.h b/chrome/browser/browsing_data/cookies_tree_model.h index be7ea213..ac0daf8d 100644 --- a/chrome/browser/browsing_data/cookies_tree_model.h +++ b/chrome/browser/browsing_data/cookies_tree_model.h
@@ -35,7 +35,6 @@ class CookieTreeDatabasesNode; class CookieTreeFileSystemNode; class CookieTreeFileSystemsNode; -class CookieTreeFlashLSONode; class CookieTreeHostNode; class CookieTreeIndexedDBNode; class CookieTreeIndexedDBsNode; @@ -100,7 +99,6 @@ TYPE_SHARED_WORKER, // This is used for CookieTreeSharedWorkerNode. TYPE_CACHE_STORAGES, // This is used for CookieTreeCacheStoragesNode. TYPE_CACHE_STORAGE, // This is used for CookieTreeCacheStorageNode. - TYPE_FLASH_LSO, // This is used for CookieTreeFlashLSONode. TYPE_MEDIA_LICENSES, // This is used for CookieTreeMediaLicensesNode. TYPE_MEDIA_LICENSE, // This is used for CookieTreeMediaLicenseNode. }; @@ -130,7 +128,6 @@ const browsing_data::SharedWorkerHelper::SharedWorkerInfo* shared_worker_info); DetailedInfo& InitCacheStorage(const content::StorageUsageInfo* usage_info); - DetailedInfo& InitFlashLSO(const std::string& flash_lso_domain); DetailedInfo& InitMediaLicense( const BrowsingDataMediaLicenseHelper::MediaLicenseInfo* media_license_info); @@ -146,7 +143,6 @@ const BrowsingDataQuotaHelper::QuotaInfo* quota_info = nullptr; const browsing_data::SharedWorkerHelper::SharedWorkerInfo* shared_worker_info = nullptr; - std::string flash_lso_domain; const BrowsingDataMediaLicenseHelper::MediaLicenseInfo* media_license_info = nullptr; }; @@ -235,7 +231,6 @@ CookieTreeCacheStoragesNode* GetOrCreateCacheStoragesNode(); CookieTreeQuotaNode* UpdateOrCreateQuotaNode( std::list<BrowsingDataQuotaHelper::QuotaInfo>::iterator quota_info); - CookieTreeFlashLSONode* GetOrCreateFlashLSONode(const std::string& domain); CookieTreeMediaLicensesNode* GetOrCreateMediaLicensesNode(); std::string canonicalized_host() const { return canonicalized_host_; } @@ -269,7 +264,6 @@ CookieTreeServiceWorkersNode* service_workers_child_ = nullptr; CookieTreeSharedWorkersNode* shared_workers_child_ = nullptr; CookieTreeCacheStoragesNode* cache_storages_child_ = nullptr; - CookieTreeFlashLSONode* flash_lso_child_ = nullptr; CookieTreeMediaLicensesNode* media_licenses_child_ = nullptr; // The URL for which this node was initially created. @@ -378,7 +372,6 @@ void PopulateServiceWorkerUsageInfo(LocalDataContainer* container); void PopulateSharedWorkerInfo(LocalDataContainer* container); void PopulateCacheStorageUsageInfo(LocalDataContainer* container); - void PopulateFlashLSOInfo(LocalDataContainer* container); void PopulateMediaLicenseInfo(LocalDataContainer* container); // Returns the Access Context Audit service provided to the cookies tree model @@ -456,9 +449,6 @@ LocalDataContainer* container, ScopedBatchUpdateNotifier* notifier, const base::string16& filter); - void PopulateFlashLSOInfoWithFilter(LocalDataContainer* container, - ScopedBatchUpdateNotifier* notifier, - const base::string16& filter); void PopulateMediaLicenseInfoWithFilter(LocalDataContainer* container, ScopedBatchUpdateNotifier* notifier, const base::string16& filter);
diff --git a/chrome/browser/browsing_data/cookies_tree_model_unittest.cc b/chrome/browser/browsing_data/cookies_tree_model_unittest.cc index e4aea65..83a1755e 100644 --- a/chrome/browser/browsing_data/cookies_tree_model_unittest.cc +++ b/chrome/browser/browsing_data/cookies_tree_model_unittest.cc
@@ -11,7 +11,6 @@ #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" -#include "chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h" #include "chrome/browser/browsing_data/mock_browsing_data_media_license_helper.h" #include "chrome/browser/browsing_data/mock_browsing_data_quota_helper.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" @@ -84,8 +83,6 @@ new browsing_data::MockSharedWorkerHelper(profile_.get()); mock_browsing_data_cache_storage_helper_ = new browsing_data::MockCacheStorageHelper(profile_.get()); - mock_browsing_data_flash_lso_helper_ = - new MockBrowsingDataFlashLSOHelper(profile_.get()); mock_browsing_data_media_license_helper_ = new MockBrowsingDataMediaLicenseHelper(profile_.get()); @@ -112,7 +109,6 @@ mock_browsing_data_session_storage_helper_ = nullptr; mock_browsing_data_local_storage_helper_ = nullptr; mock_browsing_data_database_helper_ = nullptr; - mock_browsing_data_flash_lso_helper_ = nullptr; mock_browsing_data_media_license_helper_ = nullptr; base::RunLoop().RunUntilIdle(); } @@ -128,7 +124,6 @@ mock_browsing_data_service_worker_helper_, mock_browsing_data_shared_worker_helper_, mock_browsing_data_cache_storage_helper_, - mock_browsing_data_flash_lso_helper_, mock_browsing_data_media_license_helper_); auto cookies_model = std::make_unique<CookiesTreeModel>( @@ -158,8 +153,6 @@ mock_browsing_data_shared_worker_helper_->Notify(); mock_browsing_data_cache_storage_helper_->AddCacheStorageSamples(); mock_browsing_data_cache_storage_helper_->Notify(); - mock_browsing_data_flash_lso_helper_->AddFlashLSODomain("xyz.com"); - mock_browsing_data_flash_lso_helper_->Notify(); mock_browsing_data_media_license_helper_->AddMediaLicenseSamples(); mock_browsing_data_media_license_helper_->Notify(); @@ -168,7 +161,7 @@ "Initial State 3 cookies, 2 databases, 2 local storages, " "2 session storages, 2 indexed DBs, 3 filesystems, " "2 quotas, 2 service workers, 2 shared workers," - "2 cache storages, 1 Flash LSO, 2 media licenses"); + "2 cache storages, 2 media licenses"); // 71 because there's the root, then // cshost1 -> cache storage -> https://cshost1:1/ // cshost2 -> cache storage -> https://cshost2:2/ @@ -193,9 +186,8 @@ // swhost1 -> service worker -> https://swhost1:1 // swhost2 -> service worker -> https://swhost1:2 // sharedworkerhost1 -> shared worker -> https://sharedworkerhost1:1, - // sharedworkerhost2 -> shared worker -> https://sharedworkerhost2:2, - // xyz.com -> flash_lsos - EXPECT_EQ(71, cookies_model->GetRoot()->GetTotalNodeCount()); + // sharedworkerhost2 -> shared worker -> https://sharedworkerhost2:2 + EXPECT_EQ(69, cookies_model->GetRoot()->GetTotalNodeCount()); EXPECT_EQ("A,B,C", GetDisplayedCookies(cookies_model.get())); EXPECT_EQ("http://gdbhost1:1/,http://gdbhost2:2/", GetDisplayedDatabases(cookies_model.get())); @@ -217,7 +209,6 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); } @@ -292,8 +283,6 @@ return node->GetDetailedInfo().quota_info->host + ","; case CookieTreeNode::DetailedInfo::TYPE_SHARED_WORKER: return node->GetDetailedInfo().shared_worker_info->worker.spec() + ","; - case CookieTreeNode::DetailedInfo::TYPE_FLASH_LSO: - return node->GetDetailedInfo().flash_lso_domain + ","; case CookieTreeNode::DetailedInfo::TYPE_MEDIA_LICENSE: return node->GetDetailedInfo().media_license_info->origin.spec() + ","; default: @@ -369,11 +358,6 @@ CookieTreeNode::DetailedInfo::TYPE_CACHE_STORAGE); } - std::string GetDisplayedFlashLSOs(CookiesTreeModel* cookies_model) { - return GetDisplayedNodes( - cookies_model, CookieTreeNode::DetailedInfo::TYPE_FLASH_LSO); - } - std::string GetDisplayedMediaLicenses(CookiesTreeModel* cookies_model) { return GetDisplayedNodes(cookies_model, CookieTreeNode::DetailedInfo::TYPE_MEDIA_LICENSE); @@ -420,8 +404,6 @@ mock_browsing_data_shared_worker_helper_; scoped_refptr<browsing_data::MockCacheStorageHelper> mock_browsing_data_cache_storage_helper_; - scoped_refptr<MockBrowsingDataFlashLSOHelper> - mock_browsing_data_flash_lso_helper_; scoped_refptr<MockBrowsingDataMediaLicenseHelper> mock_browsing_data_media_license_helper_; @@ -459,8 +441,6 @@ "https://sharedworkerhost1:1/app/worker.js," "https://sharedworkerhost2:2/worker.js", GetDisplayedSharedWorkers(cookies_model.get())); - EXPECT_EQ("xyz.com", - GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); } @@ -496,7 +476,6 @@ EXPECT_TRUE(mock_browsing_data_service_worker_helper_->AllDeleted()); EXPECT_TRUE(mock_browsing_data_shared_worker_helper_->AllDeleted()); EXPECT_TRUE(mock_browsing_data_cache_storage_helper_->AllDeleted()); - EXPECT_TRUE(mock_browsing_data_flash_lso_helper_->AllDeleted()); EXPECT_TRUE(mock_browsing_data_media_license_helper_->AllDeleted()); } } @@ -529,42 +508,10 @@ // 19. `sharedworkerhost2` // 20. `swhost1` // 21. `swhost2` - // 22. `xyz.com` // // Here, we'll remove them one by one, starting from the end, and // check that the state makes sense. Initially there are 71 total nodes. - // xyz.com -> flash_lsos (2 nodes) - DeleteStoredObjects(cookies_model->GetRoot()->children()[22].get()); - { - SCOPED_TRACE("`xyz.com` removed."); - EXPECT_STREQ("A,B,C", GetDisplayedCookies(cookies_model.get()).c_str()); - EXPECT_EQ("http://gdbhost1:1/,http://gdbhost2:2/", - GetDisplayedDatabases(cookies_model.get())); - EXPECT_EQ("http://host1:1/,http://host2:2/", - GetDisplayedLocalStorages(cookies_model.get())); - EXPECT_EQ("http://host1:1/,http://host2:2/", - GetDisplayedSessionStorages(cookies_model.get())); - EXPECT_EQ("http://fshost1:1/,http://fshost2:2/,http://fshost3:3/", - GetDisplayedFileSystems(cookies_model.get())); - EXPECT_EQ("http://idbhost1:1/,http://idbhost2:2/", - GetDisplayedIndexedDBs(cookies_model.get())); - EXPECT_EQ("quotahost1,quotahost2", - GetDisplayedQuotas(cookies_model.get())); - EXPECT_EQ("https://swhost1:1/,https://swhost2:2/", - GetDisplayedServiceWorkers(cookies_model.get())); - EXPECT_EQ( - "https://sharedworkerhost1:1/app/worker.js," - "https://sharedworkerhost2:2/worker.js", - GetDisplayedSharedWorkers(cookies_model.get())); - EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", - GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); - EXPECT_EQ("https://media1/,https://media2/", - GetDisplayedMediaLicenses(cookies_model.get())); - EXPECT_EQ(69, cookies_model->GetRoot()->GetTotalNodeCount()); - } - // swhost2 -> service worker -> https://swhost1:2 (3 objects) DeleteStoredObjects(cookies_model->GetRoot()->children()[21].get()); { @@ -589,7 +536,6 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(66, cookies_model->GetRoot()->GetTotalNodeCount()); @@ -618,7 +564,6 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(63, cookies_model->GetRoot()->GetTotalNodeCount()); @@ -646,7 +591,6 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(60, cookies_model->GetRoot()->GetTotalNodeCount()); @@ -672,7 +616,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(57, cookies_model->GetRoot()->GetTotalNodeCount()); @@ -699,7 +642,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(55, cookies_model->GetRoot()->GetTotalNodeCount()); @@ -724,7 +666,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(53, cookies_model->GetRoot()->GetTotalNodeCount()); @@ -749,7 +690,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(50, cookies_model->GetRoot()->GetTotalNodeCount()); @@ -774,7 +714,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(47, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -798,7 +737,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(44, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -821,7 +759,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(41, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -845,7 +782,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(36, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -867,7 +803,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(31, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -887,7 +822,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(28, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -906,7 +840,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(25, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -926,7 +859,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(22, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -946,7 +878,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(19, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -965,7 +896,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(16, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -984,7 +914,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(13, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -1003,7 +932,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(10, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -1022,7 +950,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(7, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -1041,7 +968,6 @@ EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(4, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -1059,7 +985,6 @@ EXPECT_EQ("", GetDisplayedServiceWorkers(cookies_model.get())); EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); EXPECT_EQ(1, cookies_model->GetRoot()->GetTotalNodeCount()); } @@ -1076,7 +1001,7 @@ EXPECT_STREQ("B,C", GetDisplayedCookies(cookies_model.get()).c_str()); // 69 because in this case, the origin remains, although the COOKIES // node beneath it has been deleted. - EXPECT_EQ(69, cookies_model->GetRoot()->GetTotalNodeCount()); + EXPECT_EQ(67, cookies_model->GetRoot()->GetTotalNodeCount()); EXPECT_EQ("http://gdbhost1:1/,http://gdbhost2:2/", GetDisplayedDatabases(cookies_model.get())); EXPECT_EQ("http://host1:1/,http://host2:2/", @@ -1096,7 +1021,6 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); } @@ -1124,10 +1048,9 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); - EXPECT_EQ(67, cookies_model->GetRoot()->GetTotalNodeCount()); + EXPECT_EQ(65, cookies_model->GetRoot()->GetTotalNodeCount()); } DeleteStoredObjects( @@ -1153,10 +1076,9 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); - EXPECT_EQ(65, cookies_model->GetRoot()->GetTotalNodeCount()); + EXPECT_EQ(63, cookies_model->GetRoot()->GetTotalNodeCount()); } } @@ -1188,12 +1110,11 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); - // 69 because in this case, the origin remains, although the COOKIES + // 67 because in this case, the origin remains, although the COOKIES // node beneath it has been deleted. - EXPECT_EQ(69, cookies_model->GetRoot()->GetTotalNodeCount()); + EXPECT_EQ(67, cookies_model->GetRoot()->GetTotalNodeCount()); } DeleteStoredObjects( @@ -1219,10 +1140,9 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); - EXPECT_EQ(67, cookies_model->GetRoot()->GetTotalNodeCount()); + EXPECT_EQ(65, cookies_model->GetRoot()->GetTotalNodeCount()); } DeleteStoredObjects( @@ -1248,10 +1168,9 @@ GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("https://cshost1:1/,https://cshost2:2/", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); - EXPECT_EQ(65, cookies_model->GetRoot()->GetTotalNodeCount()); + EXPECT_EQ(63, cookies_model->GetRoot()->GetTotalNodeCount()); } } @@ -1266,7 +1185,6 @@ mock_browsing_data_service_worker_helper_, mock_browsing_data_shared_worker_helper_, mock_browsing_data_cache_storage_helper_, - mock_browsing_data_flash_lso_helper_, mock_browsing_data_media_license_helper_); CookiesTreeModel cookies_model(std::move(container), special_storage_policy()); @@ -1387,7 +1305,6 @@ mock_browsing_data_service_worker_helper_, mock_browsing_data_shared_worker_helper_, mock_browsing_data_cache_storage_helper_, - mock_browsing_data_flash_lso_helper_, mock_browsing_data_media_license_helper_); CookiesTreeModel cookies_model(std::move(container), special_storage_policy()); @@ -1514,7 +1431,6 @@ mock_browsing_data_service_worker_helper_, mock_browsing_data_shared_worker_helper_, mock_browsing_data_cache_storage_helper_, - mock_browsing_data_flash_lso_helper_, mock_browsing_data_media_license_helper_); CookiesTreeModel cookies_model(std::move(container), special_storage_policy()); @@ -1558,7 +1474,6 @@ mock_browsing_data_service_worker_helper_, mock_browsing_data_shared_worker_helper_, mock_browsing_data_cache_storage_helper_, - mock_browsing_data_flash_lso_helper_, mock_browsing_data_media_license_helper_); CookiesTreeModel cookies_model(std::move(container), special_storage_policy()); @@ -1607,7 +1522,6 @@ mock_browsing_data_service_worker_helper_, mock_browsing_data_shared_worker_helper_, mock_browsing_data_cache_storage_helper_, - mock_browsing_data_flash_lso_helper_, mock_browsing_data_media_license_helper_); CookiesTreeModel cookies_model(std::move(container), special_storage_policy()); @@ -1734,7 +1648,6 @@ mock_browsing_data_service_worker_helper_, mock_browsing_data_shared_worker_helper_, mock_browsing_data_cache_storage_helper_, - mock_browsing_data_flash_lso_helper_, mock_browsing_data_media_license_helper_); CookiesTreeModel cookies_model(std::move(container), special_storage_policy()); @@ -1776,7 +1689,6 @@ mock_browsing_data_service_worker_helper_, mock_browsing_data_shared_worker_helper_, mock_browsing_data_cache_storage_helper_, - mock_browsing_data_flash_lso_helper_, mock_browsing_data_media_license_helper_); CookiesTreeModel cookies_model(std::move(container), special_storage_policy()); @@ -1864,7 +1776,6 @@ mock_browsing_data_service_worker_helper_, mock_browsing_data_shared_worker_helper_, mock_browsing_data_cache_storage_helper_, - mock_browsing_data_flash_lso_helper_, mock_browsing_data_media_license_helper_); CookiesTreeModel cookies_model(std::move(container), special_storage_policy()); @@ -1875,61 +1786,6 @@ EXPECT_EQ("A", GetDisplayedCookies(&cookies_model)); } -TEST_F(CookiesTreeModelTest, FlashFilter) { - std::unique_ptr<CookiesTreeModel> cookies_model( - CreateCookiesTreeModelWithInitialSample()); - - cookies_model->UpdateSearchResults(base::string16(base::ASCIIToUTF16("xyz"))); - { - SCOPED_TRACE("Search for 'xyz'"); - EXPECT_EQ("", GetDisplayedCookies(cookies_model.get())); - EXPECT_EQ("", GetDisplayedDatabases(cookies_model.get())); - EXPECT_EQ("", GetDisplayedLocalStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedSessionStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFileSystems(cookies_model.get())); - EXPECT_EQ("", GetDisplayedIndexedDBs(cookies_model.get())); - EXPECT_EQ("", GetDisplayedServiceWorkers(cookies_model.get())); - EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); - EXPECT_EQ("", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); - EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); - } - - // Search for any domain containing 'y'. - cookies_model->UpdateSearchResults(base::string16(base::ASCIIToUTF16("y"))); - { - SCOPED_TRACE("Search for 'y'"); - EXPECT_EQ("", GetDisplayedCookies(cookies_model.get())); - EXPECT_EQ("", GetDisplayedDatabases(cookies_model.get())); - EXPECT_EQ("", GetDisplayedLocalStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedSessionStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFileSystems(cookies_model.get())); - EXPECT_EQ("", GetDisplayedIndexedDBs(cookies_model.get())); - EXPECT_EQ("", GetDisplayedServiceWorkers(cookies_model.get())); - EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); - EXPECT_EQ("", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); - EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); - } - - // Search for any domain containing 'abc' (which doesn't match anything). - cookies_model->UpdateSearchResults(base::string16(base::ASCIIToUTF16("abc"))); - { - SCOPED_TRACE("Search for 'abc'"); - EXPECT_EQ("", GetDisplayedCookies(cookies_model.get())); - EXPECT_EQ("", GetDisplayedDatabases(cookies_model.get())); - EXPECT_EQ("", GetDisplayedLocalStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedSessionStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFileSystems(cookies_model.get())); - EXPECT_EQ("", GetDisplayedIndexedDBs(cookies_model.get())); - EXPECT_EQ("", GetDisplayedServiceWorkers(cookies_model.get())); - EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); - EXPECT_EQ("", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); - EXPECT_EQ("", GetDisplayedMediaLicenses(cookies_model.get())); - } -} - TEST_F(CookiesTreeModelTest, MediaLicensesFilter) { std::unique_ptr<CookiesTreeModel> cookies_model( CreateCookiesTreeModelWithInitialSample()); @@ -1947,7 +1803,6 @@ EXPECT_EQ("", GetDisplayedServiceWorkers(cookies_model.get())); EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/", GetDisplayedMediaLicenses(cookies_model.get())); } @@ -1965,7 +1820,6 @@ EXPECT_EQ("", GetDisplayedServiceWorkers(cookies_model.get())); EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); EXPECT_EQ("", GetDisplayedCacheStorages(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); } @@ -1994,7 +1848,6 @@ "https://sharedworkerhost1:1/app/worker.js," "https://sharedworkerhost2:2/worker.js", GetDisplayedSharedWorkers(cookies_model.get())); - EXPECT_EQ("xyz.com", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); } @@ -2020,7 +1873,6 @@ GetDisplayedServiceWorkers(cookies_model.get())); EXPECT_EQ("https://sharedworkerhost1:1/app/worker.js", GetDisplayedSharedWorkers(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/", GetDisplayedMediaLicenses(cookies_model.get())); } @@ -2040,7 +1892,6 @@ EXPECT_EQ("", GetDisplayedCacheStorages(cookies_model.get())); EXPECT_EQ("", GetDisplayedServiceWorkers(cookies_model.get())); EXPECT_EQ("", GetDisplayedSharedWorkers(cookies_model.get())); - EXPECT_EQ("", GetDisplayedFlashLSOs(cookies_model.get())); EXPECT_EQ("https://media1/,https://media2/", GetDisplayedMediaLicenses(cookies_model.get())); }
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc index 47e0891f..1e98a13 100644 --- a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc +++ b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
@@ -6,7 +6,6 @@ #include "base/bind.h" #include "build/build_config.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/profiles/profile.h" #include "components/browsing_data/content/browsing_data_helper.h" @@ -91,17 +90,6 @@ // TODO(772337): Enable session storage counting when deletion is fixed. } -#if BUILDFLAG(ENABLE_PLUGINS) - // Count origins with flash data. - flash_lso_helper_ = BrowsingDataFlashLSOHelper::Create(profile_); - if (flash_lso_helper_) { - tasks_ += 1; - flash_lso_helper_->StartFetching( - base::BindOnce(&SiteDataCountingHelper::SitesWithFlashDataCallback, - base::Unretained(this))); - } -#endif - #if defined(OS_ANDROID) // Count origins with media licenses on Android. tasks_ += 1; @@ -195,15 +183,6 @@ Done(origins); } -void SiteDataCountingHelper::SitesWithFlashDataCallback( - const std::vector<std::string>& sites) { - std::vector<GURL> origins; - for (const std::string& site : sites) { - origins.push_back(GURL(site)); - } - Done(origins); -} - void SiteDataCountingHelper::SitesWithMediaLicensesCallback( const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>& media_license_info_list) {
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper.h b/chrome/browser/browsing_data/counters/site_data_counting_helper.h index 650d0bf..6f225aa 100644 --- a/chrome/browser/browsing_data/counters/site_data_counting_helper.h +++ b/chrome/browser/browsing_data/counters/site_data_counting_helper.h
@@ -17,7 +17,6 @@ #include "third_party/blink/public/mojom/quota/quota_types.mojom-forward.h" class Profile; -class BrowsingDataFlashLSOHelper; class HostContentSettingsMap; namespace content { @@ -55,7 +54,6 @@ const std::vector<content::StorageUsageInfo>& infos); void GetQuotaOriginsCallback(const std::set<url::Origin>& origin_set, blink::mojom::StorageType type); - void SitesWithFlashDataCallback(const std::vector<std::string>& sites); void SitesWithMediaLicensesCallback( const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>& media_license_info_list); @@ -68,7 +66,6 @@ base::OnceCallback<void(int)> completion_callback_; int tasks_; std::set<std::string> unique_hosts_; - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper_; scoped_refptr<BrowsingDataMediaLicenseHelper> media_license_helper_; };
diff --git a/chrome/browser/browsing_data/local_data_container.cc b/chrome/browser/browsing_data/local_data_container.cc index 3ec30b61..e0e0d7d 100644 --- a/chrome/browser/browsing_data/local_data_container.cc +++ b/chrome/browser/browsing_data/local_data_container.cc
@@ -7,7 +7,6 @@ #include <utility> #include "base/bind.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" #include "chrome/browser/browsing_data/cookies_tree_model.h" #include "content/public/browser/storage_usage_info.h" #include "net/cookies/canonical_cookie.h" @@ -27,7 +26,6 @@ scoped_refptr<browsing_data::ServiceWorkerHelper> service_worker_helper, scoped_refptr<browsing_data::SharedWorkerHelper> shared_worker_helper, scoped_refptr<browsing_data::CacheStorageHelper> cache_storage_helper, - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper, scoped_refptr<BrowsingDataMediaLicenseHelper> media_license_helper) : appcache_helper_(std::move(appcache_helper)), cookie_helper_(std::move(cookie_helper)), @@ -40,7 +38,6 @@ service_worker_helper_(std::move(service_worker_helper)), shared_worker_helper_(std::move(shared_worker_helper)), cache_storage_helper_(std::move(cache_storage_helper)), - flash_lso_helper_(std::move(flash_lso_helper)), media_license_helper_(std::move(media_license_helper)) {} LocalDataContainer::~LocalDataContainer() {} @@ -129,13 +126,6 @@ weak_ptr_factory_.GetWeakPtr())); } - if (flash_lso_helper_.get()) { - batches_started_++; - flash_lso_helper_->StartFetching( - base::BindOnce(&LocalDataContainer::OnFlashLSOInfoLoaded, - weak_ptr_factory_.GetWeakPtr())); - } - if (media_license_helper_.get()) { batches_started_++; media_license_helper_->StartFetching( @@ -225,13 +215,6 @@ model_->PopulateCacheStorageUsageInfo(this); } -void LocalDataContainer::OnFlashLSOInfoLoaded( - const FlashLSODomainList& domains) { - flash_lso_domain_list_ = domains; - DCHECK(model_); - model_->PopulateFlashLSOInfo(this); -} - void LocalDataContainer::OnMediaLicenseInfoLoaded( const MediaLicenseInfoList& media_license_info) { media_license_info_list_ = media_license_info;
diff --git a/chrome/browser/browsing_data/local_data_container.h b/chrome/browser/browsing_data/local_data_container.h index 18bad03d..0f67e34 100644 --- a/chrome/browser/browsing_data/local_data_container.h +++ b/chrome/browser/browsing_data/local_data_container.h
@@ -26,7 +26,6 @@ #include "components/browsing_data/content/service_worker_helper.h" #include "components/browsing_data/content/shared_worker_helper.h" -class BrowsingDataFlashLSOHelper; class CookiesTreeModel; class LocalDataContainer; @@ -60,7 +59,6 @@ std::list<browsing_data::SharedWorkerHelper::SharedWorkerInfo>; using CacheStorageUsageInfoList = std::list<content::StorageUsageInfo>; using AppCacheInfoList = std::list<content::StorageUsageInfo>; - using FlashLSODomainList = std::vector<std::string>; using MediaLicenseInfoList = std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>; @@ -76,7 +74,6 @@ scoped_refptr<browsing_data::ServiceWorkerHelper> service_worker_helper, scoped_refptr<browsing_data::SharedWorkerHelper> shared_worker_helper, scoped_refptr<browsing_data::CacheStorageHelper> cache_storage_helper, - scoped_refptr<BrowsingDataFlashLSOHelper> flash_data_helper, scoped_refptr<BrowsingDataMediaLicenseHelper> media_license_helper); virtual ~LocalDataContainer(); @@ -98,7 +95,6 @@ friend class CookieTreeServiceWorkerNode; friend class CookieTreeSharedWorkerNode; friend class CookieTreeCacheStorageNode; - friend class CookieTreeFlashLSONode; // Callback methods to be invoked when fetching the data is complete. void OnAppCacheModelInfoLoaded(const AppCacheInfoList& appcache_info_list); @@ -118,7 +114,6 @@ void OnSharedWorkerInfoLoaded(const SharedWorkerInfoList& shared_worker_info); void OnCacheStorageModelInfoLoaded( const CacheStorageUsageInfoList& cache_storage_info); - void OnFlashLSOInfoLoaded(const FlashLSODomainList& domains); void OnMediaLicenseInfoLoaded(const MediaLicenseInfoList& media_license_info); // Pointers to the helper objects, needed to retreive all the types of locally @@ -134,7 +129,6 @@ scoped_refptr<browsing_data::ServiceWorkerHelper> service_worker_helper_; scoped_refptr<browsing_data::SharedWorkerHelper> shared_worker_helper_; scoped_refptr<browsing_data::CacheStorageHelper> cache_storage_helper_; - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper_; scoped_refptr<BrowsingDataMediaLicenseHelper> media_license_helper_; // Storage for all the data that was retrieved through the helper objects. @@ -150,7 +144,6 @@ ServiceWorkerUsageInfoList service_worker_info_list_; SharedWorkerInfoList shared_worker_info_list_; CacheStorageUsageInfoList cache_storage_info_list_; - FlashLSODomainList flash_lso_domain_list_; MediaLicenseInfoList media_license_info_list_; // A delegate, which must outlive this object. The update callbacks use the
diff --git a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc b/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc deleted file mode 100644 index 5d9058ff8..0000000 --- a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h" - -#include <algorithm> - -#include "testing/gtest/include/gtest/gtest.h" - -MockBrowsingDataFlashLSOHelper::MockBrowsingDataFlashLSOHelper( - content::BrowserContext* browser_context) { -} -void MockBrowsingDataFlashLSOHelper::StartFetching( - GetSitesWithFlashDataCallback callback) { - ASSERT_FALSE(callback.is_null()); - ASSERT_TRUE(callback_.is_null()); - callback_ = std::move(callback); -} - -void MockBrowsingDataFlashLSOHelper::DeleteFlashLSOsForSite( - const std::string& site, - base::OnceClosure callback) { - auto entry = std::find(domains_.begin(), domains_.end(), site); - ASSERT_TRUE(entry != domains_.end()); - domains_.erase(entry); - if (!callback.is_null()) - std::move(callback).Run(); -} - -void MockBrowsingDataFlashLSOHelper::AddFlashLSODomain( - const std::string& domain) { - domains_.push_back(domain); -} - -void MockBrowsingDataFlashLSOHelper::Notify() { - std::move(callback_).Run(domains_); - callback_ = GetSitesWithFlashDataCallback(); -} - -bool MockBrowsingDataFlashLSOHelper::AllDeleted() { - return domains_.empty(); -} - -MockBrowsingDataFlashLSOHelper::~MockBrowsingDataFlashLSOHelper() { -}
diff --git a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h b/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h deleted file mode 100644 index 5a533a29..0000000 --- a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_BROWSING_DATA_MOCK_BROWSING_DATA_FLASH_LSO_HELPER_H_ -#define CHROME_BROWSER_BROWSING_DATA_MOCK_BROWSING_DATA_FLASH_LSO_HELPER_H_ - -#include <string> -#include <vector> - -#include "base/callback.h" -#include "base/macros.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" - -class MockBrowsingDataFlashLSOHelper : public BrowsingDataFlashLSOHelper { - public: - explicit MockBrowsingDataFlashLSOHelper( - content::BrowserContext* browser_context); - - // BrowsingDataFlashLSOHelper implementation: - void StartFetching(GetSitesWithFlashDataCallback callback) override; - void DeleteFlashLSOsForSite(const std::string& site, - base::OnceClosure callback) override; - - // Adds a domain sample. - void AddFlashLSODomain(const std::string& domain); - - // Notifies the callback. - void Notify(); - - // Returns true if the domain list is empty. - bool AllDeleted(); - - protected: - ~MockBrowsingDataFlashLSOHelper() override; - - private: - GetSitesWithFlashDataCallback callback_; - - std::vector<std::string> domains_; - - DISALLOW_COPY_AND_ASSIGN(MockBrowsingDataFlashLSOHelper); -}; - -#endif // CHROME_BROWSER_BROWSING_DATA_MOCK_BROWSING_DATA_FLASH_LSO_HELPER_H_
diff --git a/chrome/browser/browsing_data/site_data_size_collector.cc b/chrome/browser/browsing_data/site_data_size_collector.cc index a924792..74142a7 100644 --- a/chrome/browser/browsing_data/site_data_size_collector.cc +++ b/chrome/browser/browsing_data/site_data_size_collector.cc
@@ -35,8 +35,7 @@ browsing_data::IndexedDBHelper* indexed_db_helper, browsing_data::FileSystemHelper* file_system_helper, browsing_data::ServiceWorkerHelper* service_worker_helper, - browsing_data::CacheStorageHelper* cache_storage_helper, - BrowsingDataFlashLSOHelper* flash_lso_helper) + browsing_data::CacheStorageHelper* cache_storage_helper) : default_storage_partition_path_(default_storage_partition_path), appcache_helper_(appcache_helper), cookie_helper_(cookie_helper), @@ -46,7 +45,6 @@ file_system_helper_(file_system_helper), service_worker_helper_(service_worker_helper), cache_storage_helper_(cache_storage_helper), - flash_lso_helper_(flash_lso_helper), in_flight_operations_(0), total_bytes_(0) {} @@ -109,12 +107,6 @@ weak_ptr_factory_.GetWeakPtr())); in_flight_operations_++; } - if (flash_lso_helper_.get()) { - flash_lso_helper_->StartFetching( - base::BindOnce(&SiteDataSizeCollector::OnFlashLSOInfoLoaded, - weak_ptr_factory_.GetWeakPtr())); - in_flight_operations_++; - } // TODO(fukino): SITE_USAGE_DATA and WEB_APP_DATA should be counted too. // All data types included in REMOVE_SITE_USAGE_DATA should be counted. } @@ -201,25 +193,6 @@ OnStorageSizeFetched(total_size); } -void SiteDataSizeCollector::OnFlashLSOInfoLoaded( - const FlashLSODomainList& domains) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - // TODO(fukino): Flash is not the only plugin. We should check all types of - // plugin data. - if (domains.empty()) { - OnStorageSizeFetched(0); - return; - } - base::FilePath pepper_data_dir_path = default_storage_partition_path_ - .Append(content::kPepperDataDirname); - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&base::ComputeDirectorySize, pepper_data_dir_path), - base::BindOnce(&SiteDataSizeCollector::OnStorageSizeFetched, - weak_ptr_factory_.GetWeakPtr())); -} - void SiteDataSizeCollector::OnStorageSizeFetched(int64_t size) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (size > 0)
diff --git a/chrome/browser/browsing_data/site_data_size_collector.h b/chrome/browser/browsing_data/site_data_size_collector.h index 231e58f..2bc5928 100644 --- a/chrome/browser/browsing_data/site_data_size_collector.h +++ b/chrome/browser/browsing_data/site_data_size_collector.h
@@ -10,7 +10,6 @@ #include <vector> #include "base/memory/weak_ptr.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" #include "chrome/browser/profiles/profile.h" #include "components/browsing_data/content/appcache_helper.h" #include "components/browsing_data/content/cache_storage_helper.h" @@ -32,7 +31,6 @@ std::list<browsing_data::FileSystemHelper::FileSystemInfo>; using ServiceWorkerUsageInfoList = std::list<content::StorageUsageInfo>; using CacheStorageUsageInfoList = std::list<content::StorageUsageInfo>; - using FlashLSODomainList = std::vector<std::string>; SiteDataSizeCollector( const base::FilePath& default_storage_partition_path, @@ -43,8 +41,7 @@ browsing_data::IndexedDBHelper* indexed_db_helper, browsing_data::FileSystemHelper* file_system_helper, browsing_data::ServiceWorkerHelper* service_worker_helper, - browsing_data::CacheStorageHelper* cache_storage_helper, - BrowsingDataFlashLSOHelper* flash_lso_helper); + browsing_data::CacheStorageHelper* cache_storage_helper); virtual ~SiteDataSizeCollector(); using FetchCallback = base::OnceCallback<void(int64_t)>; @@ -68,7 +65,6 @@ const ServiceWorkerUsageInfoList& service_worker_info_list); void OnCacheStorageModelInfoLoaded( const CacheStorageUsageInfoList& cache_storage_info_list); - void OnFlashLSOInfoLoaded(const FlashLSODomainList& domains); // Callback for when the size is fetched from each storage backend. void OnStorageSizeFetched(int64_t size); @@ -86,7 +82,6 @@ scoped_refptr<browsing_data::FileSystemHelper> file_system_helper_; scoped_refptr<browsing_data::ServiceWorkerHelper> service_worker_helper_; scoped_refptr<browsing_data::CacheStorageHelper> cache_storage_helper_; - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper_; // Callback called when sizes of all site data are fetched and accumulated. FetchCallback fetch_callback_;
diff --git a/chrome/browser/browsing_data/site_data_size_collector_unittest.cc b/chrome/browser/browsing_data/site_data_size_collector_unittest.cc index 6a241e0..6fe27d5e2 100644 --- a/chrome/browser/browsing_data/site_data_size_collector_unittest.cc +++ b/chrome/browser/browsing_data/site_data_size_collector_unittest.cc
@@ -9,7 +9,6 @@ #include "base/files/file_util.h" #include "base/run_loop.h" #include "base/stl_util.h" -#include "chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.h" #include "chrome/common/chrome_constants.h" #include "chrome/test/base/testing_profile.h" #include "components/browsing_data/content/mock_appcache_helper.h" @@ -27,12 +26,6 @@ namespace { const char kCookieFileData[] = "cookie_file_data"; -const base::FilePath::CharType kFlashDataFilename0[] = - FILE_PATH_LITERAL("flash_data_filename_0"); -const base::FilePath::CharType kFlashDataFilename1[] = - FILE_PATH_LITERAL("flash_data_filename_1"); -const char kFlashData0[] = "flash_data_zero"; -const char kFlashData1[] = "flash_data_one"; class SiteDataSizeCollectorTest : public testing::Test { public: @@ -58,18 +51,9 @@ new browsing_data::MockServiceWorkerHelper(profile_.get()); mock_browsing_data_cache_storage_helper_ = new browsing_data::MockCacheStorageHelper(profile_.get()); - mock_browsing_data_flash_lso_helper_ = - new MockBrowsingDataFlashLSOHelper(profile_.get()); base::WriteFile(profile_->GetPath().Append(chrome::kCookieFilename), kCookieFileData, base::size(kCookieFileData)); - const base::FilePath flash_data_dir = profile_->GetPath().Append( - content::kPepperDataDirname); - base::CreateDirectory(flash_data_dir); - base::WriteFile(flash_data_dir.Append(kFlashDataFilename0), kFlashData0, - base::size(kFlashData0)); - base::WriteFile(flash_data_dir.Append(kFlashDataFilename1), kFlashData1, - base::size(kFlashData1)); fetched_size_ = -1; } @@ -83,7 +67,6 @@ mock_browsing_data_session_storage_helper_ = nullptr; mock_browsing_data_local_storage_helper_ = nullptr; mock_browsing_data_database_helper_ = nullptr; - mock_browsing_data_flash_lso_helper_ = nullptr; } void FetchCallback(base::OnceClosure done, int64_t size) { @@ -114,14 +97,12 @@ mock_browsing_data_service_worker_helper_; scoped_refptr<browsing_data::MockCacheStorageHelper> mock_browsing_data_cache_storage_helper_; - scoped_refptr<MockBrowsingDataFlashLSOHelper> - mock_browsing_data_flash_lso_helper_; }; TEST_F(SiteDataSizeCollectorTest, FetchCookie) { SiteDataSizeCollector collector( profile_->GetPath(), mock_browsing_data_cookie_helper_.get(), nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); base::RunLoop run_loop; collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, @@ -140,7 +121,7 @@ TEST_F(SiteDataSizeCollectorTest, FetchCookieWithoutEntry) { SiteDataSizeCollector collector( profile_->GetPath(), mock_browsing_data_cookie_helper_.get(), nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); // Fetched size should be 0 if there are no cookies. collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, @@ -152,7 +133,7 @@ TEST_F(SiteDataSizeCollectorTest, FetchDatabase) { SiteDataSizeCollector collector( profile_->GetPath(), nullptr, mock_browsing_data_database_helper_.get(), - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, base::Unretained(this), base::OnceClosure())); @@ -165,7 +146,7 @@ SiteDataSizeCollector collector( profile_->GetPath(), nullptr, nullptr, mock_browsing_data_local_storage_helper_.get(), nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr); + nullptr, nullptr); collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, base::Unretained(this), base::OnceClosure())); @@ -178,7 +159,7 @@ SiteDataSizeCollector collector(profile_->GetPath(), nullptr, nullptr, nullptr, mock_browsing_data_appcache_helper_.get(), - nullptr, nullptr, nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr); collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, base::Unretained(this), base::OnceClosure())); @@ -188,10 +169,9 @@ } TEST_F(SiteDataSizeCollectorTest, FetchIndexedDB) { - SiteDataSizeCollector collector(profile_->GetPath(), nullptr, nullptr, - nullptr, nullptr, - mock_browsing_data_indexed_db_helper_.get(), - nullptr, nullptr, nullptr, nullptr); + SiteDataSizeCollector collector( + profile_->GetPath(), nullptr, nullptr, nullptr, nullptr, + mock_browsing_data_indexed_db_helper_.get(), nullptr, nullptr, nullptr); collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, base::Unretained(this), base::OnceClosure())); @@ -203,7 +183,7 @@ TEST_F(SiteDataSizeCollectorTest, FetchFileSystem) { SiteDataSizeCollector collector( profile_->GetPath(), nullptr, nullptr, nullptr, nullptr, nullptr, - mock_browsing_data_file_system_helper_.get(), nullptr, nullptr, nullptr); + mock_browsing_data_file_system_helper_.get(), nullptr, nullptr); collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, base::Unretained(this), base::OnceClosure())); @@ -215,8 +195,7 @@ TEST_F(SiteDataSizeCollectorTest, FetchServiceWorker) { SiteDataSizeCollector collector( profile_->GetPath(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - mock_browsing_data_service_worker_helper_.get(), - nullptr, nullptr); + mock_browsing_data_service_worker_helper_.get(), nullptr); collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, base::Unretained(this), base::OnceClosure())); @@ -228,7 +207,7 @@ TEST_F(SiteDataSizeCollectorTest, FetchCacheStorage) { SiteDataSizeCollector collector( profile_->GetPath(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, mock_browsing_data_cache_storage_helper_.get(), nullptr); + nullptr, mock_browsing_data_cache_storage_helper_.get()); collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, base::Unretained(this), base::OnceClosure())); @@ -237,43 +216,11 @@ EXPECT_EQ(3, fetched_size_); } -TEST_F(SiteDataSizeCollectorTest, FetchFlashLSO) { - SiteDataSizeCollector collector( - profile_->GetPath(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, mock_browsing_data_flash_lso_helper_.get()); - - base::RunLoop run_loop; - collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, - base::Unretained(this), - run_loop.QuitClosure())); - - // AddFlashLSODomain() actually doesn't write flash data to the file, only - // triggers the condition to take the file into account. - mock_browsing_data_flash_lso_helper_->AddFlashLSODomain("example.com"); - mock_browsing_data_flash_lso_helper_->Notify(); - // Wait until reading files on blocking pool finishes. - run_loop.Run(); - EXPECT_EQ( - static_cast<int64_t>(base::size(kFlashData0) + base::size(kFlashData1)), - fetched_size_); -} - -TEST_F(SiteDataSizeCollectorTest, FetchFlashLSOWithoutEntry) { - SiteDataSizeCollector collector( - profile_->GetPath(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, mock_browsing_data_flash_lso_helper_.get()); - - collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, - base::Unretained(this), base::OnceClosure())); - mock_browsing_data_flash_lso_helper_->Notify(); - EXPECT_EQ(0, fetched_size_); -} - TEST_F(SiteDataSizeCollectorTest, FetchMultiple) { SiteDataSizeCollector collector( profile_->GetPath(), nullptr, nullptr, nullptr, nullptr, mock_browsing_data_indexed_db_helper_.get(), nullptr, - mock_browsing_data_service_worker_helper_.get(), nullptr, nullptr); + mock_browsing_data_service_worker_helper_.get(), nullptr); collector.Fetch(base::BindOnce(&SiteDataSizeCollectorTest::FetchCallback, base::Unretained(this), base::OnceClosure()));
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index f9f9671a..9e233a4 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1411,8 +1411,8 @@ "input_method/candidate_window_controller.h", "input_method/candidate_window_controller_impl.cc", "input_method/candidate_window_controller_impl.h", - "input_method/component_extension_ime_manager_impl.cc", - "input_method/component_extension_ime_manager_impl.h", + "input_method/component_extension_ime_manager_delegate_impl.cc", + "input_method/component_extension_ime_manager_delegate_impl.h", "input_method/emoji_suggester.cc", "input_method/emoji_suggester.h", "input_method/ime_service_connector.cc", @@ -1933,6 +1933,8 @@ "net/network_diagnostics/http_firewall_routine.h", "net/network_diagnostics/http_request_manager.cc", "net/network_diagnostics/http_request_manager.h", + "net/network_diagnostics/https_firewall_routine.cc", + "net/network_diagnostics/https_firewall_routine.h", "net/network_diagnostics/https_latency_routine.cc", "net/network_diagnostics/https_latency_routine.h", "net/network_diagnostics/lan_connectivity_routine.cc", @@ -3481,6 +3483,7 @@ "net/network_diagnostics/has_secure_wifi_connection_routine_unittest.cc", "net/network_diagnostics/http_firewall_routine_unittest.cc", "net/network_diagnostics/http_request_manager_unittest.cc", + "net/network_diagnostics/https_firewall_routine_unittest.cc", "net/network_diagnostics/https_latency_routine_unittest.cc", "net/network_diagnostics/lan_connectivity_routine_unittest.cc", "net/network_diagnostics/network_diagnostics_routine_unittest.cc",
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc index f01825a..8cfebf0c 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -159,6 +159,7 @@ #include "ui/base/ime/chromeos/ime_bridge.h" #include "ui/base/ui_base_features.h" #include "ui/compositor/throughput_tracker.h" +#include "ui/compositor/throughput_tracker_host.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/events/event_constants.h" @@ -761,7 +762,7 @@ struct SmoothnessTrackerInfo { base::Optional<ui::ThroughputTracker> tracker; - base::OnceCallback<void(int smoothness)> callback; + ui::ThroughputTrackerHost::ReportCallback callback; }; using DisplaySmoothnessTrackerInfos = std::map<int64_t, SmoothnessTrackerInfo>; DisplaySmoothnessTrackerInfos* GetDisplaySmoothnessTrackerInfos() { @@ -769,8 +770,10 @@ return trackers.get(); } -// Forwards |smoothness| to the callback for |display_id| and resets. -void ForwardSmoothessAndReset(int64_t display_id, int smoothness) { +// Forwards frame rate data to the callback for |display_id| and resets. +void ForwardFrameRateDataAndReset( + int64_t display_id, + const cc::FrameSequenceMetrics::CustomReportData& data) { auto* infos = GetDisplaySmoothnessTrackerInfos(); auto it = infos->find(display_id); DCHECK(it != infos->end()); @@ -781,7 +784,7 @@ // See https://crbug.com/1098886. auto callback = std::move(it->second.callback); infos->erase(it); - std::move(callback).Run(smoothness); + std::move(callback).Run(data); } std::string ResolutionToString( @@ -3638,7 +3641,7 @@ auto* frame_header = ash::FrameHeader::Get(widget); window_info.caption_height = frame_header->GetHeaderHeight(); - const ash::CaptionButtonModel* button_model = + const chromeos::CaptionButtonModel* button_model = frame_header->GetCaptionButtonModel(); int caption_button_enabled_status = 0; int caption_button_visible_status = 0; @@ -4678,11 +4681,7 @@ auto tracker = root_window->layer()->GetCompositor()->RequestNewThroughputTracker(); - // Exclude this tracker from data collection for animations since it is for - // the display as a whole rather than for an individual animation. - tracker.Start(ash::metrics_util::ForSmoothness( - base::BindRepeating(&ForwardSmoothessAndReset, display_id), - /*exclude_from_data_collection=*/true)); + tracker.Start(base::BindOnce(&ForwardFrameRateDataAndReset, display_id)); (*infos)[display_id].tracker = std::move(tracker); return RespondNow(NoArguments()); } @@ -4715,15 +4714,16 @@ } it->second.callback = base::BindOnce( - &AutotestPrivateStopSmoothnessTrackingFunction::OnReportSmoothness, this); + &AutotestPrivateStopSmoothnessTrackingFunction::OnReportData, this); it->second.tracker->Stop(); return did_respond() ? AlreadyResponded() : RespondLater(); } -void AutotestPrivateStopSmoothnessTrackingFunction::OnReportSmoothness( - int smoothness) { - Respond(OneArgument(std::make_unique<base::Value>(smoothness))); +void AutotestPrivateStopSmoothnessTrackingFunction::OnReportData( + const cc::FrameSequenceMetrics::CustomReportData& data) { + Respond(OneArgument(std::make_unique<base::Value>( + ash::metrics_util::CalculateSmoothness(data)))); } /////////////////////////////////////////////////////////////////////////////// @@ -4844,6 +4844,7 @@ api::autotest_private::ThroughputTrackerAnimationData animation_data; animation_data.frames_expected = data.frames_expected; animation_data.frames_produced = data.frames_produced; + animation_data.jank_count = data.jank_count; result_data.emplace_back(std::move(animation_data)); }
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h index 6818901..4e56087 100644 --- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h +++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
@@ -1302,7 +1302,7 @@ ~AutotestPrivateStopSmoothnessTrackingFunction() override; ResponseAction Run() override; - void OnReportSmoothness(int smoothness); + void OnReportData(const cc::FrameSequenceMetrics::CustomReportData& data); }; class AutotestPrivateWaitForAmbientPhotoAnimationFunction
diff --git a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc b/chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.cc similarity index 89% rename from chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc rename to chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.cc index ba12732..7afae76 100644 --- a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.cc
@@ -1,8 +1,8 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h" +#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.h" #include <stddef.h> @@ -159,20 +159,24 @@ } // namespace -ComponentExtensionIMEManagerImpl::ComponentExtensionIMEManagerImpl() { +ComponentExtensionIMEManagerDelegateImpl:: + ComponentExtensionIMEManagerDelegateImpl() { ReadComponentExtensionsInfo(&component_extension_list_); } -ComponentExtensionIMEManagerImpl::~ComponentExtensionIMEManagerImpl() = default; +ComponentExtensionIMEManagerDelegateImpl:: + ~ComponentExtensionIMEManagerDelegateImpl() = default; -std::vector<ComponentExtensionIME> ComponentExtensionIMEManagerImpl::ListIME() { +std::vector<ComponentExtensionIME> +ComponentExtensionIMEManagerDelegateImpl::ListIME() { return component_extension_list_; } -void ComponentExtensionIMEManagerImpl::Load(Profile* profile, - const std::string& extension_id, - const std::string& manifest, - const base::FilePath& file_path) { +void ComponentExtensionIMEManagerDelegateImpl::Load( + Profile* profile, + const std::string& extension_id, + const std::string& manifest, + const base::FilePath& file_path) { // Check the existence of file path to avoid unnecessary extension loading // and InputMethodEngine creation, so that the virtual keyboard web content // url won't be override by IME component extensions. @@ -189,21 +193,23 @@ } std::unique_ptr<base::DictionaryValue> -ComponentExtensionIMEManagerImpl::GetManifest( +ComponentExtensionIMEManagerDelegateImpl::GetManifest( const std::string& manifest_string) { std::string error; JSONStringValueDeserializer deserializer(manifest_string); std::unique_ptr<base::Value> manifest = - deserializer.Deserialize(NULL, &error); + deserializer.Deserialize(nullptr, &error); if (!manifest.get()) LOG(ERROR) << "Failed at getting manifest"; - return std::unique_ptr<base::DictionaryValue>( + std::unique_ptr<base::DictionaryValue> ret( static_cast<base::DictionaryValue*>(manifest.release())); + return ret; } // static -bool ComponentExtensionIMEManagerImpl::IsIMEExtensionID(const std::string& id) { +bool ComponentExtensionIMEManagerDelegateImpl::IsIMEExtensionID( + const std::string& id) { for (auto& extension : allowlisted_component_extensions) { if (base::LowerCaseEqualsASCII(id, extension.id)) return true; @@ -212,7 +218,7 @@ } // static -bool ComponentExtensionIMEManagerImpl::ReadEngineComponent( +bool ComponentExtensionIMEManagerDelegateImpl::ReadEngineComponent( const ComponentExtensionIME& component_extension, const base::DictionaryValue& dict, ComponentExtensionEngine* out) { @@ -230,14 +236,14 @@ out->indicator = ""; std::set<std::string> languages; - const base::Value* language_value = NULL; + const base::Value* language_value = nullptr; if (dict.Get(extensions::manifest_keys::kLanguage, &language_value)) { if (language_value->is_string()) { std::string language_str; language_value->GetAsString(&language_str); languages.insert(language_str); } else if (language_value->is_list()) { - const base::ListValue* language_list = NULL; + const base::ListValue* language_list = nullptr; language_value->GetAsList(&language_list); for (size_t j = 0; j < language_list->GetSize(); ++j) { std::string language_str; @@ -249,7 +255,7 @@ DCHECK(!languages.empty()); out->language_codes.assign(languages.begin(), languages.end()); - const base::ListValue* layouts = NULL; + const base::ListValue* layouts = nullptr; if (!dict.GetList(extensions::manifest_keys::kLayouts, &layouts)) return false; @@ -270,8 +276,7 @@ return false; out->input_view_url = url; #else - if (dict.GetString(extensions::manifest_keys::kInputView, - &url_string)) { + if (dict.GetString(extensions::manifest_keys::kInputView, &url_string)) { GURL url = extensions::Extension::GetResourceURL( extensions::Extension::GetBaseURLFromExtensionId( component_extension.id), @@ -282,8 +287,7 @@ } #endif - if (dict.GetString(extensions::manifest_keys::kOptionsPage, - &url_string)) { + if (dict.GetString(extensions::manifest_keys::kOptionsPage, &url_string)) { GURL url = extensions::Extension::GetResourceURL( extensions::Extension::GetBaseURLFromExtensionId( component_extension.id), @@ -300,7 +304,7 @@ } // static -bool ComponentExtensionIMEManagerImpl::ReadExtensionInfo( +bool ComponentExtensionIMEManagerDelegateImpl::ReadExtensionInfo( const base::DictionaryValue& manifest, const std::string& extension_id, ComponentExtensionIME* out) { @@ -325,7 +329,7 @@ } // static -void ComponentExtensionIMEManagerImpl::ReadComponentExtensionsInfo( +void ComponentExtensionIMEManagerDelegateImpl::ReadComponentExtensionsInfo( std::vector<ComponentExtensionIME>* out_imes) { DCHECK(out_imes); for (auto& extension : allowlisted_component_extensions) {
diff --git a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h b/chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.h similarity index 83% rename from chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h rename to chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.h index 4911f37..5b852ce7 100644 --- a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h +++ b/chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.h
@@ -1,9 +1,9 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. +// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_COMPONENT_EXTENSION_IME_MANAGER_IMPL_H_ -#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_COMPONENT_EXTENSION_IME_MANAGER_IMPL_H_ +#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_COMPONENT_EXTENSION_IME_MANAGER_DELEGATE_IMPL_H_ +#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_COMPONENT_EXTENSION_IME_MANAGER_DELEGATE_IMPL_H_ #include <set> #include <vector> @@ -15,17 +15,18 @@ #include "base/threading/thread_checker.h" #include "base/values.h" #include "ui/base/ime/chromeos/component_extension_ime_manager.h" +#include "ui/base/ime/chromeos/component_extension_ime_manager_delegate.h" class Profile; namespace chromeos { // The implementation class of ComponentExtensionIMEManagerDelegate. -class ComponentExtensionIMEManagerImpl +class ComponentExtensionIMEManagerDelegateImpl : public ComponentExtensionIMEManagerDelegate { public: - ComponentExtensionIMEManagerImpl(); - ~ComponentExtensionIMEManagerImpl() override; + ComponentExtensionIMEManagerDelegateImpl(); + ~ComponentExtensionIMEManagerDelegateImpl() override; // ComponentExtensionIMEManagerDelegate overrides: std::vector<ComponentExtensionIME> ListIME() override; @@ -63,9 +64,9 @@ // The list of component extension IME. std::vector<ComponentExtensionIME> component_extension_list_; - DISALLOW_COPY_AND_ASSIGN(ComponentExtensionIMEManagerImpl); + DISALLOW_COPY_AND_ASSIGN(ComponentExtensionIMEManagerDelegateImpl); }; } // namespace chromeos -#endif // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_COMPONENT_EXTENSION_IME_MANAGER_IMPL_H_ +#endif // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_COMPONENT_EXTENSION_IME_MANAGER_DELEGATE_IMPL_H_
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc index 9a09c0b..079f4b7 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -30,7 +30,7 @@ #include "chrome/browser/browser_process_platform_part_chromeos.h" #include "chrome/browser/chromeos/input_method/assistive_window_controller.h" #include "chrome/browser/chromeos/input_method/candidate_window_controller.h" -#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h" +#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.h" #include "chrome/browser/chromeos/input_method/ui/assistive_delegate.h" #include "chrome/browser/chromeos/input_method/ui/input_method_menu_item.h" #include "chrome/browser/chromeos/input_method/ui/input_method_menu_manager.h" @@ -46,6 +46,7 @@ #include "components/user_manager/user_manager.h" #include "third_party/icu/source/common/unicode/uloc.h" #include "ui/base/ime/chromeos/component_extension_ime_manager.h" +#include "ui/base/ime/chromeos/component_extension_ime_manager_delegate.h" #include "ui/base/ime/chromeos/extension_ime_util.h" #include "ui/base/ime/chromeos/fake_ime_keyboard.h" #include "ui/base/ime/chromeos/ime_bridge.h" @@ -946,7 +947,7 @@ } // Initializes the system IME list. std::unique_ptr<ComponentExtensionIMEManagerDelegate> comp_delegate( - new ComponentExtensionIMEManagerImpl()); + new ComponentExtensionIMEManagerDelegateImpl()); component_extension_ime_manager_->Initialize(std::move(comp_delegate)); const InputMethodDescriptors& descriptors = component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor();
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc index 6389638..ba3ec3d 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -28,6 +28,7 @@ #include "chrome/test/base/testing_profile_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/ime/chromeos/component_extension_ime_manager.h" #include "ui/base/ime/chromeos/extension_ime_util.h" #include "ui/base/ime/chromeos/fake_ime_keyboard.h" #include "ui/base/ime/chromeos/fake_input_method_delegate.h"
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc index 5e80da6a..ee2a0381 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
@@ -828,18 +828,27 @@ lock_screen_utils::SetKeyboardSettings(account_id); bool use_24hour_clock = false; - if (user_manager::known_user::GetBooleanPref( + if (!user_manager::known_user::GetBooleanPref( account_id, ::prefs::kUse24HourClock, &use_24hour_clock)) { - g_browser_process->platform_part() - ->GetSystemClock() - ->SetLastFocusedPodHourClockType(use_24hour_clock ? base::k24HourClock - : base::k12HourClock); + focused_user_clock_type_.reset(); + } else { + base::HourClockType clock_type = + use_24hour_clock ? base::k24HourClock : base::k12HourClock; + if (focused_user_clock_type_.has_value()) { + focused_user_clock_type_->UpdateClockType(clock_type); + } else { + focused_user_clock_type_ = g_browser_process->platform_part() + ->GetSystemClock() + ->CreateScopedHourClockType(clock_type); + } } + focused_pod_account_id_ = account_id; } void UserSelectionScreen::HandleNoPodFocused() { focused_pod_account_id_ = EmptyAccountId(); + focused_user_clock_type_.reset(); if (display_type_ == OobeUI::kLoginDisplay) lock_screen_utils::EnforceDevicePolicyInputMethods(std::string()); }
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.h b/chrome/browser/chromeos/login/screens/user_selection_screen.h index 1b627f4..74fd96d8 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.h +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.h
@@ -21,6 +21,7 @@ #include "chrome/browser/chromeos/login/signin/token_handle_util.h" #include "chrome/browser/chromeos/login/ui/login_display.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/system/system_clock.h" #include "chromeos/components/proximity_auth/screenlock_bridge.h" #include "chromeos/dbus/cryptohome/rpc.pb.h" #include "components/account_id/account_id.h" @@ -185,6 +186,8 @@ user_manager::UserList users_to_send_; AccountId focused_pod_account_id_; + base::Optional<system::SystemClock::ScopedHourClockType> + focused_user_clock_type_; // Sometimes we might get focused pod while user session is still active. e.g. // while creating lock screen. So postpone any work until after the session
diff --git a/chrome/browser/chromeos/login/test/local_state_mixin.cc b/chrome/browser/chromeos/login/test/local_state_mixin.cc index ce78cdc..3dcbd66e 100644 --- a/chrome/browser/chromeos/login/test/local_state_mixin.cc +++ b/chrome/browser/chromeos/login/test/local_state_mixin.cc
@@ -9,6 +9,8 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_browser_main.h" #include "chrome/browser/chrome_browser_main_extra_parts.h" +#include "components/user_manager/fake_user_manager.h" +#include "components/user_manager/scoped_user_manager.h" namespace chromeos { @@ -21,7 +23,16 @@ ~TestMainExtraPart() override = default; // ChromeBrowserMainExtraParts: - void PostEarlyInitialization() override { delegate_->SetUpLocalState(); } + void PostEarlyInitialization() override { + // SaveKnownUser depends on UserManager to get the local state that has to + // be updated, and do ephemeral user checks. + // Given that user manager does not exist yet (by design), create a + // temporary fake user manager instance. + auto user_manager = std::make_unique<user_manager::FakeUserManager>(); + user_manager->set_local_state(g_browser_process->local_state()); + user_manager::ScopedUserManager scoper(std::move(user_manager)); + delegate_->SetUpLocalState(); + } private: LocalStateMixin::Delegate* const delegate_;
diff --git a/chrome/browser/chromeos/login/test/login_manager_mixin.cc b/chrome/browser/chromeos/login/test/login_manager_mixin.cc index a62da999..0380848 100644 --- a/chrome/browser/chromeos/login/test/login_manager_mixin.cc +++ b/chrome/browser/chromeos/login/test/login_manager_mixin.cc
@@ -23,9 +23,7 @@ #include "chromeos/login/auth/user_context.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" -#include "components/user_manager/fake_user_manager.h" #include "components/user_manager/known_user.h" -#include "components/user_manager/scoped_user_manager.h" namespace chromeos { @@ -108,38 +106,28 @@ } void LoginManagerMixin::SetUpLocalState() { - // SaveKnownUser depends on UserManager to get the local state that has to - // be updated, and do ephemeral user checks. - // Given that user manager does not exist yet (by design), create a - // temporary fake user manager instance. - { - auto user_manager = std::make_unique<user_manager::FakeUserManager>(); - user_manager->set_local_state(g_browser_process->local_state()); - user_manager::ScopedUserManager scoper(std::move(user_manager)); - for (const auto& user : initial_users_) { - ListPrefUpdate users_pref(g_browser_process->local_state(), - "LoggedInUsers"); - users_pref->AppendIfNotPresent( - std::make_unique<base::Value>(user.account_id.GetUserEmail())); + for (const auto& user : initial_users_) { + ListPrefUpdate users_pref(g_browser_process->local_state(), + "LoggedInUsers"); + users_pref->AppendIfNotPresent( + std::make_unique<base::Value>(user.account_id.GetUserEmail())); - DictionaryPrefUpdate user_type_update(g_browser_process->local_state(), - "UserType"); - user_type_update->SetKey(user.account_id.GetAccountIdKey(), - base::Value(static_cast<int>(user.user_type))); + DictionaryPrefUpdate user_type_update(g_browser_process->local_state(), + "UserType"); + user_type_update->SetKey(user.account_id.GetAccountIdKey(), + base::Value(static_cast<int>(user.user_type))); - DictionaryPrefUpdate user_token_update(g_browser_process->local_state(), - "OAuthTokenStatus"); - user_token_update->SetKey( - user.account_id.GetUserEmail(), - base::Value(static_cast<int>(user.token_status))); + DictionaryPrefUpdate user_token_update(g_browser_process->local_state(), + "OAuthTokenStatus"); + user_token_update->SetKey(user.account_id.GetUserEmail(), + base::Value(static_cast<int>(user.token_status))); - user_manager::known_user::UpdateId(user.account_id); + user_manager::known_user::UpdateId(user.account_id); - if (user.user_type == user_manager::USER_TYPE_CHILD) { - user_manager::known_user::SetProfileRequiresPolicy( - user.account_id, - user_manager::known_user::ProfileRequiresPolicy::kPolicyRequired); - } + if (user.user_type == user_manager::USER_TYPE_CHILD) { + user_manager::known_user::SetProfileRequiresPolicy( + user.account_id, + user_manager::known_user::ProfileRequiresPolicy::kPolicyRequired); } }
diff --git a/chrome/browser/chromeos/net/network_diagnostics/README.md b/chrome/browser/chromeos/net/network_diagnostics/README.md index 98f9a5b..defb428 100644 --- a/chrome/browser/chromeos/net/network_diagnostics/README.md +++ b/chrome/browser/chromeos/net/network_diagnostics/README.md
@@ -146,6 +146,15 @@ * `kFirewallDetected`: Firewall detected. * `kPotentialFirewall`: A firewall may potentially exist. +#### HttpsFirewall + +Tests whether a firewall is blocking HTTPS port 443. + +Problems: +* `kHighDnsResolutionFailureRate`: DNS resolution failure rate is high. +* `kFirewallDetected`: Firewall detected. +* `kPotentialFirewall`: A firewall may potentially exist. + ### Google Services Routines Tests successful communication with various Google domains.
diff --git a/chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine.cc b/chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine.cc new file mode 100644 index 0000000..a93e2cb --- /dev/null +++ b/chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine.cc
@@ -0,0 +1,160 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine.h" + +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/ranges/algorithm.h" +#include "chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_util.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "content/public/browser/storage_partition.h" +#include "services/network/public/mojom/network_context.mojom.h" + +namespace chromeos { +namespace network_diagnostics { +namespace { + +// Https port number. +constexpr int kHttpsPort = 443; +// Https scheme. +constexpr char kHttpsScheme[] = "https://"; +// Effetively, the number of random hosts to query. +// total hosts queried by this routine = random hosts + fixed hosts, where +// information about fixed hosts is found in network_diagnostics_util.cc. +constexpr int kTotalAdditionalHostsToQuery = 3; +// The length of a random eight letter prefix obtained by the characters from +// |kPossibleChars|. +constexpr int kHostPrefixLength = 8; +// The threshold describing the number of DNS resolution failures permitted. +// E.g. If 10 host resolution attempts are made, any more than two DNS failures +// would result in a problem. +constexpr double kDnsResolutionFailureRateThreshold = 0.2; +// The threshold describing number of TLS probe failures permitted. E.g. If 10 +// TLS probes are attempted, any more than two failures would result in a +// problem. This number does not take into account the number of TLS probes that +// failed due to unsuccessful DNS resolution. +constexpr double kTlsProbeFailureRateThreshold = 0.2; +// For an explanation of error codes, see "net/base/net_error_list.h". +constexpr int kRetryResponseCodes[] = {net::ERR_TIMED_OUT, + net::ERR_DNS_TIMED_OUT}; + +} // namespace + +const int kTotalNumRetries = 3; + +HttpsFirewallRoutine::HttpsFirewallRoutine() + : num_retries_(kTotalNumRetries), + tls_prober_getter_callback_(base::BindRepeating( + &HttpsFirewallRoutine::CreateAndExecuteTlsProber)) { + std::vector<std::string> url_strings = + util::GetRandomAndFixedHostsWithSchemeAndPort( + kTotalAdditionalHostsToQuery, kHostPrefixLength, kHttpsScheme, + kHttpsPort); + for (const auto& url_string : url_strings) { + urls_to_query_.push_back(GURL(url_string)); + } + num_urls_to_query_ = urls_to_query_.size(); +} + +HttpsFirewallRoutine::~HttpsFirewallRoutine() = default; + +void HttpsFirewallRoutine::RunRoutine(HttpsFirewallRoutineCallback callback) { + if (!CanRun()) { + std::move(callback).Run(verdict(), std::move(problems_)); + return; + } + routine_completed_callback_ = std::move(callback); + ProbeNextUrl(); +} + +void HttpsFirewallRoutine::AnalyzeResultsAndExecuteCallback() { + double dns_resolution_failure_rate = + static_cast<double>(dns_resolution_failures_) / + static_cast<double>(num_urls_to_query_); + double tls_probe_failure_rate = + static_cast<double>(tls_probe_failures_) / + static_cast<double>(num_no_dns_failure_tls_probes_attempted_); + + if (dns_resolution_failure_rate > kDnsResolutionFailureRateThreshold) { + set_verdict(mojom::RoutineVerdict::kProblem); + problems_.push_back( + mojom::HttpsFirewallProblem::kHighDnsResolutionFailureRate); + } else if (tls_probe_failure_rate <= kTlsProbeFailureRateThreshold) { + set_verdict(mojom::RoutineVerdict::kNoProblem); + } else if (tls_probe_failures_ == num_no_dns_failure_tls_probes_attempted_) { + set_verdict(mojom::RoutineVerdict::kProblem); + problems_.push_back(mojom::HttpsFirewallProblem::kFirewallDetected); + } else { + // It cannot be conclusively determined whether a firewall exists; however, + // since reaching this case means tls_probe_failure_rate > + // kTlsProbeFailureRateThreshold, a firewall could potentially + // exist. + set_verdict(mojom::RoutineVerdict::kProblem); + problems_.push_back(mojom::HttpsFirewallProblem::kPotentialFirewall); + } + std::move(routine_completed_callback_).Run(verdict(), std::move(problems_)); +} + +void HttpsFirewallRoutine::ProbeNextUrl() { + DCHECK(urls_to_query_.size() > 0); + + auto url = urls_to_query_.back(); + urls_to_query_.pop_back(); + AttemptProbe(url); +} + +void HttpsFirewallRoutine::AttemptProbe(const GURL& url) { + // Store the instance of TlsProber. + tls_prober_ = tls_prober_getter_callback_.Run( + base::BindRepeating(&HttpsFirewallRoutine::GetNetworkContext), url, + base::BindOnce(&HttpsFirewallRoutine::OnProbeComplete, weak_ptr(), url)); +} + +void HttpsFirewallRoutine::OnProbeComplete( + const GURL& url, + int result, + TlsProber::ProbeExitEnum probe_exit_enum) { + if (probe_exit_enum == TlsProber::ProbeExitEnum::kDnsFailure) { + dns_resolution_failures_++; + } else { + const auto* iter = base::ranges::find(kRetryResponseCodes, result); + if (iter != std::end(kRetryResponseCodes) && num_retries_ > 0) { + num_retries_--; + AttemptProbe(url); + return; + } + if (result < 0) { + tls_probe_failures_++; + } + num_no_dns_failure_tls_probes_attempted_++; + } + if (urls_to_query_.size() == 0) { + AnalyzeResultsAndExecuteCallback(); + return; + } + ProbeNextUrl(); +} + +network::mojom::NetworkContext* HttpsFirewallRoutine::GetNetworkContext() { + Profile* profile = util::GetUserProfile(); + DCHECK(profile); + + return content::BrowserContext::GetDefaultStoragePartition(profile) + ->GetNetworkContext(); +} + +std::unique_ptr<TlsProber> HttpsFirewallRoutine::CreateAndExecuteTlsProber( + TlsProber::NetworkContextGetter network_context_getter, + const GURL& url, + TlsProber::TlsProbeCompleteCallback callback) { + return std::make_unique<TlsProber>(std::move(network_context_getter), url, + std::move(callback)); +} + +} // namespace network_diagnostics +} // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine.h b/chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine.h new file mode 100644 index 0000000..a1cedda3 --- /dev/null +++ b/chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine.h
@@ -0,0 +1,102 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_HTTPS_FIREWALL_ROUTINE_H_ +#define CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_HTTPS_FIREWALL_ROUTINE_H_ + +#include <memory> +#include <vector> + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_routine.h" +#include "chrome/browser/chromeos/net/network_diagnostics/tls_prober.h" +#include "url/gurl.h" + +namespace network { +namespace mojom { +class NetworkContext; +} +} // namespace network + +namespace chromeos { +namespace network_diagnostics { + +// Number of retry attempts. +extern const int kTotalNumRetries; + +// Tests whether a firewall is blocking HTTPS port 443. +class HttpsFirewallRoutine : public NetworkDiagnosticsRoutine { + public: + using HttpsFirewallRoutineCallback = + mojom::NetworkDiagnosticsRoutines::HttpsFirewallCallback; + using TlsProberGetterCallback = + base::RepeatingCallback<std::unique_ptr<TlsProber>( + TlsProber::NetworkContextGetter network_context_getter, + const GURL& url, + TlsProber::TlsProbeCompleteCallback callback)>; + + HttpsFirewallRoutine(); + HttpsFirewallRoutine(const HttpsFirewallRoutine&) = delete; + HttpsFirewallRoutine& operator=(const HttpsFirewallRoutine&) = delete; + ~HttpsFirewallRoutine() override; + + // NetworkDiagnosticsRoutine: + void AnalyzeResultsAndExecuteCallback() override; + + // Run the core logic of this routine. Set |callback| to + // |routine_completed_callback_|, which is to be executed in + // AnalyzeResultsAndExecuteCallback(). + void RunRoutine(HttpsFirewallRoutineCallback callback); + + void set_tls_prober_getter_callback_for_testing( + TlsProberGetterCallback tls_prober_getter_callback) { + tls_prober_getter_callback_ = std::move(tls_prober_getter_callback); + } + + private: + // Gets the next URL to probe. + void ProbeNextUrl(); + + // Helper function to launch a TLS probe. + void AttemptProbe(const GURL& url); + + // Callback invoked once probe is complete. |url| is only relevant in case + // of probe retries. + void OnProbeComplete(const GURL& url, + int result, + TlsProber::ProbeExitEnum probe_exit_enum); + + // Returns the network context. + static network::mojom::NetworkContext* GetNetworkContext(); + + // Creates an instance of TlsProber. + static std::unique_ptr<TlsProber> CreateAndExecuteTlsProber( + TlsProber::NetworkContextGetter network_context_getter, + const GURL& url, + TlsProber::TlsProbeCompleteCallback callback); + + // Returns the weak pointer to |this|. + base::WeakPtr<HttpsFirewallRoutine> weak_ptr() { + return weak_factory_.GetWeakPtr(); + } + + std::vector<GURL> urls_to_query_; + int num_urls_to_query_ = 0; + int num_retries_ = 0; + int dns_resolution_failures_ = 0; + int tls_probe_failures_ = 0; + int num_no_dns_failure_tls_probes_attempted_ = 0; + TlsProberGetterCallback tls_prober_getter_callback_; + std::unique_ptr<TlsProber> tls_prober_; + std::vector<mojom::HttpsFirewallProblem> problems_; + HttpsFirewallRoutineCallback routine_completed_callback_; + + base::WeakPtrFactory<HttpsFirewallRoutine> weak_factory_{this}; +}; + +} // namespace network_diagnostics +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_NET_NETWORK_DIAGNOSTICS_HTTPS_FIREWALL_ROUTINE_H_
diff --git a/chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine_unittest.cc b/chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine_unittest.cc new file mode 100644 index 0000000..1eeb960 --- /dev/null +++ b/chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine_unittest.cc
@@ -0,0 +1,230 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine.h" + +#include <deque> +#include <memory> +#include <utility> + +#include "base/bind_helpers.h" +#include "chrome/browser/chromeos/net/network_diagnostics/fake_host_resolver.h" +#include "chrome/browser/chromeos/net/network_diagnostics/fake_network_context.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/test/browser_task_environment.h" +#include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { +namespace network_diagnostics { + +namespace { + +// The number of hosts the the routine tries to open socket connections to (if +// DNS resolution is successful). Value equals the number of random hosts +// + fixed hosts queried by HttpsFirewallRoutine. +const int kTotalHosts = 9; + +// Test implementation of TlsProber. +class TestTlsProber final : public TlsProber { + public: + TestTlsProber(TlsProber::TlsProbeCompleteCallback callback, + int result, + TlsProber::ProbeExitEnum probe_exit_enum) { + // Post an asynchronus task simulating a completed probe. This mimics the + // behavior of the production TlsProber constructor since the TestTlsProber + // instance will be complete before FinishProbe is invoked. In the + // production TlsProber, the constructor completes before DNS host + // resolution is invoked. + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce(&TestTlsProber::FinishProbe, weak_factory_.GetWeakPtr(), + std::move(callback), result, probe_exit_enum)); + } + + TestTlsProber(const TestTlsProber&) = delete; + TestTlsProber& operator=(const TestTlsProber&) = delete; + ~TestTlsProber() override = default; + + private: + void FinishProbe(TlsProber::TlsProbeCompleteCallback callback, + int result, + TlsProber::ProbeExitEnum probe_exit_enum) { + std::move(callback).Run(result, probe_exit_enum); + } + + base::WeakPtrFactory<TestTlsProber> weak_factory_{this}; +}; + +} // namespace + +class HttpsFirewallRoutineTest : public ::testing::Test { + public: + struct TlsProberReturnValue { + net::Error result; + TlsProber::ProbeExitEnum probe_exit_enum; + }; + + HttpsFirewallRoutineTest() = default; + HttpsFirewallRoutineTest(const HttpsFirewallRoutineTest&) = delete; + HttpsFirewallRoutineTest& operator=(const HttpsFirewallRoutineTest&) = delete; + + void RunRoutine( + mojom::RoutineVerdict expected_routine_verdict, + const std::vector<mojom::HttpsFirewallProblem>& expected_problems) { + https_firewall_routine_->RunRoutine(base::BindOnce( + &HttpsFirewallRoutineTest::CompareVerdict, weak_factory_.GetWeakPtr(), + expected_routine_verdict, expected_problems)); + run_loop_.Run(); + } + + void CompareVerdict( + mojom::RoutineVerdict expected_verdict, + const std::vector<mojom::HttpsFirewallProblem>& expected_problems, + mojom::RoutineVerdict actual_verdict, + const std::vector<mojom::HttpsFirewallProblem>& actual_problems) { + DCHECK(run_loop_.running()); + EXPECT_EQ(expected_verdict, actual_verdict); + EXPECT_EQ(expected_problems, actual_problems); + run_loop_.Quit(); + } + + void SetUpRoutine(std::deque<TlsProberReturnValue> fake_probe_results) { + fake_probe_results_ = std::move(fake_probe_results); + https_firewall_routine_ = std::make_unique<HttpsFirewallRoutine>(); + https_firewall_routine_->set_tls_prober_getter_callback_for_testing( + base::BindRepeating( + &HttpsFirewallRoutineTest::CreateAndExecuteTlsProber, + base::Unretained(this))); + } + + // Sets up required properties (via fakes) and runs the test. + // + // Parameters: + // |fake_probe_results|: Represents the results of TLS probes. + // |expected_routine_verdict|: Represents the expected verdict + // reported by this test. + // |expected_problems|: Represents the expected problem + // reported by this test. + void SetUpAndRunRoutine( + std::deque<TlsProberReturnValue> fake_probe_results, + mojom::RoutineVerdict expected_routine_verdict, + const std::vector<mojom::HttpsFirewallProblem>& expected_problems) { + SetUpRoutine(std::move(fake_probe_results)); + RunRoutine(expected_routine_verdict, expected_problems); + } + + std::unique_ptr<TlsProber> CreateAndExecuteTlsProber( + TlsProber::NetworkContextGetter network_context_getter, + const GURL& url, + TlsProber::TlsProbeCompleteCallback callback) { + DCHECK(fake_probe_results_.size() > 0); + + auto value = fake_probe_results_.front(); + fake_probe_results_.pop_front(); + auto test_tls_prober = std::make_unique<TestTlsProber>( + std::move(callback), value.result, value.probe_exit_enum); + return std::move(test_tls_prober); + } + + private: + content::BrowserTaskEnvironment task_environment_; + base::RunLoop run_loop_; + std::deque<TlsProberReturnValue> fake_probe_results_; + std::unique_ptr<HttpsFirewallRoutine> https_firewall_routine_; + base::WeakPtrFactory<HttpsFirewallRoutineTest> weak_factory_{this}; +}; + +TEST_F(HttpsFirewallRoutineTest, TestHighDnsResolutionFailuresRate) { + std::deque<TlsProberReturnValue> fake_probe_results; + // kTotalHosts = 9 + for (int i = 0; i < kTotalHosts; i++) { + if (i < 2) { + fake_probe_results.push_back(TlsProberReturnValue{ + net::ERR_NAME_NOT_RESOLVED, TlsProber::ProbeExitEnum::kDnsFailure}); + } else { + // Having seven successful resolutions out of nine puts us below the + // threshold needed to attempt TLS probes. + fake_probe_results.push_back( + TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess}); + } + } + SetUpAndRunRoutine( + std::move(fake_probe_results), mojom::RoutineVerdict::kProblem, + {mojom::HttpsFirewallProblem::kHighDnsResolutionFailureRate}); +} + +TEST_F(HttpsFirewallRoutineTest, TestFirewallDetection) { + std::deque<TlsProberReturnValue> fake_probe_results; + // kTotalHosts = 9 + for (int i = 0; i < kTotalHosts; i++) { + fake_probe_results.push_back(TlsProberReturnValue{ + net::ERR_FAILED, TlsProber::ProbeExitEnum::kTlsUpgradeFailure}); + } + SetUpAndRunRoutine(std::move(fake_probe_results), + mojom::RoutineVerdict::kProblem, + {mojom::HttpsFirewallProblem::kFirewallDetected}); +} + +TEST_F(HttpsFirewallRoutineTest, TestPotentialFirewallDetection) { + std::deque<TlsProberReturnValue> fake_probe_results; + // kTotalHosts = 9 + for (int i = 0; i < kTotalHosts; i++) { + if (i < 5) { + fake_probe_results.push_back( + TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess}); + } else { + // Having five connection failures and four successful connections signals + // a potential firewall. + fake_probe_results.push_back(TlsProberReturnValue{ + net::ERR_FAILED, TlsProber::ProbeExitEnum::kTcpConnectionFailure}); + } + } + SetUpAndRunRoutine(std::move(fake_probe_results), + mojom::RoutineVerdict::kProblem, + {mojom::HttpsFirewallProblem::kPotentialFirewall}); +} + +TEST_F(HttpsFirewallRoutineTest, TestNoFirewallIssues) { + std::deque<TlsProberReturnValue> fake_probe_results; + // kTotalHosts = 9 + for (int i = 0; i < kTotalHosts; i++) { + if (i < 8) { + fake_probe_results.push_back( + TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess}); + } else { + // Having one connection failure and eight successful connections puts us + // above the required threshold. + fake_probe_results.push_back(TlsProberReturnValue{ + net::ERR_FAILED, TlsProber::ProbeExitEnum::kMojoDisconnectFailure}); + } + } + SetUpAndRunRoutine(std::move(fake_probe_results), + mojom::RoutineVerdict::kNoProblem, {}); +} + +TEST_F(HttpsFirewallRoutineTest, TestContinousRetries) { + std::deque<TlsProberReturnValue> fake_probe_results; + // kTotalHosts = 9 + for (int i = 0; i < kTotalHosts; i++) { + if (i < 8) { + fake_probe_results.push_back( + TlsProberReturnValue{net::OK, TlsProber::ProbeExitEnum::kSuccess}); + } else { + // Having one socket that continuously retries until failure and eight + // sockets that make successful connections puts us above the required + // threshold. + for (int j = 0; j < kTotalNumRetries + 1; j++) { + fake_probe_results.push_back(TlsProberReturnValue{ + net::ERR_TIMED_OUT, + TlsProber::ProbeExitEnum::kMojoDisconnectFailure}); + } + } + } + SetUpAndRunRoutine(std::move(fake_probe_results), + mojom::RoutineVerdict::kNoProblem, {}); +} + +} // namespace network_diagnostics +} // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.cc b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.cc index 3028f84..27be5b5 100644 --- a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.cc +++ b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/chromeos/net/network_diagnostics/gateway_can_be_pinged_routine.h" #include "chrome/browser/chromeos/net/network_diagnostics/has_secure_wifi_connection_routine.h" #include "chrome/browser/chromeos/net/network_diagnostics/http_firewall_routine.h" +#include "chrome/browser/chromeos/net/network_diagnostics/https_firewall_routine.h" #include "chrome/browser/chromeos/net/network_diagnostics/https_latency_routine.h" #include "chrome/browser/chromeos/net/network_diagnostics/lan_connectivity_routine.h" #include "chrome/browser/chromeos/net/network_diagnostics/signal_strength_routine.h" @@ -169,6 +170,20 @@ std::move(routine), std::move(callback))); } +void NetworkDiagnostics::HttpsFirewall(HttpsFirewallCallback callback) { + auto routine = std::make_unique<HttpsFirewallRoutine>(); + // RunRoutine() takes a lambda callback that takes ownership of the routine. + // This ensures that the routine stays alive when it makes asynchronous mojo + // calls. The routine will be destroyed when the lambda exits. + routine->RunRoutine(base::BindOnce( + [](std::unique_ptr<HttpsFirewallRoutine> routine, + HttpsFirewallCallback callback, mojom::RoutineVerdict verdict, + const std::vector<mojom::HttpsFirewallProblem>& problems) { + std::move(callback).Run(verdict, std::move(problems)); + }, + std::move(routine), std::move(callback))); +} + void NetworkDiagnostics::HttpsLatency(HttpsLatencyCallback callback) { auto routine = std::make_unique<HttpsLatencyRoutine>(); // RunRoutine() takes a lambda callback that takes ownership of the routine.
diff --git a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.h b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.h index d18bb01..04352ef 100644 --- a/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.h +++ b/chrome/browser/chromeos/net/network_diagnostics/network_diagnostics.h
@@ -31,6 +31,7 @@ void SignalStrength(SignalStrengthCallback callback) override; void GatewayCanBePinged(GatewayCanBePingedCallback callback) override; void HttpFirewall(HttpFirewallCallback callback) override; + void HttpsFirewall(HttpsFirewallCallback callback) override; void HasSecureWiFiConnection( HasSecureWiFiConnectionCallback callback) override; void DnsResolverPresent(DnsResolverPresentCallback callback) override;
diff --git a/chrome/browser/chromeos/net/network_diagnostics/tls_prober.cc b/chrome/browser/chromeos/net/network_diagnostics/tls_prober.cc index 92b252b..33c0ea0 100644 --- a/chrome/browser/chromeos/net/network_diagnostics/tls_prober.cc +++ b/chrome/browser/chromeos/net/network_diagnostics/tls_prober.cc
@@ -156,6 +156,8 @@ host_resolver_->Run(url); } +TlsProber::TlsProber() = default; + TlsProber::~TlsProber() = default; void TlsProber::OnHostResolutionComplete(
diff --git a/chrome/browser/chromeos/net/network_diagnostics/tls_prober.h b/chrome/browser/chromeos/net/network_diagnostics/tls_prober.h index 40398966..9f433ec 100644 --- a/chrome/browser/chromeos/net/network_diagnostics/tls_prober.h +++ b/chrome/browser/chromeos/net/network_diagnostics/tls_prober.h
@@ -66,6 +66,10 @@ const net::ResolveErrorInfo& resolve_error_info, const base::Optional<net::AddressList>& resolved_addresses); + protected: + // Test-only constructor. + TlsProber(); + private: // On success, upgrades a TCPConnectedSocket to a TLSClientSocket. On failure, // invokes the callback passed into the TlsProber instance with a failure
diff --git a/chrome/browser/chromeos/system/system_clock.cc b/chrome/browser/chromeos/system/system_clock.cc index 392ce07..46d23e5 100644 --- a/chrome/browser/chromeos/system/system_clock.cc +++ b/chrome/browser/chromeos/system/system_clock.cc
@@ -19,7 +19,6 @@ #include "chromeos/settings/cros_settings_names.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" -#include "components/session_manager/core/session_manager.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/notification_service.h" @@ -113,21 +112,42 @@ UpdateClockType(); } -void SystemClock::SetLastFocusedPodHourClockType( +SystemClock::ScopedHourClockType::ScopedHourClockType( + base::WeakPtr<SystemClock> system_clock) + : system_clock_(std::move(system_clock)) {} + +SystemClock::ScopedHourClockType::~ScopedHourClockType() { + if (!system_clock_) + return; + system_clock_->scoped_hour_clock_type_.reset(); + system_clock_->UpdateClockType(); +} + +SystemClock::ScopedHourClockType::ScopedHourClockType( + ScopedHourClockType&& other) = default; + +SystemClock::ScopedHourClockType& SystemClock::ScopedHourClockType::operator=( + ScopedHourClockType&& other) = default; + +void SystemClock::ScopedHourClockType::UpdateClockType( + base::HourClockType clock_type) { + if (!system_clock_) + return; + system_clock_->scoped_hour_clock_type_ = clock_type; + system_clock_->UpdateClockType(); +} + +SystemClock::ScopedHourClockType SystemClock::CreateScopedHourClockType( base::HourClockType hour_clock_type) { - user_pod_was_focused_ = true; - last_focused_pod_hour_clock_type_ = hour_clock_type; + DCHECK(!scoped_hour_clock_type_.has_value()); + scoped_hour_clock_type_ = hour_clock_type; UpdateClockType(); + return ScopedHourClockType(weak_ptr_factory_.GetWeakPtr()); } bool SystemClock::ShouldUse24HourClock() const { - const session_manager::SessionState session_state = - session_manager::SessionManager::Get()->session_state(); - if (session_state == session_manager::SessionState::LOGIN_PRIMARY || - session_state == session_manager::SessionState::LOCKED) { - if (user_pod_was_focused_) - return last_focused_pod_hour_clock_type_ == base::k24HourClock; - } + if (scoped_hour_clock_type_.has_value()) + return scoped_hour_clock_type_ == base::k24HourClock; // default is used for kUse24HourClock preference on login screen and whenever // set so in user's preference const chromeos::LoginState::LoggedInUserType status =
diff --git a/chrome/browser/chromeos/system/system_clock.h b/chrome/browser/chromeos/system/system_clock.h index 76a8e687..55a42ed 100644 --- a/chrome/browser/chromeos/system/system_clock.h +++ b/chrome/browser/chromeos/system/system_clock.h
@@ -39,7 +39,27 @@ SystemClock(); ~SystemClock() override; - void SetLastFocusedPodHourClockType(base::HourClockType hour_clock_type); + // Could be used to temporary set the required clock type. At most one should + // exist at the time. + class ScopedHourClockType { + public: + explicit ScopedHourClockType(base::WeakPtr<SystemClock> system_clock); + ~ScopedHourClockType(); + + ScopedHourClockType(const ScopedHourClockType&) = delete; + ScopedHourClockType& operator=(const ScopedHourClockType&) = delete; + + ScopedHourClockType(ScopedHourClockType&&); + ScopedHourClockType& operator=(ScopedHourClockType&&); + + void UpdateClockType(base::HourClockType clock_type); + + private: + base::WeakPtr<SystemClock> system_clock_; + }; + + ScopedHourClockType CreateScopedHourClockType( + base::HourClockType hour_clock_type); void AddObserver(SystemClockObserver* observer); void RemoveObserver(SystemClockObserver* observer); @@ -67,8 +87,7 @@ void UpdateClockType(); - bool user_pod_was_focused_ = false; - base::HourClockType last_focused_pod_hour_clock_type_ = base::k12HourClock; + base::Optional<base::HourClockType> scoped_hour_clock_type_; Profile* user_profile_ = nullptr; ScopedObserver<Profile, ProfileObserver> profile_observer_{this};
diff --git a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc index 5b625ca9..e1893e98 100644 --- a/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc +++ b/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
@@ -35,7 +35,6 @@ #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #if BUILDFLAG(ENABLE_PLUGINS) -#include "chrome/browser/plugins/plugin_data_remover_helper.h" #include "chrome/browser/plugins/plugin_prefs.h" #endif @@ -387,8 +386,8 @@ #if BUILDFLAG(ENABLE_PLUGINS) void BrowsingDataRemoverFunction::CheckRemovingPluginDataSupported( scoped_refptr<PluginPrefs> plugin_prefs) { - if (!PluginDataRemoverHelper::IsSupported(plugin_prefs.get())) - removal_mask_ &= ~ChromeBrowsingDataRemoverDelegate::DATA_TYPE_PLUGIN_DATA; + // We don't support this after Flash deprecation. + removal_mask_ &= ~ChromeBrowsingDataRemoverDelegate::DATA_TYPE_PLUGIN_DATA; content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE,
diff --git a/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc b/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc index e39cfa7..55793c6 100644 --- a/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc +++ b/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
@@ -18,7 +18,7 @@ #if defined(OS_CHROMEOS) #include "ash/keyboard/ui/grit/keyboard_resources.h" -#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h" +#include "chrome/browser/chromeos/input_method/component_extension_ime_manager_delegate_impl.h" #include "ui/file_manager/grit/file_manager_resources.h" #endif @@ -48,7 +48,7 @@ } #if defined(OS_CHROMEOS) - if (chromeos::ComponentExtensionIMEManagerImpl::IsIMEExtensionID( + if (chromeos::ComponentExtensionIMEManagerDelegateImpl::IsIMEExtensionID( extension_id)) { return true; }
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.cc b/chrome/browser/extensions/extension_uninstall_dialog.cc index a066bd00..693684b 100644 --- a/chrome/browser/extensions/extension_uninstall_dialog.cc +++ b/chrome/browser/extensions/extension_uninstall_dialog.cc
@@ -73,6 +73,7 @@ gfx::NativeWindow parent, ExtensionUninstallDialog::Delegate* delegate) : profile_(profile), parent_(parent), delegate_(delegate) { + DCHECK(delegate_); if (parent) parent_window_tracker_ = NativeWindowTracker::Create(parent); }
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc index 227e5b2..3548c7a4 100644 --- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc +++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -49,6 +49,7 @@ #include "chrome/browser/chromeos/login/login_pref_names.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/metrics/chromeos_metrics_provider.h" +#include "chrome/browser/metrics/enrollment_status.h" #include "chromeos/constants/chromeos_features.h" #include "chromeos/dbus/util/version_loader.h" #include "chromeos/system/statistics_provider.h" @@ -154,18 +155,14 @@ std::string GetEnrollmentStatusString() { switch (ChromeOSMetricsProvider::GetEnrollmentStatus()) { - case ChromeOSMetricsProvider::NON_MANAGED: + case EnrollmentStatus::kNonManaged: return "Not managed"; - case ChromeOSMetricsProvider::MANAGED: + case EnrollmentStatus::kManaged: return "Managed"; - case ChromeOSMetricsProvider::UNUSED: - case ChromeOSMetricsProvider::ERROR_GETTING_ENROLLMENT_STATUS: - case ChromeOSMetricsProvider::ENROLLMENT_STATUS_MAX: + case EnrollmentStatus::kUnused: + case EnrollmentStatus::kErrorGettingStatus: return "Error retrieving status"; } - // For compilers that don't recognize all cases handled above. - NOTREACHED(); - return std::string(); } std::string GetDisplayInfoString( @@ -393,35 +390,15 @@ if (!profile || !ProfileSyncServiceFactory::HasSyncService(profile)) return; - syncer::SyncService* service = - ProfileSyncServiceFactory::GetForProfile(profile); - std::unique_ptr<base::DictionaryValue> sync_logs( - syncer::sync_ui_util::ConstructAboutInformation(service, - chrome::GetChannel())); - - // Remove identity section. - base::ListValue* details = NULL; - sync_logs->GetList(syncer::sync_ui_util::kDetailsKey, &details); - if (!details) - return; - for (auto it = details->begin(); it != details->end(); ++it) { - base::DictionaryValue* dict = NULL; - if (it->GetAsDictionary(&dict)) { - std::string title; - dict->GetString("title", &title); - if (title == syncer::sync_ui_util::kIdentityTitle) { - details->Erase(it, NULL); - break; - } - } - } - - // Add sync logs to logs. - std::string sync_logs_string; - JSONStringValueSerializer serializer(&sync_logs_string); - serializer.Serialize(*sync_logs.get()); - - response->emplace(kSyncDataKey, sync_logs_string); + // Add sync logs to |response|. + std::unique_ptr<base::DictionaryValue> sync_logs = + syncer::sync_ui_util::ConstructAboutInformation( + syncer::sync_ui_util::IncludeSensitiveData(false), + ProfileSyncServiceFactory::GetForProfile(profile), + chrome::GetChannel()); + std::string serialized_sync_logs; + JSONStringValueSerializer(&serialized_sync_logs).Serialize(*sync_logs); + response->emplace(kSyncDataKey, serialized_sync_logs); } void ChromeInternalLogSource::PopulateExtensionInfoLogs(
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc index 4149601..208e803 100644 --- a/chrome/browser/first_run/first_run.cc +++ b/chrome/browser/first_run/first_run.cc
@@ -262,17 +262,17 @@ bool value = false; if (install_prefs.GetBool( - installer::master_preferences::kMakeChromeDefaultForUser, - &value) && value) { + installer::initial_preferences::kMakeChromeDefaultForUser, &value) && + value) { out_prefs->make_chrome_default_for_user = true; } install_prefs.GetString( - installer::master_preferences::kDistroImportBookmarksFromFilePref, + installer::initial_preferences::kDistroImportBookmarksFromFilePref, &out_prefs->import_bookmarks_path); install_prefs.GetString( - installer::master_preferences::kDistroSuppressDefaultBrowserPromptPref, + installer::initial_preferences::kDistroSuppressDefaultBrowserPromptPref, &out_prefs->suppress_default_browser_prompt_for_version); } @@ -417,7 +417,7 @@ // for use in Chrome's PrefService. Strip them from the initial dictionary // before mapping it to prefs. initial_dictionary->RemoveWithoutPathExpansion( - installer::master_preferences::kDistroDict, nullptr); + installer::initial_preferences::kDistroDict, nullptr); if (!chrome_prefs::InitializePrefsFromMasterPrefs( profiles::GetDefaultProfileDir(user_data_dir),
diff --git a/chrome/browser/first_run/first_run_internal_win.cc b/chrome/browser/first_run/first_run_internal_win.cc index d7d253d2..7228a82a1 100644 --- a/chrome/browser/first_run/first_run_internal_win.cc +++ b/chrome/browser/first_run/first_run_internal_win.cc
@@ -71,8 +71,9 @@ // first run in the "other" environment (desktop or metro). bool IsEULANotAccepted(installer::InitialPreferences* install_prefs) { bool value = false; - if (install_prefs->GetBool(installer::master_preferences::kRequireEula, - &value) && value) { + if (install_prefs->GetBool(installer::initial_preferences::kRequireEula, + &value) && + value) { base::FilePath eula_sentinel; // Be conservative and show the EULA if the path to the sentinel can't be // determined.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index cd442cb..34bc18b 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -2909,11 +2909,6 @@ "expiry_milestone": 88 }, { - "name": "interest-feed-feedback", - "owners": [ "petewil", "//chrome/android/feed/OWNERS" ], - "expiry_milestone": 90 - }, - { "name": "interest-feed-v2", "owners": [ "//chrome/android/feed/OWNERS", "feed@chromium.org" ], "expiry_milestone": 95 @@ -4054,7 +4049,7 @@ { "name": "safety-tips", "owners": [ "jdeblasio", "estark", "meacer" ], - "expiry_milestone": 87 + "expiry_milestone": 88 }, { "name": "same-site-by-default-cookies", @@ -4111,6 +4106,11 @@ "expiry_milestone": 80 }, { + "name": "send-webui-javascript-error-reports", + "owners": ["iby", "cros-telemetry@google.com"], + "expiry_milestone": 93 + }, + { "name": "separate-pointing-stick-settings", "owners": [ "hcutts", "khorimoto", "zentaro" ], "expiry_milestone": 90
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 0303ba9..6e83367 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2834,10 +2834,6 @@ "Show content suggestions on the New Tab Page and Start Surface using the " "new Feed Component."; -const char kInterestFeedFeedbackDescription[] = - "Allow the user to provide feedback from a feed card."; -const char kInterestFeedFeedbackName[] = "Interest Feed Feedback"; - const char kMessagesForAndroidInfrastructureName[] = "Messages infrastructure"; const char kMessagesForAndroidInfrastructureDescription[] = "When enabled, will initialize Messages UI infrastructure"; @@ -4710,6 +4706,15 @@ #endif // defined(TOOLKIT_VIEWS) || defined(OS_ANDROID) +#if !defined(OS_WIN) && !defined(OS_FUCHSIA) +const char kSendWebUIJavaScriptErrorReportsName[] = + "Send WebUI JavaScript Error Reports"; +const char kSendWebUIJavaScriptErrorReportsDescription[] = + "If enabled, and if the user has consented to sending metrics to Google, " + "then when the JavaScript has an error on a WebUI page, an error report " + "will be sent to Google."; +#endif + #if defined(WEBRTC_USE_PIPEWIRE) const char kWebrtcPipeWireCapturerName[] = "WebRTC PipeWire support"; const char kWebrtcPipeWireCapturerDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 14b6df01..171a338 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1637,9 +1637,6 @@ extern const char kInterestFeedV2Name[]; extern const char kInterestFeedV2Description[]; -extern const char kInterestFeedFeedbackName[]; -extern const char kInterestFeedFeedbackDescription[]; - extern const char kMessagesForAndroidInfrastructureName[]; extern const char kMessagesForAndroidInfrastructureDescription[]; @@ -2757,6 +2754,11 @@ #endif // defined(TOOLKIT_VIEWS) || defined(OS_ANDROID) +#if !defined(OS_WIN) && !defined(OS_FUCHSIA) +extern const char kSendWebUIJavaScriptErrorReportsName[]; +extern const char kSendWebUIJavaScriptErrorReportsDescription[]; +#endif + #if defined(WEBRTC_USE_PIPEWIRE) extern const char kWebrtcPipeWireCapturerName[]; extern const char kWebrtcPipeWireCapturerDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 20e749bd..0fa45bfc 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -99,7 +99,6 @@ &feature_engagement::kIPHHomepagePromoCardFeature, &feed::kInterestFeedV1ClicksAndViewsConditionalUpload, &feed::kInterestFeedContentSuggestions, - &feed::kInterestFeedFeedback, &feed::kInterestFeedV2, &feed::kReportFeedUserActions, &kAdjustWebApkInstallationSpace,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index 1f70e23..ff2253f0 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -309,7 +309,6 @@ public static final String INTEREST_FEEDV1_CLICKS_AND_VIEWS_CONDITIONAL_UPLOAD = "InterestFeedV1ClickAndViewActionsConditionalUpload"; public static final String INTEREST_FEED_CONTENT_SUGGESTIONS = "InterestFeedContentSuggestions"; - public static final String INTEREST_FEED_FEEDBACK = "InterestFeedFeedback"; public static final String INTEREST_FEED_V2 = "InterestFeedV2"; public static final String KITKAT_SUPPORTED = "KitKatSupported"; public static final String LOOKALIKE_NAVIGATION_URL_SUGGESTIONS_UI =
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc index ca35c93..9f89a2c 100644 --- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc +++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -306,12 +306,6 @@ cast_channel::LastError last_error = cast_socket_service_->GetLogger()->GetLastError(socket.id()); MediaRouterChannelError error_code = RecordError(error_state, last_error); - if (logger_.is_bound()) { - logger_->LogError(mojom::LogCategory::kDiscovery, kLoggerComponent, - base::StringPrintf("Cast Channel Error Code: %d", - static_cast<int>(error_code)), - "", "", ""); - } net::IPEndPoint ip_endpoint = socket.ip_endpoint(); // Need a PostTask() here because RemoveSocket() will release the memory of @@ -331,6 +325,13 @@ std::find_if(sinks.begin(), sinks.end(), [&socket_id](const auto& entry) { return entry.second.cast_data().cast_channel_id == socket_id; }); + if (logger_.is_bound()) { + auto sink_id = sink_it == sinks.end() ? "" : sink_it->first; + logger_->LogError(mojom::LogCategory::kDiscovery, kLoggerComponent, + base::StringPrintf("MediaRouterChannelError: %d", + static_cast<int>(error_code)), + sink_id, "", ""); + } if (sink_it == sinks.end()) { return; }
diff --git a/chrome/browser/metrics/chromeos_metrics_provider.cc b/chrome/browser/metrics/chromeos_metrics_provider.cc index 4fde707..ea2f20a 100644 --- a/chrome/browser/metrics/chromeos_metrics_provider.cc +++ b/chrome/browser/metrics/chromeos_metrics_provider.cc
@@ -30,6 +30,7 @@ #include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/metrics/cached_metrics_profile.h" +#include "chrome/browser/metrics/enrollment_status.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" @@ -116,14 +117,14 @@ g_browser_process->metrics_service()->OnApplicationNotIdle(); } -ChromeOSMetricsProvider::EnrollmentStatus -ChromeOSMetricsProvider::GetEnrollmentStatus() { +EnrollmentStatus ChromeOSMetricsProvider::GetEnrollmentStatus() { policy::BrowserPolicyConnectorChromeOS* connector = g_browser_process->platform_part()->browser_policy_connector_chromeos(); if (!connector) - return ERROR_GETTING_ENROLLMENT_STATUS; + return EnrollmentStatus::kErrorGettingStatus; - return connector->IsEnterpriseManaged() ? MANAGED : NON_MANAGED; + return connector->IsEnterpriseManaged() ? EnrollmentStatus::kManaged + : EnrollmentStatus::kNonManaged; } void ChromeOSMetricsProvider::Init() { @@ -233,7 +234,9 @@ // Use current enrollment status for initial stability logs, since it's not // likely to change between browser restarts. UMA_STABILITY_HISTOGRAM_ENUMERATION( - "UMA.EnrollmentStatus", GetEnrollmentStatus(), ENROLLMENT_STATUS_MAX); + "UMA.EnrollmentStatus", GetEnrollmentStatus(), + // static_cast because we only have macros for stability histograms. + static_cast<int>(EnrollmentStatus::kMaxValue) + 1); // Record ARC-related stability metrics that should be included in initial // stability logs and all regular UMA logs.
diff --git a/chrome/browser/metrics/chromeos_metrics_provider.h b/chrome/browser/metrics/chromeos_metrics_provider.h index 1387b364..7d0fccc 100644 --- a/chrome/browser/metrics/chromeos_metrics_provider.h +++ b/chrome/browser/metrics/chromeos_metrics_provider.h
@@ -23,21 +23,12 @@ class ChromeUserMetricsExtension; } +enum class EnrollmentStatus; class PrefRegistrySimple; // Performs ChromeOS specific metrics logging. class ChromeOSMetricsProvider : public metrics::MetricsProvider { public: - // Possible device enrollment status for a Chrome OS device. - // Used by UMA histogram, so entries shouldn't be reordered or removed. - enum EnrollmentStatus { - NON_MANAGED, - UNUSED, // Formerly MANAGED_EDU, see crbug.com/462770. - MANAGED, - ERROR_GETTING_ENROLLMENT_STATUS, - ENROLLMENT_STATUS_MAX, - }; - explicit ChromeOSMetricsProvider( metrics::MetricsLogUploader::MetricServiceType service_type); ~ChromeOSMetricsProvider() override;
diff --git a/chrome/browser/metrics/enrollment_status.h b/chrome/browser/metrics/enrollment_status.h new file mode 100644 index 0000000..b6bceb09 --- /dev/null +++ b/chrome/browser/metrics/enrollment_status.h
@@ -0,0 +1,19 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_METRICS_ENROLLMENT_STATUS_H_ +#define CHROME_BROWSER_METRICS_ENROLLMENT_STATUS_H_ + +// Possible device enrollment status for a Chrome OS device. Used by both +// ash-chrome and lacros-chrome. +// Used by UMA histogram, so entries shouldn't be reordered or removed. +enum class EnrollmentStatus { + kNonManaged = 0, + kUnused = 1, // Formerly MANAGED_EDU, see crbug.com/462770. + kManaged = 2, + kErrorGettingStatus = 3, + kMaxValue = kErrorGettingStatus, +}; + +#endif // CHROME_BROWSER_METRICS_ENROLLMENT_STATUS_H_
diff --git a/chrome/browser/metrics/lacros_metrics_provider.cc b/chrome/browser/metrics/lacros_metrics_provider.cc index 02ceda5..f68bc6d 100644 --- a/chrome/browser/metrics/lacros_metrics_provider.cc +++ b/chrome/browser/metrics/lacros_metrics_provider.cc
@@ -5,11 +5,45 @@ #include "chrome/browser/metrics/lacros_metrics_provider.h" #include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" +#include "chrome/browser/metrics/enrollment_status.h" +#include "chromeos/crosapi/mojom/crosapi.mojom.h" +#include "chromeos/lacros/lacros_chrome_service_impl.h" + +namespace { + +EnrollmentStatus GetEnrollmentStatus() { + auto* service = chromeos::LacrosChromeServiceImpl::Get(); + switch (service->init_params()->device_mode) { + case crosapi::mojom::DeviceMode::kUnknown: + return EnrollmentStatus::kErrorGettingStatus; + case crosapi::mojom::DeviceMode::kNotSet: + case crosapi::mojom::DeviceMode::kConsumer: + case crosapi::mojom::DeviceMode::kLegacyRetailMode: + case crosapi::mojom::DeviceMode::kConsumerKioskAutolaunch: + return EnrollmentStatus::kNonManaged; + case crosapi::mojom::DeviceMode::kEnterprise: + case crosapi::mojom::DeviceMode::kEnterpriseActiveDirectory: + case crosapi::mojom::DeviceMode::kDemo: + return EnrollmentStatus::kManaged; + } +} + +} // namespace LacrosMetricsProvider::LacrosMetricsProvider() = default; LacrosMetricsProvider::~LacrosMetricsProvider() = default; +void LacrosMetricsProvider::ProvideStabilityMetrics( + metrics::SystemProfileProto* system_profile_proto) { + // Record whether the device we're running on is enterprise managed. + UMA_STABILITY_HISTOGRAM_ENUMERATION( + "UMA.EnrollmentStatus", GetEnrollmentStatus(), + // static_cast because we only have macros for stability histograms. + static_cast<int>(EnrollmentStatus::kMaxValue) + 1); +} + void LacrosMetricsProvider::ProvideCurrentSessionData( metrics::ChromeUserMetricsExtension* uma_proto) { base::UmaHistogramBoolean("ChromeOS.IsLacrosBrowser", true);
diff --git a/chrome/browser/metrics/lacros_metrics_provider.h b/chrome/browser/metrics/lacros_metrics_provider.h index c1e2d2b..ff466d9bf 100644 --- a/chrome/browser/metrics/lacros_metrics_provider.h +++ b/chrome/browser/metrics/lacros_metrics_provider.h
@@ -21,6 +21,8 @@ ~LacrosMetricsProvider() override; // metrics::MetricsProvider: + void ProvideStabilityMetrics( + metrics::SystemProfileProto* system_profile_proto) override; void ProvideCurrentSessionData( metrics::ChromeUserMetricsExtension* uma_proto) override; };
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc index a30141b..57510e3 100644 --- a/chrome/browser/metrics/process_memory_metrics_emitter.cc +++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -27,6 +27,7 @@ #include "components/performance_manager/public/graph/page_node.h" #include "components/performance_manager/public/graph/process_node.h" #include "components/performance_manager/public/performance_manager.h" +#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h" #include "content/public/browser/audio_service_info.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/content_switches.h" @@ -620,7 +621,8 @@ builder.Record(ukm_recorder); } -void EmitUtilityMemoryMetrics(const GlobalMemoryDump::ProcessDump& pmd, +void EmitUtilityMemoryMetrics(HistogramProcessType ptype, + const GlobalMemoryDump::ProcessDump& pmd, ukm::SourceId ukm_source_id, ukm::UkmRecorder* ukm_recorder, const base::Optional<base::TimeDelta>& uptime, @@ -628,38 +630,7 @@ Memory_Experimental builder(ukm_source_id); builder.SetProcessType(static_cast<int64_t>( memory_instrumentation::mojom::ProcessType::UTILITY)); - EmitProcessUmaAndUkm(pmd, HistogramProcessType::kUtility, uptime, record_uma, - &builder); - - builder.Record(ukm_recorder); -} - -void EmitAudioServiceMemoryMetrics( - const GlobalMemoryDump::ProcessDump& pmd, - ukm::SourceId ukm_source_id, - ukm::UkmRecorder* ukm_recorder, - const base::Optional<base::TimeDelta>& uptime, - bool record_uma) { - Memory_Experimental builder(ukm_source_id); - builder.SetProcessType(static_cast<int64_t>( - memory_instrumentation::mojom::ProcessType::UTILITY)); - EmitProcessUmaAndUkm(pmd, HistogramProcessType::kAudioService, uptime, - record_uma, &builder); - - builder.Record(ukm_recorder); -} - -void EmitNetworkServiceMemoryMetrics( - const GlobalMemoryDump::ProcessDump& pmd, - ukm::SourceId ukm_source_id, - ukm::UkmRecorder* ukm_recorder, - const base::Optional<base::TimeDelta>& uptime, - bool record_uma) { - Memory_Experimental builder(ukm_source_id); - builder.SetProcessType(static_cast<int64_t>( - memory_instrumentation::mojom::ProcessType::UTILITY)); - EmitProcessUmaAndUkm(pmd, HistogramProcessType::kNetworkService, uptime, - record_uma, &builder); + EmitProcessUmaAndUkm(pmd, ptype, uptime, record_uma, &builder); builder.Record(ukm_recorder); } @@ -890,20 +861,22 @@ break; } case memory_instrumentation::mojom::ProcessType::UTILITY: { + HistogramProcessType ptype; if (pmd.pid() == content::GetProcessIdForAudioService()) { - EmitAudioServiceMemoryMetrics( - pmd, ukm::UkmRecorder::GetNewSourceID(), GetUkmRecorder(), - GetProcessUptime(now, pmd.pid()), emit_metrics_for_all_processes); + ptype = HistogramProcessType::kAudioService; } else if (pmd.service_name() == network::mojom::NetworkService::Name_) { - EmitNetworkServiceMemoryMetrics( - pmd, ukm::UkmRecorder::GetNewSourceID(), GetUkmRecorder(), - GetProcessUptime(now, pmd.pid()), emit_metrics_for_all_processes); + ptype = HistogramProcessType::kNetworkService; + } else if (pmd.service_name() == + paint_preview::mojom::PaintPreviewCompositorCollection:: + Name_) { + ptype = HistogramProcessType::kPaintPreviewCompositor; } else { - EmitUtilityMemoryMetrics( - pmd, ukm::UkmRecorder::GetNewSourceID(), GetUkmRecorder(), - GetProcessUptime(now, pmd.pid()), emit_metrics_for_all_processes); + ptype = HistogramProcessType::kUtility; } + EmitUtilityMemoryMetrics( + ptype, pmd, ukm::UkmRecorder::GetNewSourceID(), GetUkmRecorder(), + GetProcessUptime(now, pmd.pid()), emit_metrics_for_all_processes); break; } case memory_instrumentation::mojom::ProcessType::PLUGIN:
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc index 94525d05..cb83b5b 100644 --- a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc +++ b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
@@ -14,14 +14,17 @@ #include "base/test/metrics/histogram_tester.h" #include "build/build_config.h" #include "chrome/browser/metrics/renderer_uptime_tracker.h" +#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h" #include "components/ukm/test_ukm_recorder.h" #include "content/public/test/browser_task_environment.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_recorder.h" +#include "services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.h" #include "testing/gtest/include/gtest/gtest.h" using GlobalMemoryDump = memory_instrumentation::GlobalMemoryDump; using GlobalMemoryDumpPtr = memory_instrumentation::mojom::GlobalMemoryDumpPtr; +using HistogramProcessType = memory_instrumentation::HistogramProcessType; using ProcessMemoryDumpPtr = memory_instrumentation::mojom::ProcessMemoryDumpPtr; using OSMemDumpPtr = memory_instrumentation::mojom::OSMemDumpPtr; @@ -473,45 +476,87 @@ }); } +void PopulatePaintPreviewCompositorMetrics(GlobalMemoryDumpPtr& global_dump, + MetricMap& metrics_mb) { + auto process_memory_dump = + memory_instrumentation::mojom::ProcessMemoryDump::New(); + process_memory_dump->service_name = + paint_preview::mojom::PaintPreviewCompositorCollection::Name_; + ProcessMemoryDumpPtr pmd(std::move(process_memory_dump)); + pmd->process_type = ProcessType::UTILITY; + OSMemDumpPtr os_dump = + GetFakeOSMemDump(GetResidentValue(metrics_mb) * 1024, + metrics_mb["PrivateMemoryFootprint"] * 1024, + metrics_mb["SharedMemoryFootprint"] * 1024 +#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) + // accessing PrivateSwapFootprint on other OSes will + // modify metrics_mb to create the value, which leads to + // expectation failures. + , + metrics_mb["PrivateSwapFootprint"] * 1024 +#endif + ); + pmd->os_dump = std::move(os_dump); + global_dump->process_dumps.push_back(std::move(pmd)); +} + +MetricMap GetExpectedPaintPreviewCompositorMetrics() { + return MetricMap({ + {"ProcessType", static_cast<int64_t>(ProcessType::UTILITY)}, +#if !defined(OS_MAC) + {"Resident", 10}, +#endif + {"PrivateMemoryFootprint", 30}, {"SharedMemoryFootprint", 35}, +#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) + {"PrivateSwapFootprint", 50}, +#endif + }); +} + void PopulateMetrics(GlobalMemoryDumpPtr& global_dump, - ProcessType ptype, + HistogramProcessType ptype, MetricMap& metrics_mb) { switch (ptype) { - case ProcessType::BROWSER: - PopulateBrowserMetrics(global_dump, metrics_mb); - return; - case ProcessType::RENDERER: - PopulateRendererMetrics(global_dump, metrics_mb, 101); - return; - case ProcessType::GPU: - PopulateGpuMetrics(global_dump, metrics_mb); - return; - case ProcessType::UTILITY: + case HistogramProcessType::kAudioService: PopulateAudioServiceMetrics(global_dump, metrics_mb); return; - case ProcessType::PLUGIN: - case ProcessType::OTHER: - case ProcessType::ARC: + case HistogramProcessType::kBrowser: + PopulateBrowserMetrics(global_dump, metrics_mb); + return; + case HistogramProcessType::kGpu: + PopulateGpuMetrics(global_dump, metrics_mb); + return; + case HistogramProcessType::kPaintPreviewCompositor: + PopulatePaintPreviewCompositorMetrics(global_dump, metrics_mb); + return; + case HistogramProcessType::kRenderer: + PopulateRendererMetrics(global_dump, metrics_mb, 101); + return; + case HistogramProcessType::kExtension: + case HistogramProcessType::kNetworkService: + case HistogramProcessType::kUtility: break; } // We shouldn't reach here. - FAIL() << "Unknown process type case " << ptype << "."; + CHECK(false); } -MetricMap GetExpectedProcessMetrics(ProcessType ptype) { +MetricMap GetExpectedProcessMetrics(HistogramProcessType ptype) { switch (ptype) { - case ProcessType::BROWSER: - return GetExpectedBrowserMetrics(); - case ProcessType::RENDERER: - return GetExpectedRendererMetrics(); - case ProcessType::GPU: - return GetExpectedGpuMetrics(); - case ProcessType::UTILITY: + case HistogramProcessType::kAudioService: return GetExpectedAudioServiceMetrics(); - case ProcessType::PLUGIN: - case ProcessType::OTHER: - case ProcessType::ARC: + case HistogramProcessType::kBrowser: + return GetExpectedBrowserMetrics(); + case HistogramProcessType::kGpu: + return GetExpectedGpuMetrics(); + case HistogramProcessType::kPaintPreviewCompositor: + return GetExpectedPaintPreviewCompositorMetrics(); + case HistogramProcessType::kRenderer: + return GetExpectedRendererMetrics(); + case HistogramProcessType::kExtension: + case HistogramProcessType::kNetworkService: + case HistogramProcessType::kUtility: break; } @@ -585,7 +630,7 @@ } // namespace class ProcessMemoryMetricsEmitterTest - : public testing::TestWithParam<ProcessType> { + : public testing::TestWithParam<HistogramProcessType> { public: ProcessMemoryMetricsEmitterTest() {} ~ProcessMemoryMetricsEmitterTest() override {} @@ -640,12 +685,14 @@ CheckMemoryUkmEntryMetrics(expected_entries); } -INSTANTIATE_TEST_SUITE_P(SinglePtype, - ProcessMemoryMetricsEmitterTest, - testing::Values(ProcessType::BROWSER, - ProcessType::RENDERER, - ProcessType::GPU, - ProcessType::UTILITY)); +INSTANTIATE_TEST_SUITE_P( + SinglePtype, + ProcessMemoryMetricsEmitterTest, + testing::Values(HistogramProcessType::kBrowser, + HistogramProcessType::kRenderer, + HistogramProcessType::kGpu, + HistogramProcessType::kPaintPreviewCompositor, + HistogramProcessType::kAudioService)); TEST_F(ProcessMemoryMetricsEmitterTest, CollectsExtensionProcessUKMs) { MetricMap expected_metrics = GetExpectedRendererMetrics(); @@ -668,10 +715,17 @@ } TEST_F(ProcessMemoryMetricsEmitterTest, CollectsManyProcessUKMsSingleDump) { - std::vector<ProcessType> entries_ptypes = { - ProcessType::BROWSER, ProcessType::RENDERER, ProcessType::GPU, - ProcessType::UTILITY, ProcessType::UTILITY, ProcessType::GPU, - ProcessType::RENDERER, ProcessType::BROWSER, + std::vector<HistogramProcessType> entries_ptypes = { + HistogramProcessType::kBrowser, + HistogramProcessType::kRenderer, + HistogramProcessType::kGpu, + HistogramProcessType::kAudioService, + HistogramProcessType::kPaintPreviewCompositor, + HistogramProcessType::kPaintPreviewCompositor, + HistogramProcessType::kAudioService, + HistogramProcessType::kGpu, + HistogramProcessType::kRenderer, + HistogramProcessType::kBrowser, }; GlobalMemoryDumpPtr global_dump( @@ -693,11 +747,15 @@ } TEST_F(ProcessMemoryMetricsEmitterTest, CollectsManyProcessUKMsManyDumps) { - std::vector<std::vector<ProcessType>> entries_ptypes = { - {ProcessType::BROWSER, ProcessType::RENDERER, ProcessType::GPU, - ProcessType::UTILITY}, - {ProcessType::UTILITY, ProcessType::GPU, ProcessType::RENDERER, - ProcessType::BROWSER}, + std::vector<std::vector<HistogramProcessType>> entries_ptypes = { + {HistogramProcessType::kBrowser, HistogramProcessType::kRenderer, + HistogramProcessType::kGpu, + HistogramProcessType::kPaintPreviewCompositor, + HistogramProcessType::kAudioService}, + {HistogramProcessType::kBrowser, HistogramProcessType::kRenderer, + HistogramProcessType::kGpu, + HistogramProcessType::kPaintPreviewCompositor, + HistogramProcessType::kAudioService}, }; std::vector<MetricMap> entries_metrics;
diff --git a/chrome/browser/nearby_sharing/incoming_frames_reader_unittest.cc b/chrome/browser/nearby_sharing/incoming_frames_reader_unittest.cc index 0e5f0a6..8d778ed 100644 --- a/chrome/browser/nearby_sharing/incoming_frames_reader_unittest.cc +++ b/chrome/browser/nearby_sharing/incoming_frames_reader_unittest.cc
@@ -11,9 +11,9 @@ #include "base/time/time.h" #include "chrome/browser/nearby_sharing/fake_nearby_connection.h" #include "chrome/browser/nearby_sharing/mock_nearby_process_manager.h" -#include "chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.h" #include "chrome/services/sharing/public/proto/wire_format.pb.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.h" #include "content/public/test/browser_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -78,7 +78,7 @@ FakeNearbyConnection& connection() { return mock_nearby_connection_; } - testing::StrictMock<MockNearbySharingDecoder>& decoder() { + testing::StrictMock<chromeos::nearby::MockNearbySharingDecoder>& decoder() { return mock_decoder_; } @@ -89,7 +89,7 @@ TestingProfile profile_; FakeNearbyConnection mock_nearby_connection_; testing::StrictMock<MockNearbyProcessManager> mock_process_manager_; - testing::StrictMock<MockNearbySharingDecoder> mock_decoder_; + testing::StrictMock<chromeos::nearby::MockNearbySharingDecoder> mock_decoder_; IncomingFramesReader frames_reader_; }; @@ -116,7 +116,8 @@ DecodeFrame(testing::Eq(introduction_frame), testing::_)) .WillOnce(testing::Invoke( [&](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New(); mojo_v1frame->set_introduction( @@ -144,7 +145,8 @@ DecodeFrame(testing::Eq(introduction_frame), testing::_)) .WillOnce(testing::Invoke( [&](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New(); mojo_v1frame->set_introduction( @@ -177,7 +179,8 @@ EXPECT_CALL(decoder(), DecodeFrame(testing::_, testing::_)) .WillOnce(testing::Invoke( [&](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { EXPECT_EQ(cancel_frame, data); sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New(); @@ -189,7 +192,8 @@ })) .WillOnce(testing::Invoke( [&](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { EXPECT_EQ(introduction_frame, data); sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New(); @@ -223,7 +227,8 @@ EXPECT_CALL(decoder(), DecodeFrame(testing::_, testing::_)) .WillOnce(testing::Invoke( [&](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { EXPECT_EQ(cancel_frame, data); sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New(); @@ -235,7 +240,8 @@ })) .WillOnce(testing::Invoke( [&](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { EXPECT_EQ(introduction_frame, data); sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New();
diff --git a/chrome/browser/nearby_sharing/mock_nearby_connections.cc b/chrome/browser/nearby_sharing/mock_nearby_connections.cc deleted file mode 100644 index 5dd7b68..0000000 --- a/chrome/browser/nearby_sharing/mock_nearby_connections.cc +++ /dev/null
@@ -1,9 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/nearby_sharing/mock_nearby_connections.h" - -MockNearbyConnections::MockNearbyConnections() = default; - -MockNearbyConnections::~MockNearbyConnections() = default;
diff --git a/chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.cc b/chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.cc deleted file mode 100644 index afe9073c..0000000 --- a/chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.cc +++ /dev/null
@@ -1,9 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.h" - -MockNearbySharingDecoder::MockNearbySharingDecoder() = default; - -MockNearbySharingDecoder::~MockNearbySharingDecoder() = default;
diff --git a/chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.h b/chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.h deleted file mode 100644 index 4e4794b6..0000000 --- a/chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_NEARBY_SHARING_MOCK_NEARBY_SHARING_DECODER_H_ -#define CHROME_BROWSER_NEARBY_SHARING_MOCK_NEARBY_SHARING_DECODER_H_ - -#include "chromeos/services/nearby/public/mojom/nearby_decoder.mojom.h" -#include "testing/gmock/include/gmock/gmock.h" - -class MockNearbySharingDecoder : public sharing::mojom::NearbySharingDecoder { - public: - MockNearbySharingDecoder(); - explicit MockNearbySharingDecoder(const MockNearbySharingDecoder&) = delete; - MockNearbySharingDecoder& operator=(const MockNearbySharingDecoder&) = delete; - ~MockNearbySharingDecoder() override; - - // sharing::mojom::NearbySharingDecoder: - MOCK_METHOD(void, - DecodeAdvertisement, - (const std::vector<uint8_t>& data, - DecodeAdvertisementCallback callback), - (override)); - MOCK_METHOD(void, - DecodeFrame, - (const std::vector<uint8_t>& data, DecodeFrameCallback callback), - (override)); -}; - -#endif // CHROME_BROWSER_NEARBY_SHARING_MOCK_NEARBY_SHARING_DECODER_H_
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc index f4ed152d..591b8c8 100644 --- a/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc
@@ -12,11 +12,11 @@ #include "base/test/bind_test_util.h" #include "base/test/mock_callback.h" #include "chrome/browser/nearby_sharing/constants.h" -#include "chrome/browser/nearby_sharing/mock_nearby_connections.h" #include "chrome/browser/nearby_sharing/mock_nearby_process_manager.h" #include "chrome/browser/nearby_sharing/nearby_connection_impl.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/services/nearby/public/cpp/mock_nearby_connections.h" #include "chromeos/services/nearby/public/mojom/nearby_connections_types.mojom.h" #include "content/public/test/browser_task_environment.h" #include "mojo/public/cpp/bindings/remote.h" @@ -363,7 +363,8 @@ std::unique_ptr<net::test::MockNetworkChangeNotifier> network_notifier_ = net::test::MockNetworkChangeNotifier::Create(); base::ScopedDisallowBlocking disallow_blocking_; - testing::NiceMock<MockNearbyConnections> nearby_connections_; + testing::NiceMock<chromeos::nearby::MockNearbyConnections> + nearby_connections_; testing::NiceMock<MockNearbyProcessManager> nearby_process_manager_; NearbyConnectionsManagerImpl nearby_connections_manager_{ &nearby_process_manager_, &profile_};
diff --git a/chrome/browser/nearby_sharing/nearby_process_manager_unittest.cc b/chrome/browser/nearby_sharing/nearby_process_manager_unittest.cc index 2f80bcd..ef0371d 100644 --- a/chrome/browser/nearby_sharing/nearby_process_manager_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_process_manager_unittest.cc
@@ -16,13 +16,13 @@ #include "base/test/bind_test_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h" -#include "chrome/browser/nearby_sharing/mock_nearby_connections.h" -#include "chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.h" #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" +#include "chromeos/services/nearby/public/cpp/mock_nearby_connections.h" +#include "chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.h" #include "chromeos/services/nearby/public/mojom/nearby_connections.mojom.h" #include "chromeos/services/nearby/public/mojom/nearby_connections_types.mojom.h" #include "chromeos/services/nearby/public/mojom/nearby_decoder.mojom.h" @@ -57,8 +57,9 @@ CreateNearbyConnectionsCallback callback) override { dependencies_ = std::move(dependencies); mojo::PendingRemote<NearbyConnectionsMojom> remote; - mojo::MakeSelfOwnedReceiver(std::make_unique<MockNearbyConnections>(), - remote.InitWithNewPipeAndPassReceiver()); + mojo::MakeSelfOwnedReceiver( + std::make_unique<chromeos::nearby::MockNearbyConnections>(), + remote.InitWithNewPipeAndPassReceiver()); std::move(callback).Run(std::move(remote)); run_loop_connections.Quit(); @@ -67,8 +68,9 @@ void CreateNearbySharingDecoder( CreateNearbySharingDecoderCallback callback) override { mojo::PendingRemote<NearbySharingDecoderMojom> remote; - mojo::MakeSelfOwnedReceiver(std::make_unique<MockNearbySharingDecoder>(), - remote.InitWithNewPipeAndPassReceiver()); + mojo::MakeSelfOwnedReceiver( + std::make_unique<chromeos::nearby::MockNearbySharingDecoder>(), + remote.InitWithNewPipeAndPassReceiver()); std::move(callback).Run(std::move(remote)); run_loop_decoder.Quit();
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc index 5e0dfd1..52f06110 100644 --- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
@@ -37,7 +37,6 @@ #include "chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_local_device_data_manager.h" #include "chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.h" #include "chrome/browser/nearby_sharing/mock_nearby_process_manager.h" -#include "chrome/browser/nearby_sharing/mock_nearby_sharing_decoder.h" #include "chrome/browser/nearby_sharing/nearby_connections_manager.h" #include "chrome/browser/nearby_sharing/nearby_share_default_device_name.h" #include "chrome/browser/nearby_sharing/power_client.h" @@ -51,6 +50,7 @@ #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" +#include "chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.h" #include "chromeos/services/nearby/public/mojom/nearby_connections_types.mojom.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/test/browser_task_environment.h" @@ -520,7 +520,8 @@ .WillOnce(testing::Invoke( [is_incoming]( const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New(); mojo_v1frame->set_paired_key_encryption( @@ -542,7 +543,8 @@ DecodeFrame(testing::Eq(result_bytes), testing::_)) .WillOnce(testing::Invoke( [=](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New(); mojo_v1frame->set_paired_key_result( @@ -560,10 +562,10 @@ bool return_empty_advertisement) { EXPECT_CALL(mock_decoder_, DecodeAdvertisement(testing::Eq(endpoint_info), testing::_)) - .WillOnce(testing::Invoke( - [=](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeAdvertisementCallback - callback) { + .WillOnce( + testing::Invoke([=](const std::vector<uint8_t>& data, + chromeos::nearby::MockNearbySharingDecoder:: + DecodeAdvertisementCallback callback) { if (return_empty_advertisement) { std::move(callback).Run(nullptr); return; @@ -584,7 +586,8 @@ EXPECT_CALL(mock_decoder_, DecodeFrame(testing::Eq(bytes), testing::_)) .WillOnce(testing::Invoke( [=](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { std::move(callback).Run(return_empty_introduction_frame ? GetEmptyIntroductionFrame() : GetValidIntroductionFrame()); @@ -599,7 +602,8 @@ EXPECT_CALL(mock_decoder_, DecodeFrame(testing::Eq(bytes), testing::_)) .WillOnce(testing::Invoke( [=](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { std::move(callback).Run(GetConnectionResponseFrame(status)); })); connection_.AppendReadableData(bytes); @@ -886,7 +890,7 @@ bool is_bluetooth_powered_ = true; device::BluetoothAdapter::Observer* adapter_observer_ = nullptr; scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_bluetooth_adapter_; - NiceMock<MockNearbySharingDecoder> mock_decoder_; + NiceMock<chromeos::nearby::MockNearbySharingDecoder> mock_decoder_; FakeNearbyConnection connection_; }; @@ -2121,7 +2125,8 @@ EXPECT_CALL(mock_decoder_, DecodeFrame(testing::Eq(bytes), testing::_)) .WillOnce(testing::Invoke( [](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { std::vector<sharing::mojom::FileMetadataPtr> mojo_file_metadatas; mojo_file_metadatas.push_back(sharing::mojom::FileMetadata::New( "name", sharing::mojom::FileMetadata::Type::kAudio, @@ -2191,7 +2196,8 @@ EXPECT_CALL(mock_decoder_, DecodeFrame(testing::Eq(bytes), testing::_)) .WillOnce(testing::Invoke( [](const std::vector<uint8_t>& data, - MockNearbySharingDecoder::DecodeFrameCallback callback) { + chromeos::nearby::MockNearbySharingDecoder::DecodeFrameCallback + callback) { std::vector<sharing::mojom::FileMetadataPtr> mojo_file_metadatas; mojo_file_metadatas.push_back(sharing::mojom::FileMetadata::New( "name_1", sharing::mojom::FileMetadata::Type::kAudio,
diff --git a/chrome/browser/pepper_flash_settings_manager.cc b/chrome/browser/pepper_flash_settings_manager.cc deleted file mode 100644 index 13a9f0db..0000000 --- a/chrome/browser/pepper_flash_settings_manager.cc +++ /dev/null
@@ -1,1042 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/pepper_flash_settings_manager.h" - -#include <map> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/files/file_util.h" -#include "base/sequenced_task_runner_helpers.h" -#include "base/strings/utf_string_conversions.h" -#include "base/task/thread_pool.h" -#include "build/build_config.h" -#include "chrome/browser/plugins/plugin_prefs.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/renderer_host/pepper/device_id_fetcher.h" -#include "chrome/common/pref_names.h" -#include "components/pref_registry/pref_registry_syncable.h" -#include "components/prefs/pref_service.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/pepper_flash_settings_helper.h" -#include "content/public/browser/plugin_service.h" -#include "content/public/common/content_constants.h" -#include "content/public/common/webplugininfo.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_listener.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "url/gurl.h" - -using content::BrowserThread; - -class PepperFlashSettingsManager::Core - : public IPC::Listener, - public base::RefCountedThreadSafe<Core, BrowserThread::DeleteOnIOThread> { - public: - Core(base::WeakPtr<PepperFlashSettingsManager> manager, - content::BrowserContext* browser_context); - - void Initialize(); - - // Notifies the core that it has been detached. Afterwards, no method should - // be called any more. - void Detach(); - - void DeauthorizeContentLicenses(uint32_t request_id); - void GetPermissionSettings( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type); - void SetDefaultPermission(uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific); - void SetSitePermission(uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites); - void GetSitesWithData(uint32_t request_id); - void ClearSiteData(uint32_t request_id, - const std::string& site, - uint64_t flags, - uint64_t max_age); - - // IPC::Listener implementation. - bool OnMessageReceived(const IPC::Message& message) override; - void OnChannelError() override; - - private: - friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>; - friend class base::DeleteHelper<Core>; - - enum RequestType { - INVALID_REQUEST_TYPE = 0, - DEAUTHORIZE_CONTENT_LICENSES, - GET_PERMISSION_SETTINGS, - SET_DEFAULT_PERMISSION, - SET_SITE_PERMISSION, - GET_SITES_WITH_DATA, - CLEAR_SITE_DATA, - }; - - enum State { - STATE_UNINITIALIZED = 0, - STATE_INITIALIZED, - STATE_ERROR, - STATE_DETACHED, - }; - - struct PendingRequest { - PendingRequest() - : id(0), - type(INVALID_REQUEST_TYPE), - setting_type(PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC), - permission(PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT), - clear_site_specific(false), - flags(0), - max_age(0) { - } - - uint32_t id; - RequestType type; - - // Used by GET_PERMISSION_SETTINGS, SET_DEFAULT_PERMISSION and - // SET_SITE_PERMISSION. - PP_Flash_BrowserOperations_SettingType setting_type; - - // Used by SET_DEFAULT_PERMISSION. - PP_Flash_BrowserOperations_Permission permission; - bool clear_site_specific; - - // Used by SET_SITE_PERMISSION. - ppapi::FlashSiteSettings sites; - - // Used by CLEAR_SITE_DATA - std::string site; - uint64_t flags; - uint64_t max_age; - }; - - ~Core() override; - - void ConnectToChannel(bool success, const IPC::ChannelHandle& handle); - - void InitializeOnIOThread(); - void DeauthorizeContentLicensesOnIOThread(uint32_t request_id); - void DeauthorizeContentLicensesAsync(uint32_t request_id, - const base::FilePath& profile_path); - void DeauthorizeContentLicensesInPlugin(uint32_t request_id, bool success); - void GetPermissionSettingsOnIOThread( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type); - void SetDefaultPermissionOnIOThread( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific); - void SetSitePermissionOnIOThread( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites); - void GetSitesWithDataOnIOThread(uint32_t request_id); - void ClearSiteDataOnIOThread(uint32_t request_id, - const std::string& site, - uint64_t flags, - uint64_t max_age); - void DetachOnIOThread(); - - void NotifyErrorFromIOThread(); - - void NotifyDeauthorizeContentLicensesCompleted(uint32_t request_id, - bool success); - void NotifyGetPermissionSettingsCompleted( - uint32_t request_id, - bool success, - PP_Flash_BrowserOperations_Permission default_permission, - const ppapi::FlashSiteSettings& sites); - void NotifySetDefaultPermissionCompleted(uint32_t request_id, bool success); - void NotifySetSitePermissionCompleted(uint32_t request_id, bool success); - void NotifyGetSitesWithDataCompleted(uint32_t request_id, - const std::vector<std::string>& sites); - void NotifyClearSiteDataCompleted(uint32_t request_id, bool success); - - void NotifyError( - const std::vector<std::pair<uint32_t, RequestType>>& notifications); - - // Message handlers. - void OnDeauthorizeContentLicensesResult(uint32_t request_id, bool success); - void OnGetPermissionSettingsResult( - uint32_t request_id, - bool success, - PP_Flash_BrowserOperations_Permission default_permission, - const ppapi::FlashSiteSettings& sites); - void OnSetDefaultPermissionResult(uint32_t request_id, bool success); - void OnSetSitePermissionResult(uint32_t request_id, bool success); - void OnGetSitesWithDataResult(uint32_t request_id, - const std::vector<std::string>& sites); - void OnClearSiteDataResult(uint32_t request_id, bool success); - - // Used only on the UI thread. - base::WeakPtr<PepperFlashSettingsManager> manager_; - - // Used only on the I/O thread. - base::FilePath plugin_data_path_; - - // The channel is NULL until we have opened a connection to the broker - // process. Used only on the I/O thread. - std::unique_ptr<IPC::Channel> channel_; - - // Used only on the I/O thread. - State state_; - - // Requests that need to be sent once the channel to the broker process is - // established. Used only on the I/O thread. - std::vector<PendingRequest> pending_requests_; - // Requests that have been sent but haven't got replied. Used only on the - // I/O thread. - std::map<uint32_t, RequestType> pending_responses_; - - // Used only on the I/O thread. - scoped_refptr<content::PepperFlashSettingsHelper> helper_; - - // Path for the current profile. Must be retrieved on the UI thread from the - // browser context when we start so we can use it later on the I/O thread. - base::FilePath browser_context_path_; - - scoped_refptr<PluginPrefs> plugin_prefs_; -}; - -PepperFlashSettingsManager::Core::Core( - base::WeakPtr<PepperFlashSettingsManager> manager, - content::BrowserContext* browser_context) - : manager_(manager), - state_(STATE_UNINITIALIZED), - browser_context_path_(browser_context->GetPath()), - plugin_prefs_(PluginPrefs::GetForProfile( - Profile::FromBrowserContext(browser_context))) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); -} - -PepperFlashSettingsManager::Core::~Core() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); -} - -void PepperFlashSettingsManager::Core::Initialize() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::InitializeOnIOThread, this)); -} - -void PepperFlashSettingsManager::Core::Detach() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // This call guarantees that one ref is retained until we get to the DETACHED - // state. This is important. Otherwise, if the ref count drops to zero on the - // UI thread (which posts a task to delete this object on the I/O thread) - // while the I/O thread doesn't know about it, methods on the I/O thread might - // increase the ref count again and cause double deletion. - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::DetachOnIOThread, this)); -} - -void PepperFlashSettingsManager::Core::DeauthorizeContentLicenses( - uint32_t request_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::DeauthorizeContentLicensesOnIOThread, - this, request_id)); -} - -void PepperFlashSettingsManager::Core::GetPermissionSettings( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::GetPermissionSettingsOnIOThread, this, - request_id, setting_type)); -} - -void PepperFlashSettingsManager::Core::SetDefaultPermission( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(&Core::SetDefaultPermissionOnIOThread, this, request_id, - setting_type, permission, clear_site_specific)); -} - -void PepperFlashSettingsManager::Core::SetSitePermission( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::SetSitePermissionOnIOThread, this, - request_id, setting_type, sites)); -} - -void PepperFlashSettingsManager::Core::GetSitesWithData(uint32_t request_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(&Core::GetSitesWithDataOnIOThread, this, request_id)); -} - -void PepperFlashSettingsManager::Core::ClearSiteData(uint32_t request_id, - const std::string& site, - uint64_t flags, - uint64_t max_age) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::ClearSiteDataOnIOThread, this, - request_id, site, flags, max_age)); -} - -bool PepperFlashSettingsManager::Core::OnMessageReceived( - const IPC::Message& message) { - IPC_BEGIN_MESSAGE_MAP(Core, message) - IPC_MESSAGE_HANDLER(PpapiHostMsg_DeauthorizeContentLicensesResult, - OnDeauthorizeContentLicensesResult) - IPC_MESSAGE_HANDLER(PpapiHostMsg_GetPermissionSettingsResult, - OnGetPermissionSettingsResult) - IPC_MESSAGE_HANDLER(PpapiHostMsg_SetDefaultPermissionResult, - OnSetDefaultPermissionResult) - IPC_MESSAGE_HANDLER(PpapiHostMsg_SetSitePermissionResult, - OnSetSitePermissionResult) - IPC_MESSAGE_HANDLER(PpapiHostMsg_GetSitesWithDataResult, - OnGetSitesWithDataResult) - IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult, - OnClearSiteDataResult) - IPC_MESSAGE_UNHANDLED_ERROR() - IPC_END_MESSAGE_MAP() - - return true; -} - -void PepperFlashSettingsManager::Core::OnChannelError() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (state_ == STATE_DETACHED) - return; - - NotifyErrorFromIOThread(); -} - -void PepperFlashSettingsManager::Core::ConnectToChannel( - bool success, - const IPC::ChannelHandle& handle) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (state_ == STATE_DETACHED) - return; - - DCHECK(state_ == STATE_UNINITIALIZED); - DCHECK(!channel_.get()); - - if (!success) { - DLOG(ERROR) << "Couldn't open plugin channel"; - NotifyErrorFromIOThread(); - return; - } - - channel_ = IPC::Channel::CreateClient(handle, this, - base::ThreadTaskRunnerHandle::Get()); - if (!channel_->Connect()) { - DLOG(ERROR) << "Couldn't connect to plugin"; - NotifyErrorFromIOThread(); - return; - } - - state_ = STATE_INITIALIZED; - - std::vector<PendingRequest> temp_pending_requests; - temp_pending_requests.swap(pending_requests_); - for (auto iter = temp_pending_requests.begin(); - iter != temp_pending_requests.end(); ++iter) { - switch (iter->type) { - case INVALID_REQUEST_TYPE: - NOTREACHED(); - break; - case DEAUTHORIZE_CONTENT_LICENSES: - DeauthorizeContentLicensesOnIOThread(iter->id); - break; - case GET_PERMISSION_SETTINGS: - GetPermissionSettingsOnIOThread(iter->id, iter->setting_type); - break; - case SET_DEFAULT_PERMISSION: - SetDefaultPermissionOnIOThread( - iter->id, iter->setting_type, iter->permission, - iter->clear_site_specific); - break; - case SET_SITE_PERMISSION: - SetSitePermissionOnIOThread(iter->id, iter->setting_type, iter->sites); - break; - case GET_SITES_WITH_DATA: - GetSitesWithDataOnIOThread(iter->id); - break; - case CLEAR_SITE_DATA: - ClearSiteDataOnIOThread(iter->id, iter->site, iter->flags, - iter->max_age); - break; - } - } -} - -void PepperFlashSettingsManager::Core::InitializeOnIOThread() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_EQ(STATE_UNINITIALIZED, state_); - - content::WebPluginInfo plugin_info; - if (!PepperFlashSettingsManager::IsPepperFlashInUse(plugin_prefs_.get(), - &plugin_info)) { - NotifyErrorFromIOThread(); - return; - } - - base::FilePath profile_path = - browser_context_path_.Append(content::kPepperDataDirname); -#if defined(OS_WIN) - plugin_data_path_ = profile_path.Append(plugin_info.name); -#else - plugin_data_path_ = profile_path.Append(base::UTF16ToUTF8(plugin_info.name)); -#endif - - helper_ = content::PepperFlashSettingsHelper::Create(); - helper_->OpenChannelToBroker(plugin_info.path, - base::BindOnce(&Core::ConnectToChannel, this)); -} - -void PepperFlashSettingsManager::Core::DeauthorizeContentLicensesOnIOThread( - uint32_t request_id) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_NE(STATE_DETACHED, state_); - - if (state_ == STATE_UNINITIALIZED) { - PendingRequest request; - request.id = request_id; - request.type = DEAUTHORIZE_CONTENT_LICENSES; - pending_requests_.push_back(request); - return; - } - - pending_responses_.insert( - std::make_pair(request_id, DEAUTHORIZE_CONTENT_LICENSES)); - if (state_ == STATE_ERROR) { - NotifyErrorFromIOThread(); - return; - } - -#if defined(OS_CHROMEOS) - base::ThreadPool::PostTask( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&Core::DeauthorizeContentLicensesAsync, this, request_id, - browser_context_path_)); -#else - DeauthorizeContentLicensesInPlugin(request_id, true); -#endif -} - -// TODO(raymes): This is temporary code to migrate ChromeOS devices to the new -// scheme for generating device IDs. Delete this once we are sure most ChromeOS -// devices have been migrated. -void PepperFlashSettingsManager::Core::DeauthorizeContentLicensesAsync( - uint32_t request_id, - const base::FilePath& profile_path) { - // ChromeOS used to store the device ID in a file but this is no longer used. - // Wipe that file. - const base::FilePath& device_id_path = - DeviceIDFetcher::GetLegacyDeviceIDPath(profile_path); - bool success = base::DeleteFile(device_id_path); - - content::GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::DeauthorizeContentLicensesInPlugin, this, - request_id, success)); -} - -void PepperFlashSettingsManager::Core::DeauthorizeContentLicensesInPlugin( - uint32_t request_id, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!success) { - NotifyErrorFromIOThread(); - return; - } - IPC::Message* msg = - new PpapiMsg_DeauthorizeContentLicenses(request_id, plugin_data_path_); - if (!channel_->Send(msg)) { - DLOG(ERROR) << "Couldn't send DeauthorizeContentLicenses message"; - // A failure notification for the current request will be sent since - // |pending_responses_| has been updated. - NotifyErrorFromIOThread(); - } -} - -void PepperFlashSettingsManager::Core::GetPermissionSettingsOnIOThread( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_NE(STATE_DETACHED, state_); - - if (state_ == STATE_UNINITIALIZED) { - PendingRequest request; - request.id = request_id; - request.type = GET_PERMISSION_SETTINGS; - request.setting_type = setting_type; - pending_requests_.push_back(request); - return; - } - - pending_responses_.insert( - std::make_pair(request_id, GET_PERMISSION_SETTINGS)); - if (state_ == STATE_ERROR) { - NotifyErrorFromIOThread(); - return; - } - - IPC::Message* msg = new PpapiMsg_GetPermissionSettings( - request_id, plugin_data_path_, setting_type); - if (!channel_->Send(msg)) { - DLOG(ERROR) << "Couldn't send GetPermissionSettings message"; - // A failure notification for the current request will be sent since - // |pending_responses_| has been updated. - NotifyErrorFromIOThread(); - } -} - -void PepperFlashSettingsManager::Core::SetDefaultPermissionOnIOThread( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_NE(STATE_DETACHED, state_); - - if (state_ == STATE_UNINITIALIZED) { - PendingRequest request; - request.id = request_id; - request.type = SET_DEFAULT_PERMISSION; - request.setting_type = setting_type; - request.permission = permission; - request.clear_site_specific = clear_site_specific; - pending_requests_.push_back(request); - return; - } - - pending_responses_.insert(std::make_pair(request_id, SET_DEFAULT_PERMISSION)); - if (state_ == STATE_ERROR) { - NotifyErrorFromIOThread(); - return; - } - - IPC::Message* msg = new PpapiMsg_SetDefaultPermission( - request_id, plugin_data_path_, setting_type, permission, - clear_site_specific); - if (!channel_->Send(msg)) { - DLOG(ERROR) << "Couldn't send SetDefaultPermission message"; - // A failure notification for the current request will be sent since - // |pending_responses_| has been updated. - NotifyErrorFromIOThread(); - } -} - -void PepperFlashSettingsManager::Core::SetSitePermissionOnIOThread( - uint32_t request_id, - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_NE(STATE_DETACHED, state_); - - if (state_ == STATE_UNINITIALIZED) { - pending_requests_.push_back(PendingRequest()); - PendingRequest& request = pending_requests_.back(); - request.id = request_id; - request.type = SET_SITE_PERMISSION; - request.setting_type = setting_type; - request.sites = sites; - return; - } - - pending_responses_.insert(std::make_pair(request_id, SET_SITE_PERMISSION)); - if (state_ == STATE_ERROR) { - NotifyErrorFromIOThread(); - return; - } - - IPC::Message* msg = new PpapiMsg_SetSitePermission( - request_id, plugin_data_path_, setting_type, sites); - if (!channel_->Send(msg)) { - DLOG(ERROR) << "Couldn't send SetSitePermission message"; - // A failure notification for the current request will be sent since - // |pending_responses_| has been updated. - NotifyErrorFromIOThread(); - } -} - -void PepperFlashSettingsManager::Core::GetSitesWithDataOnIOThread( - uint32_t request_id) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_NE(STATE_DETACHED, state_); - - if (state_ == STATE_UNINITIALIZED) { - pending_requests_.push_back(PendingRequest()); - PendingRequest& request = pending_requests_.back(); - request.id = request_id; - request.type = GET_SITES_WITH_DATA; - return; - } - - pending_responses_.insert(std::make_pair(request_id, GET_SITES_WITH_DATA)); - if (state_ == STATE_ERROR) { - NotifyErrorFromIOThread(); - return; - } - - IPC::Message* msg = new PpapiMsg_GetSitesWithData( - request_id, plugin_data_path_); - if (!channel_->Send(msg)) { - DLOG(ERROR) << "Couldn't send GetSitesWithData message"; - // A failure notification for the current request will be sent since - // |pending_responses_| has been updated. - NotifyErrorFromIOThread(); - } -} - -void PepperFlashSettingsManager::Core::ClearSiteDataOnIOThread( - uint32_t request_id, - const std::string& site, - uint64_t flags, - uint64_t max_age) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_NE(STATE_DETACHED, state_); - - if (state_ == STATE_UNINITIALIZED) { - pending_requests_.push_back(PendingRequest()); - PendingRequest& request = pending_requests_.back(); - request.id = request_id; - request.type = CLEAR_SITE_DATA; - request.site = site; - request.flags = flags; - request.max_age = max_age; - return; - } - - pending_responses_.insert(std::make_pair(request_id, CLEAR_SITE_DATA)); - if (state_ == STATE_ERROR) { - NotifyErrorFromIOThread(); - return; - } - - IPC::Message* msg = new PpapiMsg_ClearSiteData( - request_id, plugin_data_path_, site, flags, max_age); - if (!channel_->Send(msg)) { - DLOG(ERROR) << "Couldn't send ClearSiteData message"; - // A failure notification for the current request will be sent since - // |pending_responses_| has been updated. - NotifyErrorFromIOThread(); - } -} - -void PepperFlashSettingsManager::Core::DetachOnIOThread() { - state_ = STATE_DETACHED; -} - -void PepperFlashSettingsManager::Core::NotifyErrorFromIOThread() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (state_ == STATE_DETACHED) - return; - - state_ = STATE_ERROR; - std::vector<std::pair<uint32_t, RequestType>> notifications; - for (auto iter = pending_requests_.begin(); iter != pending_requests_.end(); - ++iter) { - notifications.push_back(std::make_pair(iter->id, iter->type)); - } - pending_requests_.clear(); - notifications.insert(notifications.end(), pending_responses_.begin(), - pending_responses_.end()); - pending_responses_.clear(); - - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::NotifyError, this, notifications)); -} - -void PepperFlashSettingsManager::Core:: - NotifyDeauthorizeContentLicensesCompleted(uint32_t request_id, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (manager_.get()) { - manager_->client_->OnDeauthorizeFlashContentLicensesCompleted(request_id, - success); - } -} - -void PepperFlashSettingsManager::Core::NotifyGetPermissionSettingsCompleted( - uint32_t request_id, - bool success, - PP_Flash_BrowserOperations_Permission default_permission, - const ppapi::FlashSiteSettings& sites) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (manager_.get()) { - manager_->client_->OnGetPermissionSettingsCompleted( - request_id, success, default_permission, sites); - } -} - -void PepperFlashSettingsManager::Core::NotifySetDefaultPermissionCompleted( - uint32_t request_id, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (manager_.get()) { - manager_->client_->OnSetDefaultPermissionCompleted( - request_id, success); - } -} - -void PepperFlashSettingsManager::Core::NotifySetSitePermissionCompleted( - uint32_t request_id, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (manager_.get()) { - manager_->client_->OnSetSitePermissionCompleted( - request_id, success); - } -} - -void PepperFlashSettingsManager::Core::NotifyGetSitesWithDataCompleted( - uint32_t request_id, - const std::vector<std::string>& sites) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (manager_.get()) { - manager_->client_->OnGetSitesWithDataCompleted( - request_id, sites); - } -} - -void PepperFlashSettingsManager::Core::NotifyClearSiteDataCompleted( - uint32_t request_id, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - if (manager_.get()) - manager_->client_->OnClearSiteDataCompleted(request_id, success); -} - -void PepperFlashSettingsManager::Core::NotifyError( - const std::vector<std::pair<uint32_t, RequestType>>& notifications) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - scoped_refptr<Core> protector(this); - for (auto iter = notifications.begin(); iter != notifications.end(); ++iter) { - // Check |manager_| for each iteration in case it is destroyed in one of - // the callbacks. - if (!manager_.get()) - return; - - switch (iter->second) { - case INVALID_REQUEST_TYPE: - NOTREACHED(); - break; - case DEAUTHORIZE_CONTENT_LICENSES: - manager_->client_->OnDeauthorizeFlashContentLicensesCompleted( - iter->first, false); - break; - case GET_PERMISSION_SETTINGS: - manager_->client_->OnGetPermissionSettingsCompleted( - iter->first, false, PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT, - ppapi::FlashSiteSettings()); - break; - case SET_DEFAULT_PERMISSION: - manager_->client_->OnSetDefaultPermissionCompleted( - iter->first, false); - break; - case SET_SITE_PERMISSION: - manager_->client_->OnSetSitePermissionCompleted(iter->first, false); - break; - case GET_SITES_WITH_DATA: - manager_->client_->OnGetSitesWithDataCompleted( - iter->first, std::vector<std::string>()); - break; - case CLEAR_SITE_DATA: - manager_->client_->OnClearSiteDataCompleted(iter->first, false); - break; - } - } - - if (manager_.get()) - manager_->OnError(this); -} - -void PepperFlashSettingsManager::Core::OnDeauthorizeContentLicensesResult( - uint32_t request_id, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (state_ == STATE_DETACHED) - return; - - DLOG_IF(ERROR, !success) << "DeauthorizeContentLicenses returned error"; - - auto iter = pending_responses_.find(request_id); - if (iter == pending_responses_.end()) - return; - - DCHECK_EQ(iter->second, DEAUTHORIZE_CONTENT_LICENSES); - - pending_responses_.erase(iter); - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(&Core::NotifyDeauthorizeContentLicensesCompleted, this, - request_id, success)); -} - -void PepperFlashSettingsManager::Core::OnGetPermissionSettingsResult( - uint32_t request_id, - bool success, - PP_Flash_BrowserOperations_Permission default_permission, - const ppapi::FlashSiteSettings& sites) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (state_ == STATE_DETACHED) - return; - - DLOG_IF(ERROR, !success) << "GetPermissionSettings returned error"; - - auto iter = pending_responses_.find(request_id); - if (iter == pending_responses_.end()) - return; - - DCHECK_EQ(iter->second, GET_PERMISSION_SETTINGS); - - pending_responses_.erase(iter); - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, - base::BindOnce(&Core::NotifyGetPermissionSettingsCompleted, this, - request_id, success, default_permission, sites)); -} - -void PepperFlashSettingsManager::Core::OnSetDefaultPermissionResult( - uint32_t request_id, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (state_ == STATE_DETACHED) - return; - - DLOG_IF(ERROR, !success) << "SetDefaultPermission returned error"; - - auto iter = pending_responses_.find(request_id); - if (iter == pending_responses_.end()) - return; - - DCHECK_EQ(iter->second, SET_DEFAULT_PERMISSION); - - pending_responses_.erase(iter); - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::NotifySetDefaultPermissionCompleted, - this, request_id, success)); -} - -void PepperFlashSettingsManager::Core::OnSetSitePermissionResult( - uint32_t request_id, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (state_ == STATE_DETACHED) - return; - - DLOG_IF(ERROR, !success) << "SetSitePermission returned error"; - - auto iter = pending_responses_.find(request_id); - if (iter == pending_responses_.end()) - return; - - DCHECK_EQ(iter->second, SET_SITE_PERMISSION); - - pending_responses_.erase(iter); - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::NotifySetSitePermissionCompleted, this, - request_id, success)); -} - -void PepperFlashSettingsManager::Core::OnGetSitesWithDataResult( - uint32_t request_id, - const std::vector<std::string>& sites) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (state_ == STATE_DETACHED) - return; - - auto iter = pending_responses_.find(request_id); - if (iter == pending_responses_.end()) - return; - - DCHECK_EQ(iter->second, GET_SITES_WITH_DATA); - - pending_responses_.erase(iter); - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::NotifyGetSitesWithDataCompleted, this, - request_id, sites)); -} - -void PepperFlashSettingsManager::Core::OnClearSiteDataResult( - uint32_t request_id, - bool success) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (state_ == STATE_DETACHED) - return; - - DLOG_IF(ERROR, !success) << "ClearSiteData returned error"; - - auto iter = pending_responses_.find(request_id); - if (iter == pending_responses_.end()) - return; - - DCHECK_EQ(iter->second, CLEAR_SITE_DATA); - - pending_responses_.erase(iter); - content::GetUIThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Core::NotifyClearSiteDataCompleted, this, - request_id, success)); -} - -PepperFlashSettingsManager::PepperFlashSettingsManager( - Client* client, - content::BrowserContext* browser_context) - : client_(client), browser_context_(browser_context), next_request_id_(1) { - DCHECK(client); - DCHECK(browser_context); -} - -PepperFlashSettingsManager::~PepperFlashSettingsManager() { - if (core_.get()) - core_->Detach(); -} - -// static -bool PepperFlashSettingsManager::IsPepperFlashInUse( - PluginPrefs* plugin_prefs, - content::WebPluginInfo* plugin_info) { - if (!plugin_prefs) - return false; - - content::PluginService* plugin_service = - content::PluginService::GetInstance(); - std::vector<content::WebPluginInfo> plugins; - plugin_service->GetPluginInfoArray( - GURL(), content::kFlashPluginSwfMimeType, false, &plugins, NULL); - - for (auto iter = plugins.begin(); iter != plugins.end(); ++iter) { - if (iter->is_pepper_plugin() && plugin_prefs->IsPluginEnabled(*iter)) { - if (plugin_info) - *plugin_info = *iter; - return true; - } - } - return false; -} - -// static -void PepperFlashSettingsManager::RegisterProfilePrefs( - user_prefs::PrefRegistrySyncable* registry) { - registry->RegisterBooleanPref(prefs::kPepperFlashSettingsEnabled, true); -} - -uint32_t PepperFlashSettingsManager::DeauthorizeContentLicenses( - PrefService* prefs) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - // Clear the device ID salt which has the effect of regenerating a device - // ID. Since this happens synchronously (and on the UI thread), we don't have - // to add it to a pending request. - prefs->ClearPref(prefs::kDRMSalt); - - EnsureCoreExists(); - uint32_t id = GetNextRequestId(); - core_->DeauthorizeContentLicenses(id); - return id; -} - -uint32_t PepperFlashSettingsManager::GetPermissionSettings( - PP_Flash_BrowserOperations_SettingType setting_type) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - EnsureCoreExists(); - uint32_t id = GetNextRequestId(); - core_->GetPermissionSettings(id, setting_type); - return id; -} - -uint32_t PepperFlashSettingsManager::SetDefaultPermission( - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - EnsureCoreExists(); - uint32_t id = GetNextRequestId(); - core_->SetDefaultPermission(id, setting_type, permission, - clear_site_specific); - return id; -} - -uint32_t PepperFlashSettingsManager::SetSitePermission( - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - EnsureCoreExists(); - uint32_t id = GetNextRequestId(); - core_->SetSitePermission(id, setting_type, sites); - return id; -} - -uint32_t PepperFlashSettingsManager::GetSitesWithData() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - EnsureCoreExists(); - uint32_t id = GetNextRequestId(); - core_->GetSitesWithData(id); - return id; -} - -uint32_t PepperFlashSettingsManager::ClearSiteData(const std::string& site, - uint64_t flags, - uint64_t max_age) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - EnsureCoreExists(); - uint32_t id = GetNextRequestId(); - core_->ClearSiteData(id, site, flags, max_age); - return id; -} - -uint32_t PepperFlashSettingsManager::GetNextRequestId() { - return next_request_id_++; -} - -void PepperFlashSettingsManager::EnsureCoreExists() { - if (!core_.get()) { - core_ = new Core(weak_ptr_factory_.GetWeakPtr(), browser_context_); - core_->Initialize(); - } -} - -void PepperFlashSettingsManager::OnError(Core* core) { - DCHECK(core); - if (core != core_.get()) - return; - - core_->Detach(); - core_.reset(); -}
diff --git a/chrome/browser/pepper_flash_settings_manager.h b/chrome/browser/pepper_flash_settings_manager.h deleted file mode 100644 index 9cd2c5d..0000000 --- a/chrome/browser/pepper_flash_settings_manager.h +++ /dev/null
@@ -1,141 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PEPPER_FLASH_SETTINGS_MANAGER_H_ -#define CHROME_BROWSER_PEPPER_FLASH_SETTINGS_MANAGER_H_ - -#include <stdint.h> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "ppapi/c/private/ppp_flash_browser_operations.h" -#include "ppapi/shared_impl/ppp_flash_browser_operations_shared.h" - -class PluginPrefs; -class PrefService; - -namespace content { -class BrowserContext; -struct WebPluginInfo; -} - -namespace user_prefs { -class PrefRegistrySyncable; -} - -// PepperFlashSettingsManager communicates with a PPAPI broker process to -// read/write Pepper Flash settings. -class PepperFlashSettingsManager { - public: - class Client { - public: - virtual ~Client() {} - - virtual void OnDeauthorizeFlashContentLicensesCompleted(uint32_t request_id, - bool success) {} - virtual void OnGetPermissionSettingsCompleted( - uint32_t request_id, - bool success, - PP_Flash_BrowserOperations_Permission default_permission, - const ppapi::FlashSiteSettings& sites) {} - - virtual void OnSetDefaultPermissionCompleted(uint32_t request_id, - bool success) {} - - virtual void OnSetSitePermissionCompleted(uint32_t request_id, - bool success) {} - - virtual void OnGetSitesWithDataCompleted( - uint32_t request_id, - const std::vector<std::string>& sites) {} - - virtual void OnClearSiteDataCompleted(uint32_t request_id, bool success) {} - }; - - // |client| must outlive this object. It is guaranteed that |client| won't - // receive any notifications after this object goes away. - PepperFlashSettingsManager(Client* client, - content::BrowserContext* browser_context); - ~PepperFlashSettingsManager(); - - // |plugin_info| will be updated if it is not NULL and the method returns - // true. - static bool IsPepperFlashInUse(PluginPrefs* plugin_prefs, - content::WebPluginInfo* plugin_info); - - static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); - - // Requests to deauthorize content licenses. - // Client::OnDeauthorizeFlashContentLicensesCompleted() will be called when - // the operation is completed. - // The return value is the same as the request ID passed into - // Client::OnDeauthorizeFlashContentLicensesCompleted(). - uint32_t DeauthorizeContentLicenses(PrefService* prefs); - - // Gets permission settings. - // Client::OnGetPermissionSettingsCompleted() will be called when the - // operation is completed. - uint32_t GetPermissionSettings( - PP_Flash_BrowserOperations_SettingType setting_type); - - // Sets default permission. - // Client::OnSetDefaultPermissionCompleted() will be called when the - // operation is completed. - uint32_t SetDefaultPermission( - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific); - - // Sets site-specific permission. - // Client::OnSetSitePermissionCompleted() will be called when the operation - // is completed. - uint32_t SetSitePermission( - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites); - - // Gets a list of sites that have stored data. - // Client::OnGetSitesWithDataCompleted() will be called when the operation is - // completed. - uint32_t GetSitesWithData(); - - // Clears data for a certain site. - // Client::OnClearSiteDataompleted() will be called when the operation is - // completed. - uint32_t ClearSiteData(const std::string& site, - uint64_t flags, - uint64_t max_age); - - private: - // Core does most of the work. It is ref-counted so that its lifespan can be - // independent of the containing object's: - // - The manager can be deleted on the UI thread while the core still being - // used on the I/O thread. - // - The manager can delete the core when it encounters errors and create - // another one to handle new requests. - class Core; - - uint32_t GetNextRequestId(); - - void EnsureCoreExists(); - - // Notifies us that an error occurred in |core|. - void OnError(Core* core); - - // |client_| is not owned by this object and must outlive it. - Client* client_; - - // The browser context for the profile. - content::BrowserContext* browser_context_; - - scoped_refptr<Core> core_; - - uint32_t next_request_id_; - - base::WeakPtrFactory<PepperFlashSettingsManager> weak_ptr_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(PepperFlashSettingsManager); -}; - -#endif // CHROME_BROWSER_PEPPER_FLASH_SETTINGS_MANAGER_H_
diff --git a/chrome/browser/performance_manager/frame_node_impl_browsertest.cc b/chrome/browser/performance_manager/frame_node_impl_browsertest.cc new file mode 100644 index 0000000..bc2816ab8 --- /dev/null +++ b/chrome/browser/performance_manager/frame_node_impl_browsertest.cc
@@ -0,0 +1,239 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/performance_manager/graph/frame_node_impl.h" + +#include "base/run_loop.h" +#include "base/test/bind_test_util.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/performance_manager/graph/page_node_impl.h" +#include "components/performance_manager/performance_manager_impl.h" +#include "components/performance_manager/public/graph/page_node.h" +#include "content/public/test/browser_test.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/rect_f.h" + +namespace performance_manager { + +namespace { + +class FrameNodeImplBrowserTest : public InProcessBrowserTest { + public: + FrameNodeImplBrowserTest() = default; + ~FrameNodeImplBrowserTest() override = default; +}; + +} // namespace + +IN_PROC_BROWSER_TEST_F(FrameNodeImplBrowserTest, + ViewportIntersection_OutOfView) { + ASSERT_TRUE(embedded_test_server()->Start()); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + const GURL main_frame_url( + embedded_test_server()->GetURL("/iframe_out_of_view.html")); + + base::WeakPtr<PageNode> page_node = + PerformanceManager::GetPageNodeForWebContents( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Navigate. + browser()->OpenURL(content::OpenURLParams(main_frame_url, content::Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + // Ensure that loading is complete. + content::WaitForLoadStop( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Verify that the viewport intersection has been set correctly on the graph. + base::RunLoop run_loop; + auto call_on_graph_cb = base::BindLambdaForTesting([&]() { + EXPECT_TRUE(page_node); + auto children = page_node.get()->GetMainFrameNode()->GetChildFrameNodes(); + EXPECT_EQ(1U, children.size()); + auto* iframe = + performance_manager::FrameNodeImpl::FromNode(*children.begin()); + EXPECT_TRUE(iframe->viewport_intersection().IsEmpty()); + run_loop.Quit(); + }); + PerformanceManager::CallOnGraph(FROM_HERE, call_on_graph_cb); + run_loop.Run(); +} + +IN_PROC_BROWSER_TEST_F(FrameNodeImplBrowserTest, ViewportIntersection_Hidden) { + ASSERT_TRUE(embedded_test_server()->Start()); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + const GURL main_frame_url( + embedded_test_server()->GetURL("/iframe_hidden.html")); + + base::WeakPtr<PageNode> page_node = + PerformanceManager::GetPageNodeForWebContents( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Navigate. + browser()->OpenURL(content::OpenURLParams(main_frame_url, content::Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + // Ensure that loading is complete. + content::WaitForLoadStop( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Verify that the viewport intersection has been set correctly on the graph. + base::RunLoop run_loop; + auto call_on_graph_cb = base::BindLambdaForTesting([&]() { + EXPECT_TRUE(page_node); + auto children = page_node.get()->GetMainFrameNode()->GetChildFrameNodes(); + EXPECT_EQ(1U, children.size()); + auto* iframe = + performance_manager::FrameNodeImpl::FromNode(*children.begin()); + EXPECT_TRUE(iframe->viewport_intersection().IsEmpty()); + run_loop.Quit(); + }); + PerformanceManager::CallOnGraph(FROM_HERE, call_on_graph_cb); + run_loop.Run(); +} + +IN_PROC_BROWSER_TEST_F(FrameNodeImplBrowserTest, + ViewportIntersection_PartiallyVisible) { + ASSERT_TRUE(embedded_test_server()->Start()); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + const GURL main_frame_url( + embedded_test_server()->GetURL("/iframe_partially_visible.html")); + + base::WeakPtr<PageNode> page_node = + PerformanceManager::GetPageNodeForWebContents( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Navigate. + browser()->OpenURL(content::OpenURLParams(main_frame_url, content::Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + // Ensure that loading is complete. + content::WaitForLoadStop( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Verify that the viewport intersection has been set correctly on the graph. + base::RunLoop run_loop; + auto call_on_graph_cb = base::BindLambdaForTesting([&]() { + EXPECT_TRUE(page_node); + auto children = page_node.get()->GetMainFrameNode()->GetChildFrameNodes(); + EXPECT_EQ(1U, children.size()); + auto* iframe = + performance_manager::FrameNodeImpl::FromNode(*children.begin()); + + // The frame is a 100x100 px square centered on the origin of the viewport. + // Thus only the bottom right quarter is visible + const gfx::Rect kExpectedViewportIntersection(0, 0, 50, 50); + EXPECT_EQ(iframe->viewport_intersection(), kExpectedViewportIntersection); + run_loop.Quit(); + }); + PerformanceManager::CallOnGraph(FROM_HERE, call_on_graph_cb); + run_loop.Run(); +} + +IN_PROC_BROWSER_TEST_F(FrameNodeImplBrowserTest, ViewportIntersection_Scaled) { + ASSERT_TRUE(embedded_test_server()->Start()); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + const GURL main_frame_url( + embedded_test_server()->GetURL("/iframe_scaled.html")); + + base::WeakPtr<PageNode> page_node = + PerformanceManager::GetPageNodeForWebContents( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Navigate. + browser()->OpenURL(content::OpenURLParams(main_frame_url, content::Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + // Ensure that loading is complete. + content::WaitForLoadStop( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Verify that the viewport intersection has been set correctly on the graph. + base::RunLoop run_loop; + auto call_on_graph_cb = base::BindLambdaForTesting([&]() { + EXPECT_TRUE(page_node); + auto children = page_node.get()->GetMainFrameNode()->GetChildFrameNodes(); + EXPECT_EQ(1U, children.size()); + auto* iframe = + performance_manager::FrameNodeImpl::FromNode(*children.begin()); + + // The iframe is a 200x200 px square centered at (200, 200) scaled to 1.5x + // its size from it's center. + + // The size should be 50% larger. + EXPECT_EQ(iframe->viewport_intersection().size(), gfx::Size(300, 300)); + + // Because the resulting square is still centered at (200, 200), its origin + // is (200-width/2, 200-height/2) = (50, 50) + EXPECT_EQ(iframe->viewport_intersection().origin(), gfx::Point(50, 50)); + + run_loop.Quit(); + }); + PerformanceManager::CallOnGraph(FROM_HERE, call_on_graph_cb); + run_loop.Run(); +} + +IN_PROC_BROWSER_TEST_F(FrameNodeImplBrowserTest, ViewportIntersection_Rotated) { + ASSERT_TRUE(embedded_test_server()->Start()); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + + const GURL main_frame_url( + embedded_test_server()->GetURL("/iframe_rotated.html")); + + base::WeakPtr<PageNode> page_node = + PerformanceManager::GetPageNodeForWebContents( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Navigate. + browser()->OpenURL(content::OpenURLParams(main_frame_url, content::Referrer(), + WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + // Ensure that loading is complete. + content::WaitForLoadStop( + browser()->tab_strip_model()->GetActiveWebContents()); + + // Verify that the viewport intersection has been set correctly on the graph. + base::RunLoop run_loop; + auto call_on_graph_cb = base::BindLambdaForTesting([&]() { + EXPECT_TRUE(page_node); + auto children = page_node.get()->GetMainFrameNode()->GetChildFrameNodes(); + EXPECT_EQ(1U, children.size()); + auto* iframe = + performance_manager::FrameNodeImpl::FromNode(*children.begin()); + + // The iframe is a 100x100 px square centered at (150, 150) rotated by 45 + // degree around its center. + + // This results in a diamond shape also centered at (150, 150), whose width + // can be calculated with the pythagorean theorem. + const float width = sqrt(100 * 100 + 100 * 100); + const float start = 150 - width / 2; + const gfx::RectF enclosing_rectf(start, start, width, width); + + // Thus the expectation for the viewport intersection is to be equal to the + // smallest Rect that encloses the |enclosing_rectf|. + const gfx::Rect expected_viewport_intersection = + ToEnclosingRect(enclosing_rectf); + + EXPECT_EQ(iframe->viewport_intersection(), expected_viewport_intersection); + + run_loop.Quit(); + }); + PerformanceManager::CallOnGraph(FROM_HERE, call_on_graph_cb); + run_loop.Run(); +} + +} // namespace performance_manager
diff --git a/chrome/browser/plugins/plugin_data_remover_helper.cc b/chrome/browser/plugins/plugin_data_remover_helper.cc deleted file mode 100644 index 0f7d6b78..0000000 --- a/chrome/browser/plugins/plugin_data_remover_helper.cc +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/plugins/plugin_data_remover_helper.h" - -#include "chrome/browser/plugins/plugin_prefs.h" -#include "content/public/browser/plugin_data_remover.h" -#include "content/public/common/webplugininfo.h" - -// static -bool PluginDataRemoverHelper::IsSupported(PluginPrefs* plugin_prefs) { - std::vector<content::WebPluginInfo> plugins; - content::PluginDataRemover::GetSupportedPlugins(&plugins); - for (std::vector<content::WebPluginInfo>::const_iterator it = plugins.begin(); - it != plugins.end(); ++it) { - if (plugin_prefs->IsPluginEnabled(*it)) - return true; - } - return false; -}
diff --git a/chrome/browser/plugins/plugin_data_remover_helper.h b/chrome/browser/plugins/plugin_data_remover_helper.h deleted file mode 100644 index 92eac31..0000000 --- a/chrome/browser/plugins/plugin_data_remover_helper.h +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_PLUGINS_PLUGIN_DATA_REMOVER_HELPER_H_ -#define CHROME_BROWSER_PLUGINS_PLUGIN_DATA_REMOVER_HELPER_H_ - -class PluginPrefs; - -class PluginDataRemoverHelper { - public: - // Like PluginDataRemover::IsSupported, but checks that the returned plugin - // is enabled by PluginPrefs. - static bool IsSupported(PluginPrefs* plugin_prefs); -}; - -#endif // CHROME_BROWSER_PLUGINS_PLUGIN_DATA_REMOVER_HELPER_H_
diff --git a/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc b/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc index dd0b051..42768e69 100644 --- a/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc +++ b/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc
@@ -311,6 +311,8 @@ void ChromeBrowserCloudManagementControllerDesktop::ShutDown() { if (policy_invalidator_) policy_invalidator_->Shutdown(); + if (commands_invalidator_) + commands_invalidator_->Shutdown(); } MachineLevelUserCloudPolicyManager* @@ -393,7 +395,6 @@ ->core(), base::DefaultClock::GetInstance(), PolicyInvalidationScope::kCBCM); commands_invalidator_->Initialize(invalidation_service_.get()); - commands_invalidator_->Start(); } }
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index c6037af..7226d38 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -343,9 +343,6 @@ { key::kSafeSitesFilterBehavior, policy_prefs::kSafeSitesFilterBehavior, base::Value::Type::INTEGER }, - { key::kSendFilesForMalwareCheck, - prefs::kSafeBrowsingSendFilesForMalwareCheck, - base::Value::Type::INTEGER }, { key::kAmbientAuthenticationInPrivateModesEnabled, prefs::kAmbientAuthenticationInPrivateModesEnabled, base::Value::Type::INTEGER }, @@ -694,9 +691,6 @@ { key::kAllowPasswordProtectedFiles, prefs::kAllowPasswordProtectedFiles, base::Value::Type::INTEGER }, - { key::kCheckContentCompliance, - prefs::kCheckContentCompliance, - base::Value::Type::INTEGER }, { key::kBlockUnsupportedFiletypes, prefs::kBlockUnsupportedFiletypes, base::Value::Type::INTEGER },
diff --git a/chrome/browser/policy/messaging_layer/upload/meet_device_telemetry_report_handler.cc b/chrome/browser/policy/messaging_layer/upload/meet_device_telemetry_report_handler.cc index 93b53e6..baee5505 100644 --- a/chrome/browser/policy/messaging_layer/upload/meet_device_telemetry_report_handler.cc +++ b/chrome/browser/policy/messaging_layer/upload/meet_device_telemetry_report_handler.cc
@@ -32,15 +32,33 @@ namespace { -// Common Key names used when building the dictionary to pass to the Chrome -// Reporting API. +// Common Key names used when building the Event dictionary to pass to the +// Chrome Reporting API. +// When sent the event should look like this: +// { +// "time": "2017-01-15T01:30:15.01Z", // Timestamp in RFC3339 format +// "reportingRecordEvent": { +// "destination": 3, +// "dmToken": "abcdef1234", +// "timestampUs"": 123456, +// "data": "String of Data" +// } +// } +constexpr char kTime[] = "time"; +constexpr char kReportingRecordEvent[] = "reportingRecordEvent"; + +// Common key names used when builing the ReportingRecordEvent dictionary to +// pass to Chrome Reporting API. This is the dictionary indicated by +// |kReportingRecordEvent|. This dictionary is a direct 1:1 relation to the +// reporting::Record proto. constexpr char kDestination[] = "destination"; constexpr char kDmToken[] = "dmToken"; constexpr char kTimestampUs[] = "timestampUs"; constexpr char kData[] = "data"; -base::Value ConvertRecordProtoToValue(const Record& record, - const base::Value& context) { +// Takes a reporting::Record and converts it to the |kReportingRecordEvent| +// dictionary. +base::Value ConvertRecordProtoToValue(const Record& record) { base::Value record_fields{base::Value::Type::DICTIONARY}; if (record.has_destination()) { record_fields.SetIntKey(kDestination, record.destination()); @@ -58,8 +76,39 @@ if (record.has_data()) { // No data indicates gap, empty data is still data. record_fields.SetStringKey(kData, record.data()); } + return record_fields; +} + +// Generates a RFC3999 time string. +std::string GetTimeString(const base::Time& timestamp) { + base::Time::Exploded time_exploded; + timestamp.UTCExplode(&time_exploded); + std::string time_str = base::StringPrintf( + "%d-%02d-%02dT%02d:%02d:%02d.%03dZ", time_exploded.year, + time_exploded.month, time_exploded.day_of_month, time_exploded.hour, + time_exploded.minute, time_exploded.second, time_exploded.millisecond); + return time_str; +} + +// Creates a list of Event dictionaries from a Record. (Note: Currently takes +// one Record and makes a list with one Event). +base::Value ConvertRecordProtoToEventList(const Record& record) { + // Create the Event Dictionary + base::Value event{base::Value::Type::DICTIONARY}; + + // Set the |kReportingRecordEvent| key to the Record dictionary. + event.SetKey(kReportingRecordEvent, ConvertRecordProtoToValue(record)); + + // Build the timestamp and set the |kTime| to the RFC3999 version. + base::Time timestamp = + base::Time::UnixEpoch() + + base::TimeDelta::FromMicroseconds(record.timestamp_us()); + event.SetStringKey(kTime, GetTimeString(timestamp)); + + // Build the list and append the event. base::Value records_list{base::Value::Type::LIST}; - records_list.Append(std::move(record_fields)); + records_list.Append(std::move(event)); + return records_list; } @@ -85,7 +134,7 @@ StatusOr<base::Value> MeetDeviceTelemetryReportHandler::ConvertRecord( const Record& record) const { base::Value context = reporting::GetContext(profile_); - base::Value event_list = ConvertRecordProtoToValue(record, context); + base::Value event_list = ConvertRecordProtoToEventList(record); return policy::RealtimeReportingJobConfiguration::BuildReport( std::move(event_list), std::move(context)); }
diff --git a/chrome/browser/policy/messaging_layer/upload/meet_device_telemetry_report_handler_unittest.cc b/chrome/browser/policy/messaging_layer/upload/meet_device_telemetry_report_handler_unittest.cc index ebd5142..029e0006 100644 --- a/chrome/browser/policy/messaging_layer/upload/meet_device_telemetry_report_handler_unittest.cc +++ b/chrome/browser/policy/messaging_layer/upload/meet_device_telemetry_report_handler_unittest.cc
@@ -45,13 +45,20 @@ return false; } const base::Value& event = *events_list.begin(); - const auto destination = event.FindIntKey("destination"); + + const auto* reporting_record_event = event.FindKey("reportingRecordEvent"); + if (reporting_record_event == nullptr) { + LOG(ERROR) << "'reportingRecordEvent' is missing" << event; + return false; + } + + const auto destination = reporting_record_event->FindIntKey("destination"); if (!destination.has_value() || destination.value() != Destination::MEET_DEVICE_TELEMETRY) { LOG(ERROR) << "'destination' is wrong or missing"; return false; } - const std::string* const data = event.FindStringKey("data"); + const std::string* const data = reporting_record_event->FindStringKey("data"); if (!data) { LOG(ERROR) << "'data' is missing"; return false;
diff --git a/chrome/browser/portal/OWNERS b/chrome/browser/portal/OWNERS index bf4f802..1c33ce23 100644 --- a/chrome/browser/portal/OWNERS +++ b/chrome/browser/portal/OWNERS
@@ -1,3 +1,3 @@ file://third_party/blink/renderer/core/html/portal/OWNERS -# COMPONENT: Blink>HTML>Portal +# COMPONENT: Blink>Portals
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 79e853c..1576e23 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -192,7 +192,6 @@ #endif #if BUILDFLAG(ENABLE_PLUGINS) -#include "chrome/browser/pepper_flash_settings_manager.h" #include "chrome/browser/plugins/plugin_info_host_impl.h" #include "chrome/browser/plugins/plugins_resource_service.h" #include "chrome/browser/renderer_host/pepper/device_id_fetcher.h" @@ -832,7 +831,6 @@ #if BUILDFLAG(ENABLE_PLUGINS) DeviceIDFetcher::RegisterProfilePrefs(registry); - PepperFlashSettingsManager::RegisterProfilePrefs(registry); PluginInfoHostImpl::RegisterUserPrefs(registry); #endif
diff --git a/chrome/browser/profile_resetter/brandcoded_default_settings.cc b/chrome/browser/profile_resetter/brandcoded_default_settings.cc index 9ad5ded..bffc9de 100644 --- a/chrome/browser/profile_resetter/brandcoded_default_settings.cc +++ b/chrome/browser/profile_resetter/brandcoded_default_settings.cc
@@ -67,8 +67,7 @@ base::DictionaryValue* extensions = NULL; if (master_dictionary_ && master_dictionary_->GetDictionary( - installer::master_preferences::kExtensionsBlock, - &extensions)) { + installer::initial_preferences::kExtensionsBlock, &extensions)) { for (base::DictionaryValue::Iterator extension_id(*extensions); !extension_id.IsAtEnd(); extension_id.Advance()) { if (crx_file::id_util::IdIsValid(extension_id.key()))
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn index 2de2d11..db837b4 100644 --- a/chrome/browser/resources/BUILD.gn +++ b/chrome/browser/resources/BUILD.gn
@@ -111,19 +111,20 @@ grit_flags = [ "-E", "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir), + "-E", + "root_src_dir=" + rebase_path("//", root_build_dir), ] - if (optimize_webui) { - source = "bookmarks/bookmarks_resources_vulcanized.grd" - - deps = [ "//chrome/browser/resources/bookmarks:build" ] - } else { - source = "bookmarks/bookmarks_resources.grd" - - deps = [ "//chrome/browser/resources/bookmarks:web_components" ] - } - defines = chrome_grit_defines + + # These arguments are needed since the grd is generated at build time. + enable_input_discovery_for_gn_analyze = false + defines += [ "SHARED_INTERMEDIATE_DIR=" + + rebase_path(root_gen_dir, root_build_dir) ] + bookmarks_gen_dir = "$root_gen_dir/chrome/browser/resources/bookmarks" + source = "$bookmarks_gen_dir/bookmarks_resources.grd" + deps = [ "//chrome/browser/resources/bookmarks:build_grd" ] + outputs = [ "grit/bookmarks_resources.h", "grit/bookmarks_resources_map.cc",
diff --git a/chrome/browser/resources/bookmarks/BUILD.gn b/chrome/browser/resources/bookmarks/BUILD.gn index 7552c8be..200e3089 100644 --- a/chrome/browser/resources/bookmarks/BUILD.gn +++ b/chrome/browser/resources/bookmarks/BUILD.gn
@@ -6,16 +6,22 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/grit/preprocess_grit.gni") import("//tools/polymer/html_to_js.gni") +import("//ui/webui/resources/tools/generate_grd.gni") import("../optimize_webui.gni") +preprocess_folder = "preprocessed" +preprocess_manifest = "preprocessed_manifest.json" +preprocess_gen_manifest = "preprocessed_gen_manifest.json" + if (optimize_webui) { - preprocess_folder = "preprocessed" + build_manifest = "build_manifest.json" optimize_webui("build") { host = "bookmarks" input = rebase_path("$target_gen_dir/$preprocess_folder", root_build_dir) js_out_files = [ "bookmarks.rollup.js" ] js_module_in_files = [ "bookmarks.js" ] + out_manifest = "$target_gen_dir/$build_manifest" deps = [ ":preprocess", @@ -24,45 +30,67 @@ ] excludes = [ "chrome://resources/js/cr.m.js" ] } +} - preprocess_grit("preprocess") { - in_folder = "./" - out_folder = "$target_gen_dir/$preprocess_folder" - in_files = [ - "actions.js", - "api_listener.js", - "bookmarks.js", - "browser_proxy.js", - "constants.js", - "debouncer.js", - "dialog_focus_manager.js", - "dnd_manager.js", - "mouse_focus_behavior.js", - "reducers.js", - "store_client.js", - "store.js", - "types.js", - "util.js", +generate_grd("build_grd") { + input_files = [ "bookmarks.html" ] + input_files_base_dir = rebase_path(".", "//") + if (optimize_webui) { + deps = [ ":build" ] + manifest_files = [ "$target_gen_dir/$build_manifest" ] + } else { + deps = [ + ":preprocess", + ":preprocess_generated", + ] + manifest_files = [ + "$target_gen_dir/$preprocess_manifest", + "$target_gen_dir/$preprocess_gen_manifest", ] } + grd_prefix = "bookmarks" + out_grd = "$target_gen_dir/${grd_prefix}_resources.grd" +} - preprocess_grit("preprocess_generated") { - deps = [ ":web_components" ] - in_folder = target_gen_dir - out_folder = "$target_gen_dir/$preprocess_folder" - in_files = [ - "app.js", - "command_manager.js", - "edit_dialog.js", - "folder_node.js", - "item.js", - "list.js", - "router.js", - "shared_style.js", - "shared_vars.js", - "toolbar.js", - ] - } +preprocess_grit("preprocess") { + in_folder = "./" + out_folder = "$target_gen_dir/$preprocess_folder" + out_manifest = "$target_gen_dir/$preprocess_manifest" + in_files = [ + "actions.js", + "api_listener.js", + "bookmarks.js", + "browser_proxy.js", + "constants.js", + "debouncer.js", + "dialog_focus_manager.js", + "dnd_manager.js", + "mouse_focus_behavior.js", + "reducers.js", + "store_client.js", + "store.js", + "types.js", + "util.js", + ] +} + +preprocess_grit("preprocess_generated") { + deps = [ ":web_components" ] + in_folder = target_gen_dir + out_folder = "$target_gen_dir/$preprocess_folder" + out_manifest = "$target_gen_dir/$preprocess_gen_manifest" + in_files = [ + "app.js", + "command_manager.js", + "edit_dialog.js", + "folder_node.js", + "item.js", + "list.js", + "router.js", + "shared_style.js", + "shared_vars.js", + "toolbar.js", + ] } html_to_js("web_components") {
diff --git a/chrome/browser/resources/bookmarks/bookmarks_resources.grd b/chrome/browser/resources/bookmarks/bookmarks_resources.grd deleted file mode 100644 index 49e6c95..0000000 --- a/chrome/browser/resources/bookmarks/bookmarks_resources.grd +++ /dev/null
@@ -1,94 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<grit latest_public_release="0" current_release="1" output_all_resource_defines="false"> - <outputs> - <output filename="grit/bookmarks_resources.h" type="rc_header"> - <emit emit_type='prepend'></emit> - </output> - <output filename="grit/bookmarks_resources_map.cc" - type="resource_file_map_source" /> - <output filename="grit/bookmarks_resources_map.h" - type="resource_map_header" /> - <output filename="bookmarks_resources.pak" type="data_package" /> - </outputs> - <release seq="1"> - <includes> - <include name="IDR_BOOKMARKS_APP_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/app.js" - use_base_dir="false" type="BINDATA" preprocess="true" /> - <include name="IDR_BOOKMARKS_COMMAND_MANAGER_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/command_manager.js" - use_base_dir="false" type="BINDATA" /> - <include name="IDR_BOOKMARKS_EDIT_DIALOG_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/edit_dialog.js" - use_base_dir="false" type="BINDATA" /> - <include name="IDR_BOOKMARKS_FOLDER_NODE_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/folder_node.js" - use_base_dir="false" type="BINDATA" /> - <include name="IDR_BOOKMARKS_ITEM_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/item.js" - use_base_dir="false" type="BINDATA" preprocess="true" /> - <include name="IDR_BOOKMARKS_LIST_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/list.js" - use_base_dir="false" type="BINDATA" /> - <include name="IDR_BOOKMARKS_ROUTER_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/router.js" - use_base_dir="false" type="BINDATA" /> - <include name="IDR_BOOKMARKS_SHARED_STYLE_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/shared_style.js" - use_base_dir="false" type="BINDATA" preprocess="true" /> - <include name="IDR_BOOKMARKS_SHARED_VARS_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/shared_vars.js" - use_base_dir="false" type="BINDATA" /> - <include name="IDR_BOOKMARKS_TOOLBAR_JS" - file="${root_gen_dir}/chrome/browser/resources/bookmarks/toolbar.js" - use_base_dir="false" type="BINDATA" /> - </includes> - <structures> - <structure name="IDR_BOOKMARKS_ACTIONS_JS" - file="actions.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_API_LISTENER_JS" - file="api_listener.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_BOOKMARKS_HTML" - file="bookmarks.html" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_BOOKMARKS_JS" - file="bookmarks.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_BROWSER_PROXY_JS" - file="browser_proxy.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_CONSTANTS_JS" - file="constants.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_DEBOUNCER_JS" - file="debouncer.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_DIALOG_FOCUS_MANAGER_JS" - file="dialog_focus_manager.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_DND_MANAGER_JS" - file="dnd_manager.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_MOUSE_FOCUS_BEHAVIOR_JS" - file="mouse_focus_behavior.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_REDUCERS_JS" - file="reducers.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_STORE_CLIENT_JS" - file="store_client.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_STORE_JS" - file="store.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_TYPES_JS" - file="types.js" - type="chrome_html" /> - <structure name="IDR_BOOKMARKS_UTIL_JS" - file="util.js" - type="chrome_html" /> - </structures> - </release> -</grit>
diff --git a/chrome/browser/resources/bookmarks/bookmarks_resources_vulcanized.grd b/chrome/browser/resources/bookmarks/bookmarks_resources_vulcanized.grd deleted file mode 100644 index 28c9308..0000000 --- a/chrome/browser/resources/bookmarks/bookmarks_resources_vulcanized.grd +++ /dev/null
@@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<grit latest_public_release="0" current_release="1" output_all_resource_defines="false"> - <outputs> - <output filename="grit/bookmarks_resources.h" type="rc_header"> - <emit emit_type='prepend'></emit> - </output> - <output filename="grit/bookmarks_resources_map.cc" - type="resource_map_source" /> - <output filename="grit/bookmarks_resources_map.h" - type="resource_map_header" /> - <output filename="bookmarks_resources.pak" type="data_package" /> - </outputs> - <release seq="1"> - <includes> - <include name="IDR_BOOKMARKS_BOOKMARKS_HTML" - file="bookmarks.html" - type="chrome_html" /> - <include name="IDR_BOOKMARKS_BOOKMARKS_ROLLUP_JS" - file="${root_gen_dir}\chrome\browser\resources\bookmarks\bookmarks.rollup.js" - use_base_dir="false" - type="chrome_html" /> - </includes> - </release> -</grit>
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tabs_api_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tabs_api_handler.js index 8a8ebe3f..fe8e456 100644 --- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/tabs_api_handler.js +++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/tabs_api_handler.js
@@ -54,6 +54,10 @@ * @param {Object} tab */ onCreated(tab) { + if (!tab.highlighted) { + return; + } + if (TabsApiHandler.shouldOutputSpeechAndBraille) { ChromeVox.tts.speak( this.msg_('chrome_tab_created'), QueueMode.FLUSH,
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js index badcf00..d9596922 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
@@ -84,6 +84,16 @@ return; } + this.setAttribute('aria-label', this.dataItem.ariaLabel); + this.tabIndex = 0; + this.addEventListener('keypress', e => { + if (e.keyCode == 13) + this.parentNode.selectedItem = this.dataItem; + }); + this.addEventListener('mousedown', e => { + e.preventDefault(); + }); + if (this.thumbnail_) { this.appendChild(this.thumbnail_); this.callback_(this.dataModelId_, this.dataItem.wallpaperId); @@ -94,15 +104,6 @@ // Do not show the image until |cropImageToFitGrid_| is done. imageEl.style.visibility = 'hidden'; imageEl.setAttribute('aria-hidden', 'true'); - this.setAttribute('aria-label', this.dataItem.ariaLabel); - this.tabIndex = 0; - this.addEventListener('keypress', e => { - if (e.keyCode == 13) - this.parentNode.selectedItem = this.dataItem; - }); - this.addEventListener('mousedown', e => { - e.preventDefault(); - }); imageEl.classList.add('thumbnail'); cr.defineProperty(imageEl, 'offline', cr.PropertyKind.BOOL_ATTR);
diff --git a/chrome/browser/resources/feedback/css/feedback.css b/chrome/browser/resources/feedback/css/feedback.css index b8c20b9..8c48895 100644 --- a/chrome/browser/resources/feedback/css/feedback.css +++ b/chrome/browser/resources/feedback/css/feedback.css
@@ -97,6 +97,11 @@ margin-inline-end: 9px; } +.content .description-empty-notification { + color: rgb(204, 0, 0); + font-weight: bold; +} + .content .checkbox-field-container { -webkit-align-items: center; display: -webkit-flex;
diff --git a/chrome/browser/resources/feedback/html/default.html b/chrome/browser/resources/feedback/html/default.html index e25e8a7..9c7fc73 100644 --- a/chrome/browser/resources/feedback/html/default.html +++ b/chrome/browser/resources/feedback/html/default.html
@@ -32,6 +32,8 @@ <div id="content-pane" class="content"> <p id="free-form-text" i18n-content="freeFormText"></p> <textarea id="description-text" aria-labelledby="free-form-text"></textarea> + <div id="description-empty-error" class="description-empty-notification" + role="alert" i18n-content="noDescription" hidden></div> <div> <p id="additional-info-label" i18n-content="additionalInfo"><p> </div>
diff --git a/chrome/browser/resources/feedback/js/feedback.js b/chrome/browser/resources/feedback/js/feedback.js index 4479017..0d625b73 100644 --- a/chrome/browser/resources/feedback/js/feedback.js +++ b/chrome/browser/resources/feedback/js/feedback.js
@@ -189,9 +189,18 @@ */ function sendReport() { if ($('description-text').value.length == 0) { + // Don't need to re-hide this or reset the aria label in the non-empty case + // because the report will always be sent if we get past this if statement. + $('description-empty-error').hidden = false; + + // Return focus to the textarea but first change its aria-labelledby so that + // the screen reader reads the error first when describing it. const description = $('description-text'); - description.placeholder = loadTimeData.getString('noDescription'); + description.setAttribute('aria-labelledby', 'description-empty-error'); description.focus(); + + // We added a line of text, so make sure the app window is big enough. + resizeAppWindow(); return false; }
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index 0149def..02c5f089 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -196,6 +196,7 @@ ":os_page_visibility", ":os_route", ":os_settings_routes", + ":pref_to_setting_metric_converter", ":route_origin_behavior", ":search_handler", "ambient_mode_page:closure_compile", @@ -267,6 +268,10 @@ ] } +js_library("pref_to_setting_metric_converter") { + deps = [ "//chrome/browser/ui/webui/settings/chromeos/constants:mojom_js_library_for_compile" ] +} + js_library("route_origin_behavior") { deps = [ ":os_route", @@ -343,6 +348,7 @@ # ":os_settings.m", # ":os_settings_icons_css.m", ":os_settings_routes.m", + ":pref_to_setting_metric_converter.m", ":route_origin_behavior.m", #":search_handler.m", @@ -411,6 +417,12 @@ extra_deps = [ ":modulize" ] } +js_library("pref_to_setting_metric_converter.m") { + sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/pref_to_setting_metric_converter.m.js" ] + deps = [ "//chrome/browser/ui/webui/settings/chromeos/constants:mojom_js_library_for_compile" ] + extra_deps = [ ":modulize" ] +} + js_library("route_origin_behavior.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/route_origin_behavior.m.js" ] deps = [ @@ -497,13 +509,14 @@ js_modulizer("modulize") { input_files = [ + "deep_linking_behavior.js", "metrics_recorder.js", "os_settings_routes.js", "route_origin_behavior.js", "search_handler.js", "os_route.js", "os_page_visibility.js", - "deep_linking_behavior.js", + "pref_to_setting_metric_converter.js", ] namespace_rewrites = os_settings_namespace_rewrites }
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_page.js b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_page.js index 05d89d3c..852862c9 100644 --- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_page.js +++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_page.js
@@ -114,7 +114,7 @@ this.onPageContentDataChanged_.bind(this)); this.browserProxy_.getPageContentData().then( - this.onPageContentDataChanged_.bind(this)); + this.onInitialPageContentDataFetched_.bind(this)); }, /** @@ -437,6 +437,25 @@ * @param {!settings.MultiDevicePageContentData} newData * @private */ + onInitialPageContentDataFetched_(newData) { + this.onPageContentDataChanged_(newData); + + if (this.pageContentData.isNotificationAccessGranted) { + return; + } + + // Show the notification access dialog if the url contains the correct + // param. + const urlParams = settings.Router.getInstance().getQueryParameters(); + if (urlParams.get('showNotificationAccessSetupDialog') !== null) { + this.showNotificationAccessSetupDialog_ = true; + } + }, + + /** + * @param {!settings.MultiDevicePageContentData} newData + * @private + */ onPageContentDataChanged_(newData) { this.pageContentData = newData; this.leaveNestedPageIfNoHostIsSet_();
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.html b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.html index 7909ff7a..d43da74 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.html +++ b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.html
@@ -65,6 +65,18 @@ localized-string="[[eolMessageWithMonthAndYear]]"> </settings-localized-link> </div> + <template is="dom-if" if="[[isHostnameSettingEnabled_]]"> + <div class="settings-box two-line"> + <div class="start"> + <div role="heading">$i18n{aboutDeviceName}</div> + <div aria-hidden="true" class="secondary"> + ChromeOS-102938 + </div> + </div> + <cr-icon-button class="icon-edit"> + </cr-icon-button> + </div> + </template> <div id="buildDetailsLinkContainer" class="settings-box"> <div class="start" id="aboutBuildDetailsTitle"> $i18n{aboutBuildDetailsTitle}
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.js b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.js index 6226383..91364439 100644 --- a/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.js +++ b/chrome/browser/resources/settings/chromeos/os_about_page/detailed_build_info.js
@@ -48,6 +48,15 @@ chromeos.settings.mojom.Setting.kCopyDetailedBuildInfo, ]), }, + + /** @private */ + isHostnameSettingEnabled_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('isHostnameSettingEnabled'); + }, + readOnly: true, + }, }, /** @override */
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp index 044b62e..9080e5e7 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp +++ b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
@@ -623,6 +623,11 @@ file="page_visibility.js" preprocess="true" compress="false" type="BINDATA" /> + <include name="IDR_OS_SETTINGS_PREF_TO_SETTING_METRIC_CONVERTER_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/pref_to_setting_metric_converter.m.js" + use_base_dir="false" + compress="false" + type="BINDATA" /> <include name="IDR_OS_SETTINGS_MULTIDEVICE_PAGE_M_JS" file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_page.m.js" use_base_dir="false"
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_settings_ui/BUILD.gn index 5a3dde0c..54b8e6d 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_ui/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/BUILD.gn
@@ -13,6 +13,7 @@ "..:metrics_recorder", "..:os_page_visibility", "..:os_route", + "..:pref_to_setting_metric_converter", "../..:global_scroll_target_behavior", "../..:router", "../../prefs",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html index 45b5fbfa..b79cb58 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html
@@ -16,10 +16,13 @@ <link rel="import" href="../../i18n_setup.html"> <link rel="import" href="../../settings_shared_css.html"> <link rel="import" href="../os_page_visibility.html"> +<link rel="import" href="../pref_to_setting_metric_converter.html"> <link rel="import" href="../../prefs/prefs.html"> <link rel="import" href="../os_route.html"> <link rel="import" href="../../router.html"> <link rel="import" href="../../settings_vars_css.html"> +<script src="chrome://os-settings/constants/setting.mojom-lite.js"></script> +<script src="chrome://os-settings/search/user_action_recorder.mojom-lite.js"></script> <dom-module id="os-settings-ui"> <template>
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js index 2676d3f..ace4f90 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js +++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.js
@@ -125,9 +125,16 @@ */ activeRoute_: null, + /** + * Converts prefs to settings metrics to help record pref changes. + * @private {PrefToSettingMetricConverter} + */ + prefToSettingMetricConverter_: null, + /** @override */ created() { settings.Router.getInstance().initializeRouteFromUrl(); + this.prefToSettingMetricConverter_ = new PrefToSettingMetricConverter(); }, /** @@ -350,10 +357,26 @@ }, /** + * @param {!CustomEvent<!{prefKey: string, prefValue: *}>} e * @private */ - onSettingChange_() { - settings.recordSettingChange(); + onSettingChange_(e) { + const {prefKey, prefValue} = e.detail; + const settingMetric = + this.prefToSettingMetricConverter_.convertPrefToSettingMetric( + prefKey, prefValue); + + // New metrics for this setting pref have not yet been implemented. + if (!settingMetric) { + settings.recordSettingChange(); + return; + } + + const setting = /** @type {!chromeos.settings.mojom.Setting} */ ( + settingMetric.setting); + const value = /** @type {!chromeos.settings.mojom.SettingChangeValue} */ ( + settingMetric.value); + settings.recordSettingChange(setting, value); }, /**
diff --git a/chrome/browser/resources/settings/chromeos/pref_to_setting_metric_converter.html b/chrome/browser/resources/settings/chromeos/pref_to_setting_metric_converter.html new file mode 100644 index 0000000..c01b23f --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/pref_to_setting_metric_converter.html
@@ -0,0 +1,3 @@ +<script src="chrome://os-settings/constants/setting.mojom-lite.js"></script> +<script src="chrome://os-settings/search/user_action_recorder.mojom-lite.js"></script> +<script src="pref_to_setting_metric_converter.js"></script> \ No newline at end of file
diff --git a/chrome/browser/resources/settings/chromeos/pref_to_setting_metric_converter.js b/chrome/browser/resources/settings/chromeos/pref_to_setting_metric_converter.js new file mode 100644 index 0000000..9de73272 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/pref_to_setting_metric_converter.js
@@ -0,0 +1,38 @@ +/* Copyright 2020 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ + +/** + * @fileoverview Helper class for converting a given settings pref to a pair of + * setting ID and setting change value. Used to record metrics about changes + * to pref-based settings. + */ + +// clang-format off +// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js' +// #import '../constants/setting.mojom-lite.js'; +// #import '../search/user_action_recorder.mojom-lite.js'; +// clang-format on + +/* export */ class PrefToSettingMetricConverter { + /** + * @param {string} prefKey + * @param {*} prefValue + * @return {?{setting: !chromeos.settings.mojom.Setting, value: + * !chromeos.settings.mojom.SettingChangeValue}} + */ + convertPrefToSettingMetric(prefKey, prefValue) { + switch (prefKey) { + // device_page/keyboard.js + case 'settings.language.send_function_keys': + return { + setting: chromeos.settings.mojom.Setting.kKeyboardFunctionKeys, + value: {boolValue: /** @type {boolean} */ (prefValue)} + }; + + // pref to setting metric not implemented. + default: + return null; + } + } +}
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd index 6a682ea..62921a83 100644 --- a/chrome/browser/resources/settings/os_settings_resources.grd +++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -985,6 +985,12 @@ <structure name="IDR_OS_SETTINGS_OS_PAGE_VISIBILITY_JS" file="chromeos/os_page_visibility.js" compress="false" type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_PREF_TO_SETTING_METRIC_CONVERTER_HTML" + file="chromeos/pref_to_setting_metric_converter.html" + compress="false" type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_PREF_TO_SETTING_METRIC_CONVERTER_JS" + file="chromeos/pref_to_setting_metric_converter.js" + compress="false" type="chrome_html" /> <!-- TODO(jamescook): Remove after sync settings is forked. --> <structure name="IDR_OS_SETTINGS_PERSONALIZATION_OPTIONS_HTML" file="privacy_page/personalization_options.html"
diff --git a/chrome/browser/resources/settings/prefs/prefs.js b/chrome/browser/resources/settings/prefs/prefs.js index 0054068..0748061 100644 --- a/chrome/browser/resources/settings/prefs/prefs.js +++ b/chrome/browser/resources/settings/prefs/prefs.js
@@ -213,7 +213,9 @@ // settingsPrivate.setPref and potentially trigger an IPC loop.) if (!deepEqual(prefStoreValue, prefObj.value)) { // <if expr="chromeos"> - this.fire('user-action-setting-change'); + this.fire( + 'user-action-setting-change', + {prefKey: key, prefValue: prefObj.value}); // </if> this.settingsApi_.setPref(
diff --git a/chrome/browser/resources/video_tutorials/video_player.js b/chrome/browser/resources/video_tutorials/video_player.js index 01cd9dd..07d019c 100644 --- a/chrome/browser/resources/video_tutorials/video_player.js +++ b/chrome/browser/resources/video_tutorials/video_player.js
@@ -15,7 +15,7 @@ function onVideoEnded() { // Resize the poster. - video.style.classList.add('video-ended'); + video.classList.add('video-ended'); video.controls = false; }
diff --git a/chrome/browser/safe_browsing/android/BUILD.gn b/chrome/browser/safe_browsing/android/BUILD.gn index 7a34ed4..a8a16a3 100644 --- a/chrome/browser/safe_browsing/android/BUILD.gn +++ b/chrome/browser/safe_browsing/android/BUILD.gn
@@ -46,10 +46,12 @@ "//components/prefs/android:java", "//components/user_prefs/android:java", "//third_party/android_deps:androidx_annotation_annotation_java", + "//third_party/android_deps:androidx_core_core_java", "//third_party/android_deps:androidx_fragment_fragment_java", "//third_party/android_deps:androidx_preference_preference_java", "//third_party/android_deps:androidx_vectordrawable_vectordrawable_java", "//ui/android:ui_full_java", + "//ui/android:ui_no_recycler_view_java", ] annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] srcjar_deps = [ ":safe_browsing_enums" ]
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/RadioButtonGroupSafeBrowsingPreference.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/RadioButtonGroupSafeBrowsingPreference.java index f71d9b8..2157733 100644 --- a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/RadioButtonGroupSafeBrowsingPreference.java +++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/RadioButtonGroupSafeBrowsingPreference.java
@@ -11,10 +11,12 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.core.content.ContextCompat; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; import org.chromium.chrome.browser.safe_browsing.SafeBrowsingState; +import org.chromium.chrome.browser.safe_browsing.metrics.SettingsAccessPoint; import org.chromium.components.browser_ui.settings.ManagedPreferenceDelegate; import org.chromium.components.browser_ui.settings.ManagedPreferencesUtils; import org.chromium.components.browser_ui.widget.RadioButtonWithDescription; @@ -53,6 +55,7 @@ private RadioButtonWithDescription mNoProtection; private @SafeBrowsingState int mSafeBrowsingState; private boolean mIsEnhancedProtectionEnabled; + private @SettingsAccessPoint int mAccessPoint; private OnSafeBrowsingModeDetailsRequested mSafeBrowsingModeDetailsRequestedListener; private ManagedPreferenceDelegate mManagedPrefDelegate; @@ -65,11 +68,13 @@ * Set Safe Browsing state and Enhanced Protection state. Called before onBindViewHolder. * @param safeBrowsingState The current Safe Browsing state. * @param isEnhancedProtectionEnabled Whether to show the Enhanced Protection button. + * @param accessPoint Where this preference was triggered to be created. */ - public void init( - @SafeBrowsingState int safeBrowsingState, boolean isEnhancedProtectionEnabled) { + public void init(@SafeBrowsingState int safeBrowsingState, boolean isEnhancedProtectionEnabled, + @SettingsAccessPoint int accessPoint) { mSafeBrowsingState = safeBrowsingState; mIsEnhancedProtectionEnabled = isEnhancedProtectionEnabled; + mAccessPoint = accessPoint; assert ((mSafeBrowsingState != SafeBrowsingState.ENHANCED_PROTECTION) || mIsEnhancedProtectionEnabled) : "Safe Browsing state shouldn't be enhanced protection when the flag is disabled."; @@ -95,6 +100,10 @@ if (mIsEnhancedProtectionEnabled) { mEnhancedProtection = (RadioButtonWithDescriptionAndAuxButton) holder.findViewById( R.id.enhanced_protection); + if (mAccessPoint == SettingsAccessPoint.SURFACE_EXPLORER_PROMO_SLINGER) { + mEnhancedProtection.setBackgroundColor(ContextCompat.getColor( + getContext(), R.color.preference_highlighted_bg_color)); + } mEnhancedProtection.setVisibility(View.VISIBLE); mEnhancedProtection.setAuxButtonClickedListener(this); }
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/SafeBrowsingSettingsFragment.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/SafeBrowsingSettingsFragment.java index 5a213fb..3bf4e9c 100644 --- a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/SafeBrowsingSettingsFragment.java +++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/SafeBrowsingSettingsFragment.java
@@ -83,7 +83,8 @@ mSafeBrowsingPreference = findPreference(PREF_SAFE_BROWSING); mSafeBrowsingPreference.init(SafeBrowsingBridge.getSafeBrowsingState(), ChromeFeatureList.isEnabled( - ChromeFeatureList.SAFE_BROWSING_ENHANCED_PROTECTION_ENABLED)); + ChromeFeatureList.SAFE_BROWSING_ENHANCED_PROTECTION_ENABLED), + mAccessPoint); mSafeBrowsingPreference.setSafeBrowsingModeDetailsRequestedListener(this); mSafeBrowsingPreference.setManagedPreferenceDelegate(managedPreferenceDelegate); mSafeBrowsingPreference.setOnPreferenceChangeListener(this);
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index c940747..6880af4 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -1068,7 +1068,7 @@ const tab_groups::TabGroupVisualData group1_data = *tsm->group_model()->GetTabGroup(group1)->visual_data(); const tab_groups::TabGroupVisualData group2_data( - base::ASCIIToUTF16("Foo"), tab_groups::TabGroupColorId::kBlue); + base::ASCIIToUTF16("Foo"), tab_groups::TabGroupColorId::kBlue, true); tsm->group_model()->GetTabGroup(group2)->SetVisualData(group2_data); Browser* const new_browser = QuitBrowserAndRestore(browser(), 5); @@ -1080,10 +1080,13 @@ new_tsm->group_model()->GetTabGroup(group1)->visual_data(); const tab_groups::TabGroupVisualData* const group2_restored_data = new_tsm->group_model()->GetTabGroup(group2)->visual_data(); + EXPECT_EQ(group1_data.title(), group1_restored_data->title()); EXPECT_EQ(group1_data.color(), group1_restored_data->color()); + EXPECT_EQ(group1_data.is_collapsed(), group1_restored_data->is_collapsed()); EXPECT_EQ(group2_data.title(), group2_restored_data->title()); EXPECT_EQ(group2_data.color(), group2_restored_data->color()); + EXPECT_EQ(group2_data.is_collapsed(), group2_restored_data->is_collapsed()); } INSTANTIATE_TEST_SUITE_P(WithAndWithoutReset,
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc index 582654c..887452b 100644 --- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc +++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
@@ -161,7 +161,14 @@ { base::ScopedBlockingCall scoped_blocking_call( FROM_HERE, base::BlockingType::MAY_BLOCK); - base::CopyFile(path, path.AddExtension(BACKUP_EXTENSION)); + base::FilePath backup_path = path.AddExtension(BACKUP_EXTENSION); + if (!custom_words.empty()) { + base::CopyFile(path, backup_path); + } else { + // The wordlist was just cleared, clean up the .backup file for privacy + // reasons. + base::DeleteFile(backup_path); + } base::ImportantFileWriter::WriteFileAtomically(path, content.str()); } } @@ -211,6 +218,10 @@ to_remove_.insert(word); } +void SpellcheckCustomDictionary::Change::Clear() { + clear_ = true; +} + int SpellcheckCustomDictionary::Change::Sanitize( const std::set<std::string>& words) { int result = VALID_CHANGE; @@ -265,6 +276,14 @@ return base::Contains(words_, word); } +void SpellcheckCustomDictionary::Clear() { + std::unique_ptr<Change> dictionary_change(new Change); + dictionary_change->Clear(); + Apply(*dictionary_change); + Notify(*dictionary_change); + Save(std::move(dictionary_change)); +} + void SpellcheckCustomDictionary::AddObserver(Observer* observer) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(observer); @@ -424,6 +443,10 @@ std::unique_ptr<LoadFileResult> result = LoadDictionaryFileReliably(path); + // Clear. + if (dictionary_change->clear()) + result->words.clear(); + // Add words. result->words.insert(dictionary_change->to_add().begin(), dictionary_change->to_add().end()); @@ -460,6 +483,8 @@ void SpellcheckCustomDictionary::Apply(const Change& dictionary_change) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (dictionary_change.clear()) + words_.clear(); if (!dictionary_change.to_add().empty()) { words_.insert(dictionary_change.to_add().begin(), dictionary_change.to_add().end());
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.h b/chrome/browser/spellchecker/spellcheck_custom_dictionary.h index 445ab77..17f726f 100644 --- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.h +++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.h
@@ -57,6 +57,10 @@ // Removes |word| in this change. void RemoveWord(const std::string& word); + // Clear the whole dictionary before doing other operations. When saved, + // also deletes the backup file. + void Clear(); + // Prepares this change to be applied to |words| by removing duplicate and // invalid words from words to be added and removing missing words from // words to be removed. Returns a bitmap of |ChangeSanitationResult| values. @@ -70,8 +74,13 @@ return to_remove_; } + // Returns true if the dictionary should be cleared first. + bool clear() const { return clear_; } + // Returns true if there are no changes to be made. Otherwise returns false. - bool empty() const { return to_add_.empty() && to_remove_.empty(); } + bool empty() const { + return !clear_ && to_add_.empty() && to_remove_.empty(); + } private: // The words to be added. @@ -80,6 +89,9 @@ // The words to be removed. std::set<std::string> to_remove_; + // Whether to clear everything before adding words. + bool clear_ = false; + DISALLOW_COPY_AND_ASSIGN(Change); }; @@ -130,6 +142,9 @@ // Returns true if the dictionary contains |word|. Otherwise returns false. bool HasWord(const std::string& word) const; + // Removes all words in the dictionary, and schedules a write to disk. + void Clear(); + // Adds |observer| to be notified of dictionary events and changes. void AddObserver(Observer* observer); @@ -162,6 +177,9 @@ friend class DictionarySyncIntegrationTestHelper; friend class SpellcheckCustomDictionaryTest; + FRIEND_TEST_ALL_PREFIXES(ChromeBrowsingDataRemoverDelegateTest, + WipeCustomDictionaryData); + // Returns the list of words in the custom spellcheck dictionary at |path|. // Validates that the custom dictionary file does not have duplicates and // contains only valid words. Must be called on the FILE thread.
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc index 2dd5348..d927008 100644 --- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc +++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -606,9 +606,12 @@ } std::string ProfileSyncServiceHarness::GetServiceStatus() { + // This method is only used in test code for debugging purposes, so it's fine + // to include sensitive data in ConstructAboutInformation(). std::unique_ptr<base::DictionaryValue> value( - syncer::sync_ui_util::ConstructAboutInformation(service(), - chrome::GetChannel())); + syncer::sync_ui_util::ConstructAboutInformation( + syncer::sync_ui_util::IncludeSensitiveData(true), service(), + chrome::GetChannel())); std::string service_status; base::JSONWriter::WriteWithOptions( *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &service_status);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index cc51e2b..16ad388 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -2658,6 +2658,7 @@ "//chromeos/strings", "//chromeos/system", "//chromeos/ui/base", + "//chromeos/ui/frame", "//chromeos/ui/vector_icons", "//components/arc", "//components/assist_ranker",
diff --git a/chrome/browser/ui/ash/system_tray_client_browsertest.cc b/chrome/browser/ui/ash/system_tray_client_browsertest.cc index 2569dd59..2101442 100644 --- a/chrome/browser/ui/ash/system_tray_client_browsertest.cc +++ b/chrome/browser/ui/ash/system_tray_client_browsertest.cc
@@ -8,8 +8,10 @@ #include "ash/public/cpp/ash_view_ids.h" #include "ash/public/cpp/login_screen_test_api.h" #include "ash/public/cpp/system_tray_test_api.h" +#include "base/i18n/time_formatting.h" #include "chrome/browser/chromeos/login/lock/screen_locker_tester.h" #include "chrome/browser/chromeos/login/login_manager_test.h" +#include "chrome/browser/chromeos/login/test/local_state_mixin.h" #include "chrome/browser/chromeos/login/test/login_manager_mixin.h" #include "chrome/browser/chromeos/login/ui/user_adding_screen.h" #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" @@ -22,6 +24,7 @@ #include "chromeos/strings/grit/chromeos_strings.h" #include "components/account_id/account_id.h" #include "components/prefs/pref_service.h" +#include "components/user_manager/known_user.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" @@ -147,3 +150,36 @@ EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(account_id2_)); EXPECT_FALSE(tray_test_api->Is24HourClock()); } + +class SystemTrayClientClockUnknownPrefTest + : public SystemTrayClientClockTest, + public chromeos::LocalStateMixin::Delegate { + public: + // chromeos::localStateMixin::Delegate: + void SetUpLocalState() override { + // Set preference for the first user only. + user_manager::known_user::SetBooleanPref(account_id1_, + ::prefs::kUse24HourClock, true); + + ASSERT_FALSE(user_manager::known_user::GetBooleanPref( + account_id2_, ::prefs::kUse24HourClock, nullptr)); + } + + protected: + chromeos::LocalStateMixin local_state_{&mixin_host_, this}; +}; + +IN_PROC_BROWSER_TEST_F(SystemTrayClientClockUnknownPrefTest, SwitchToDefault) { + // Check default value. + ASSERT_EQ(base::GetHourClockType(), base::k12HourClock); + + auto tray_test_api = ash::SystemTrayTestApi::Create(); + // Check user with the set preference. + EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(account_id1_)); + EXPECT_TRUE(tray_test_api->Is24HourClock()); + + // Should get back to the default 12 hours because there is not preference for + // the second user. + EXPECT_TRUE(ash::LoginScreenTestApi::FocusUser(account_id2_)); + EXPECT_FALSE(tray_test_api->Is24HourClock()); +}
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc index e2230f76..0aad1304 100644 --- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc +++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
@@ -575,9 +575,6 @@ } UpdateSaveCardIcon(); - - if (observer_for_testing_) - observer_for_testing_->OnBubbleClosed(); } const LegalMessageLines& SaveCardBubbleControllerImpl::GetLegalMessageLines() @@ -866,6 +863,9 @@ case BubbleType::INACTIVE: NOTREACHED(); } + + if (observer_for_testing_) + observer_for_testing_->OnIconShown(); } void SaveCardBubbleControllerImpl::UpdateSaveCardIcon() {
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h index e1054db..a792278 100644 --- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h +++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h
@@ -39,7 +39,7 @@ class ObserverForTest { public: virtual void OnBubbleShown() = 0; - virtual void OnBubbleClosed() = 0; + virtual void OnIconShown() = 0; }; ~SaveCardBubbleControllerImpl() override;
diff --git a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc index f0c7abc..ae993f5 100644 --- a/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc +++ b/chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.cc
@@ -15,8 +15,8 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "components/sync/base/client_tag_hash.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine/model_type_processor.h" -#include "components/sync/engine/non_blocking_sync_common.h" #include "components/sync/model/entity_data.h" #include "components/sync/model_impl/in_memory_metadata_change_list.h" #include "components/sync/protocol/session_specifics.pb.h"
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc index 72a7c817..8d09925 100644 --- a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc +++ b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
@@ -150,6 +150,7 @@ // Various events that can be waited on by the DialogEventWaiter. enum DialogEvent : int { OFFERED_LOCAL_SAVE, + OFFERED_UPLOAD_SAVE, REQUESTED_UPLOAD_SAVE, DYNAMIC_FORM_PARSED, RECEIVED_GET_UPLOAD_DETAILS_RESPONSE, @@ -158,7 +159,7 @@ SHOW_CARD_SAVED_FEEDBACK, STRIKE_CHANGE_COMPLETE, BUBBLE_SHOWN, - BUBBLE_CLOSED + ICON_SHOWN }; // SyncTest::SetUpOnMainThread: @@ -218,6 +219,7 @@ ->GetFormDataImporter() ->credit_card_save_manager_.get(); credit_card_save_manager_->SetEventObserverForTesting(this); + AddEventObserverToController(); // Set up this class as the ObserverForTest implementation. AutofillHandler* autofill_handler = @@ -245,6 +247,12 @@ } // CreditCardSaveManager::ObserverForTest: + void OnOfferUploadSave() override { + if (event_waiter_) + event_waiter_->OnEvent(DialogEvent::OFFERED_UPLOAD_SAVE); + } + + // CreditCardSaveManager::ObserverForTest: void OnDecideToRequestUploadSave() override { if (event_waiter_) event_waiter_->OnEvent(DialogEvent::REQUESTED_UPLOAD_SAVE); @@ -287,9 +295,9 @@ } // SaveCardBubbleControllerImpl::ObserverForTest: - void OnBubbleClosed() override { + void OnIconShown() override { if (event_waiter_) - event_waiter_->OnEvent(DialogEvent::BUBBLE_CLOSED); + event_waiter_->OnEvent(DialogEvent::ICON_SHOWN); } inline views::Combobox* month_input() { @@ -349,7 +357,8 @@ } void SubmitFormAndWaitForCardLocalSaveBubble() { - ResetEventWaiterForSequence({DialogEvent::OFFERED_LOCAL_SAVE}); + ResetEventWaiterForSequence( + {DialogEvent::OFFERED_LOCAL_SAVE, DialogEvent::BUBBLE_SHOWN}); SubmitForm(); WaitForObservedEvent(); WaitForAnimationToEnd(); @@ -362,7 +371,8 @@ SetUploadDetailsRpcPaymentsAccepts(); ResetEventWaiterForSequence( {DialogEvent::REQUESTED_UPLOAD_SAVE, - DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE}); + DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE, + DialogEvent::OFFERED_UPLOAD_SAVE, DialogEvent::BUBBLE_SHOWN}); SubmitForm(); WaitForObservedEvent(); WaitForAnimationToEnd(); @@ -674,15 +684,9 @@ return specified_view; } - void ClickOnCancelButton(bool strike_expected = false) { + void ClickOnCancelButton() { SaveCardBubbleViews* save_card_bubble_views = GetSaveCardBubbleViews(); DCHECK(save_card_bubble_views); - if (strike_expected) { - ResetEventWaiterForSequence( - {DialogEvent::STRIKE_CHANGE_COMPLETE, DialogEvent::BUBBLE_CLOSED}); - } else { - ResetEventWaiterForSequence({DialogEvent::BUBBLE_CLOSED}); - } ClickOnDialogViewWithIdAndWait(DialogViewId::CANCEL_BUTTON); DCHECK(!GetSaveCardBubbleViews()); } @@ -690,7 +694,6 @@ void ClickOnCloseButton() { SaveCardBubbleViews* save_card_bubble_views = GetSaveCardBubbleViews(); DCHECK(save_card_bubble_views); - ResetEventWaiterForSequence({DialogEvent::BUBBLE_CLOSED}); ClickOnDialogViewAndWait(save_card_bubble_views->GetBubbleFrameView() ->GetCloseButtonForTesting()); DCHECK(!GetSaveCardBubbleViews()); @@ -698,7 +701,7 @@ SaveCardBubbleViews* GetSaveCardBubbleViews() { SaveCardBubbleController* save_card_bubble_controller = - SaveCardBubbleController::GetOrCreate(GetActiveWebContents()); + SaveCardBubbleController::Get(GetActiveWebContents()); if (!save_card_bubble_controller) return nullptr; SaveCardBubbleView* save_card_bubble_view = @@ -728,15 +731,10 @@ void OpenSettingsFromManageCardsPrompt() { FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - - // Adding an event observer to the controller so we can wait for the bubble - // to show. - AddEventObserverToController(); ReduceAnimationTime(); #if !defined(OS_CHROMEOS) - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); #endif // Click [Save] should close the offer-to-save bubble and show "Card saved" @@ -764,7 +762,8 @@ void AddEventObserverToController() { SaveCardBubbleControllerImpl* save_card_bubble_controller_impl = - SaveCardBubbleControllerImpl::FromWebContents(GetActiveWebContents()); + static_cast<SaveCardBubbleControllerImpl*>( + SaveCardBubbleController::GetOrCreate(GetActiveWebContents())); DCHECK(save_card_bubble_controller_impl); save_card_bubble_controller_impl->SetEventObserverForTesting(this); } @@ -855,7 +854,9 @@ // Clicking [No thanks] should cancel and close it. base::HistogramTester histogram_tester; - ClickOnCancelButton(/*strike_expected=*/true); + ResetEventWaiterForSequence({DialogEvent::STRIKE_CHANGE_COMPLETE}); + ClickOnCancelButton(); + WaitForObservedEvent(); // UMA should have recorded bubble rejection. histogram_tester.ExpectUniqueSample( @@ -871,17 +872,13 @@ FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); ReduceAnimationTime(); - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); // Click [Save] should close the offer-to-save bubble // and pop up the sign-in promo. base::UserActionTester user_action_tester; - ClickOnDialogViewWithId(DialogViewId::OK_BUTTON); + ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON); WaitForObservedEvent(); // Sign-in promo should be showing and user actions should have recorded @@ -920,7 +917,7 @@ ResetEventWaiterForSequence( {DialogEvent::REQUESTED_UPLOAD_SAVE, DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE, - DialogEvent::OFFERED_LOCAL_SAVE}); + DialogEvent::OFFERED_LOCAL_SAVE, DialogEvent::BUBBLE_SHOWN}); FillForm(); SubmitForm(); WaitForObservedEvent(); @@ -947,17 +944,13 @@ FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); ReduceAnimationTime(); - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); // Click [Save] should close the offer-to-save bubble // and pop up the sign-in promo. base::UserActionTester user_action_tester; - ClickOnDialogViewWithId(DialogViewId::OK_BUTTON); + ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON); WaitForObservedEvent(); // User actions should have recorded impression. @@ -985,17 +978,13 @@ FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); ReduceAnimationTime(); - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); // Click [Save] should close the offer-to-save bubble // and pop up the sign-in promo. base::UserActionTester user_action_tester; - ClickOnDialogViewWithId(DialogViewId::OK_BUTTON); + ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON); WaitForObservedEvent(); // Click on [Sign in] button. @@ -1018,16 +1007,12 @@ views::test::AXEventCounter counter(views::AXEventManager::Get()); EXPECT_EQ(0, counter.GetCount(ax::mojom::Event::kAlert)); - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); ReduceAnimationTime(); - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); // Click [Save] should close the offer-to-save bubble // and pop up the sign-in promo. - ClickOnDialogViewWithId(DialogViewId::OK_BUTTON); + ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON); WaitForObservedEvent(); EXPECT_EQ(1, counter.GetCount(ax::mojom::Event::kAlert)); @@ -1217,7 +1202,7 @@ ResetEventWaiterForSequence( {DialogEvent::REQUESTED_UPLOAD_SAVE, DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE, - DialogEvent::OFFERED_LOCAL_SAVE}); + DialogEvent::OFFERED_LOCAL_SAVE, DialogEvent::BUBBLE_SHOWN}); SubmitForm(); WaitForObservedEvent(); EXPECT_TRUE(FindViewInBubbleById(DialogViewId::MAIN_CONTENT_VIEW_LOCAL) @@ -1292,7 +1277,9 @@ // Clicking [No thanks] should cancel and close it. base::HistogramTester histogram_tester; - ClickOnCancelButton(/*strike_expected=*/true); + ResetEventWaiterForSequence({DialogEvent::STRIKE_CHANGE_COMPLETE}); + ClickOnCancelButton(); + WaitForObservedEvent(); // UMA should have recorded bubble rejection. histogram_tester.ExpectUniqueSample( @@ -1565,7 +1552,7 @@ ResetEventWaiterForSequence( {DialogEvent::REQUESTED_UPLOAD_SAVE, DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE, - DialogEvent::OFFERED_LOCAL_SAVE}); + DialogEvent::OFFERED_LOCAL_SAVE, DialogEvent::BUBBLE_SHOWN}); NavigateTo(kCreditCardAndAddressUploadForm); FillForm(); SubmitForm(); @@ -1591,7 +1578,7 @@ ResetEventWaiterForSequence( {DialogEvent::REQUESTED_UPLOAD_SAVE, DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE, - DialogEvent::OFFERED_LOCAL_SAVE}); + DialogEvent::OFFERED_LOCAL_SAVE, DialogEvent::BUBBLE_SHOWN}); NavigateTo(kCreditCardAndAddressUploadForm); FillForm(); SubmitForm(); @@ -1634,7 +1621,8 @@ WaitForObservedEvent(); ResetEventWaiterForSequence( {DialogEvent::REQUESTED_UPLOAD_SAVE, - DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE}); + DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE, + DialogEvent::OFFERED_UPLOAD_SAVE, DialogEvent::BUBBLE_SHOWN}); SubmitForm(); WaitForObservedEvent(); EXPECT_TRUE(GetSaveCardBubbleViews()); @@ -2011,9 +1999,6 @@ // Clicking the [X] close button should dismiss the bubble. ClickOnCloseButton(); - // Add an event observer to the controller to detect strike changes. - AddEventObserverToController(); - base::HistogramTester histogram_tester; // Wait long enough to avoid bubble stickiness, then navigate away from the @@ -2046,9 +2031,6 @@ // Clicking the [X] close button should dismiss the bubble. ClickOnCloseButton(); - // Add an event observer to the controller to detect strike changes. - AddEventObserverToController(); - base::HistogramTester histogram_tester; // Wait long enough to avoid bubble stickiness, then navigate away from the @@ -2073,7 +2055,9 @@ // Clicking [No thanks] should cancel and close it. base::HistogramTester histogram_tester; - ClickOnCancelButton(/*strike_expected=*/true); + ResetEventWaiterForSequence({DialogEvent::STRIKE_CHANGE_COMPLETE}); + ClickOnCancelButton(); + WaitForObservedEvent(); // Ensure that a strike was added. histogram_tester.ExpectUniqueSample( @@ -2094,7 +2078,9 @@ // Clicking [No thanks] should cancel and close it. base::HistogramTester histogram_tester; - ClickOnCancelButton(/*strike_expected=*/true); + ResetEventWaiterForSequence({DialogEvent::STRIKE_CHANGE_COMPLETE}); + ClickOnCancelButton(); + WaitForObservedEvent(); // Ensure that a strike was added. histogram_tester.ExpectUniqueSample( @@ -2108,8 +2094,6 @@ // strikes are added if the card already has max strikes. IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest, StrikeDatabase_Local_FullFlowTest) { - bool controller_observer_set = false; - // Show and ignore the bubble enough times in order to accrue maximum strikes. for (int i = 0; i < credit_card_save_manager_->GetCreditCardSaveStrikeDatabase() @@ -2117,17 +2101,11 @@ ++i) { FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - - if (!controller_observer_set) { - // Add an event observer to the controller. - AddEventObserverToController(); - ReduceAnimationTime(); - controller_observer_set = true; - } + ReduceAnimationTime(); base::HistogramTester histogram_tester; ResetEventWaiterForSequence({DialogEvent::STRIKE_CHANGE_COMPLETE}); - ClickOnCancelButton(/*strike_expected=*/true); + ClickOnCancelButton(); WaitForObservedEvent(); // Ensure that a strike was added due to the bubble being declined. @@ -2141,7 +2119,8 @@ // Submit the form a fourth time. Since the card now has maximum strikes (3), // the icon should be shown but the bubble should not. - ResetEventWaiterForSequence({DialogEvent::OFFERED_LOCAL_SAVE}); + ResetEventWaiterForSequence( + {DialogEvent::OFFERED_LOCAL_SAVE, DialogEvent::ICON_SHOWN}); FillForm(); SubmitForm(); WaitForObservedEvent(); @@ -2180,8 +2159,6 @@ IN_PROC_BROWSER_TEST_F( SaveCardBubbleViewsFullFormBrowserTestWithAutofillUpstream, StrikeDatabase_Upload_FullFlowTest) { - bool controller_observer_set = false; - // Start sync. harness_->SetupSync(); @@ -2192,17 +2169,12 @@ ++i) { FillForm(); SubmitFormAndWaitForCardUploadSaveBubble(); - - if (!controller_observer_set) { - // Add an event observer to the controller. - AddEventObserverToController(); - ReduceAnimationTime(); - controller_observer_set = true; - } + ReduceAnimationTime(); base::HistogramTester histogram_tester; - ClickOnCancelButton(/*strike_expected=*/true); + ResetEventWaiterForSequence({DialogEvent::STRIKE_CHANGE_COMPLETE}); + ClickOnCancelButton(); WaitForObservedEvent(); // Ensure that a strike was added due to the bubble being declined. @@ -2218,7 +2190,8 @@ // the icon should be shown but the bubble should not. ResetEventWaiterForSequence( {DialogEvent::REQUESTED_UPLOAD_SAVE, - DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE}); + DialogEvent::RECEIVED_GET_UPLOAD_DETAILS_RESPONSE, + DialogEvent::OFFERED_UPLOAD_SAVE, DialogEvent::ICON_SHOWN}); NavigateTo(kCreditCardAndAddressUploadForm); FillForm(); SubmitForm(); @@ -2310,7 +2283,6 @@ FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); ClickOnCloseButton(); - AddEventObserverToController(); ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); ClickOnView(GetSaveCardIconView()); WaitForObservedEvent(); @@ -2460,6 +2432,7 @@ SetUploadCardRpcPaymentsFails(); ResetEventWaiterForSequence({DialogEvent::RECEIVED_UPLOAD_CARD_RESPONSE, DialogEvent::STRIKE_CHANGE_COMPLETE, + DialogEvent::ICON_SHOWN, DialogEvent::SHOW_CARD_SAVED_FEEDBACK}); WaitForObservedEvent(); @@ -2481,7 +2454,6 @@ AutofillMetrics::CREDIT_CARD_UPLOAD_FEEDBACK_FAILURE_BUBBLE_SHOWN, 0); // Click on the icon. - AddEventObserverToController(); ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); ClickOnView(GetSaveCardIconView()); WaitForObservedEvent(); @@ -2507,15 +2479,11 @@ FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); // Click [Save] should close the offer-to-save bubble // and pop up the sign-in promo. - ClickOnDialogViewWithId(DialogViewId::OK_BUTTON); + ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON); WaitForObservedEvent(); // Ensures the credit card icon is not visible. @@ -2533,21 +2501,15 @@ FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); // Click [Save] should close the offer-to-save bubble // and pop up the sign-in promo. - ClickOnDialogViewWithId(DialogViewId::OK_BUTTON); + ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON); WaitForObservedEvent(); // Close the sign-in promo. - ResetEventWaiterForSequence({DialogEvent::BUBBLE_CLOSED}); ClickOnCloseButton(); - WaitForObservedEvent(); // Ensures the neither credit card icon nor the manage cards bubble is // showing. @@ -2606,18 +2568,13 @@ Local_Metrics_SigninImpressionManageCards) { FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); ReduceAnimationTime(); - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); // Click [Save] should close the offer-to-save bubble // and pop up the sign-in promo. base::UserActionTester user_action_tester; - ClickOnDialogViewWithId(DialogViewId::OK_BUTTON); + ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON); WaitForObservedEvent(); // Close promo. @@ -2640,15 +2597,10 @@ Local_ClickingIconShowsManageCards) { FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); ReduceAnimationTime(); #if !defined(OS_CHROMEOS) - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); #endif // Click [Save] should close the offer-to-save bubble and show "Card saved" @@ -2680,15 +2632,10 @@ Local_ManageCardsDoneButtonClosesBubble) { FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); ReduceAnimationTime(); #if !defined(OS_CHROMEOS) - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); #endif // Click [Save] should close the offer-to-save bubble and show "Card saved" @@ -2725,18 +2672,13 @@ Local_Metrics_AcceptingFootnotePromoManageCards) { FillForm(); SubmitFormAndWaitForCardLocalSaveBubble(); - - // Adding an event observer to the controller so we can wait for the bubble to - // show. - AddEventObserverToController(); ReduceAnimationTime(); - ResetEventWaiterForSequence( - {DialogEvent::BUBBLE_CLOSED, DialogEvent::BUBBLE_SHOWN}); + ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN}); // Click [Save] should close the offer-to-save bubble // and pop up the sign-in promo. base::UserActionTester user_action_tester; - ClickOnDialogViewWithId(DialogViewId::OK_BUTTON); + ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON); WaitForObservedEvent(); // Close promo.
diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc index 951602a5..c57103d 100644 --- a/chrome/browser/ui/views/collected_cookies_views.cc +++ b/chrome/browser/ui/views/collected_cookies_views.cc
@@ -8,7 +8,6 @@ #include <utility> #include "base/macros.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" #include "chrome/browser/browsing_data/cookies_tree_model.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/browser/infobars/infobar_service.h" @@ -109,7 +108,7 @@ shared_objects.local_storages(), shared_objects.session_storages(), shared_objects.appcaches(), shared_objects.indexed_dbs(), shared_objects.file_systems(), nullptr, shared_objects.service_workers(), - shared_objects.shared_workers(), shared_objects.cache_storages(), nullptr, + shared_objects.shared_workers(), shared_objects.cache_storages(), nullptr); return std::make_unique<CookiesTreeModel>(std::move(container), nullptr);
diff --git a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc index 2debb24..2d7683c 100644 --- a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc +++ b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
@@ -4,8 +4,6 @@ #include <memory> -#include "base/compiler_specific.h" -#include "base/macros.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -25,11 +23,13 @@ #include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/dialog_model.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" #include "ui/gfx/geometry/insets.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" +#include "ui/views/bubble/bubble_dialog_model_host.h" #include "ui/views/controls/button/checkbox.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" @@ -39,7 +39,8 @@ #include "ui/views/window/dialog_delegate.h" namespace { -class ExtensionUninstallDialogDelegateView; + +constexpr int kCheckboxId = 1; // Views implementation of the uninstall dialog. class ExtensionUninstallDialogViews @@ -49,61 +50,28 @@ Profile* profile, gfx::NativeWindow parent, extensions::ExtensionUninstallDialog::Delegate* delegate); + ExtensionUninstallDialogViews(const ExtensionUninstallDialogViews&) = delete; + ExtensionUninstallDialogViews& operator=( + const ExtensionUninstallDialogViews&) = delete; ~ExtensionUninstallDialogViews() override; - // Called when the ExtensionUninstallDialogDelegate has been destroyed to make - // sure we invalidate pointers. This object will also be freed. - void DialogDelegateDestroyed(); - - // Forwards the accept and cancels to the delegate. - void DialogAccepted(bool checkbox_checked); - void DialogCanceled(); + // Forwards that the dialog has been accepted to the delegate. + void DialogAccepted(); + // Reports a canceled dialog to the delegate (unless accepted). + void DialogClosing(); private: void Show() override; - ExtensionUninstallDialogDelegateView* view_ = nullptr; + // Pointer to the DialogModel for the dialog. This is cleared when the dialog + // is being closed and OnDialogClosed is reported. As such it prevents access + // to the dialog after it's been closed, as well as preventing multiple + // reports of OnDialogClosed. + ui::DialogModel* dialog_model_ = nullptr; - DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogViews); -}; - -// The dialog's view, owned by the views framework. -class ExtensionUninstallDialogDelegateView - : public views::BubbleDialogDelegateView { - public: - // Constructor for view component of dialog. triggering_extension may be null - // if the uninstall dialog was manually triggered (from chrome://extensions). - ExtensionUninstallDialogDelegateView( - ExtensionUninstallDialogViews* dialog_view, - ToolbarActionView* anchor_view, - const extensions::Extension* extension, - const extensions::Extension* triggering_extension, - const gfx::ImageSkia* image); - ~ExtensionUninstallDialogDelegateView() override; - - // Called when the ExtensionUninstallDialog has been destroyed to make sure - // we invalidate pointers. - void DialogDestroyed() { dialog_ = nullptr; } - - private: - // views::View: - const char* GetClassName() const override; - - // views::DialogDelegateView: - gfx::Size CalculatePreferredSize() const override; - - // views::WidgetDelegate: - ui::ModalType GetModalType() const override { - return is_bubble_ ? ui::MODAL_TYPE_NONE : ui::MODAL_TYPE_WINDOW; - } - - ExtensionUninstallDialogViews* dialog_; - const bool is_bubble_; - - views::Label* heading_; - views::Checkbox* checkbox_; - - DISALLOW_COPY_AND_ASSIGN(ExtensionUninstallDialogDelegateView); + // WeakPtrs because the associated dialog may outlive |this|, which is owned + // by the caller of extensions::ExtensionsUninstallDialog::Create(). + base::WeakPtrFactory<ExtensionUninstallDialogViews> weak_ptr_factory_{this}; }; ExtensionUninstallDialogViews::ExtensionUninstallDialogViews( @@ -113,14 +81,52 @@ : extensions::ExtensionUninstallDialog(profile, parent, delegate) {} ExtensionUninstallDialogViews::~ExtensionUninstallDialogViews() { - // Close the widget (the views framework will delete view_). - if (view_) { - view_->DialogDestroyed(); - view_->GetWidget()->CloseNow(); - } + if (dialog_model_) + dialog_model_->host()->Close(); + DCHECK(!dialog_model_); } void ExtensionUninstallDialogViews::Show() { + // TODO(pbos): Consider separating dialog model from views code. + ui::DialogModel::Builder dialog_builder; + dialog_builder + .SetTitle( + l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_TITLE, + base::UTF8ToUTF16(extension()->name()))) + .OverrideShowCloseButton(false) + .SetWindowClosingCallback( + base::BindOnce(&ExtensionUninstallDialogViews::DialogClosing, + weak_ptr_factory_.GetWeakPtr())) + .SetIcon(ui::ImageModel::FromImageSkia( + gfx::ImageSkiaOperations::CreateResizedImage( + icon(), skia::ImageOperations::ResizeMethod::RESIZE_GOOD, + gfx::Size(extension_misc::EXTENSION_ICON_SMALL, + extension_misc::EXTENSION_ICON_SMALL)))) + .AddOkButton( + base::BindOnce(&ExtensionUninstallDialogViews::DialogAccepted, + weak_ptr_factory_.GetWeakPtr()), + l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON)) + .AddCancelButton( + base::OnceClosure() /* Cancel is covered by WindowClosingCallback */); + + if (triggering_extension()) { + dialog_builder.AddBodyText( + ui::DialogModelLabel( + l10n_util::GetStringFUTF16( + IDS_EXTENSION_PROMPT_UNINSTALL_TRIGGERED_BY_EXTENSION, + base::UTF8ToUTF16(triggering_extension()->name()))) + .set_is_secondary() + .set_allow_character_break()); + } + + if (ShouldShowCheckbox()) { + dialog_builder.AddCheckbox(kCheckboxId, + ui::DialogModelLabel(GetCheckboxLabel())); + } + + std::unique_ptr<ui::DialogModel> dialog_model = dialog_builder.Build(); + dialog_model_ = dialog_model.get(); + BrowserView* const browser_view = parent() ? BrowserView::GetBrowserViewForNativeWindow(parent()) : nullptr; ToolbarActionView* anchor_view = nullptr; @@ -141,154 +147,48 @@ if (reference_view && reference_view->GetVisible()) anchor_view = reference_view; } - view_ = new ExtensionUninstallDialogDelegateView( - this, anchor_view, extension(), triggering_extension(), &icon()); + if (anchor_view) { + auto bubble = std::make_unique<views::BubbleDialogModelHost>( + std::move(dialog_model), anchor_view, views::BubbleBorder::TOP_RIGHT); + if (container) { container->ShowWidgetForExtension( - views::BubbleDialogDelegateView::CreateBubble(view_), + views::BubbleDialogDelegateView::CreateBubble(std::move(bubble)), extension()->id()); } else { DCHECK(!base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)); - views::BubbleDialogDelegateView::CreateBubble(view_)->Show(); + views::BubbleDialogDelegateView::CreateBubble(std::move(bubble))->Show(); } } else { - constrained_window::CreateBrowserModalDialogViews(view_, parent())->Show(); + // TODO(pbos): Add unique_ptr version of CreateBrowserModalDialogViews and + // remove .release(). + constrained_window::CreateBrowserModalDialogViews( + views::BubbleDialogModelHost::CreateModal(std::move(dialog_model), + ui::MODAL_TYPE_WINDOW) + .release(), + parent()) + ->Show(); } -} - -void ExtensionUninstallDialogViews::DialogDelegateDestroyed() { - // Checks view_ to ensure OnDialogClosed() will not be called twice. - if (view_) { - view_ = nullptr; - OnDialogClosed(CLOSE_ACTION_CANCELED); - } -} - -void ExtensionUninstallDialogViews::DialogAccepted(bool checkbox_checked) { - // The widget gets destroyed when the dialog is accepted. - DCHECK(view_); - view_->DialogDestroyed(); - view_ = nullptr; - - OnDialogClosed(checkbox_checked ? CLOSE_ACTION_UNINSTALL_AND_CHECKBOX_CHECKED - : CLOSE_ACTION_UNINSTALL); -} - -void ExtensionUninstallDialogViews::DialogCanceled() { - // The widget gets destroyed when the dialog is canceled. - DCHECK(view_); - view_->DialogDestroyed(); - view_ = nullptr; - OnDialogClosed(CLOSE_ACTION_CANCELED); -} - -ExtensionUninstallDialogDelegateView::ExtensionUninstallDialogDelegateView( - ExtensionUninstallDialogViews* dialog_view, - ToolbarActionView* anchor_view, - const extensions::Extension* extension, - const extensions::Extension* triggering_extension, - const gfx::ImageSkia* image) - : BubbleDialogDelegateView(anchor_view, - anchor_view ? views::BubbleBorder::TOP_RIGHT - : views::BubbleBorder::NONE), - dialog_(dialog_view), - is_bubble_(anchor_view != nullptr), - checkbox_(nullptr) { - SetButtonLabel( - ui::DIALOG_BUTTON_OK, - l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON)); - SetIcon(gfx::ImageSkiaOperations::CreateResizedImage( - *image, skia::ImageOperations::ResizeMethod::RESIZE_GOOD, - gfx::Size(extension_misc::EXTENSION_ICON_SMALL, - extension_misc::EXTENSION_ICON_SMALL))); - SetShowCloseButton(false); - SetShowIcon(true); - SetTitle(l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_UNINSTALL_TITLE, - base::UTF8ToUTF16(extension->name()))); - - SetAcceptCallback(base::BindOnce( - [](ExtensionUninstallDialogDelegateView* view) { - if (view->dialog_) { - view->dialog_->DialogAccepted(view->checkbox_ && - view->checkbox_->GetChecked()); - } - }, - base::Unretained(this))); - SetCancelCallback(base::BindOnce( - [](ExtensionUninstallDialogDelegateView* view) { - if (view->dialog_) - view->dialog_->DialogCanceled(); - }, - base::Unretained(this))); - - ChromeLayoutProvider* provider = ChromeLayoutProvider::Get(); - SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, gfx::Insets(), - provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL))); - - // Add margins for the icon plus the icon-title padding so that the dialog - // contents align with the title text. - set_margins( - margins() + - gfx::Insets(0, margins().left() + extension_misc::EXTENSION_ICON_SMALL, 0, - 0)); - - if (triggering_extension) { - heading_ = new views::Label( - l10n_util::GetStringFUTF16( - IDS_EXTENSION_PROMPT_UNINSTALL_TRIGGERED_BY_EXTENSION, - base::UTF8ToUTF16(triggering_extension->name())), - views::style::CONTEXT_DIALOG_BODY_TEXT, views::style::STYLE_SECONDARY); - heading_->SetMultiLine(true); - heading_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - heading_->SetAllowCharacterBreak(true); - AddChildView(heading_); - } - - if (dialog_->ShouldShowCheckbox()) { - checkbox_ = new views::Checkbox(dialog_->GetCheckboxLabel()); - checkbox_->SetMultiLine(true); - AddChildView(checkbox_); - } - - if (anchor_view) - anchor_view->AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr); - chrome::RecordDialogCreation(chrome::DialogIdentifier::EXTENSION_UNINSTALL); } -ExtensionUninstallDialogDelegateView::~ExtensionUninstallDialogDelegateView() { - // If we're here, 2 things could have happened. Either the user closed the - // dialog nicely and one of the installed/canceled methods has been called - // (in which case dialog_ will be null), *or* neither of them have been - // called and we are being forced closed by our parent widget. In this case, - // we need to make sure to notify dialog_ not to call us again, since we're - // about to be freed by the Widget framework. - if (dialog_) - dialog_->DialogDelegateDestroyed(); - - // If there is still a toolbar action view its ink drop should be deactivated - // when the uninstall dialog goes away. This lookup is repeated as the dialog - // can go away during dialog's lifetime (especially when uninstalling). - views::View* anchor_view = GetAnchorView(); - if (anchor_view) { - static_cast<ToolbarActionView*>(anchor_view) - ->AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr); - } +void ExtensionUninstallDialogViews::DialogAccepted() { + DCHECK(dialog_model_); + const bool checkbox_is_checked = + ShouldShowCheckbox() && + dialog_model_->GetCheckboxByUniqueId(kCheckboxId)->is_checked(); + dialog_model_ = nullptr; + OnDialogClosed(checkbox_is_checked + ? CLOSE_ACTION_UNINSTALL_AND_CHECKBOX_CHECKED + : CLOSE_ACTION_UNINSTALL); } -const char* ExtensionUninstallDialogDelegateView::GetClassName() const { - return "ExtensionUninstallDialogDelegateView"; -} - -gfx::Size ExtensionUninstallDialogDelegateView::CalculatePreferredSize() const { - const int width = - ChromeLayoutProvider::Get()->GetDistanceMetric( - is_bubble_ ? views::DISTANCE_BUBBLE_PREFERRED_WIDTH - : views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH) - - margins().width(); - return gfx::Size(width, GetHeightForWidth(width)); +void ExtensionUninstallDialogViews::DialogClosing() { + if (!dialog_model_) + return; + dialog_model_ = nullptr; + OnDialogClosed(CLOSE_ACTION_CANCELED); } } // namespace
diff --git a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc index ef96aad..86c94d2 100644 --- a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc +++ b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc
@@ -135,7 +135,6 @@ EXPECT_TRUE(delegate.canceled()); } -#if defined(OS_CHROMEOS) // Test that we don't crash when uninstalling an extension from a web app // window in Ash. Context: crbug.com/825554 IN_PROC_BROWSER_TEST_F(ExtensionUninstallDialogViewBrowserTest, @@ -155,12 +154,13 @@ Browser* app_browser = web_app::LaunchWebAppBrowser(browser()->profile(), app_id); + TestExtensionUninstallDialogDelegate delegate{base::DoNothing()}; std::unique_ptr<extensions::ExtensionUninstallDialog> dialog; { base::RunLoop run_loop; dialog = extensions::ExtensionUninstallDialog::Create( app_browser->profile(), app_browser->window()->GetNativeWindow(), - nullptr); + &delegate); run_loop.RunUntilIdle(); } @@ -172,7 +172,6 @@ run_loop.RunUntilIdle(); } } -#endif // defined(OS_CHROMEOS) class ParameterizedExtensionUninstallDialogViewBrowserTest : public InProcessBrowserTest,
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view.h b/chrome/browser/ui/views/extensions/extensions_menu_view.h index bf1ae29..8fee724f 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_view.h +++ b/chrome/browser/ui/views/extensions/extensions_menu_view.h
@@ -103,6 +103,7 @@ // the view directly is more friendly to unit test setups. static base::AutoReset<bool> AllowInstancesForTesting(); + private: // A "section" within the menu, based on the extension's current access to // the page. struct Section {
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc index d5a7dc8..54c18114 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
@@ -37,6 +37,7 @@ #include "extensions/test/test_extension_dir.h" #include "testing/gmock/include/gmock/gmock.h" #include "ui/views/animation/ink_drop.h" +#include "ui/views/bubble/bubble_dialog_model_host.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/layout/animating_layout_manager.h" #include "ui/views/layout/animating_layout_manager_test_util.h" @@ -88,7 +89,7 @@ // Trigger uninstall dialog. views::NamedWidgetShownWaiter waiter( views::test::AnyWidgetTestPasskey{}, - "ExtensionUninstallDialogDelegateView"); + views::BubbleDialogModelHost::kViewClassName); extensions::ExtensionContextMenuModel menu_model( extensions()[0].get(), browser(), extensions::ExtensionContextMenuModel::PINNED, nullptr,
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc index b2fb889..d1d9a08 100644 --- a/chrome/browser/ui/views/find_bar_view.cc +++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -127,50 +127,67 @@ // FindBarView, public: FindBarView::FindBarView(FindBarHost* host) { - auto find_text = std::make_unique<views::Textfield>(); - find_text->SetID(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD); - find_text->SetDefaultWidthInChars(30); - find_text->SetMinimumWidthInChars(1); + auto find_text = + views::Builder<views::Textfield>() + .SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FIND)) + .SetBorder(views::NullBorder()) + .SetDefaultWidthInChars(30) + .SetID(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD) + .SetMinimumWidthInChars(1) + .SetTextInputFlags(ui::TEXT_INPUT_FLAG_AUTOCORRECT_OFF) + .Build(); + + // TODO(kerenzhu): set_controller() should be supported in Builder<TextField>. find_text->set_controller(this); - find_text->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FIND)); - find_text->SetTextInputFlags(ui::TEXT_INPUT_FLAG_AUTOCORRECT_OFF); + find_text_ = AddChildView(std::move(find_text)); SetHost(host); - auto match_count_text = std::make_unique<FindBarMatchCountLabel>(); - match_count_text->SetCanProcessEventsWithinSubtree(false); + auto match_count_text = views::Builder<FindBarMatchCountLabel>() + .SetCanProcessEventsWithinSubtree(false) + .Build(); match_count_text_ = AddChildView(std::move(match_count_text)); - auto separator = std::make_unique<views::Separator>(); - separator->SetCanProcessEventsWithinSubtree(false); + auto separator = views::Builder<views::Separator>() + .SetCanProcessEventsWithinSubtree(false) + .Build(); separator_ = AddChildView(std::move(separator)); - auto find_previous_button = std::make_unique<views::ImageButton>(this); - SetCommonButtonAttributes(find_previous_button.get()); - find_previous_button->SetID(VIEW_ID_FIND_IN_PAGE_PREVIOUS_BUTTON); - find_previous_button->SetTooltipText( - l10n_util::GetStringUTF16(IDS_FIND_IN_PAGE_PREVIOUS_TOOLTIP)); - find_previous_button->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_ACCNAME_PREVIOUS)); + auto find_previous_button = + views::Builder<views::ImageButton>() + .SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_PREVIOUS)) + .SetID(VIEW_ID_FIND_IN_PAGE_PREVIOUS_BUTTON) + .SetTooltipText( + l10n_util::GetStringUTF16(IDS_FIND_IN_PAGE_PREVIOUS_TOOLTIP)) + .Build(); + find_previous_button->set_callback(base::BindRepeating( + &FindBarView::FindNext, base::Unretained(this), true)); find_previous_button_ = AddChildView(std::move(find_previous_button)); + SetCommonButtonAttributes(find_previous_button_); - auto find_next_button = std::make_unique<views::ImageButton>(this); - SetCommonButtonAttributes(find_next_button.get()); - find_next_button->SetID(VIEW_ID_FIND_IN_PAGE_NEXT_BUTTON); - find_next_button->SetTooltipText( - l10n_util::GetStringUTF16(IDS_FIND_IN_PAGE_NEXT_TOOLTIP)); - find_next_button->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_ACCNAME_NEXT)); + auto find_next_button = + views::Builder<views::ImageButton>() + .SetID(VIEW_ID_FIND_IN_PAGE_NEXT_BUTTON) + .SetTooltipText( + l10n_util::GetStringUTF16(IDS_FIND_IN_PAGE_NEXT_TOOLTIP)) + .SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_NEXT)) + .Build(); + find_next_button->set_callback(base::BindRepeating( + &FindBarView::FindNext, base::Unretained(this), false)); find_next_button_ = AddChildView(std::move(find_next_button)); + SetCommonButtonAttributes(find_next_button_); - auto close_button = std::make_unique<views::ImageButton>(this); - SetCommonButtonAttributes(close_button.get()); - close_button->SetID(VIEW_ID_FIND_IN_PAGE_CLOSE_BUTTON); - close_button->SetTooltipText( - l10n_util::GetStringUTF16(IDS_FIND_IN_PAGE_CLOSE_TOOLTIP)); - close_button->SetAnimationDuration(base::TimeDelta()); + auto close_button = views::Builder<views::ImageButton>() + .SetID(VIEW_ID_FIND_IN_PAGE_CLOSE_BUTTON) + .SetTooltipText(l10n_util::GetStringUTF16( + IDS_FIND_IN_PAGE_CLOSE_TOOLTIP)) + .SetAnimationDuration(base::TimeDelta()) + .Build(); + close_button->set_callback(base::BindRepeating(&FindBarView::EndFindSession, + base::Unretained(this))); close_button_ = AddChildView(std::move(close_button)); + SetCommonButtonAttributes(close_button_); EnableCanvasFlippingForRTLUI(true); @@ -214,8 +231,6 @@ views::kMarginsKey, gfx::Insets(toast_label_vertical_margin + horizontal_margin)); - find_text_->SetBorder(views::NullBorder()); - auto* manager = SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal, gfx::Insets(provider->GetInsetsMetric(INSETS_TOAST) - horizontal_margin), @@ -344,40 +359,6 @@ } //////////////////////////////////////////////////////////////////////////////// -// FindBarView, views::ButtonListener implementation: - -void FindBarView::ButtonPressed( - views::Button* sender, const ui::Event& event) { - if (!find_bar_host_) - return; - - switch (sender->GetID()) { - case VIEW_ID_FIND_IN_PAGE_PREVIOUS_BUTTON: - case VIEW_ID_FIND_IN_PAGE_NEXT_BUTTON: - if (!find_text_->GetText().empty()) { - find_in_page::FindTabHelper* find_tab_helper = - find_in_page::FindTabHelper::FromWebContents( - find_bar_host_->GetFindBarController()->web_contents()); - find_tab_helper->StartFinding( - find_text_->GetText(), - sender->GetID() == - VIEW_ID_FIND_IN_PAGE_NEXT_BUTTON, /* forward_direction */ - false /* case_sensitive */, - true /* find_match */); - } - break; - case VIEW_ID_FIND_IN_PAGE_CLOSE_BUTTON: - find_bar_host_->GetFindBarController()->EndFindSession( - find_in_page::SelectionAction::kKeep, - find_in_page::ResultAction::kKeep); - break; - default: - NOTREACHED() << "Unknown button"; - break; - } -} - -//////////////////////////////////////////////////////////////////////////////// // FindBarView, views::TextfieldController implementation: bool FindBarView::HandleKeyEvent(views::Textfield* sender, @@ -464,6 +445,27 @@ } } +void FindBarView::FindNext(bool reverse) { + if (!find_bar_host_) + return; + if (!find_text_->GetText().empty()) { + find_in_page::FindTabHelper* find_tab_helper = + find_in_page::FindTabHelper::FromWebContents( + find_bar_host_->GetFindBarController()->web_contents()); + find_tab_helper->StartFinding(find_text_->GetText(), + !reverse, /* forward_direction */ + false, /* case_sensitive */ + true /* find_match */); + } +} + +void FindBarView::EndFindSession() { + if (!find_bar_host_) + return; + find_bar_host_->GetFindBarController()->EndFindSession( + find_in_page::SelectionAction::kKeep, find_in_page::ResultAction::kKeep); +} + void FindBarView::UpdateMatchCountAppearance(bool no_match) { bool enable_buttons = !find_text_->GetText().empty() && !no_match; find_previous_button_->SetEnabled(enable_buttons);
diff --git a/chrome/browser/ui/views/find_bar_view.h b/chrome/browser/ui/views/find_bar_view.h index 7d53239b..bb88f0509 100644 --- a/chrome/browser/ui/views/find_bar_view.h +++ b/chrome/browser/ui/views/find_bar_view.h
@@ -43,7 +43,6 @@ //////////////////////////////////////////////////////////////////////////////// class FindBarView : public views::View, public DropdownBarHostDelegate, - public views::ButtonListener, public views::TextfieldController { public: METADATA_HEADER(FindBarView); @@ -81,9 +80,6 @@ // DropdownBarHostDelegate: void FocusAndSelectAll() override; - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - // views::TextfieldController: bool HandleKeyEvent(views::Textfield* sender, const ui::KeyEvent& key_event) override; @@ -94,6 +90,12 @@ // Starts finding |search_text|. If the text is empty, stops finding. void Find(const base::string16& search_text); + // Find the next/previous occurrence of search text when clicking the + // next/previous button. + void FindNext(bool reverse = false); + // End the current find session and close the find bubble. + void EndFindSession(); + // Updates the appearance for the match count label. void UpdateMatchCountAppearance(bool no_match);
diff --git a/chrome/browser/ui/views/frame/browser_frame_header_ash.cc b/chrome/browser/ui/views/frame/browser_frame_header_ash.cc index 8ee5569a..e762460 100644 --- a/chrome/browser/ui/views/frame/browser_frame_header_ash.cc +++ b/chrome/browser/ui/views/frame/browser_frame_header_ash.cc
@@ -5,13 +5,13 @@ #include "chrome/browser/ui/views/frame/browser_frame_header_ash.h" #include "ash/public/cpp/ash_constants.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/frame_utils.h" #include "ash/public/cpp/tablet_mode.h" #include "base/check.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chromeos/ui/base/window_properties.h" #include "chromeos/ui/base/window_state_type.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkPaint.h" @@ -112,7 +112,7 @@ views::Widget* target_widget, views::View* view, AppearanceProvider* appearance_provider, - ash::FrameCaptionButtonContainerView* caption_button_container) + chromeos::FrameCaptionButtonContainerView* caption_button_container) : FrameHeader(target_widget, view) { DCHECK(appearance_provider); DCHECK(caption_button_container);
diff --git a/chrome/browser/ui/views/frame/browser_frame_header_ash.h b/chrome/browser/ui/views/frame/browser_frame_header_ash.h index 842c76df..f299ea84 100644 --- a/chrome/browser/ui/views/frame/browser_frame_header_ash.h +++ b/chrome/browser/ui/views/frame/browser_frame_header_ash.h
@@ -31,7 +31,7 @@ views::Widget* target_widget, views::View* view, AppearanceProvider* appearance_provider, - ash::FrameCaptionButtonContainerView* caption_button_container); + chromeos::FrameCaptionButtonContainerView* caption_button_container); ~BrowserFrameHeaderAsh() override; // Returns the amount that the frame background is inset from the left edge of
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc index 37cd7ebc..7e7e76c2 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -7,10 +7,8 @@ #include <algorithm> #include "ash/public/cpp/app_types.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/default_frame_header.h" #include "ash/public/cpp/frame_utils.h" -#include "ash/public/cpp/tablet_mode.h" #include "ash/public/cpp/window_properties.h" #include "ash/wm/window_util.h" #include "base/metrics/user_metrics.h" @@ -40,6 +38,7 @@ #include "chromeos/ui/base/chromeos_ui_constants.h" #include "chromeos/ui/base/window_properties.h" #include "chromeos/ui/base/window_state_type.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "content/public/browser/web_contents.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/accessibility/ax_enums.mojom.h" @@ -95,7 +94,7 @@ } BrowserNonClientFrameViewAsh::~BrowserNonClientFrameViewAsh() { - ash::TabletMode::Get()->RemoveObserver(this); + chromeos::TabletState::Get()->RemoveObserver(this); ImmersiveModeController* immersive_controller = browser_view()->immersive_mode_controller(); @@ -104,7 +103,8 @@ } void BrowserNonClientFrameViewAsh::Init() { - caption_button_container_ = new ash::FrameCaptionButtonContainerView(frame()); + caption_button_container_ = + new chromeos::FrameCaptionButtonContainerView(frame()); caption_button_container_->UpdateCaptionButtonState(false /*=animate*/); AddChildView(caption_button_container_); @@ -133,7 +133,7 @@ if (browser->profile()->IsOffTheRecord()) window->SetProperty(ash::kBlockedForAssistantSnapshotKey, true); - ash::TabletMode::Get()->AddObserver(this); + chromeos::TabletState::Get()->AddObserver(this); if (frame()->ShouldDrawFrameHeader()) frame_header_ = CreateFrameHeader(); @@ -414,12 +414,19 @@ : BrowserFrameActiveState::kInactive); } -void BrowserNonClientFrameViewAsh::OnTabletModeStarted() { - OnTabletModeToggled(true); -} - -void BrowserNonClientFrameViewAsh::OnTabletModeEnded() { - OnTabletModeToggled(false); +void BrowserNonClientFrameViewAsh::OnTabletStateChanged( + chromeos::TabletState::State state) { + switch (state) { + case chromeos::TabletState::State::kInTabletMode: + OnTabletModeToggled(true); + return; + case chromeos::TabletState::State::kInClamshellMode: + OnTabletModeToggled(false); + return; + case chromeos::TabletState::State::kEnteringTabletMode: + case chromeos::TabletState::State::kExitingTabletMode: + break; + } } void BrowserNonClientFrameViewAsh::OnTabletModeToggled(bool enabled) { @@ -558,7 +565,7 @@ bool BrowserNonClientFrameViewAsh::ShouldShowCaptionButtonsWhenNotInOverview() const { return UsePackagedAppHeaderStyle(browser_view()->browser()) || - !ash::TabletMode::Get()->InTabletMode(); + !chromeos::TabletState::Get()->InTabletMode(); } int BrowserNonClientFrameViewAsh::GetToolbarLeftInset() const {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h index f21b1fd3..a9cca17 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
@@ -7,7 +7,6 @@ #include <memory> -#include "ash/public/cpp/tablet_mode_observer.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -16,6 +15,7 @@ #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "chrome/browser/ui/views/tab_icon_view_model.h" +#include "chromeos/ui/base/tablet_state.h" #include "ui/aura/window.h" #include "ui/aura/window_observer.h" @@ -26,15 +26,15 @@ class ProfileIndicatorIcon; class TabIconView; -namespace ash { +namespace chromeos { class FrameCaptionButtonContainerView; -} // namespace ash +} // namespace chromeos // Provides the BrowserNonClientFrameView for Chrome OS. class BrowserNonClientFrameViewAsh : public BrowserNonClientFrameView, public BrowserFrameHeaderAsh::AppearanceProvider, - public ash::TabletModeObserver, + public chromeos::TabletState::Observer, public TabIconViewModel, public aura::WindowObserver, public ImmersiveModeController::Observer { @@ -81,9 +81,8 @@ int GetFrameHeaderImageYInset() override; gfx::ImageSkia GetFrameHeaderOverlayImage(bool active) override; - // ash::TabletModeObserver: - void OnTabletModeStarted() override; - void OnTabletModeEnded() override; + // chromeos::TabletState::Observer: + void OnTabletStateChanged(chromeos::TabletState::State) override; void OnTabletModeToggled(bool enabled); @@ -202,7 +201,8 @@ aura::Window* GetFrameWindow(); // View which contains the window controls. - ash::FrameCaptionButtonContainerView* caption_button_container_ = nullptr; + chromeos::FrameCaptionButtonContainerView* caption_button_container_ = + nullptr; // For popups, the window icon. TabIconView* window_icon_ = nullptr;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc index 8475d73..814bb0b0d 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -5,7 +5,6 @@ #include <string> #include "ash/public/cpp/ash_switches.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/default_frame_header.h" #include "ash/public/cpp/frame_header.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h" @@ -74,6 +73,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/ui/base/chromeos_ui_constants.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "components/account_id/account_id.h" #include "components/autofill/core/common/password_form.h" #include "components/keep_alive_registry/keep_alive_types.h" @@ -462,7 +462,7 @@ static_cast<BrowserNonClientFrameViewAsh*>( widget->non_client_view()->frame_view()); - ash::FrameCaptionButtonContainerView::TestApi test( + chromeos::FrameCaptionButtonContainerView::TestApi test( frame_view->caption_button_container_); EXPECT_TRUE(test.size_button()->icon_definition_for_test()); } @@ -1242,7 +1242,7 @@ IN_PROC_BROWSER_TEST_P(WebAppNonClientFrameViewAshTest, ActiveStateOfButtonMatchesWidget) { SetUpWebApp(); - ash::FrameCaptionButtonContainerView::TestApi test( + chromeos::FrameCaptionButtonContainerView::TestApi test( GetFrameViewAsh(browser_view_)->caption_button_container_); EXPECT_TRUE(test.size_button()->paint_as_active()); EXPECT_TRUE(GetPaintingAsActive());
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc index 7ae902e..6a3e4574 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
@@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h" #include "ash/public/cpp/test/shell_test_api.h" #include "base/macros.h" @@ -26,6 +25,7 @@ #include "chrome/common/web_application_info.h" #include "chrome/test/base/ui_test_utils.h" #include "chrome/test/permissions/permission_request_manager_test_api.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "content/public/test/browser_test.h" #include "content/public/test/content_mock_cert_verifier.h" #include "net/cert/mock_cert_verifier.h" @@ -272,9 +272,9 @@ BrowserNonClientFrameViewAsh* frame_view = static_cast<BrowserNonClientFrameViewAsh*>( browser_view->GetWidget()->non_client_view()->frame_view()); - ash::FrameCaptionButtonContainerView* caption_button_container = + chromeos::FrameCaptionButtonContainerView* caption_button_container = frame_view->caption_button_container_; - ash::FrameCaptionButtonContainerView::TestApi frame_test_api( + chromeos::FrameCaptionButtonContainerView::TestApi frame_test_api( caption_button_container); EXPECT_TRUE(frame_test_api.size_button()->GetVisible());
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc b/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc index a1f5484..2dacdb2 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/translate/translate_bubble_view_browsertest.cc
@@ -23,6 +23,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/translate/core/browser/translate_manager.h" +#include "components/translate/core/common/translate_switches.h" #include "content/public/test/browser_test.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_features.h" @@ -40,9 +41,25 @@ void SetUp() override { set_open_about_blank_on_browser_launch(true); TranslateManager::SetIgnoreMissingKeyForTesting(true); + ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); InProcessBrowserTest::SetUp(); } + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII( + switches::kTranslateScriptURL, + embedded_test_server()->GetURL("/mock_translate_script.js").spec()); + } + + void SetUpOnMainThread() override { + embedded_test_server()->StartAcceptingConnections(); + } + + void TearDownOnMainThread() override { + EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); + InProcessBrowserTest::TearDownOnMainThread(); + } + protected: void NavigateAndWaitForLanguageDetection(const GURL& url, const std::string& expected_lang) { @@ -69,8 +86,7 @@ EXPECT_FALSE(TranslateBubbleView::GetCurrentBubble()); // Show a French page and wait until the bubble is shown. - GURL french_url = ui_test_utils::GetTestUrl( - base::FilePath(), base::FilePath(FILE_PATH_LITERAL("french_page.html"))); + GURL french_url = GURL(embedded_test_server()->GetURL("/french_page.html")); NavigateAndWaitForLanguageDetection(french_url, "fr"); EXPECT_TRUE(TranslateBubbleView::GetCurrentBubble()); @@ -86,8 +102,7 @@ EXPECT_FALSE(TranslateBubbleView::GetCurrentBubble()); // Show a French page and wait until the bubble is shown. - GURL french_url = ui_test_utils::GetTestUrl( - base::FilePath(), base::FilePath(FILE_PATH_LITERAL("french_page.html"))); + GURL french_url = GURL(embedded_test_server()->GetURL("/french_page.html")); NavigateAndWaitForLanguageDetection(french_url, "fr"); EXPECT_TRUE(TranslateBubbleView::GetCurrentBubble()); @@ -108,8 +123,7 @@ // Open another tab to load a French page on background. int french_index = active_index + 1; - GURL french_url = ui_test_utils::GetTestUrl( - base::FilePath(), base::FilePath(FILE_PATH_LITERAL("french_page.html"))); + GURL french_url = GURL(embedded_test_server()->GetURL("/french_page.html")); chrome::AddTabAt(browser(), french_url, french_index, false); EXPECT_EQ(active_index, browser()->tab_strip_model()->active_index()); EXPECT_EQ(2, browser()->tab_strip_model()->count()); @@ -136,8 +150,7 @@ views::test::AXEventCounter counter(views::AXEventManager::Get()); EXPECT_EQ(0, counter.GetCount(ax::mojom::Event::kAlert)); - GURL french_url = ui_test_utils::GetTestUrl( - base::FilePath(), base::FilePath(FILE_PATH_LITERAL("french_page.html"))); + GURL french_url = GURL(embedded_test_server()->GetURL("/french_page.html")); NavigateAndWaitForLanguageDetection(french_url, "fr"); // TODO(crbug.com/1082217): This should produce one event instead of two.
diff --git a/chrome/browser/ui/views/translate/translate_language_browsertest.cc b/chrome/browser/ui/views/translate/translate_language_browsertest.cc index 05a2c28..734ff17 100644 --- a/chrome/browser/ui/views/translate/translate_language_browsertest.cc +++ b/chrome/browser/ui/views/translate/translate_language_browsertest.cc
@@ -40,14 +40,10 @@ namespace { -const base::FilePath::CharType kEnglishTestPath[] = - FILE_PATH_LITERAL("english_page.html"); -const base::FilePath::CharType kItalianTestPath[] = - FILE_PATH_LITERAL("italian_page.html"); -const base::FilePath::CharType kFrenchTestPath[] = - FILE_PATH_LITERAL("french_page.html"); -const base::FilePath::CharType kGermanTestPath[] = - FILE_PATH_LITERAL("german_page.html"); +const char kEnglishTestPath[] = "/english_page.html"; +const char kItalianTestPath[] = "/italian_page.html"; +const char kFrenchTestPath[] = "/french_page.html"; +const char kGermanTestPath[] = "/german_page.html"; static const char kTestValidScript[] = "var google = {};" @@ -115,7 +111,7 @@ browser_ = incognito ? CreateIncognitoBrowser() : browser(); } - void NavigateToUrl(const base::FilePath::StringPieceType path) { + void NavigateToUrl(const char* path) { // Close previous Translate bubble, if it exists. This is intended to // prevent a race condition in which the previous page's call to // TranslateBubbleView::WindowClosing doesn't occur until after the new page @@ -124,13 +120,11 @@ // TODO(789593): investigate a more robust fix. TranslateBubbleView::CloseCurrentBubble(); - const GURL url = - ui_test_utils::GetTestUrl(base::FilePath(), base::FilePath(path)); - ui_test_utils::NavigateToURL(browser_, url); + ui_test_utils::NavigateToURL(browser_, + GURL(embedded_test_server()->GetURL(path))); } - void CheckForTranslateUI(const base::FilePath::StringPieceType path, - const bool expect_translate) { + void CheckForTranslateUI(const char* path, const bool expect_translate) { ASSERT_TRUE(browser_); auto waiter = CreateTranslateWaiter(
diff --git a/chrome/browser/ui/webui/bookmarks/bookmarks_ui.cc b/chrome/browser/ui/webui/bookmarks/bookmarks_ui.cc index 3f361b5..a1b0b5ed 100644 --- a/chrome/browser/ui/webui/bookmarks/bookmarks_ui.cc +++ b/chrome/browser/ui/webui/bookmarks/bookmarks_ui.cc
@@ -35,11 +35,6 @@ namespace { -#if !BUILDFLAG(OPTIMIZE_WEBUI) -constexpr char kGeneratedPath[] = - "@out_folder@/gen/chrome/browser/resources/bookmarks/"; -#endif - void AddLocalizedString(content::WebUIDataSource* source, const std::string& message, int id) { @@ -51,16 +46,9 @@ content::WebUIDataSource* CreateBookmarksUIHTMLSource(Profile* profile) { content::WebUIDataSource* source = content::WebUIDataSource::Create(chrome::kChromeUIBookmarksHost); - -#if BUILDFLAG(OPTIMIZE_WEBUI) - webui::SetupBundledWebUIDataSource(source, "bookmarks.js", - IDR_BOOKMARKS_BOOKMARKS_ROLLUP_JS, - IDR_BOOKMARKS_BOOKMARKS_HTML); -#else webui::SetupWebUIDataSource( - source, base::make_span(kBookmarksResources, kBookmarksResourcesSize), - kGeneratedPath, IDR_BOOKMARKS_BOOKMARKS_HTML); -#endif + source, base::make_span(kBookmarksResources, kBookmarksResourcesSize), "", + IDR_BOOKMARKS_BOOKMARKS_HTML); // Build an Accelerator to describe undo shortcut // NOTE: the undo shortcut is also defined in bookmarks/command_manager.js
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index dbf47b56..a12da572 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -1218,17 +1218,27 @@ lock_screen_utils::SetKeyboardSettings(account_id); bool use_24hour_clock = false; - if (user_manager::known_user::GetBooleanPref( + if (!user_manager::known_user::GetBooleanPref( account_id, prefs::kUse24HourClock, &use_24hour_clock)) { - g_browser_process->platform_part() - ->GetSystemClock() - ->SetLastFocusedPodHourClockType(use_24hour_clock ? base::k24HourClock - : base::k12HourClock); + focused_user_clock_type_.reset(); + return; + } + + base::HourClockType clock_type = + use_24hour_clock ? base::k24HourClock : base::k12HourClock; + + if (focused_user_clock_type_.has_value()) { + focused_user_clock_type_->UpdateClockType(clock_type); + } else { + focused_user_clock_type_ = g_browser_process->platform_part() + ->GetSystemClock() + ->CreateScopedHourClockType(clock_type); } } void SigninScreenHandler::HandleNoPodFocused() { focused_pod_account_id_.reset(); + focused_user_clock_type_.reset(); } void SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts(
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h index 0555bef..128fb8a 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -22,6 +22,7 @@ #include "chrome/browser/chromeos/login/signin_specifics.h" #include "chrome/browser/chromeos/login/ui/login_display.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/system/system_clock.h" #include "chrome/browser/ui/webui/chromeos/login/base_webui_handler.h" #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" @@ -420,6 +421,8 @@ std::unique_ptr<LoginFeedback> login_feedback_; std::unique_ptr<AccountId> focused_pod_account_id_; + base::Optional<system::SystemClock::ScopedHourClockType> + focused_user_clock_type_; base::WeakPtrFactory<SigninScreenHandler> weak_factory_{this};
diff --git a/chrome/browser/ui/webui/cookies_tree_model_util.cc b/chrome/browser/ui/webui/cookies_tree_model_util.cc index 8d98f53..f12d382 100644 --- a/chrome/browser/ui/webui/cookies_tree_model_util.cc +++ b/chrome/browser/ui/webui/cookies_tree_model_util.cc
@@ -255,12 +255,6 @@ usage_info.last_modified))); break; } - case CookieTreeNode::DetailedInfo::TYPE_FLASH_LSO: { - dict->SetString(kKeyType, "flash_lso"); - - dict->SetString(kKeyDomain, node.GetDetailedInfo().flash_lso_domain); - break; - } case CookieTreeNode::DetailedInfo::TYPE_MEDIA_LICENSE: { dict->SetString(kKeyType, "media_license");
diff --git a/chrome/browser/ui/webui/discards/graph_dump_impl.h b/chrome/browser/ui/webui/discards/graph_dump_impl.h index 79b4762..95f8c22 100644 --- a/chrome/browser/ui/webui/discards/graph_dump_impl.h +++ b/chrome/browser/ui/webui/discards/graph_dump_impl.h
@@ -105,6 +105,8 @@ void OnFirstContentfulPaint( const performance_manager::FrameNode* frame_node, base::TimeDelta time_since_navigation_start) override {} + void OnViewportIntersectionChanged( + const performance_manager::FrameNode* frame_node) override {} // PageNodeObserver implementation: void OnPageNodeAdded(const performance_manager::PageNode* page_node) override;
diff --git a/chrome/browser/ui/webui/settings/chromeos/about_section.cc b/chrome/browser/ui/webui/settings/chromeos/about_section.cc index c123e9a..8738c88 100644 --- a/chrome/browser/ui/webui/settings/chromeos/about_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/about_section.cc
@@ -186,6 +186,7 @@ {"aboutProductTitle", IDS_PRODUCT_NAME}, {"aboutEndOfLifeTitle", IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_TITLE}, + {"aboutDeviceName", IDS_SETTINGS_ABOUT_PAGE_DEVICE_NAME}, {"aboutRelaunchAndPowerwash", IDS_SETTINGS_ABOUT_PAGE_RELAUNCH_AND_POWERWASH}, {"aboutRollbackInProgress", IDS_SETTINGS_UPGRADE_ROLLBACK_IN_PROGRESS}, @@ -307,6 +308,8 @@ html_source->AddBoolean("aboutIsDeveloperMode", base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kSystemDevMode)); + html_source->AddBoolean("isHostnameSettingEnabled", + features::IsHostnameSettingEnabled()); html_source->AddString("endOfLifeMessage", l10n_util::GetStringFUTF16(
diff --git a/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.cc b/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.cc index 7c8d870b..21bdb9b8 100644 --- a/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.cc +++ b/chrome/browser/ui/webui/settings/chromeos/calculator/size_calculator.cc
@@ -11,7 +11,6 @@ #include "base/task/thread_pool.h" #include "base/values.h" #include "chrome/browser/browsing_data/browsing_data_file_system_util.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" #include "chrome/browser/chromeos/crostini/crostini_features.h" #include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/profiles/profile.h" @@ -184,8 +183,7 @@ new browsing_data::ServiceWorkerHelper( storage_partition->GetServiceWorkerContext()), new browsing_data::CacheStorageHelper( - storage_partition->GetCacheStorageContext()), - BrowsingDataFlashLSOHelper::Create(profile_)); + storage_partition->GetCacheStorageContext())); } site_data_size_collector_->Fetch( base::BindOnce(&BrowsingDataSizeCalculator::OnGetBrowsingDataSize,
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_section.cc b/chrome/browser/ui/webui/settings/chromeos/device_section.cc index b9688248..5dcb2914 100644 --- a/chrome/browser/ui/webui/settings/chromeos/device_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/device_section.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/stylus_utils.h" #include "base/command_line.h" #include "base/feature_list.h" +#include "base/metrics/histogram_functions.h" #include "base/no_destructor.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -842,8 +843,15 @@ bool DeviceSection::LogMetric(mojom::Setting setting, base::Value& value) const { - // Unimplemented. - return false; + switch (setting) { + case mojom::Setting::kKeyboardFunctionKeys: + base::UmaHistogramBoolean("ChromeOS.Settings.Device.KeyboardFunctionKeys", + value.GetBool()); + return true; + + default: + return false; + } } void DeviceSection::RegisterHierarchy(HierarchyGenerator* generator) const {
diff --git a/chrome/browser/ui/webui/settings/chromeos/settings_user_action_tracker.h b/chrome/browser/ui/webui/settings/chromeos/settings_user_action_tracker.h index 6d5e320e..c77b0a29 100644 --- a/chrome/browser/ui/webui/settings/chromeos/settings_user_action_tracker.h +++ b/chrome/browser/ui/webui/settings/chromeos/settings_user_action_tracker.h
@@ -42,6 +42,8 @@ TestRecordSettingChangedBool); FRIEND_TEST_ALL_PREFIXES(SettingsUserActionTrackerTest, TestRecordSettingChangedInt); + FRIEND_TEST_ALL_PREFIXES(SettingsUserActionTrackerTest, + TestRecordSettingChangedBoolPref); // mojom::UserActionRecorder: void RecordPageFocus() override;
diff --git a/chrome/browser/ui/webui/settings/chromeos/settings_user_action_tracker_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/settings_user_action_tracker_unittest.cc index d545b37f..a4c61d65 100644 --- a/chrome/browser/ui/webui/settings/chromeos/settings_user_action_tracker_unittest.cc +++ b/chrome/browser/ui/webui/settings/chromeos/settings_user_action_tracker_unittest.cc
@@ -33,6 +33,8 @@ void SetUp() override { fake_hierarchy_.AddSettingMetadata(mojom::Section::kBluetooth, mojom::Setting::kBluetoothOnOff); + fake_hierarchy_.AddSettingMetadata(mojom::Section::kDevice, + mojom::Setting::kKeyboardFunctionKeys); fake_hierarchy_.AddSettingMetadata(mojom::Section::kPeople, mojom::Setting::kAddAccount); } @@ -86,5 +88,29 @@ mojom::Setting::kAddAccount); } +TEST_F(SettingsUserActionTrackerTest, TestRecordSettingChangedBoolPref) { + // Record that the keyboard function keys setting was toggled off. This + // setting is controlled by a pref and uses the pref-to-setting-metric + // converter flow. + tracker_.RecordSettingChangeWithDetails( + mojom::Setting::kKeyboardFunctionKeys, + mojom::SettingChangeValue::NewBoolValue(false)); + + // The umbrella metric for which setting was changed should be updated. Note + // that kKeyboardFunctionKeys has enum value of 411. + histogram_tester_.ExpectTotalCount("ChromeOS.Settings.SettingChanged", + /*count=*/1); + histogram_tester_.ExpectBucketCount("ChromeOS.Settings.SettingChanged", + /*sample=*/411, + /*count=*/1); + + // The LogMetric fn in the Device section should have been called. + const FakeOsSettingsSection* device_section = + static_cast<const FakeOsSettingsSection*>( + fake_sections_.GetSection(mojom::Section::kDevice)); + EXPECT_TRUE(device_section->logged_metrics().back() == + mojom::Setting::kKeyboardFunctionKeys); +} + } // namespace settings. } // namespace chromeos.
diff --git a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc b/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc index 602c098..6a9918d 100644 --- a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc +++ b/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc
@@ -80,9 +80,6 @@ {CookieTreeNode::DetailedInfo::TYPE_CACHE_STORAGE, IDS_SETTINGS_COOKIES_CACHE_STORAGE}, - {CookieTreeNode::DetailedInfo::TYPE_FLASH_LSO, - IDS_SETTINGS_COOKIES_FLASH_LSO}, - {CookieTreeNode::DetailedInfo::TYPE_MEDIA_LICENSES, IDS_SETTINGS_COOKIES_MEDIA_LICENSE}, {CookieTreeNode::DetailedInfo::TYPE_MEDIA_LICENSE,
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc index 3ddf0c9..fc70ad9 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
@@ -19,7 +19,6 @@ #include "base/test/simple_test_clock.h" #include "base/values.h" #include "build/build_config.h" -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/test_extension_system.h" @@ -105,43 +104,6 @@ {{"http://127.0.0.1", "location"}, {true, ""}}, // Localhost is secure. {{"http://[::1]", "location"}, {true, ""}}}; -#if BUILDFLAG(ENABLE_PLUGINS) -// Waits until a change is observed in content settings. -class FlashContentSettingsChangeWaiter : public content_settings::Observer { - public: - explicit FlashContentSettingsChangeWaiter(Profile* profile) - : profile_(profile) { - HostContentSettingsMapFactory::GetForProfile(profile)->AddObserver(this); - } - FlashContentSettingsChangeWaiter(const FlashContentSettingsChangeWaiter&) = - delete; - FlashContentSettingsChangeWaiter& operator=( - const FlashContentSettingsChangeWaiter&) = delete; - ~FlashContentSettingsChangeWaiter() override { - HostContentSettingsMapFactory::GetForProfile(profile_)->RemoveObserver( - this); - } - - // content_settings::Observer: - void OnContentSettingChanged( - const ContentSettingsPattern& primary_pattern, - const ContentSettingsPattern& secondary_pattern, - ContentSettingsType content_type, - const std::string& resource_identifier) override { - if (content_type == ContentSettingsType::PLUGINS) - Proceed(); - } - - void Wait() { run_loop_.Run(); } - - private: - void Proceed() { run_loop_.Quit(); } - - Profile* profile_; - base::RunLoop run_loop_; -}; -#endif - std::string GenerateFakeAppId(const GURL& url) { return web_app::GenerateAppIdFromURL(url); } @@ -191,9 +153,7 @@ : kNotifications(site_settings::ContentSettingsTypeToGroupName( ContentSettingsType::NOTIFICATIONS)), kCookies(site_settings::ContentSettingsTypeToGroupName( - ContentSettingsType::COOKIES)), - kFlash(site_settings::ContentSettingsTypeToGroupName( - ContentSettingsType::PLUGINS)) { + ContentSettingsType::COOKIES)) { #if defined(OS_CHROMEOS) user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>( std::make_unique<chromeos::MockUserManager>()); @@ -472,7 +432,6 @@ /*service_worker_helper=*/nullptr, /*data_shared_worker_helper=*/nullptr, /*cache_storage_helper=*/nullptr, - /*flash_lso_helper=*/nullptr, /*media_license_helper=*/nullptr); auto mock_cookies_tree_model = std::make_unique<CookiesTreeModel>( std::move(container), profile()->GetExtensionSpecialStoragePolicy()); @@ -516,7 +475,6 @@ // Content setting group name for the relevant ContentSettingsType. const std::string kNotifications; const std::string kCookies; - const std::string kFlash; const ContentSettingsType kPermissionNotifications = ContentSettingsType::NOTIFICATIONS; @@ -571,7 +529,6 @@ get_all_sites_args.AppendString(kCallbackId); base::Value category_list(base::Value::Type::LIST); category_list.Append(kNotifications); - category_list.Append(kFlash); get_all_sites_args.Append(std::move(category_list)); // Test all sites is empty when there are no preferences. @@ -596,7 +553,8 @@ map->SetContentSettingDefaultScope(url1, url1, ContentSettingsType::NOTIFICATIONS, std::string(), CONTENT_SETTING_BLOCK); - map->SetContentSettingDefaultScope(url2, url2, ContentSettingsType::PLUGINS, + map->SetContentSettingDefaultScope(url2, url2, + ContentSettingsType::NOTIFICATIONS, std::string(), CONTENT_SETTING_ALLOW); handler()->HandleGetAllSites(&get_all_sites_args); @@ -624,7 +582,8 @@ // Add an additional exception belonging to a different eTLD+1. const GURL url3("https://example2.net"); - map->SetContentSettingDefaultScope(url3, url3, ContentSettingsType::PLUGINS, + map->SetContentSettingDefaultScope(url3, url3, + ContentSettingsType::NOTIFICATIONS, std::string(), CONTENT_SETTING_BLOCK); handler()->HandleGetAllSites(&get_all_sites_args); @@ -774,7 +733,6 @@ get_recent_permissions_args.AppendString(kCallbackId); base::Value category_list(base::Value::Type::LIST); category_list.Append(kNotifications); - category_list.Append(kFlash); get_recent_permissions_args.Append(std::move(category_list)); get_recent_permissions_args.Append(3); @@ -839,26 +797,21 @@ ASSERT_TRUE(data.arg2()->GetBool()); base::Value::ConstListView recent_permissions = data.arg3()->GetList(); - EXPECT_EQ(3UL, recent_permissions.size()); + EXPECT_EQ(2UL, recent_permissions.size()); EXPECT_EQ(url1.spec(), - recent_permissions[2].FindKey("origin")->GetString()); - EXPECT_EQ(url2.spec(), recent_permissions[1].FindKey("origin")->GetString()); EXPECT_EQ(url1.spec(), recent_permissions[0].FindKey("origin")->GetString()); EXPECT_TRUE(recent_permissions[0].FindKey("incognito")->GetBool()); EXPECT_FALSE(recent_permissions[1].FindKey("incognito")->GetBool()); - EXPECT_FALSE(recent_permissions[2].FindKey("incognito")->GetBool()); base::Value::ConstListView incognito_url1_permissions = recent_permissions[0].FindKey("recentPermissions")->GetList(); base::Value::ConstListView url1_permissions = - recent_permissions[2].FindKey("recentPermissions")->GetList(); - base::Value::ConstListView url2_permissions = recent_permissions[1].FindKey("recentPermissions")->GetList(); - EXPECT_EQ(2UL, incognito_url1_permissions.size()); + EXPECT_EQ(1UL, incognito_url1_permissions.size()); EXPECT_EQ(kNotifications, incognito_url1_permissions[0].FindKey("type")->GetString()); @@ -867,20 +820,9 @@ EXPECT_EQ(kEmbargo, incognito_url1_permissions[0].FindKey("source")->GetString()); - EXPECT_EQ(kFlash, - incognito_url1_permissions[1].FindKey("type")->GetString()); - EXPECT_EQ(kAllowed, - incognito_url1_permissions[1].FindKey("setting")->GetString()); - EXPECT_EQ(kPreference, - incognito_url1_permissions[1].FindKey("source")->GetString()); - EXPECT_EQ(kNotifications, url1_permissions[0].FindKey("type")->GetString()); EXPECT_EQ(kBlocked, url1_permissions[0].FindKey("setting")->GetString()); EXPECT_EQ(kEmbargo, url1_permissions[0].FindKey("source")->GetString()); - - EXPECT_EQ(kFlash, url2_permissions[0].FindKey("type")->GetString()); - EXPECT_EQ(kAllowed, url2_permissions[0].FindKey("setting")->GetString()); - EXPECT_EQ(kPreference, url2_permissions[0].FindKey("source")->GetString()); } } @@ -1390,55 +1332,6 @@ site_settings::SiteSettingSource::kDefault, 4U); } -#if BUILDFLAG(ENABLE_PLUGINS) -TEST_F(SiteSettingsHandlerTest, ChangingFlashSettingForSiteIsRemembered) { - ChromePluginServiceFilter::GetInstance()->RegisterProfile(profile()); - FlashContentSettingsChangeWaiter waiter(profile()); - - const std::string origin_with_port("https://www.example.com:443"); - // The display name won't show the port if it's default for that scheme. - const std::string origin("https://www.example.com"); - base::ListValue get_args; - get_args.AppendString(kCallbackId); - get_args.AppendString(origin_with_port); - const GURL url(origin_with_port); - - HostContentSettingsMap* map = - HostContentSettingsMapFactory::GetForProfile(profile()); - // Make sure the site being tested doesn't already have this marker set. - EXPECT_EQ(nullptr, - map->GetWebsiteSetting(url, url, ContentSettingsType::PLUGINS_DATA, - std::string(), nullptr)); - - // Change the Flash setting. - base::ListValue set_args; - set_args.AppendString(origin_with_port); - { - auto category_list = std::make_unique<base::ListValue>(); - category_list->AppendString(kFlash); - set_args.Append(std::move(category_list)); - } - set_args.AppendString( - content_settings::ContentSettingToString(CONTENT_SETTING_BLOCK)); - handler()->HandleSetOriginPermissions(&set_args); - EXPECT_EQ(1U, web_ui()->call_data().size()); - waiter.Wait(); - - // Check that this site has now been marked for displaying Flash always, then - // clear it and check this works. - EXPECT_NE(nullptr, - map->GetWebsiteSetting(url, url, ContentSettingsType::PLUGINS_DATA, - std::string(), nullptr)); - base::ListValue clear_args; - clear_args.AppendString(origin_with_port); - handler()->HandleSetOriginPermissions(&set_args); - handler()->HandleClearFlashPref(&clear_args); - EXPECT_EQ(nullptr, - map->GetWebsiteSetting(url, url, ContentSettingsType::PLUGINS_DATA, - std::string(), nullptr)); -} -#endif - TEST_F(SiteSettingsHandlerTest, GetAndSetForInvalidURLs) { const std::string origin("arbitrary string"); EXPECT_FALSE(GURL(origin).is_valid());
diff --git a/chrome/browser/ui/webui/sync_internals_browsertest.js b/chrome/browser/ui/webui/sync_internals_browsertest.js index 2be5fd4..837c9c4f 100644 --- a/chrome/browser/ui/webui/sync_internals_browsertest.js +++ b/chrome/browser/ui/webui/sync_internals_browsertest.js
@@ -205,7 +205,6 @@ 'num_live': 'Live Entries', 'message': 'Message', 'state': 'State', - 'group_type': 'Group Type', }, { 'status': 'ok', @@ -214,7 +213,6 @@ 'num_live': 2793, 'message': '', 'state': 'Running', - 'group_type': 'Group UI', }, ], 'unrecoverable_error_detected': false
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.cc b/chrome/browser/ui/webui/sync_internals_message_handler.cc index cba4246..eddf879c 100644 --- a/chrome/browser/ui/webui/sync_internals_message_handler.cc +++ b/chrome/browser/ui/webui/sync_internals_message_handler.cc
@@ -65,7 +65,11 @@ SyncInternalsMessageHandler::SyncInternalsMessageHandler() : SyncInternalsMessageHandler(base::BindRepeating( - &syncer::sync_ui_util::ConstructAboutInformation)) {} + &syncer::sync_ui_util::ConstructAboutInformation, + syncer::sync_ui_util::IncludeSensitiveData(true))) { + // This class serves to display debug information to the user, so it's fine to + // include sensitive data in ConstructAboutInformation() above. +} SyncInternalsMessageHandler::SyncInternalsMessageHandler( AboutSyncDataDelegate about_sync_data_delegate)
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java index 48c4972..553afdc 100644 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java +++ b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java
@@ -4,13 +4,13 @@ package org.chromium.chrome.browser.video_tutorials; -import org.chromium.components.browser_ui.widget.image_tiles.ImageTile; - /** * Class encapsulating data needed to show a video tutorial on the UI. */ -public class Tutorial extends ImageTile { +public class Tutorial { public final @FeatureType int featureType; + public final String title; + public final String accessibilityText; public final String videoUrl; public final String posterUrl; public final String captionUrl; @@ -20,16 +20,13 @@ /** Constructor */ public Tutorial(@FeatureType int featureType, String title, String videoUrl, String posterUrl, String captionUrl, String shareUrl, int videoLength) { - super(createIdFromFeatureType(featureType), title, title); this.featureType = featureType; + this.title = title; + this.accessibilityText = title; this.videoUrl = videoUrl; this.posterUrl = posterUrl; this.captionUrl = captionUrl; this.shareUrl = shareUrl; this.videoLength = videoLength; } - - private static String createIdFromFeatureType(int featureType) { - return String.valueOf(featureType); - } }
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java index a840685..3634e886 100644 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java +++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java
@@ -50,7 +50,7 @@ @Override public void showVideoIPH(Tutorial tutorial) { mModel.set(VideoIPHProperties.VISIBILITY, true); - mModel.set(VideoIPHProperties.DISPLAY_TITLE, tutorial.displayTitle); + mModel.set(VideoIPHProperties.DISPLAY_TITLE, tutorial.title); mModel.set(VideoIPHProperties.VIDEO_LENGTH, VideoTutorialUtils.getVideoLengthString(tutorial.videoLength)); mModel.set(VideoIPHProperties.CLICK_LISTENER, () -> mOnClickListener.onResult(tutorial));
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java index 4079c7e..76bc411a 100644 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java +++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java
@@ -78,9 +78,9 @@ public void testShowIPH() { final Tutorial tutorial = createDummyTutorial(); TestThreadUtils.runOnUiThreadBlocking(() -> { mCoordinator.showVideoIPH(tutorial); }); - onView(withText(tutorial.displayTitle)).check(matches(isDisplayed())); + onView(withText(tutorial.title)).check(matches(isDisplayed())); onView(withText("5:35")).check(matches(isDisplayed())); - onView(withText(tutorial.displayTitle)).perform(ViewActions.click()); + onView(withText(tutorial.title)).perform(ViewActions.click()); Mockito.verify(mOnClickListener).onResult(Mockito.any()); onView(withId(R.id.close_button)).perform(ViewActions.click()); Mockito.verify(mOnDismissListener).onResult(Mockito.any());
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorTest.java index 484b47519..69e41bc 100644 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorTest.java +++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorTest.java
@@ -81,10 +81,10 @@ @SmallTest public void testShowList() { Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - onView(withText(tutorial.displayTitle)).check(matches(isDisplayed())); + onView(withText(tutorial.title)).check(matches(isDisplayed())); onView(withText(VideoTutorialUtils.getVideoLengthString(tutorial.videoLength))) .check(matches(isDisplayed())); - onView(withText(tutorial.displayTitle)).perform(ViewActions.click()); + onView(withText(tutorial.title)).perform(ViewActions.click()); Mockito.verify(mClickCallback).onResult(tutorial); } }
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java index bc5b9ee..cd5d6ae 100644 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java +++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java
@@ -57,7 +57,7 @@ private PropertyModel buildModelFromTutorial(Tutorial tutorial) { PropertyModel.Builder builder = new PropertyModel.Builder(TutorialCardProperties.ALL_KEYS) - .with(TutorialCardProperties.TITLE, tutorial.displayTitle) + .with(TutorialCardProperties.TITLE, tutorial.title) .with(TutorialCardProperties.VIDEO_LENGTH, VideoTutorialUtils.getVideoLengthString(tutorial.videoLength)) .with(TutorialCardProperties.CLICK_CALLBACK,
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java index 4934635d..83415ab 100644 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java +++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java
@@ -65,10 +65,16 @@ private static String histogramSuffixFromFeatureType(@FeatureType int feature) { switch (feature) { + case FeatureType.CHROME_INTRO: + return "ChromeIntro"; case FeatureType.DOWNLOAD: return "Download"; case FeatureType.SEARCH: return "Search"; + case FeatureType.VOICE_SEARCH: + return "VoiceSearch"; + case FeatureType.SUMMARY: + return "Summary"; default: return "Unknown"; }
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl index 4d83442a..9b7b395 100644 --- a/chrome/common/extensions/api/autotest_private.idl +++ b/chrome/common/extensions/api/autotest_private.idl
@@ -569,6 +569,9 @@ long framesExpected; // Number of frames actually shown for this animation. long framesProduced; + // Number of janks during this animation. A jank is counted when the current + // frame latency is larger than previous ones. + long jankCount; }; // Callback invoked to report the collection ui::ThroughputTracker data
diff --git a/chrome/common/ppapi_utils.cc b/chrome/common/ppapi_utils.cc index e760aa5..69fadf88 100644 --- a/chrome/common/ppapi_utils.cc +++ b/chrome/common/ppapi_utils.cc
@@ -75,7 +75,6 @@ #include "ppapi/c/private/ppb_file_ref_private.h" #include "ppapi/c/private/ppb_find_private.h" #include "ppapi/c/private/ppb_flash_font_file.h" -#include "ppapi/c/private/ppb_flash_fullscreen.h" #include "ppapi/c/private/ppb_host_resolver_private.h" #include "ppapi/c/private/ppb_isolated_file_system_private.h" #include "ppapi/c/private/ppb_pdf.h"
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc index c4a4e40..61d930b 100644 --- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc +++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -247,9 +247,11 @@ BSTR* error_text) { base::string16 user_name; base::string16 domain_name; + OSUserManager* os_user_manager = OSUserManager::Get(); + DCHECK(os_user_manager); bool is_ad_user = - OSUserManager::Get()->IsDeviceDomainJoined() && !sam_account_name.empty(); + os_user_manager->IsDeviceDomainJoined() && !sam_account_name.empty(); // Login via existing AD account mapping when the device is domain joined if // the AD account mapping is available. if (is_ad_user) { @@ -302,6 +304,14 @@ re2::RE2::FullMatch(local_account_name, "un:([^,]+)(?:,sn:([^,]+))?", &username, &serial_number); + // Only collect those user names that exist on the windows device. + base::string16 existing_sid; + HRESULT hr = os_user_manager->GetUserSID( + OSUserManager::GetLocalDomain().c_str(), + base::UTF8ToUTF16(username).c_str(), &existing_sid); + if (FAILED(hr)) + continue; + LOGFN(VERBOSE) << "RE2 username : " << username; LOGFN(VERBOSE) << "RE2 serial_number : " << serial_number; @@ -334,8 +344,6 @@ domain_name = OSUserManager::GetLocalDomain(); } - OSUserManager* os_user_manager = OSUserManager::Get(); - DCHECK(os_user_manager); LOGFN(VERBOSE) << "Get user sid for user " << user_name << " and domain name " << domain_name; HRESULT hr = os_user_manager->GetUserSID(domain_name.c_str(),
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc index 3145a51..058cf5f 100644 --- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc +++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
@@ -1832,6 +1832,49 @@ ASSERT_EQ(S_OK, FinishLogonProcess(true, true, 0)); } +// Customer configured invalid local account info. +TEST_F(GcpGaiaCredentialBaseCloudLocalAccountTest, + GetSerialization_InvalidLocalAccountToSerialNumberConfigured) { + // Set token result a valid access token. + fake_http_url_fetcher_factory()->SetFakeResponse( + GURL(gaia_urls_->oauth2_token_url().spec().c_str()), + FakeWinHttpUrlFetcher::Headers(), "{\"access_token\": \"dummy_token\"}"); + + // Set a fake serial number. + base::string16 serial_number = L"1234"; + GoogleRegistrationDataForTesting g_registration_data(serial_number); + + const wchar_t invalid_user_name_1[] = L"invalid_user_name_1"; + const wchar_t invalid_user_name_2[] = L"invalid_user_name_2"; + + // Invalid configuration in admin sdk. Don't set valid usernames. + std::string admin_sdk_response = base::StringPrintf( + "{\"customSchemas\": {\"Enhanced_desktop_security\": " + "{\"Local_Windows_accounts\":" + "[{ \"value\": \"un:%ls,sn:%ls\" },{ \"value\": \"un:%ls,sn:%ls\"}]}}}", + invalid_user_name_1, serial_number.c_str(), invalid_user_name_2, + serial_number.c_str()); + fake_http_url_fetcher_factory()->SetFakeResponse( + GURL(get_cd_user_url_.c_str()), FakeWinHttpUrlFetcher::Headers(), + admin_sdk_response); + + Microsoft::WRL::ComPtr<ITestCredential> test; + ASSERT_EQ(S_OK, cred_.As(&test)); + + ASSERT_EQ(S_OK, StartLogonProcessAndWait()); + + // Make sure new user was created since no valid mapping was found. + PSID sid = nullptr; + fake_os_user_manager()->GetUserSID(OSUserManager::GetLocalDomain().c_str(), + kDefaultUsername, &sid); + ASSERT_NE(nullptr, sid); + + // New user is created. + EXPECT_EQ(2ul, fake_os_user_manager()->GetUserCount()); + + ASSERT_EQ(S_OK, FinishLogonProcess(true, true, 0)); +} + TEST_F(GcpGaiaCredentialBaseCloudLocalAccountTest, MultipleLocalAccountInfo) { // Add the user as a local user. const wchar_t user_name[] = L"local_user"; @@ -1977,6 +2020,223 @@ } TEST_F(GcpGaiaCredentialBaseCloudLocalAccountTest, + OnlyOneValidUserToSerialMapping) { + // Add the user as a local user. + const wchar_t user_name[] = L"local_user"; + const wchar_t password[] = L"password"; + + CComBSTR local_sid; + DWORD error; + HRESULT hr = fake_os_user_manager()->AddUser( + user_name, password, L"fullname", L"comment", true, &local_sid, &error); + ASSERT_EQ(S_OK, hr); + ASSERT_EQ(0u, error); + + // Set token result as a valid access token. + fake_http_url_fetcher_factory()->SetFakeResponse( + GURL(gaia_urls_->oauth2_token_url().spec().c_str()), + FakeWinHttpUrlFetcher::Headers(), "{\"access_token\": \"dummy_token\"}"); + + std::string admin_sdk_response; + // Set a fake serial number. + base::string16 serial_number = L"1234"; + GoogleRegistrationDataForTesting g_registration_data(serial_number); + + const wchar_t another_user_name1[] = L"another_local_user_1"; + + // Set valid response from admin sdk with Local_Windows_accounts containing + // multiple mappings with matching "serial_number" in it and another + // one without serial number. + admin_sdk_response = base::StringPrintf( + "{\"customSchemas\": {\"Enhanced_desktop_security\": " + "{\"Local_Windows_accounts\":" + "[{ \"value\": \"un:%ls,sn:%ls\" },{ \"value\": \"un:%ls,sn:%ls\" }]}}}", + another_user_name1, serial_number.c_str(), user_name, + serial_number.c_str()); + fake_http_url_fetcher_factory()->SetFakeResponse( + GURL(get_cd_user_url_.c_str()), FakeWinHttpUrlFetcher::Headers(), + admin_sdk_response); + + Microsoft::WRL::ComPtr<ITestCredential> test; + ASSERT_EQ(S_OK, cred_.As(&test)); + + ASSERT_EQ(S_OK, StartLogonProcessAndWait()); + + EXPECT_EQ(test->GetFinalEmail(), kDefaultEmail); + + // Make sure no user was created and the login happens on the + // existing user instead. + PSID sid = nullptr; + EXPECT_EQ( + HRESULT_FROM_WIN32(NERR_UserNotFound), + fake_os_user_manager()->GetUserSID( + OSUserManager::GetLocalDomain().c_str(), kDefaultUsername, &sid)); + ASSERT_EQ(nullptr, sid); + + // Finishing logon process should trigger credential changed and trigger + // GetSerialization. + ASSERT_EQ(S_OK, FinishLogonProcess(true, true, 0)); + + // Verify that the registry entry for the user was created. + std::wstring sid_str(local_sid, SysStringLen(local_sid)); + + wchar_t gaia_id[256]; + ULONG length = base::size(gaia_id); + HRESULT gaia_id_hr = + GetUserProperty(sid_str.c_str(), kUserId, gaia_id, &length); + ASSERT_EQ(S_OK, gaia_id_hr); + ASSERT_TRUE(gaia_id[0]); + + // Verify that the authentication results dictionary is now empty. + ASSERT_TRUE(test->IsAuthenticationResultsEmpty()); +} + +TEST_F(GcpGaiaCredentialBaseCloudLocalAccountTest, OnlyOneValidUserMapping) { + // Add the user as a local user. + const wchar_t user_name[] = L"local_user"; + const wchar_t password[] = L"password"; + + CComBSTR local_sid; + DWORD error; + HRESULT hr = fake_os_user_manager()->AddUser( + user_name, password, L"fullname", L"comment", true, &local_sid, &error); + ASSERT_EQ(S_OK, hr); + ASSERT_EQ(0u, error); + + // Set token result as a valid access token. + fake_http_url_fetcher_factory()->SetFakeResponse( + GURL(gaia_urls_->oauth2_token_url().spec().c_str()), + FakeWinHttpUrlFetcher::Headers(), "{\"access_token\": \"dummy_token\"}"); + + std::string admin_sdk_response; + // Set a fake serial number. + base::string16 serial_number = L"1234"; + GoogleRegistrationDataForTesting g_registration_data(serial_number); + + const wchar_t another_user_name1[] = L"another_local_user_1"; + + // Set valid response from admin sdk with Local_Windows_accounts containing + // multiple mappings with matching "serial_number" in it and another + // one without serial number. + admin_sdk_response = base::StringPrintf( + "{\"customSchemas\": {\"Enhanced_desktop_security\": " + "{\"Local_Windows_accounts\":" + "[{ \"value\": \"un:%ls,sn:%ls\" },{ \"value\": \"un:%ls,sn:%ls\" }]}}}", + another_user_name1, serial_number.c_str(), user_name, + serial_number.c_str()); + fake_http_url_fetcher_factory()->SetFakeResponse( + GURL(get_cd_user_url_.c_str()), FakeWinHttpUrlFetcher::Headers(), + admin_sdk_response); + + Microsoft::WRL::ComPtr<ITestCredential> test; + ASSERT_EQ(S_OK, cred_.As(&test)); + + ASSERT_EQ(S_OK, StartLogonProcessAndWait()); + + EXPECT_EQ(test->GetFinalEmail(), kDefaultEmail); + + // Make sure no user was created and the login happens on the + // existing user instead. + PSID sid = nullptr; + EXPECT_EQ( + HRESULT_FROM_WIN32(NERR_UserNotFound), + fake_os_user_manager()->GetUserSID( + OSUserManager::GetLocalDomain().c_str(), kDefaultUsername, &sid)); + ASSERT_EQ(nullptr, sid); + + // Finishing logon process should trigger credential changed and trigger + // GetSerialization. + ASSERT_EQ(S_OK, FinishLogonProcess(true, true, 0)); + + // Verify that the registry entry for the user was created. + std::wstring sid_str(local_sid, SysStringLen(local_sid)); + + wchar_t gaia_id[256]; + ULONG length = base::size(gaia_id); + HRESULT gaia_id_hr = + GetUserProperty(sid_str.c_str(), kUserId, gaia_id, &length); + ASSERT_EQ(S_OK, gaia_id_hr); + ASSERT_TRUE(gaia_id[0]); + + // Verify that the authentication results dictionary is now empty. + ASSERT_TRUE(test->IsAuthenticationResultsEmpty()); +} + +TEST_F(GcpGaiaCredentialBaseCloudLocalAccountTest, + InvalidUsersToSerialNumberMapping) { + // Add the user as a local user. + const wchar_t user_name[] = L"local_user"; + const wchar_t password[] = L"password"; + + CComBSTR local_sid; + DWORD error; + HRESULT hr = fake_os_user_manager()->AddUser( + user_name, password, L"fullname", L"comment", true, &local_sid, &error); + ASSERT_EQ(S_OK, hr); + ASSERT_EQ(0u, error); + + // Set token result as a valid access token. + fake_http_url_fetcher_factory()->SetFakeResponse( + GURL(gaia_urls_->oauth2_token_url().spec().c_str()), + FakeWinHttpUrlFetcher::Headers(), "{\"access_token\": \"dummy_token\"}"); + + std::string admin_sdk_response; + // Set a fake serial number. + base::string16 serial_number = L"1234"; + GoogleRegistrationDataForTesting g_registration_data(serial_number); + + const wchar_t another_user_name1[] = L"another_local_user_1"; + const wchar_t another_user_name2[] = L"another_local_user_2"; + + // Set valid response from admin sdk with Local_Windows_accounts containing + // multiple mappings with matching "serial_number" in it and another + // one without serial number. + admin_sdk_response = base::StringPrintf( + "{\"customSchemas\": {\"Enhanced_desktop_security\": " + "{\"Local_Windows_accounts\":" + "[{ \"value\": \"un:%ls,sn:%ls\" },{ \"value\": \"un:%ls,sn:%ls\" },{ " + " \"value\": \"un:%ls\" }]}}}", + another_user_name1, serial_number.c_str(), another_user_name2, + serial_number.c_str(), user_name); + fake_http_url_fetcher_factory()->SetFakeResponse( + GURL(get_cd_user_url_.c_str()), FakeWinHttpUrlFetcher::Headers(), + admin_sdk_response); + + Microsoft::WRL::ComPtr<ITestCredential> test; + ASSERT_EQ(S_OK, cred_.As(&test)); + + ASSERT_EQ(S_OK, StartLogonProcessAndWait()); + + EXPECT_EQ(test->GetFinalEmail(), kDefaultEmail); + + // Make sure no user was created and the login happens on the + // existing user instead. + PSID sid = nullptr; + EXPECT_EQ( + HRESULT_FROM_WIN32(NERR_UserNotFound), + fake_os_user_manager()->GetUserSID( + OSUserManager::GetLocalDomain().c_str(), kDefaultUsername, &sid)); + ASSERT_EQ(nullptr, sid); + + // Finishing logon process should trigger credential changed and trigger + // GetSerialization. + ASSERT_EQ(S_OK, FinishLogonProcess(true, true, 0)); + + // Verify that the registry entry for the user was created. + std::wstring sid_str(local_sid, SysStringLen(local_sid)); + + wchar_t gaia_id[256]; + ULONG length = base::size(gaia_id); + HRESULT gaia_id_hr = + GetUserProperty(sid_str.c_str(), kUserId, gaia_id, &length); + ASSERT_EQ(S_OK, gaia_id_hr); + ASSERT_TRUE(gaia_id[0]); + + // Verify that the authentication results dictionary is now empty. + ASSERT_TRUE(test->IsAuthenticationResultsEmpty()); +} + +TEST_F(GcpGaiaCredentialBaseCloudLocalAccountTest, MultipleValidLocalAccountInfoMapping) { // Set token result as a valid access token. fake_http_url_fetcher_factory()->SetFakeResponse(
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index bc321ff..c07de45 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc
@@ -320,7 +320,7 @@ InstallShortcutLevel install_level, InstallShortcutOperation install_operation) { bool do_not_create_any_shortcuts = false; - prefs.GetBool(master_preferences::kDoNotCreateAnyShortcuts, + prefs.GetBool(initial_preferences::kDoNotCreateAnyShortcuts, &do_not_create_any_shortcuts); if (do_not_create_any_shortcuts) return; @@ -329,11 +329,11 @@ bool do_not_create_desktop_shortcut = false; bool do_not_create_quick_launch_shortcut = false; bool do_not_create_taskbar_shortcut = false; - prefs.GetBool(master_preferences::kDoNotCreateDesktopShortcut, + prefs.GetBool(initial_preferences::kDoNotCreateDesktopShortcut, &do_not_create_desktop_shortcut); - prefs.GetBool(master_preferences::kDoNotCreateQuickLaunchShortcut, + prefs.GetBool(initial_preferences::kDoNotCreateQuickLaunchShortcut, &do_not_create_quick_launch_shortcut); - prefs.GetBool(master_preferences::kDoNotCreateTaskbarShortcut, + prefs.GetBool(initial_preferences::kDoNotCreateTaskbarShortcut, &do_not_create_taskbar_shortcut); // The default operation on update is to overwrite shortcuts with the @@ -505,7 +505,8 @@ installer_state.SetStage(REGISTERING_CHROME); bool make_chrome_default = false; - prefs.GetBool(master_preferences::kMakeChromeDefault, &make_chrome_default); + prefs.GetBool(initial_preferences::kMakeChromeDefault, + &make_chrome_default); // If this is not the user's first Chrome install, but they have chosen // Chrome to become their default browser on the download page, we must @@ -514,7 +515,7 @@ bool force_chrome_default_for_user = false; if (result == NEW_VERSION_UPDATED || result == INSTALL_REPAIRED || result == OLD_VERSION_DOWNGRADE || result == IN_USE_DOWNGRADE) { - prefs.GetBool(master_preferences::kMakeChromeDefaultForUser, + prefs.GetBool(initial_preferences::kMakeChromeDefaultForUser, &force_chrome_default_for_user); }
diff --git a/chrome/installer/setup/install_unittest.cc b/chrome/installer/setup/install_unittest.cc index 13f57d7..99ca64b 100644 --- a/chrome/installer/setup/install_unittest.cc +++ b/chrome/installer/setup/install_unittest.cc
@@ -280,9 +280,9 @@ const char* pref_name; bool is_desired; } desired_prefs[] = { - {installer::master_preferences::kDoNotCreateDesktopShortcut, + {installer::initial_preferences::kDoNotCreateDesktopShortcut, do_not_create_desktop_shortcut}, - {installer::master_preferences::kDoNotCreateQuickLaunchShortcut, + {installer::initial_preferences::kDoNotCreateQuickLaunchShortcut, do_not_create_quick_launch_shortcut}, };
diff --git a/chrome/installer/setup/installer_state.cc b/chrome/installer/setup/installer_state.cc index e2ecd9fb..33f4fe5 100644 --- a/chrome/installer/setup/installer_state.cc +++ b/chrome/installer/setup/installer_state.cc
@@ -63,14 +63,14 @@ const InstallationState& machine_state) { Clear(); - set_level(GetMasterPreference(prefs, master_preferences::kSystemLevel, false) + set_level(GetMasterPreference(prefs, initial_preferences::kSystemLevel, false) ? SYSTEM_LEVEL : USER_LEVEL); verbose_logging_ = - GetMasterPreference(prefs, master_preferences::kVerboseLogging, false); + GetMasterPreference(prefs, initial_preferences::kVerboseLogging, false); - msi_ = GetMasterPreference(prefs, master_preferences::kMsi, false); + msi_ = GetMasterPreference(prefs, initial_preferences::kMsi, false); if (!msi_) { const ProductState* product_state = machine_state.GetProductState(system_install());
diff --git a/chrome/installer/setup/setup_install_details.cc b/chrome/installer/setup/setup_install_details.cc index fd4b3ad..f25607c 100644 --- a/chrome/installer/setup/setup_install_details.cc +++ b/chrome/installer/setup/setup_install_details.cc
@@ -60,7 +60,7 @@ // In all three cases the value is sussed out in MasterPreferences // initialization. bool system_level = false; - master_preferences.GetBool(installer::master_preferences::kSystemLevel, + master_preferences.GetBool(installer::initial_preferences::kSystemLevel, &system_level); details->set_system_level(system_level);
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 5a339503a..10892c3 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc
@@ -1203,7 +1203,7 @@ installer_state.SetStage(FINISHING); bool do_not_register_for_update_launch = false; - prefs.GetBool(master_preferences::kDoNotRegisterForUpdateLaunch, + prefs.GetBool(initial_preferences::kDoNotRegisterForUpdateLaunch, &do_not_register_for_update_launch); bool write_chrome_launch_string = (!do_not_register_for_update_launch && @@ -1217,7 +1217,7 @@ VLOG(1) << "First install successful."; // We never want to launch Chrome in system level install mode. bool do_not_launch_chrome = false; - prefs.GetBool(master_preferences::kDoNotLaunchChrome, + prefs.GetBool(initial_preferences::kDoNotLaunchChrome, &do_not_launch_chrome); if (!system_install && !do_not_launch_chrome) LaunchChromeBrowser(installer_state.target_path()); @@ -1236,7 +1236,7 @@ installer_state.target_path().AppendASCII( installer::kDefaultMasterPrefs)); std::string install_id; - if (prefs.GetString(installer::master_preferences::kMsiProductId, + if (prefs.GetString(installer::initial_preferences::kMsiProductId, &install_id)) { // A currently active MSI install will have specified the master- // preferences file on the command-line that includes the product-id. @@ -1322,7 +1322,7 @@ InitializeInstallDetails(cmd_line, prefs); bool system_install = false; - prefs.GetBool(installer::master_preferences::kSystemLevel, &system_install); + prefs.GetBool(installer::initial_preferences::kSystemLevel, &system_install); VLOG(1) << "system install is " << system_install; InstallationState original_state;
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc index b65b6739..675de27 100644 --- a/chrome/installer/setup/setup_util.cc +++ b/chrome/installer/setup/setup_util.cc
@@ -597,7 +597,8 @@ bool IsDowngradeAllowed(const MasterPreferences& prefs) { bool allow_downgrade = false; - return prefs.GetBool(master_preferences::kAllowDowngrade, &allow_downgrade) && + return prefs.GetBool(initial_preferences::kAllowDowngrade, + &allow_downgrade) && allow_downgrade; }
diff --git a/chrome/installer/util/initial_preferences.cc b/chrome/installer/util/initial_preferences.cc index af7e0ab..41c47c33 100644 --- a/chrome/installer/util/initial_preferences.cc +++ b/chrome/installer/util/initial_preferences.cc
@@ -116,26 +116,26 @@ const char* distribution_switch; } translate_switches[] = { {installer::switches::kAllowDowngrade, - installer::master_preferences::kAllowDowngrade}, + installer::initial_preferences::kAllowDowngrade}, {installer::switches::kDisableLogging, - installer::master_preferences::kDisableLogging}, - {installer::switches::kMsi, installer::master_preferences::kMsi}, + installer::initial_preferences::kDisableLogging}, + {installer::switches::kMsi, installer::initial_preferences::kMsi}, {installer::switches::kDoNotRegisterForUpdateLaunch, - installer::master_preferences::kDoNotRegisterForUpdateLaunch}, + installer::initial_preferences::kDoNotRegisterForUpdateLaunch}, {installer::switches::kDoNotLaunchChrome, - installer::master_preferences::kDoNotLaunchChrome}, + installer::initial_preferences::kDoNotLaunchChrome}, {installer::switches::kMakeChromeDefault, - installer::master_preferences::kMakeChromeDefault}, + installer::initial_preferences::kMakeChromeDefault}, {installer::switches::kSystemLevel, - installer::master_preferences::kSystemLevel}, + installer::initial_preferences::kSystemLevel}, {installer::switches::kVerboseLogging, - installer::master_preferences::kVerboseLogging}, + installer::initial_preferences::kVerboseLogging}, }; - std::string name(installer::master_preferences::kDistroDict); + std::string name(installer::initial_preferences::kDistroDict); for (size_t i = 0; i < base::size(translate_switches); ++i) { if (cmd_line.HasSwitch(translate_switches[i].cmd_line_switch)) { - name.assign(installer::master_preferences::kDistroDict); + name.assign(installer::initial_preferences::kDistroDict); name.append(".").append(translate_switches[i].distribution_switch); master_dictionary_->SetBoolean(name, true); } @@ -145,8 +145,8 @@ std::wstring str_value( cmd_line.GetSwitchValueNative(installer::switches::kLogFile)); if (!str_value.empty()) { - name.assign(installer::master_preferences::kDistroDict); - name.append(".").append(installer::master_preferences::kLogFile); + name.assign(installer::initial_preferences::kDistroDict); + name.append(".").append(installer::initial_preferences::kLogFile); master_dictionary_->SetString(name, str_value); } @@ -158,14 +158,14 @@ env->GetVar(env_vars::kGoogleUpdateIsMachineEnvVar, &is_machine_var); if (is_machine_var == "1") { VLOG(1) << "Taking system-level from environment."; - name.assign(installer::master_preferences::kDistroDict); - name.append(".").append(installer::master_preferences::kSystemLevel); + name.assign(installer::initial_preferences::kDistroDict); + name.append(".").append(installer::initial_preferences::kSystemLevel); master_dictionary_->SetBoolean(name, true); } } // Cache a pointer to the distribution dictionary. Ignore errors if any. - master_dictionary_->GetDictionary(installer::master_preferences::kDistroDict, + master_dictionary_->GetDictionary(installer::initial_preferences::kDistroDict, &distribution_); #endif } @@ -195,7 +195,7 @@ } else { // Cache a pointer to the distribution dictionary. master_dictionary_->GetDictionary( - installer::master_preferences::kDistroDict, &distribution_); + installer::initial_preferences::kDistroDict, &distribution_); } EnforceLegacyPreferences(); @@ -216,9 +216,9 @@ GetBool(kCreateAllShortcuts, &create_all_shortcuts); if (!create_all_shortcuts) { distribution_->SetBoolean( - installer::master_preferences::kDoNotCreateDesktopShortcut, true); + installer::initial_preferences::kDoNotCreateDesktopShortcut, true); distribution_->SetBoolean( - installer::master_preferences::kDoNotCreateQuickLaunchShortcut, true); + installer::initial_preferences::kDoNotCreateQuickLaunchShortcut, true); } // Deprecated boolean import master preferences now mapped to their duplicates @@ -282,8 +282,8 @@ bool MasterPreferences::GetExtensionsBlock( base::DictionaryValue** extensions) const { - return master_dictionary_->GetDictionary(master_preferences::kExtensionsBlock, - extensions); + return master_dictionary_->GetDictionary( + initial_preferences::kExtensionsBlock, extensions); } std::string MasterPreferences::GetCompressedVariationsSeed() const {
diff --git a/chrome/installer/util/initial_preferences_constants.cc b/chrome/installer/util/initial_preferences_constants.cc index 73b4478e..718b1d5f 100644 --- a/chrome/installer/util/initial_preferences_constants.cc +++ b/chrome/installer/util/initial_preferences_constants.cc
@@ -5,7 +5,7 @@ #include "chrome/installer/util/initial_preferences_constants.h" namespace installer { -namespace master_preferences { +namespace initial_preferences { const char kDisableLogging[] = "disable_logging"; const char kDistroDict[] = "distribution"; @@ -31,5 +31,5 @@ const char kExtensionsBlock[] = "extensions.settings"; const char kAllowDowngrade[] = "allow_downgrade"; -} // namespace master_preferences +} // namespace initial_preferences } // namespace installer
diff --git a/chrome/installer/util/initial_preferences_constants.h b/chrome/installer/util/initial_preferences_constants.h index ae9df5f..c3230ae5 100644 --- a/chrome/installer/util/initial_preferences_constants.h +++ b/chrome/installer/util/initial_preferences_constants.h
@@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// This file contains the constants used to process master_preferences files +// This file contains the constants used to process initial_preferences files // used by setup and first run. #ifndef CHROME_INSTALLER_UTIL_INITIAL_PREFERENCES_CONSTANTS_H_ #define CHROME_INSTALLER_UTIL_INITIAL_PREFERENCES_CONSTANTS_H_ namespace installer { -namespace master_preferences { +namespace initial_preferences { // All the preferences below are expected to be inside the JSON "distribution" // block. Some of them also have equivalent command line option. If same option -// is specified in master preference as well as command line, the command line +// is specified in initial preference as well as command line, the command line // value takes precedence. // Boolean pref that disables all logging. @@ -59,12 +59,12 @@ extern const char kSystemLevel[]; // Boolean. Run installer in verbose mode. Cmd line override present. extern const char kVerboseLogging[]; -// Name of the block that contains the extensions on the master preferences. +// Name of the block that contains the extensions on the initial preferences. extern const char kExtensionsBlock[]; // Boolean. Allow Chrome to be downgraded to a previous version if true. extern const char kAllowDowngrade[]; -} // namespace master_preferences +} // namespace initial_preferences } // namespace installer #endif // CHROME_INSTALLER_UTIL_INITIAL_PREFERENCES_CONSTANTS_H_
diff --git a/chrome/installer/util/initial_preferences_unittest.cc b/chrome/installer/util/initial_preferences_unittest.cc index 0149e82d..0c5734e91 100644 --- a/chrome/installer/util/initial_preferences_unittest.cc +++ b/chrome/installer/util/initial_preferences_unittest.cc
@@ -94,16 +94,16 @@ EXPECT_TRUE(prefs.read_from_file()); const char* const expected_true[] = { - installer::master_preferences::kDoNotCreateAnyShortcuts, - installer::master_preferences::kDoNotCreateDesktopShortcut, - installer::master_preferences::kDoNotCreateQuickLaunchShortcut, - installer::master_preferences::kDoNotCreateTaskbarShortcut, - installer::master_preferences::kDoNotLaunchChrome, - installer::master_preferences::kMakeChromeDefault, - installer::master_preferences::kMakeChromeDefaultForUser, - installer::master_preferences::kSystemLevel, - installer::master_preferences::kVerboseLogging, - installer::master_preferences::kRequireEula, + installer::initial_preferences::kDoNotCreateAnyShortcuts, + installer::initial_preferences::kDoNotCreateDesktopShortcut, + installer::initial_preferences::kDoNotCreateQuickLaunchShortcut, + installer::initial_preferences::kDoNotCreateTaskbarShortcut, + installer::initial_preferences::kDoNotLaunchChrome, + installer::initial_preferences::kMakeChromeDefault, + installer::initial_preferences::kMakeChromeDefaultForUser, + installer::initial_preferences::kSystemLevel, + installer::initial_preferences::kVerboseLogging, + installer::initial_preferences::kRequireEula, }; for (size_t i = 0; i < base::size(expected_true); ++i) { @@ -114,7 +114,7 @@ std::string str_value; EXPECT_TRUE(prefs.GetString( - installer::master_preferences::kDistroImportBookmarksFromFilePref, + installer::initial_preferences::kDistroImportBookmarksFromFilePref, &str_value)); EXPECT_STREQ("c:\\foo", str_value.c_str()); } @@ -136,9 +136,9 @@ EXPECT_TRUE(prefs.read_from_file()); ExpectedBooleans expected_bool[] = { - {installer::master_preferences::kDoNotCreateDesktopShortcut, true}, - {installer::master_preferences::kDoNotCreateQuickLaunchShortcut, true}, - {installer::master_preferences::kDoNotLaunchChrome, false}, + {installer::initial_preferences::kDoNotCreateDesktopShortcut, true}, + {installer::initial_preferences::kDoNotCreateQuickLaunchShortcut, true}, + {installer::initial_preferences::kDoNotLaunchChrome, false}, }; bool value = false; @@ -148,9 +148,9 @@ } const char* const missing_bools[] = { - installer::master_preferences::kDoNotRegisterForUpdateLaunch, - installer::master_preferences::kMakeChromeDefault, - installer::master_preferences::kMakeChromeDefaultForUser, + installer::initial_preferences::kDoNotRegisterForUpdateLaunch, + installer::initial_preferences::kMakeChromeDefault, + installer::initial_preferences::kMakeChromeDefaultForUser, }; for (size_t i = 0; i < base::size(missing_bools); ++i) { @@ -159,7 +159,7 @@ std::string str_value; EXPECT_FALSE(prefs.GetString( - installer::master_preferences::kDistroImportBookmarksFromFilePref, + installer::initial_preferences::kDistroImportBookmarksFromFilePref, &str_value)); } @@ -248,9 +248,9 @@ // Check prefs that do not have any equivalent command line option. ExpectedBooleans expected_bool[] = { - {installer::master_preferences::kDoNotLaunchChrome, true}, - {installer::master_preferences::kSystemLevel, true}, - {installer::master_preferences::kVerboseLogging, false}, + {installer::initial_preferences::kDoNotLaunchChrome, true}, + {installer::initial_preferences::kSystemLevel, true}, + {installer::initial_preferences::kVerboseLogging, false}, }; // Now check that prefs got merged correctly. @@ -269,7 +269,7 @@ cmd_line.ParseFromString(cmd_str); installer::MasterPreferences prefs2(cmd_line); ExpectedBooleans expected_bool2[] = { - {installer::master_preferences::kDoNotLaunchChrome, true}, + {installer::initial_preferences::kDoNotLaunchChrome, true}, }; for (size_t i = 0; i < base::size(expected_bool2); ++i) { @@ -279,9 +279,9 @@ } EXPECT_FALSE( - prefs2.GetBool(installer::master_preferences::kSystemLevel, &value)); + prefs2.GetBool(installer::initial_preferences::kSystemLevel, &value)); EXPECT_FALSE( - prefs2.GetBool(installer::master_preferences::kVerboseLogging, &value)); + prefs2.GetBool(installer::initial_preferences::kVerboseLogging, &value)); } TEST_F(MasterPreferencesTest, TestDefaultInstallConfig) { @@ -312,11 +312,11 @@ bool do_not_create_desktop_shortcut = false; bool do_not_create_quick_launch_shortcut = false; bool do_not_create_taskbar_shortcut = false; - prefs.GetBool(installer::master_preferences::kDoNotCreateDesktopShortcut, + prefs.GetBool(installer::initial_preferences::kDoNotCreateDesktopShortcut, &do_not_create_desktop_shortcut); - prefs.GetBool(installer::master_preferences::kDoNotCreateQuickLaunchShortcut, + prefs.GetBool(installer::initial_preferences::kDoNotCreateQuickLaunchShortcut, &do_not_create_quick_launch_shortcut); - prefs.GetBool(installer::master_preferences::kDoNotCreateTaskbarShortcut, + prefs.GetBool(installer::initial_preferences::kDoNotCreateTaskbarShortcut, &do_not_create_taskbar_shortcut); // create_all_shortcuts is a legacy preference that should only enforce // do_not_create_desktop_shortcut and do_not_create_quick_launch_shortcut @@ -360,11 +360,11 @@ bool do_not_create_desktop_shortcut = false; bool do_not_create_quick_launch_shortcut = false; bool do_not_create_taskbar_shortcut = false; - prefs.GetBool(installer::master_preferences::kDoNotCreateDesktopShortcut, + prefs.GetBool(installer::initial_preferences::kDoNotCreateDesktopShortcut, &do_not_create_desktop_shortcut); - prefs.GetBool(installer::master_preferences::kDoNotCreateQuickLaunchShortcut, + prefs.GetBool(installer::initial_preferences::kDoNotCreateQuickLaunchShortcut, &do_not_create_quick_launch_shortcut); - prefs.GetBool(installer::master_preferences::kDoNotCreateTaskbarShortcut, + prefs.GetBool(installer::initial_preferences::kDoNotCreateTaskbarShortcut, &do_not_create_taskbar_shortcut); EXPECT_FALSE(do_not_create_desktop_shortcut); EXPECT_FALSE(do_not_create_quick_launch_shortcut); @@ -384,11 +384,11 @@ bool do_not_create_desktop_shortcut = false; bool do_not_create_quick_launch_shortcut = false; bool do_not_create_taskbar_shortcut = false; - prefs.GetBool(installer::master_preferences::kDoNotCreateDesktopShortcut, + prefs.GetBool(installer::initial_preferences::kDoNotCreateDesktopShortcut, &do_not_create_desktop_shortcut); - prefs.GetBool(installer::master_preferences::kDoNotCreateQuickLaunchShortcut, + prefs.GetBool(installer::initial_preferences::kDoNotCreateQuickLaunchShortcut, &do_not_create_quick_launch_shortcut); - prefs.GetBool(installer::master_preferences::kDoNotCreateTaskbarShortcut, + prefs.GetBool(installer::initial_preferences::kDoNotCreateTaskbarShortcut, &do_not_create_taskbar_shortcut); EXPECT_FALSE(do_not_create_desktop_shortcut); EXPECT_FALSE(do_not_create_quick_launch_shortcut); @@ -401,7 +401,7 @@ installer::MasterPreferences prefs( base::CommandLine(base::FilePath(FILE_PATH_LITERAL("setup.exe")))); bool value = false; - prefs.GetBool(installer::master_preferences::kSystemLevel, &value); + prefs.GetBool(installer::initial_preferences::kSystemLevel, &value); EXPECT_FALSE(value); } { @@ -409,7 +409,7 @@ installer::MasterPreferences prefs( base::CommandLine(base::FilePath(FILE_PATH_LITERAL("setup.exe")))); bool value = false; - prefs.GetBool(installer::master_preferences::kSystemLevel, &value); + prefs.GetBool(installer::initial_preferences::kSystemLevel, &value); EXPECT_TRUE(value); } { @@ -417,7 +417,7 @@ installer::MasterPreferences prefs( base::CommandLine(base::FilePath(FILE_PATH_LITERAL("setup.exe")))); bool value = false; - prefs.GetBool(installer::master_preferences::kSystemLevel, &value); + prefs.GetBool(installer::initial_preferences::kSystemLevel, &value); EXPECT_FALSE(value); } { @@ -425,7 +425,7 @@ installer::MasterPreferences prefs( base::CommandLine(base::FilePath(FILE_PATH_LITERAL("setup.exe")))); bool value = false; - prefs.GetBool(installer::master_preferences::kSystemLevel, &value); + prefs.GetBool(installer::initial_preferences::kSystemLevel, &value); EXPECT_FALSE(value); } }
diff --git a/chrome/installer/util/logging_installer.cc b/chrome/installer/util/logging_installer.cc index 9f6f09a..9c98481 100644 --- a/chrome/installer/util/logging_installer.cc +++ b/chrome/installer/util/logging_installer.cc
@@ -80,7 +80,7 @@ installer_logging_ = true; bool value = false; - if (prefs.GetBool(installer::master_preferences::kDisableLogging, &value) && + if (prefs.GetBool(installer::initial_preferences::kDisableLogging, &value) && value) { return; } @@ -93,7 +93,7 @@ settings.log_file_path = log_file_path.value().c_str(); logging::InitLogging(settings); - if (prefs.GetBool(installer::master_preferences::kVerboseLogging, &value) && + if (prefs.GetBool(installer::initial_preferences::kVerboseLogging, &value) && value) { logging::SetMinLogLevel(logging::LOG_VERBOSE); } else { @@ -112,7 +112,7 @@ base::FilePath GetLogFilePath(const installer::MasterPreferences& prefs) { std::string path; - prefs.GetString(installer::master_preferences::kLogFile, &path); + prefs.GetString(installer::initial_preferences::kLogFile, &path); if (!path.empty()) return base::FilePath(base::UTF8ToWide(path));
diff --git a/chrome/services/sharing/nearby/platform_v2/ble_medium.cc b/chrome/services/sharing/nearby/platform_v2/ble_medium.cc index ff38696c..58e16ca8 100644 --- a/chrome/services/sharing/nearby/platform_v2/ble_medium.cc +++ b/chrome/services/sharing/nearby/platform_v2/ble_medium.cc
@@ -40,7 +40,7 @@ service_uuid, std::vector<uint8_t>(advertisement.data(), advertisement.data() + advertisement.size()), - &pending_advertisement); + /*use_scan_data=*/true, &pending_advertisement); if (!success || !pending_advertisement.is_valid()) return false;
diff --git a/chrome/services/sharing/nearby/test_support/fake_adapter.cc b/chrome/services/sharing/nearby/test_support/fake_adapter.cc index 452affa6..b43dd9d 100644 --- a/chrome/services/sharing/nearby/test_support/fake_adapter.cc +++ b/chrome/services/sharing/nearby/test_support/fake_adapter.cc
@@ -106,6 +106,7 @@ void FakeAdapter::RegisterAdvertisement( const device::BluetoothUUID& service_uuid, const std::vector<uint8_t>& service_data, + bool use_scan_response, RegisterAdvertisementCallback callback) { if (!should_advertisement_registration_succeed_) { std::move(callback).Run(mojo::NullRemote());
diff --git a/chrome/services/sharing/nearby/test_support/fake_adapter.h b/chrome/services/sharing/nearby/test_support/fake_adapter.h index 188759b..372fbbc 100644 --- a/chrome/services/sharing/nearby/test_support/fake_adapter.h +++ b/chrome/services/sharing/nearby/test_support/fake_adapter.h
@@ -29,6 +29,7 @@ AddObserverCallback callback) override; void RegisterAdvertisement(const device::BluetoothUUID& service_uuid, const std::vector<uint8_t>& service_data, + bool use_scan_response, RegisterAdvertisementCallback callback) override; void SetDiscoverable(bool discoverable, SetDiscoverableCallback callback) override;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index e1d041a..7be09ad2 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1168,6 +1168,7 @@ "../browser/pdf/pdf_extension_test_util.cc", "../browser/pdf/pdf_extension_test_util.h", "../browser/performance_manager/background_tab_loading_policy_browsertest.cc", + "../browser/performance_manager/frame_node_impl_browsertest.cc", "../browser/performance_manager/graph/page_node_impl_browsertest.cc", "../browser/performance_manager/mechanisms/page_discarder_browsertest.cc", "../browser/performance_manager/page_load_tracker_decorator_browsertest.cc", @@ -4841,12 +4842,8 @@ "../browser/nearby_sharing/instantmessaging/receive_messages_express_unittest.cc", "../browser/nearby_sharing/instantmessaging/send_message_express_unittest.cc", "../browser/nearby_sharing/instantmessaging/stream_parser_unittest.cc", - "../browser/nearby_sharing/mock_nearby_connections.cc", - "../browser/nearby_sharing/mock_nearby_connections.h", "../browser/nearby_sharing/mock_nearby_process_manager.cc", "../browser/nearby_sharing/mock_nearby_process_manager.h", - "../browser/nearby_sharing/mock_nearby_sharing_decoder.cc", - "../browser/nearby_sharing/mock_nearby_sharing_decoder.h", "../browser/nearby_sharing/mock_nearby_sharing_service.cc", "../browser/nearby_sharing/mock_nearby_sharing_service.h", "../browser/nearby_sharing/nearby_confirmation_manager_unittest.cc", @@ -4981,6 +4978,7 @@ "//chrome/services/sharing/nearby/platform_v2:unit_tests", "//chromeos/assistant:buildflags", "//chromeos/services/machine_learning/public/cpp:test_support", + "//chromeos/services/nearby/public/cpp:test_support", "//components/arc:arc_test_support", ] }
diff --git a/chrome/test/data/iframe_hidden.html b/chrome/test/data/iframe_hidden.html new file mode 100644 index 0000000..48f3b25e --- /dev/null +++ b/chrome/test/data/iframe_hidden.html
@@ -0,0 +1,4 @@ +<html><head><title>iframe test</title></head> +<body> +<iframe src="title1.html" style="display:none;"></iframe> +</body></html>
diff --git a/chrome/test/data/iframe_out_of_view.html b/chrome/test/data/iframe_out_of_view.html new file mode 100644 index 0000000..ef0575d --- /dev/null +++ b/chrome/test/data/iframe_out_of_view.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<body> + <style> + body { + width: 100%; + height: 100%; + margin: 0; + } + + iframe { + width: 400px; + height: 400px; + /* The size of the margin is bigger than the viewport */ + margin: 300%; + border: 0; + padding: 0; + overflow: scroll; + } + </style> + <p> Single <iframe> which is positioned out of view. </p> + <iframe src="title1.html"> + </iframe> + <p> Iframe should be positioned way above </p> +</body> +</html>
diff --git a/chrome/test/data/iframe_partially_visible.html b/chrome/test/data/iframe_partially_visible.html new file mode 100644 index 0000000..307845b --- /dev/null +++ b/chrome/test/data/iframe_partially_visible.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> + <style> + iframe { + position: absolute; + left: -50px; + top: -50px; + width: 100px; + height: 100px; + /* Removing external factor that might affect pixel accuracy */ + border: none; + padding: 0; + margin: 0; + } + </style> + <iframe src="title1.html"> + </iframe> +</html>
diff --git a/chrome/test/data/iframe_rotated.html b/chrome/test/data/iframe_rotated.html new file mode 100644 index 0000000..df30229 --- /dev/null +++ b/chrome/test/data/iframe_rotated.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + <style> + iframe { + position: absolute; + left: 100px; + top: 100px; + width: 100px; + height: 100px; + transform: rotate(45deg); + /* Removing external factor that might affect pixel accuracy */ + border: none; + padding: 0; + margin: 0; + } + </style> + <iframe src="title1.html"> + </iframe> +</html>
diff --git a/chrome/test/data/iframe_scaled.html b/chrome/test/data/iframe_scaled.html new file mode 100644 index 0000000..59b13319 --- /dev/null +++ b/chrome/test/data/iframe_scaled.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + <style> + iframe { + position: absolute; + left: 100px; + top: 100px; + width: 200px; + height: 200px; + transform: scale(1.5); + /* Removing external factor that might affect pixel accuracy */ + border: none; + padding: 0; + margin: 0; + } + </style> + <iframe src="title1.html"> + </iframe> +</html>
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index c9f00a8..696db6d 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -7621,18 +7621,6 @@ ] }, - "SendFilesForMalwareCheck": { - "os": ["win", "linux", "mac", "chromeos"], - "policy_pref_mapping_test": [ - { - "policies": { - "SendFilesForMalwareCheck": 2 - }, - "prefs": { "safebrowsing.send_files_for_malware_check": {} } - } - ] - }, - "UnsafeEventsReportingEnabled": { "os": ["win", "linux", "mac", "chromeos"], "policy_pref_mapping_test": [ @@ -7681,16 +7669,6 @@ ] }, - "CheckContentCompliance": { - "os": ["win", "linux", "mac", "chromeos"], - "policy_pref_mapping_test": [ - { - "policies": { "CheckContentCompliance": 0 }, - "prefs": { "safebrowsing.check_content_compliance": { "local_state": true } } - } - ] - }, - "URLsToCheckComplianceOfDownloadedContent": { "os": ["win", "linux", "mac", "chromeos"], "policy_pref_mapping_test": [
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_page_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_page_tests.js index 619236d..596e61e 100644 --- a/chrome/test/data/webui/settings/chromeos/multidevice_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/multidevice_page_tests.js
@@ -181,6 +181,38 @@ 'Setup multidevice button should be focused for settingId=200.'); }); + test('Open notification access setup dialog route param', async () => { + settings.Router.getInstance().navigateTo( + settings.routes.MULTIDEVICE_FEATURES, + new URLSearchParams('showNotificationAccessSetupDialog=true')); + + PolymerTest.clearBody(); + browserProxy = new multidevice.TestMultideviceBrowserProxy(); + settings.MultiDeviceBrowserProxyImpl.instance_ = browserProxy; + + multidevicePage = document.createElement('settings-multidevice-page'); + assertTrue(!!multidevicePage); + + document.body.appendChild(multidevicePage); + await browserProxy.whenCalled('getPageContentData'); + + Polymer.dom.flush(); + assertTrue(!!multidevicePage.$$( + 'settings-multidevice-notification-access-setup-dialog')); + + // Close the dialog. + multidevicePage.showNotificationAccessSetupDialog_ = false; + Polymer.dom.flush(); + + // A change in pageContentData will not cause the notification access + // setup dialog to reappaear + setPageContentData({}); + Polymer.dom.flush(); + + assertFalse(!!multidevicePage.$$( + 'settings-multidevice-notification-access-setup-dialog')); + }); + test('headings render based on mode and host', function() { for (const mode of ALL_MODES) { setHostData(mode);
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc index fa4a67b..c57e75f 100644 --- a/chrome/test/ppapi/ppapi_browsertest.cc +++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -191,75 +191,6 @@ // Interface tests. // -// Flaky, http://crbug.com/111355 -TEST_PPAPI_OUT_OF_PROCESS(DISABLED_Broker) - -IN_PROC_BROWSER_TEST_F(PPAPIBrokerInfoBarTest, Accept) { - // Accepting the infobar should grant permission to access the PPAPI broker. - InfoBarObserver observer(this); - observer.ExpectInfoBarAndAccept(true); - - // PPB_Broker_Trusted::IsAllowed should return false before the infobar is - // popped and true after the infobar is popped. - RunTest("Broker_IsAllowedPermissionDenied"); - RunTest("Broker_ConnectPermissionGranted"); - RunTest("Broker_IsAllowedPermissionGranted"); - - // It should also set a content settings exception for the site. - GURL url = GetTestFileUrl("Broker_ConnectPermissionGranted"); - HostContentSettingsMap* content_settings = - HostContentSettingsMapFactory::GetForProfile(browser()->profile()); - EXPECT_EQ(CONTENT_SETTING_ALLOW, - content_settings->GetContentSetting( - url, url, ContentSettingsType::PPAPI_BROKER, std::string())); -} - -IN_PROC_BROWSER_TEST_F(PPAPIBrokerInfoBarTest, Deny) { - // Canceling the infobar should deny permission to access the PPAPI broker. - InfoBarObserver observer(this); - observer.ExpectInfoBarAndAccept(false); - - // PPB_Broker_Trusted::IsAllowed should return false before and after the - // infobar is popped. - RunTest("Broker_IsAllowedPermissionDenied"); - RunTest("Broker_ConnectPermissionDenied"); - RunTest("Broker_IsAllowedPermissionDenied"); - - // It should also set a content settings exception for the site. - GURL url = GetTestFileUrl("Broker_ConnectPermissionDenied"); - HostContentSettingsMap* content_settings = - HostContentSettingsMapFactory::GetForProfile(browser()->profile()); - EXPECT_EQ(CONTENT_SETTING_BLOCK, - content_settings->GetContentSetting( - url, url, ContentSettingsType::PPAPI_BROKER, std::string())); -} - -IN_PROC_BROWSER_TEST_F(PPAPIBrokerInfoBarTest, Blocked) { - // Block access to the PPAPI broker. - HostContentSettingsMapFactory::GetForProfile(browser()->profile()) - ->SetDefaultContentSetting(ContentSettingsType::PPAPI_BROKER, - CONTENT_SETTING_BLOCK); - - // We shouldn't see an infobar. - InfoBarObserver observer(this); - - RunTest("Broker_ConnectPermissionDenied"); - RunTest("Broker_IsAllowedPermissionDenied"); -} - -IN_PROC_BROWSER_TEST_F(PPAPIBrokerInfoBarTest, Allowed) { - // Always allow access to the PPAPI broker. - HostContentSettingsMapFactory::GetForProfile(browser()->profile()) - ->SetDefaultContentSetting(ContentSettingsType::PPAPI_BROKER, - CONTENT_SETTING_ALLOW); - - // We shouldn't see an infobar. - InfoBarObserver observer(this); - - RunTest("Broker_ConnectPermissionGranted"); - RunTest("Broker_IsAllowedPermissionGranted"); -} - // Flaky on Windows https://crbug.com/1059468 #if !defined(OS_WIN) || !defined(ARCH_CPU_32_BITS) TEST_PPAPI_NACL(Console) @@ -2211,20 +2142,6 @@ TEST_PPAPI_NACL(MessageLoop_Basics) TEST_PPAPI_NACL(MessageLoop_Post) -// Mac/Aura reach NOTIMPLEMENTED/time out. -// mac: http://crbug.com/96767 -// aura: http://crbug.com/104384 -// cros: http://crbug.com/396502 -// windows: http://crbug.com/899893 -// linux: http://crbug.com/899893 -#if defined(OS_MAC) || defined(OS_CHROMEOS) || defined(OS_WIN) || \ - defined(OS_LINUX) -#define MAYBE_FlashFullscreen DISABLED_FlashFullscreen -#else -#define MAYBE_FlashFullscreen FlashFullscreen -#endif -TEST_PPAPI_OUT_OF_PROCESS(MAYBE_FlashFullscreen) - TEST_PPAPI_OUT_OF_PROCESS(PDF) #if BUILDFLAG(ENABLE_NACL)
diff --git a/chrome/updater/app/app_install.cc b/chrome/updater/app/app_install.cc index 4b63401..6cc35ef 100644 --- a/chrome/updater/app/app_install.cc +++ b/chrome/updater/app/app_install.cc
@@ -157,7 +157,7 @@ return app_id; } } else { - VLOG(1) << "Tag parsing returned " << static_cast<int>(error) << "."; + VLOG(1) << "Tag parsing returned " << error << "."; } } return command_line->GetSwitchValueASCII(kAppIdSwitch);
diff --git a/chrome/updater/app/server/mac/service_delegate.mm b/chrome/updater/app/server/mac/service_delegate.mm index 6599f92a..ff625caa 100644 --- a/chrome/updater/app/server/mac/service_delegate.mm +++ b/chrome/updater/app/server/mac/service_delegate.mm
@@ -65,7 +65,7 @@ reply:(void (^_Nonnull)(int rc))reply { auto cb = base::BindOnce(base::RetainBlock(^(updater::UpdateService::Result error) { - VLOG(0) << "UpdateAll complete: error = " << static_cast<int>(error); + VLOG(0) << "UpdateAll complete: error = " << error; if (reply) reply(static_cast<int>(error)); @@ -112,7 +112,7 @@ reply:(void (^_Nonnull)(int rc))reply { auto cb = base::BindOnce(base::RetainBlock(^(updater::UpdateService::Result error) { - VLOG(0) << "Update complete: error = " << static_cast<int>(error); + VLOG(0) << "Update complete: error = " << error; if (reply) reply(static_cast<int>(error));
diff --git a/chrome/updater/app/server/win/service_main.cc b/chrome/updater/app/server/win/service_main.cc index c2851e8..f4257de7 100644 --- a/chrome/updater/app/server/win/service_main.cc +++ b/chrome/updater/app/server/win/service_main.cc
@@ -43,7 +43,7 @@ return ERROR_BAD_ARGUMENTS; int ret = service->Start(); - DCHECK_NE(ret, static_cast<int>(STILL_ACTIVE)); + DCHECK_NE(ret, int{STILL_ACTIVE}); return ret; }
diff --git a/chrome/updater/crash_reporter.cc b/chrome/updater/crash_reporter.cc index 4abe358..ec96de24 100644 --- a/chrome/updater/crash_reporter.cc +++ b/chrome/updater/crash_reporter.cc
@@ -116,8 +116,7 @@ } argv_as_utf8[argv.size()] = nullptr; - return crashpad::HandlerMain(static_cast<int>(argv.size()), - argv_as_utf8.get(), + return crashpad::HandlerMain(argv.size(), argv_as_utf8.get(), /*user_stream_sources=*/nullptr); }
diff --git a/chrome/updater/device_management/dm_client.cc b/chrome/updater/device_management/dm_client.cc index 285ffbc..8ed33b16 100644 --- a/chrome/updater/device_management/dm_client.cc +++ b/chrome/updater/device_management/dm_client.cc
@@ -148,8 +148,7 @@ } if (result != RequestResult::kSuccess) { - VLOG(1) << "Device registration skipped with DM error: " - << static_cast<int>(result); + VLOG(1) << "Device registration skipped with DM error: " << result; base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(request_callback_), result)); return; @@ -241,8 +240,7 @@ } if (result != RequestResult::kSuccess) { - VLOG(1) << "Policy fetch skipped with DM error: " - << static_cast<int>(result); + VLOG(1) << "Policy fetch skipped with DM error: " << result; base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(request_callback_), result)); return;
diff --git a/chrome/updater/device_management/dm_client.h b/chrome/updater/device_management/dm_client.h index dba13aa..16737001 100644 --- a/chrome/updater/device_management/dm_client.h +++ b/chrome/updater/device_management/dm_client.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include <memory> +#include <ostream> #include <string> #include "base/callback.h" @@ -135,6 +136,11 @@ SEQUENCE_CHECKER(sequence_checker_); }; +inline std::ostream& operator<<(std::ostream& os, + const DMClient::RequestResult& request_result) { + return os << static_cast<int>(request_result); +} + } // namespace updater #endif // CHROME_UPDATER_DEVICE_MANAGEMENT_DM_CLIENT_H_
diff --git a/chrome/updater/device_management/dm_policy_manager.cc b/chrome/updater/device_management/dm_policy_manager.cc index 4fac804..268ec4c 100644 --- a/chrome/updater/device_management/dm_policy_manager.cc +++ b/chrome/updater/device_management/dm_policy_manager.cc
@@ -65,8 +65,7 @@ if (!omaha_settings_.has_auto_update_check_period_minutes()) return false; - *minutes = - static_cast<int>(omaha_settings_.auto_update_check_period_minutes()); + *minutes = int{omaha_settings_.auto_update_check_period_minutes()}; return true; }
diff --git a/chrome/updater/tag.cc b/chrome/updater/tag.cc index a0f0e4ca..0a0d5940 100644 --- a/chrome/updater/tag.cc +++ b/chrome/updater/tag.cc
@@ -517,5 +517,74 @@ return ParseAppInstallerDataArgs(app_installer_data_args.value(), args); } +std::ostream& operator<<(std::ostream& os, const ErrorCode& error_code) { + switch (error_code) { + case ErrorCode::kSuccess: + return os << "ErrorCode::kSuccess"; + case ErrorCode::kUnrecognizedName: + return os << "ErrorCode::kUnrecognizedName"; + case ErrorCode::kTagIsInvalid: + return os << "ErrorCode::kTagIsInvalid"; + case ErrorCode::kAttributeMustHaveValue: + return os << "ErrorCode::kAttributeMustHaveValue"; + case ErrorCode::kApp_AppIdNotSpecified: + return os << "ErrorCode::kApp_AppIdNotSpecified"; + case ErrorCode::kApp_ExperimentLabelsCannotBeWhitespace: + return os << "ErrorCode::kApp_ExperimentLabelsCannotBeWhitespace"; + case ErrorCode::kApp_AppIdIsNotValid: + return os << "ErrorCode::kApp_AppIdIsNotValid"; + case ErrorCode::kApp_AppNameCannotBeWhitespace: + return os << "ErrorCode::kApp_AppNameCannotBeWhitespace"; + case ErrorCode::kApp_NeedsAdminValueIsInvalid: + return os << "ErrorCode::kApp_NeedsAdminValueIsInvalid"; + case ErrorCode::kAppInstallerData_AppIdNotFound: + return os << "ErrorCode::kAppInstallerData_AppIdNotFound"; + case ErrorCode::kAppInstallerData_InstallerDataCannotBeSpecifiedBeforeAppId: + return os << "ErrorCode::kAppInstallerData_" + "InstallerDataCannotBeSpecifiedBeforeAppId"; + case ErrorCode::kGlobal_BundleNameCannotBeWhitespace: + return os << "ErrorCode::kGlobal_BundleNameCannotBeWhitespace"; + case ErrorCode::kGlobal_ExperimentLabelsCannotBeWhitespace: + return os << "ErrorCode::kGlobal_ExperimentLabelsCannotBeWhitespace"; + case ErrorCode::kGlobal_BrowserTypeIsInvalid: + return os << "ErrorCode::kGlobal_BrowserTypeIsInvalid"; + case ErrorCode::kGlobal_FlightingValueIsNotABoolean: + return os << "ErrorCode::kGlobal_FlightingValueIsNotABoolean"; + case ErrorCode::kGlobal_UsageStatsValueIsInvalid: + return os << "ErrorCode::kGlobal_UsageStatsValueIsInvalid"; + } +} + +std::ostream& operator<<(std::ostream& os, + const AppArgs::NeedsAdmin& needs_admin) { + switch (needs_admin) { + case AppArgs::NeedsAdmin::kNo: + return os << "AppArgs::NeedsAdmin::kNo"; + case AppArgs::NeedsAdmin::kYes: + return os << "AppArgs::NeedsAdmin::kYes"; + case AppArgs::NeedsAdmin::kPrefers: + return os << "AppArgs::NeedsAdmin::kPrefers"; + } +} + +std::ostream& operator<<(std::ostream& os, + const TagArgs::BrowserType& browser_type) { + switch (browser_type) { + case TagArgs::BrowserType::kUnknown: + return os << "TagArgs::BrowserType::kUnknown"; + case TagArgs::BrowserType::kDefault: + return os << "TagArgs::BrowserType::kDefault"; + case TagArgs::BrowserType::kInternetExplorer: + return os << "TagArgs::BrowserType::kInternetExplorer"; + case TagArgs::BrowserType::kFirefox: + return os << "TagArgs::BrowserType::kFirefox"; + case TagArgs::BrowserType::kChrome: + return os << "TagArgs::BrowserType::kChrome"; + default: + return os << "TagArgs::BrowserType(" << static_cast<int>(browser_type) + << ")"; + } +} + } // namespace tagging } // namespace updater
diff --git a/chrome/updater/tag.h b/chrome/updater/tag.h index 6ab16516..64845d5 100644 --- a/chrome/updater/tag.h +++ b/chrome/updater/tag.h
@@ -5,6 +5,7 @@ #ifndef CHROME_UPDATER_TAG_H_ #define CHROME_UPDATER_TAG_H_ +#include <ostream> #include <string> #include <vector> @@ -54,6 +55,8 @@ base::Optional<NeedsAdmin> needs_admin; }; +std::ostream& operator<<(std::ostream&, const AppArgs::NeedsAdmin&); + // This struct contains the attributes parsed from a metainstaller tag. An empty // string in std::string members indicates that the given attribute did not // appear in the tag. @@ -93,6 +96,8 @@ std::vector<AppArgs> apps; }; +std::ostream& operator<<(std::ostream&, const TagArgs::BrowserType&); + // List of possible error states that the parser can encounter. enum class ErrorCode { // Parsing succeeded. @@ -150,6 +155,8 @@ kGlobal_UsageStatsValueIsInvalid, }; +std::ostream& operator<<(std::ostream&, const ErrorCode&); + // The metainstaller tag contains the metadata used to configure the updater as // a metainstaller. This usually comes from a 3rd party source, either as // command-line arguments or embedded in the metainstaller image after it is @@ -214,6 +221,7 @@ ErrorCode Parse(base::StringPiece tag, base::Optional<base::StringPiece> app_installer_data_args, TagArgs* args); + } // namespace tagging } // namespace updater
diff --git a/chrome/updater/tag_unittest.cc b/chrome/updater/tag_unittest.cc index 5d88319..a4196e3 100644 --- a/chrome/updater/tag_unittest.cc +++ b/chrome/updater/tag_unittest.cc
@@ -5,7 +5,6 @@ #include "chrome/updater/tag.h" #include "base/strings/string_piece.h" -#include "chrome/updater/unittest_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace {
diff --git a/chrome/updater/test/integration_tests_win.cc b/chrome/updater/test/integration_tests_win.cc index bc8fa00..cab64f3 100644 --- a/chrome/updater/test/integration_tests_win.cc +++ b/chrome/updater/test/integration_tests_win.cc
@@ -107,7 +107,7 @@ L"http://localhost:8367"), ERROR_SUCCESS); ASSERT_EQ(key.WriteValue(base::UTF8ToUTF16(kDevOverrideKeyUseCUP).c_str(), - static_cast<DWORD>(0)), + DWORD{0}), ERROR_SUCCESS); }
diff --git a/chrome/updater/test/test_app/update_client.cc b/chrome/updater/test/test_app/update_client.cc index a3e653b..24e632ec 100644 --- a/chrome/updater/test/test_app/update_client.cc +++ b/chrome/updater/test/test_app/update_client.cc
@@ -86,8 +86,7 @@ void UpdateClient::RegistrationCompleted(base::OnceCallback<void(int)> callback, UpdateService::Result result) { if (result != UpdateService::Result::kSuccess) { - LOG(ERROR) << "Updater registration error: " - << base::NumberToString(static_cast<int>(result)); + LOG(ERROR) << "Updater registration error: " << result; } callback_task_runner_->PostTask(
diff --git a/chrome/updater/tools/certificate_tag.cc b/chrome/updater/tools/certificate_tag.cc index cbea349..99e872a 100644 --- a/chrome/updater/tools/certificate_tag.cc +++ b/chrome/updater/tools/certificate_tag.cc
@@ -118,10 +118,8 @@ // http://msdn.microsoft.com/en-us/library/windows/desktop/ms680305(v=vs.85).aspx. !CBS_get_u32le(&optional_header, &cert_entry_virtual_addr) || !CBS_get_u32le(&optional_header, &cert_entry_size) || - static_cast<size_t>(cert_entry_virtual_addr) + cert_entry_size < - cert_entry_size || - static_cast<size_t>(cert_entry_virtual_addr) + cert_entry_size != - CBS_len(&bin)) { + size_t{cert_entry_virtual_addr} + cert_entry_size < cert_entry_size || + size_t{cert_entry_virtual_addr} + cert_entry_size != CBS_len(&bin)) { return base::nullopt; }
diff --git a/chrome/updater/unittest_util.cc b/chrome/updater/unittest_util.cc index 074e582..58c8c055 100644 --- a/chrome/updater/unittest_util.cc +++ b/chrome/updater/unittest_util.cc
@@ -5,90 +5,11 @@ #include "chrome/updater/unittest_util.h" #include "base/version.h" -#include "chrome/updater/tag.h" namespace updater { const char kChromeAppId[] = "{8A69D345-D564-463C-AFF1-A69D9E530F96}"; -namespace tagging { - -std::ostream& operator<<(std::ostream& os, const ErrorCode& error_code) { - switch (error_code) { - case ErrorCode::kSuccess: - return os << "ErrorCode::kSuccess"; - case ErrorCode::kUnrecognizedName: - return os << "ErrorCode::kUnrecognizedName"; - case ErrorCode::kTagIsInvalid: - return os << "ErrorCode::kTagIsInvalid"; - case ErrorCode::kAttributeMustHaveValue: - return os << "ErrorCode::kAttributeMustHaveValue"; - case ErrorCode::kApp_AppIdNotSpecified: - return os << "ErrorCode::kApp_AppIdNotSpecified"; - case ErrorCode::kApp_ExperimentLabelsCannotBeWhitespace: - return os << "ErrorCode::kApp_ExperimentLabelsCannotBeWhitespace"; - case ErrorCode::kApp_AppIdIsNotValid: - return os << "ErrorCode::kApp_AppIdIsNotValid"; - case ErrorCode::kApp_AppNameCannotBeWhitespace: - return os << "ErrorCode::kApp_AppNameCannotBeWhitespace"; - case ErrorCode::kApp_NeedsAdminValueIsInvalid: - return os << "ErrorCode::kApp_NeedsAdminValueIsInvalid"; - case ErrorCode::kAppInstallerData_AppIdNotFound: - return os << "ErrorCode::kAppInstallerData_AppIdNotFound"; - case ErrorCode::kAppInstallerData_InstallerDataCannotBeSpecifiedBeforeAppId: - return os << "ErrorCode::kAppInstallerData_" - "InstallerDataCannotBeSpecifiedBeforeAppId"; - case ErrorCode::kGlobal_BundleNameCannotBeWhitespace: - return os << "ErrorCode::kGlobal_BundleNameCannotBeWhitespace"; - case ErrorCode::kGlobal_ExperimentLabelsCannotBeWhitespace: - return os << "ErrorCode::kGlobal_ExperimentLabelsCannotBeWhitespace"; - case ErrorCode::kGlobal_BrowserTypeIsInvalid: - return os << "ErrorCode::kGlobal_BrowserTypeIsInvalid"; - case ErrorCode::kGlobal_FlightingValueIsNotABoolean: - return os << "ErrorCode::kGlobal_FlightingValueIsNotABoolean"; - case ErrorCode::kGlobal_UsageStatsValueIsInvalid: - return os << "ErrorCode::kGlobal_UsageStatsValueIsInvalid"; - default: - return os << "ErrorCode(" << static_cast<int>(error_code) << ")"; - } -} - -std::ostream& operator<<(std::ostream& os, - const AppArgs::NeedsAdmin& needs_admin) { - switch (needs_admin) { - case AppArgs::NeedsAdmin::kNo: - return os << "AppArgs::NeedsAdmin::kNo"; - case AppArgs::NeedsAdmin::kYes: - return os << "AppArgs::NeedsAdmin::kYes"; - case AppArgs::NeedsAdmin::kPrefers: - return os << "AppArgs::NeedsAdmin::kPrefers"; - default: - return os << "AppArgs::NeedsAdmin(" << static_cast<int>(needs_admin) - << ")"; - } -} - -std::ostream& operator<<(std::ostream& os, - const TagArgs::BrowserType& browser_type) { - switch (browser_type) { - case TagArgs::BrowserType::kUnknown: - return os << "TagArgs::BrowserType::kUnknown"; - case TagArgs::BrowserType::kDefault: - return os << "TagArgs::BrowserType::kDefault"; - case TagArgs::BrowserType::kInternetExplorer: - return os << "TagArgs::BrowserType::kInternetExplorer"; - case TagArgs::BrowserType::kFirefox: - return os << "TagArgs::BrowserType::kFirefox"; - case TagArgs::BrowserType::kChrome: - return os << "TagArgs::BrowserType::kChrome"; - default: - return os << "TagArgs::BrowserType(" << static_cast<int>(browser_type) - << ")"; - } -} - -} // namespace tagging - bool operator==(const UpdateService::UpdateState& lhs, const UpdateService::UpdateState& rhs) { const bool versions_equal = @@ -103,63 +24,5 @@ lhs.error_code == rhs.error_code && lhs.extra_code1 == rhs.extra_code1; } -std::ostream& operator<<(std::ostream& os, - const UpdateService::UpdateState& update_state) { - auto state_formatter = [update_state]() { - switch (update_state.state) { - case UpdateService::UpdateState::State::kUnknown: - return "unknown"; - case UpdateService::UpdateState::State::kNotStarted: - return "not started"; - case UpdateService::UpdateState::State::kCheckingForUpdates: - return "checking for updates"; - case UpdateService::UpdateState::State::kUpdateAvailable: - return "update available"; - case UpdateService::UpdateState::State::kDownloading: - return "downloading"; - case UpdateService::UpdateState::State::kInstalling: - return "installing"; - case UpdateService::UpdateState::State::kUpdated: - return "updated"; - case UpdateService::UpdateState::State::kNoUpdate: - return "no update"; - case UpdateService::UpdateState::State::kUpdateError: - return "update error"; - } - }; - - auto version_formatter = [update_state]() { - return update_state.next_version.IsValid() - ? update_state.next_version.GetString() - : ""; - }; - - auto error_category_formatter = [update_state]() { - switch (update_state.error_category) { - case UpdateService::ErrorCategory::kNone: - return "none"; - case UpdateService::ErrorCategory::kDownload: - return "download"; - case UpdateService::ErrorCategory::kUnpack: - return "unpack"; - case UpdateService::ErrorCategory::kInstall: - return "install"; - case UpdateService::ErrorCategory::kService: - return "service"; - case UpdateService::ErrorCategory::kUpdateCheck: - return "update check"; - } - }; - - return os << "UpdateState {app_id: " << update_state.app_id - << ", state: " << state_formatter() - << ", next_version: " << version_formatter() - << ", downloaded_bytes: " << update_state.downloaded_bytes - << ", total_bytes: " << update_state.total_bytes - << ", install_progress: " << update_state.install_progress - << ", error_category: " << error_category_formatter() - << ", error_code: " << update_state.error_code - << ", extra_code1: " << update_state.extra_code1 << "}"; -} } // namespace updater
diff --git a/chrome/updater/unittest_util.h b/chrome/updater/unittest_util.h index 932c0b7..bfd82af 100644 --- a/chrome/updater/unittest_util.h +++ b/chrome/updater/unittest_util.h
@@ -5,38 +5,12 @@ #ifndef CHROME_UPDATER_UNITTEST_UTIL_H_ #define CHROME_UPDATER_UNITTEST_UTIL_H_ -#include <ostream> -#include <string> - -#include "base/optional.h" -#include "chrome/updater/tag.h" #include "chrome/updater/update_service.h" -// Externally-defined printers for base types. -namespace base { - -template <class T> -std::ostream& operator<<(std::ostream& os, const base::Optional<T>& opt) { - if (opt.has_value()) { - return os << opt.value(); - } else { - return os << "base::nullopt"; - } -} - -} // namespace base - -// Externally-defined printers for chrome/updater-related types. namespace updater { extern const char kChromeAppId[]; -namespace tagging { -std::ostream& operator<<(std::ostream&, const ErrorCode&); -std::ostream& operator<<(std::ostream&, const AppArgs::NeedsAdmin&); -std::ostream& operator<<(std::ostream&, const TagArgs::BrowserType&); -} // namespace tagging - bool operator==(const UpdateService::UpdateState& lhs, const UpdateService::UpdateState& rhs); inline bool operator!=(const UpdateService::UpdateState& lhs, @@ -44,9 +18,6 @@ return !(lhs == rhs); } -std::ostream& operator<<(std::ostream& os, - const UpdateService::UpdateState& update_state); - } // namespace updater #endif // CHROME_UPDATER_UNITTEST_UTIL_H_
diff --git a/chrome/updater/update_service.cc b/chrome/updater/update_service.cc index 280ae5d..db66dc7 100644 --- a/chrome/updater/update_service.cc +++ b/chrome/updater/update_service.cc
@@ -4,6 +4,8 @@ #include "chrome/updater/update_service.h" +#include <ostream> + namespace updater { UpdateService::UpdateState::UpdateState() = default; @@ -15,4 +17,63 @@ UpdateState&&) = default; UpdateService::UpdateState::~UpdateState() = default; +std::ostream& operator<<(std::ostream& os, + const UpdateService::UpdateState& update_state) { + auto state_formatter = [update_state]() { + switch (update_state.state) { + case UpdateService::UpdateState::State::kUnknown: + return "unknown"; + case UpdateService::UpdateState::State::kNotStarted: + return "not started"; + case UpdateService::UpdateState::State::kCheckingForUpdates: + return "checking for updates"; + case UpdateService::UpdateState::State::kUpdateAvailable: + return "update available"; + case UpdateService::UpdateState::State::kDownloading: + return "downloading"; + case UpdateService::UpdateState::State::kInstalling: + return "installing"; + case UpdateService::UpdateState::State::kUpdated: + return "updated"; + case UpdateService::UpdateState::State::kNoUpdate: + return "no update"; + case UpdateService::UpdateState::State::kUpdateError: + return "update error"; + } + }; + + auto version_formatter = [update_state]() { + return update_state.next_version.IsValid() + ? update_state.next_version.GetString() + : ""; + }; + + auto error_category_formatter = [update_state]() { + switch (update_state.error_category) { + case UpdateService::ErrorCategory::kNone: + return "none"; + case UpdateService::ErrorCategory::kDownload: + return "download"; + case UpdateService::ErrorCategory::kUnpack: + return "unpack"; + case UpdateService::ErrorCategory::kInstall: + return "install"; + case UpdateService::ErrorCategory::kService: + return "service"; + case UpdateService::ErrorCategory::kUpdateCheck: + return "update check"; + } + }; + + return os << "UpdateState {app_id: " << update_state.app_id + << ", state: " << state_formatter() + << ", next_version: " << version_formatter() + << ", downloaded_bytes: " << update_state.downloaded_bytes + << ", total_bytes: " << update_state.total_bytes + << ", install_progress: " << update_state.install_progress + << ", error_category: " << error_category_formatter() + << ", error_code: " << update_state.error_code + << ", extra_code1: " << update_state.extra_code1 << "}"; +} + } // namespace updater
diff --git a/chrome/updater/update_service.h b/chrome/updater/update_service.h index c68650a..bfefebd2 100644 --- a/chrome/updater/update_service.h +++ b/chrome/updater/update_service.h
@@ -5,6 +5,7 @@ #ifndef CHROME_UPDATER_UPDATE_SERVICE_H_ #define CHROME_UPDATER_UPDATE_SERVICE_H_ +#include <ostream> #include <string> #include "base/callback_forward.h" @@ -54,6 +55,8 @@ // A function argument was invalid. kInvalidArgument = 7, + + // Change the traits class in this file when adding new values. }; // Run time errors are organized in specific categories to indicate the @@ -203,6 +206,13 @@ // These specializations must be defined in the |updater| namespace. template <> +struct EnumTraits<UpdateService::Result> { + using Result = UpdateService::Result; + static constexpr Result first_elem = Result::kSuccess; + static constexpr Result last_elem = Result::kInvalidArgument; +}; + +template <> struct EnumTraits<UpdateService::UpdateState::State> { using State = UpdateService::UpdateState::State; static constexpr State first_elem = State::kUnknown; @@ -216,6 +226,14 @@ static constexpr ErrorCategory last_elem = ErrorCategory::kUpdateCheck; }; +inline std::ostream& operator<<(std::ostream& os, + const UpdateService::Result& result) { + return os << static_cast<int>(result); +} + +std::ostream& operator<<(std::ostream& os, + const UpdateService::UpdateState& update_state); + // A factory method to create an UpdateService class instance. scoped_refptr<UpdateService> CreateUpdateService();
diff --git a/chrome/updater/util.h b/chrome/updater/util.h index b84eae05..839e09f 100644 --- a/chrome/updater/util.h +++ b/chrome/updater/util.h
@@ -5,6 +5,7 @@ #ifndef CHROME_UPDATER_UTIL_H_ #define CHROME_UPDATER_UTIL_H_ +#include <ostream> #include <type_traits> #include "base/files/file_path.h" @@ -14,6 +15,20 @@ class GURL; +// Externally-defined printers for base types. +namespace base { + +template <class T> +std::ostream& operator<<(std::ostream& os, const base::Optional<T>& opt) { + if (opt.has_value()) { + return os << opt.value(); + } else { + return os << "base::nullopt"; + } +} + +} // namespace base + namespace updater { // Returns the base directory common to all versions of the updater. For
diff --git a/chrome/updater/util_unittest.cc b/chrome/updater/util_unittest.cc index 3000ef6..3f4dde8f 100644 --- a/chrome/updater/util_unittest.cc +++ b/chrome/updater/util_unittest.cc
@@ -4,6 +4,8 @@ #include "chrome/updater/util.h" +#include <ostream> + #include "base/optional.h" #include "testing/gtest/include/gtest/gtest.h" @@ -15,6 +17,10 @@ kVal3 = 1, }; +std::ostream& operator<<(std::ostream& os, const MyEnum& e) { + return os << "MyEnum: " << static_cast<int>(e); +} + template <> struct EnumTraits<MyEnum> { static constexpr MyEnum first_elem = MyEnum::kVal1;
diff --git a/chrome/updater/win/installer/installer.cc b/chrome/updater/win/installer/installer.cc index 66eb9ea4..a713917 100644 --- a/chrome/updater/win/installer/installer.cc +++ b/chrome/updater/win/installer/installer.cc
@@ -273,8 +273,7 @@ bool IsAclSupportedForPath(const wchar_t* path) { PathString volume; DWORD flags = 0; - return ::GetVolumePathName(path, volume.get(), - static_cast<DWORD>(volume.capacity())) && + return ::GetVolumePathName(path, volume.get(), DWORD{volume.capacity()}) && ::GetVolumeInformation(volume.get(), nullptr, 0, nullptr, nullptr, &flags, nullptr, 0) && (flags & FILE_PERSISTENT_ACLS); @@ -415,14 +414,13 @@ PathString* work_dir, ProcessExitResult* exit_code) { PathString base_path; - DWORD len = - ::GetTempPath(static_cast<DWORD>(base_path.capacity()), base_path.get()); + DWORD len = ::GetTempPath(DWORD{base_path.capacity()}, base_path.get()); if (!len || len >= base_path.capacity() || !CreateWorkDir(base_path.get(), work_dir, exit_code)) { // Problem creating the work dir under TEMP path, so try using the // current directory as the base path. len = ::GetModuleFileName(module, base_path.get(), - static_cast<DWORD>(base_path.capacity())); + DWORD{base_path.capacity()}); if (len >= base_path.capacity() || !len) return false; // Can't even get current directory? Return an error. @@ -495,8 +493,7 @@ // While unpacking the binaries, we paged in a whole bunch of memory that // we don't need anymore. Let's give it back to the pool before running // setup. - ::SetProcessWorkingSetSize(::GetCurrentProcess(), static_cast<SIZE_T>(-1), - static_cast<SIZE_T>(-1)); + ::SetProcessWorkingSetSize(::GetCurrentProcess(), SIZE_T{-1}, SIZE_T{-1}); PathString setup_path; if (!setup_path.assign(unpack_path.value().c_str()) ||
diff --git a/chrome/updater/win/installer/pe_resource.cc b/chrome/updater/win/installer/pe_resource.cc index c7b2a1b..01293f3b 100644 --- a/chrome/updater/win/installer/pe_resource.cc +++ b/chrome/updater/win/installer/pe_resource.cc
@@ -46,8 +46,8 @@ const size_t write_amount = std::min(kMaxWriteAmount, resource_size - total_written); DWORD written = 0; - if (!::WriteFile(out_file, data + total_written, - static_cast<DWORD>(write_amount), &written, nullptr)) { + if (!::WriteFile(out_file, data + total_written, DWORD{write_amount}, + &written, nullptr)) { ::CloseHandle(out_file); return false; }
diff --git a/chrome/updater/win/installer/regkey.cc b/chrome/updater/win/installer/regkey.cc index 7716f02..102a728b 100644 --- a/chrome/updater/win/installer/regkey.cc +++ b/chrome/updater/win/installer/regkey.cc
@@ -18,7 +18,7 @@ wchar_t* value, size_t value_size) const { DWORD type = 0; - DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t)); + DWORD byte_length = DWORD{value_size * sizeof(wchar_t)}; LONG result = ::RegQueryValueEx(key_, value_name, nullptr, &type, reinterpret_cast<BYTE*>(value), &byte_length); if (result == ERROR_SUCCESS) {
diff --git a/chrome/updater/win/installer/string_unittest.cc b/chrome/updater/win/installer/string_unittest.cc index d36b3a040..49a1ce9c 100644 --- a/chrome/updater/win/installer/string_unittest.cc +++ b/chrome/updater/win/installer/string_unittest.cc
@@ -26,7 +26,7 @@ static const wchar_t kTestString[] = L"1234567890"; StackString<MAX_PATH> str; - EXPECT_EQ(static_cast<size_t>(MAX_PATH), str.capacity()); + EXPECT_EQ(size_t{MAX_PATH}, str.capacity()); std::wstring compare_str; @@ -42,7 +42,7 @@ EXPECT_EQ(0, compare_str.compare(str.get())); } - EXPECT_GT(static_cast<size_t>(MAX_PATH), str.length()); + EXPECT_GT(size_t{MAX_PATH}, str.length()); // Now we've exhausted the space we allocated for the string, // so append should fail.
diff --git a/chrome/updater/win/tag_extractor.cc b/chrome/updater/win/tag_extractor.cc index 18c5011..34b49d5 100644 --- a/chrome/updater/win/tag_extractor.cc +++ b/chrome/updater/win/tag_extractor.cc
@@ -13,6 +13,7 @@ #include <vector> #include "base/numerics/checked_math.h" +#include "base/strings/string16.h" #include "base/win/pe_image_reader.h" #include "build/build_config.h" #include "chrome/updater/win/tag_extractor_impl.h" @@ -97,8 +98,7 @@ // Converts the UTF-16 tag from big-endian to little-endian. size_t tag_utf16_idx = 0; for (auto it = tag_buf; it < tag_buf_end; it += sizeof(uint16_t)) { - tag_utf16[tag_utf16_idx] = - static_cast<std::wstring::value_type>(BigEndianReadU16(it)); + tag_utf16[tag_utf16_idx] = std::wstring::value_type{BigEndianReadU16(it)}; ++tag_utf16_idx; } @@ -157,7 +157,7 @@ if (!base::CheckedNumeric<ptrdiff_t>(end - it).AssignIfValid(&dist_to_end)) return end; - return it + std::min(distance, static_cast<size_t>(dist_to_end)); + return it + std::min(distance, size_t{dist_to_end}); } bool CheckRange(BinaryConstIt it, size_t size, BinaryConstIt end) { @@ -168,7 +168,7 @@ if (!base::CheckedNumeric<ptrdiff_t>(end - it).AssignIfValid(&dist_to_end)) return false; - return size <= static_cast<size_t>(dist_to_end); + return size <= size_t{dist_to_end}; } std::string ExtractTagFromBuffer(const std::vector<uint8_t>& binary, @@ -209,8 +209,8 @@ std::vector<uint8_t> binary(file_size.QuadPart); DWORD bytes_read = 0; - if (!::ReadFile(file_handle, &binary[0], static_cast<DWORD>(binary.size()), - &bytes_read, nullptr)) { + if (!::ReadFile(file_handle, &binary[0], DWORD{binary.size()}, &bytes_read, + nullptr)) { ::CloseHandle(file_handle); return std::string(); }
diff --git a/chrome/updater/win/task_scheduler.cc b/chrome/updater/win/task_scheduler.cc index a7711d3..4e3c39c 100644 --- a/chrome/updater/win/task_scheduler.cc +++ b/chrome/updater/win/task_scheduler.cc
@@ -109,7 +109,7 @@ NameSamCompatible, user_name->AllocateBytes(user_name_size * sizeof(OLECHAR)), &user_name_size)) { - DCHECK_NE(static_cast<DWORD>(ERROR_MORE_DATA), ::GetLastError()); + DCHECK_NE(DWORD{ERROR_MORE_DATA}, ::GetLastError()); PLOG(ERROR) << "GetUserNameEx failed."; return false; }
diff --git a/chrome/updater/win/ui/owner_draw_controls.cc b/chrome/updater/win/ui/owner_draw_controls.cc index aafc9ac..0538e02d 100644 --- a/chrome/updater/win/ui/owner_draw_controls.cc +++ b/chrome/updater/win/ui/owner_draw_controls.cc
@@ -611,7 +611,7 @@ current_position_ = kMinPosition; } } else { - current_position_ = std::min(static_cast<int>(new_position), kMaxPosition); + current_position_ = std::min(int{new_position}, kMaxPosition); } if (current_position_ < kMinPosition) @@ -662,7 +662,7 @@ if (is_set_marquee && !is_marquee_mode_) { current_position_ = kMinPosition; - SetTimer(kMarqueeTimerId, static_cast<UINT>(update_msec)); + SetTimer(kMarqueeTimerId, UINT{update_msec}); is_marquee_mode_ = true; } else if (!is_set_marquee && is_marquee_mode_) { KillTimer(kMarqueeTimerId);
diff --git a/chrome/updater/win/ui/splash_screen.cc b/chrome/updater/win/ui/splash_screen.cc index fe2d304..ecce7aed 100644 --- a/chrome/updater/win/ui/splash_screen.cc +++ b/chrome/updater/win/ui/splash_screen.cc
@@ -29,7 +29,7 @@ uint8_t AlphaScaleToAlphaValue(int alpha_scale) { DCHECK(alpha_scale >= 0 && alpha_scale <= 100); - return static_cast<uint8_t>(alpha_scale * 255 / 100); + return uint8_t{alpha_scale * 255 / 100}; } } // namespace
diff --git a/chrome/updater/win/update_service_out_of_process.cc b/chrome/updater/win/update_service_out_of_process.cc index 278dd72..c744576 100644 --- a/chrome/updater/win/update_service_out_of_process.cc +++ b/chrome/updater/win/update_service_out_of_process.cc
@@ -225,12 +225,7 @@ update_service_state.extra_code1 = extra_code1; } - DVLOG(4) << "{update state: " << static_cast<int>(update_service_state.state) - << ", downloaded_bytes: " << update_service_state.downloaded_bytes - << ", total_bytes: " << update_service_state.total_bytes - << ", install_progress: " << update_service_state.install_progress - << ", error_code: " << update_service_state.error_code - << ", extra_code1: " << update_service_state.extra_code1 << "}"; + DVLOG(4) << update_service_state; return update_service_state; } @@ -243,7 +238,7 @@ base::win::ScopedBstr message; CHECK(SUCCEEDED(complete_status->get_statusCode(&code))); - DVLOG(2) << "ICompleteStatus::OnComplete(" << static_cast<int>(code) << ")"; + DVLOG(2) << "ICompleteStatus::OnComplete(" << code << ")"; return static_cast<UpdateService::Result>(code); }
diff --git a/chrome/updater/win/util.h b/chrome/updater/win/util.h index 5cfc03a..63f7d1ab 100644 --- a/chrome/updater/win/util.h +++ b/chrome/updater/win/util.h
@@ -30,9 +30,8 @@ HRESULT HRESULTFromUpdaterError(Error error) { constexpr ULONG kCustomerBit = 0x20000000; constexpr ULONG kFacilityOmaha = 67; - return static_cast<HRESULT>(static_cast<ULONG>(SEVERITY_ERROR) | - kCustomerBit | (kFacilityOmaha << 16) | - static_cast<ULONG>(error)); + return HRESULT{ULONG{SEVERITY_ERROR} | kCustomerBit | (kFacilityOmaha << 16) | + ULONG{error}}; } // Checks whether a process is running with the image |executable|. Returns true
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt index 89908e5..a7154600 100644 --- a/chromeos/profiles/orderfile.newest.txt +++ b/chromeos/profiles/orderfile.newest.txt
@@ -1 +1 @@ -chromeos-chrome-orderfile-field-87-4265.0-1601890590-benchmark-87.0.4280.16-r1.orderfile.xz +chromeos-chrome-orderfile-field-87-4277.0-1602498224-benchmark-87.0.4280.18-r1.orderfile.xz
diff --git a/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc b/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc index 6f4682b..6248097e 100644 --- a/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc +++ b/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
@@ -210,6 +210,10 @@ (NetworkDiagnosticsRoutines::HttpFirewallCallback), (override)); MOCK_METHOD(void, + HttpsFirewall, + (NetworkDiagnosticsRoutines::HttpsFirewallCallback), + (override)); + MOCK_METHOD(void, HttpsLatency, (NetworkDiagnosticsRoutines::HttpsLatencyCallback), (override));
diff --git a/chromeos/services/nearby/public/cpp/BUILD.gn b/chromeos/services/nearby/public/cpp/BUILD.gn new file mode 100644 index 0000000..96f771d --- /dev/null +++ b/chromeos/services/nearby/public/cpp/BUILD.gn
@@ -0,0 +1,21 @@ +# Copyright 2020 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +static_library("test_support") { + testonly = true + + sources = [ + "mock_nearby_connections.cc", + "mock_nearby_connections.h", + "mock_nearby_sharing_decoder.cc", + "mock_nearby_sharing_decoder.h", + ] + + deps = [ + "//base", + "//chromeos/services/nearby/public/mojom", + "//mojo/public/cpp/bindings/", + "//testing/gmock", + ] +}
diff --git a/chromeos/services/nearby/public/cpp/mock_nearby_connections.cc b/chromeos/services/nearby/public/cpp/mock_nearby_connections.cc new file mode 100644 index 0000000..400bc59 --- /dev/null +++ b/chromeos/services/nearby/public/cpp/mock_nearby_connections.cc
@@ -0,0 +1,19 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/services/nearby/public/cpp/mock_nearby_connections.h" + +namespace chromeos { +namespace nearby { + +MockNearbyConnections::MockNearbyConnections() { + mojo::PendingRemote<NearbyConnectionsMojom> pending_remote; + receiver_.Bind(pending_remote.InitWithNewPipeAndPassReceiver()); + shared_remote_.Bind(std::move(pending_remote), /*bind_task_runner=*/nullptr); +} + +MockNearbyConnections::~MockNearbyConnections() = default; + +} // namespace nearby +} // namespace chromeos
diff --git a/chrome/browser/nearby_sharing/mock_nearby_connections.h b/chromeos/services/nearby/public/cpp/mock_nearby_connections.h similarity index 85% rename from chrome/browser/nearby_sharing/mock_nearby_connections.h rename to chromeos/services/nearby/public/cpp/mock_nearby_connections.h index 067e9073..f374c0b2 100644 --- a/chrome/browser/nearby_sharing/mock_nearby_connections.h +++ b/chromeos/services/nearby/public/cpp/mock_nearby_connections.h
@@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_NEARBY_SHARING_MOCK_NEARBY_CONNECTIONS_H_ -#define CHROME_BROWSER_NEARBY_SHARING_MOCK_NEARBY_CONNECTIONS_H_ +#ifndef CHROMEOS_SERVICES_NEARBY_PUBLIC_CPP_MOCK_NEARBY_CONNECTIONS_H_ +#define CHROMEOS_SERVICES_NEARBY_PUBLIC_CPP_MOCK_NEARBY_CONNECTIONS_H_ #include "chromeos/services/nearby/public/mojom/nearby_connections.mojom.h" - +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/shared_remote.h" #include "testing/gmock/include/gmock/gmock.h" using NearbyConnectionsMojom = @@ -24,6 +25,9 @@ using PayloadListener = location::nearby::connections::mojom::PayloadListener; using PayloadPtr = location::nearby::connections::mojom::PayloadPtr; +namespace chromeos { +namespace nearby { + class MockNearbyConnections : public NearbyConnectionsMojom { public: MockNearbyConnections(); @@ -31,6 +35,10 @@ MockNearbyConnections& operator=(const MockNearbyConnections&) = delete; ~MockNearbyConnections() override; + const mojo::SharedRemote<NearbyConnectionsMojom>& shared_remote() const { + return shared_remote_; + } + MOCK_METHOD(void, StartAdvertising, (const std::vector<uint8_t>& endpoint_info, @@ -97,6 +105,13 @@ base::File output_file, RegisterPayloadFileCallback callback), (override)); + + private: + mojo::Receiver<NearbyConnectionsMojom> receiver_{this}; + mojo::SharedRemote<NearbyConnectionsMojom> shared_remote_; }; -#endif // CHROME_BROWSER_NEARBY_SHARING_MOCK_NEARBY_CONNECTIONS_H_ +} // namespace nearby +} // namespace chromeos + +#endif // CHROMEOS_SERVICES_NEARBY_PUBLIC_CPP_MOCK_NEARBY_CONNECTIONS_H_
diff --git a/chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.cc b/chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.cc new file mode 100644 index 0000000..624bdb9 --- /dev/null +++ b/chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.cc
@@ -0,0 +1,19 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.h" + +namespace chromeos { +namespace nearby { + +MockNearbySharingDecoder::MockNearbySharingDecoder() { + mojo::PendingRemote<sharing::mojom::NearbySharingDecoder> pending_remote; + receiver_.Bind(pending_remote.InitWithNewPipeAndPassReceiver()); + shared_remote_.Bind(std::move(pending_remote), /*bind_task_runner=*/nullptr); +} + +MockNearbySharingDecoder::~MockNearbySharingDecoder() = default; + +} // namespace nearby +} // namespace chromeos
diff --git a/chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.h b/chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.h new file mode 100644 index 0000000..24e565d --- /dev/null +++ b/chromeos/services/nearby/public/cpp/mock_nearby_sharing_decoder.h
@@ -0,0 +1,47 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_SERVICES_NEARBY_PUBLIC_CPP_MOCK_NEARBY_SHARING_DECODER_H_ +#define CHROMEOS_SERVICES_NEARBY_PUBLIC_CPP_MOCK_NEARBY_SHARING_DECODER_H_ + +#include "chromeos/services/nearby/public/mojom/nearby_decoder.mojom.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/shared_remote.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromeos { +namespace nearby { + +class MockNearbySharingDecoder : public sharing::mojom::NearbySharingDecoder { + public: + MockNearbySharingDecoder(); + explicit MockNearbySharingDecoder(const MockNearbySharingDecoder&) = delete; + MockNearbySharingDecoder& operator=(const MockNearbySharingDecoder&) = delete; + ~MockNearbySharingDecoder() override; + + const mojo::SharedRemote<sharing::mojom::NearbySharingDecoder>& + shared_remote() const { + return shared_remote_; + } + + // sharing::mojom::NearbySharingDecoder: + MOCK_METHOD(void, + DecodeAdvertisement, + (const std::vector<uint8_t>& data, + DecodeAdvertisementCallback callback), + (override)); + MOCK_METHOD(void, + DecodeFrame, + (const std::vector<uint8_t>& data, DecodeFrameCallback callback), + (override)); + + private: + mojo::Receiver<sharing::mojom::NearbySharingDecoder> receiver_{this}; + mojo::SharedRemote<sharing::mojom::NearbySharingDecoder> shared_remote_; +}; + +} // namespace nearby +} // namespace chromeos + +#endif // CHROMEOS_SERVICES_NEARBY_PUBLIC_CPP_MOCK_NEARBY_SHARING_DECODER_H_
diff --git a/chromeos/services/network_health/public/mojom/network_diagnostics.mojom b/chromeos/services/network_health/public/mojom/network_diagnostics.mojom index 506bfb6..a21bcf6 100644 --- a/chromeos/services/network_health/public/mojom/network_diagnostics.mojom +++ b/chromeos/services/network_health/public/mojom/network_diagnostics.mojom
@@ -99,6 +99,17 @@ kPotentialFirewall, }; +// Problems related to the HttpsFirewall routine. +[Extensible] +enum HttpsFirewallProblem { + // DNS resolution failure rate is high. + kHighDnsResolutionFailureRate, + // Firewall detected. + kFirewallDetected, + // A firewall may potentially exist. + kPotentialFirewall, +}; + // Problems related to the HttpsLatency routine. [Extensible] enum HttpsLatencyProblem { @@ -156,6 +167,10 @@ HttpFirewall() => (RoutineVerdict verdict, array<HttpFirewallProblem> problems); + // Tests whether a firewall is blocking HTTPS port 443. + HttpsFirewall() => (RoutineVerdict verdict, + array<HttpsFirewallProblem> problems); + // Tests whether the HTTPS latency is within established tolerance levels for // the system. HttpsLatency() => (RoutineVerdict verdict,
diff --git a/chromeos/ui/base/tablet_state.cc b/chromeos/ui/base/tablet_state.cc index c657002..b4cde3e 100644 --- a/chromeos/ui/base/tablet_state.cc +++ b/chromeos/ui/base/tablet_state.cc
@@ -26,9 +26,24 @@ g_instance = nullptr; } +void TabletState::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void TabletState::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + bool TabletState::InTabletMode() const { return state_ == TabletState::kInTabletMode || state_ == TabletState::kEnteringTabletMode; } +void TabletState::SetState(State state) { + state_ = state; + + for (auto& observer : observers_) + observer.OnTabletStateChanged(state_); +} + } // namespace chromeos
diff --git a/chromeos/ui/base/tablet_state.h b/chromeos/ui/base/tablet_state.h index b3176c6..b14ca62 100644 --- a/chromeos/ui/base/tablet_state.h +++ b/chromeos/ui/base/tablet_state.h
@@ -6,6 +6,7 @@ #define CHROMEOS_UI_BASE_TABLET_STATE_H_ #include "base/component_export.h" +#include "base/observer_list.h" namespace ash { class TabletModeController; @@ -31,12 +32,21 @@ kExitingTabletMode, }; + class COMPONENT_EXPORT(CHROMEOS_UI_BASE) Observer { + public: + virtual void OnTabletStateChanged(State state) = 0; + + protected: + virtual ~Observer() = default; + }; + TabletState(); TabletState(const TabletState&) = delete; TabletState& operator=(const TabletState&) = delete; ~TabletState(); - // TODO(http://crbug.com/1113900): Introduce Add|RemoveObserver support. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); // Returns true if the system is in tablet mode. bool InTabletMode() const; @@ -48,7 +58,9 @@ // the tablet state. friend class ash::TabletModeController; - void SetState(State state) { state_ = state; } + void SetState(State state); + + base::ObserverList<Observer>::Unchecked observers_; State state_ = State::kInClamshellMode; };
diff --git a/chromeos/ui/frame/BUILD.gn b/chromeos/ui/frame/BUILD.gn new file mode 100644 index 0000000..88a9f08 --- /dev/null +++ b/chromeos/ui/frame/BUILD.gn
@@ -0,0 +1,35 @@ +# Copyright 2020 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_chromeos || is_lacros, + "Non-Chrome-OS or Lacros builds must not depend on //chromeos") + +# C++ headers and sources that can be used by both ash and lacros builds. +source_set("frame") { + defines = [ "IS_CHROMEOS_UI_FRAME_IMPL" ] + + sources = [ + "caption_buttons/caption_button_model.h", + "caption_buttons/frame_back_button.cc", + "caption_buttons/frame_back_button.h", + "caption_buttons/frame_caption_button_container_view.cc", + "caption_buttons/frame_caption_button_container_view.h", + "caption_buttons/frame_size_button.cc", + "caption_buttons/frame_size_button.h", + "caption_buttons/frame_size_button_delegate.h", + "caption_buttons/snap_controller.cc", + "caption_buttons/snap_controller.h", + ] + + deps = [ + "//base", + "//chromeos/ui/base", + "//chromeos/ui/vector_icons", + "//skia", + "//ui/aura", + "//ui/base", + "//ui/strings:ui_strings_grit", + "//ui/views", + ] +}
diff --git a/chromeos/ui/frame/DEPS b/chromeos/ui/frame/DEPS new file mode 100644 index 0000000..b2b9550 --- /dev/null +++ b/chromeos/ui/frame/DEPS
@@ -0,0 +1,10 @@ +include_rules = [ + "+ui/aura", + "+ui/base", + "+ui/compositor/scoped_animation_duration_scale_mode.h", + "+ui/events/event_sink.h", + "+ui/gfx", + "+ui/strings/grit/ui_strings.h", + "+ui/views", + "+third_party/skia", +]
diff --git a/ash/public/cpp/caption_buttons/caption_button_model.h b/chromeos/ui/frame/caption_buttons/caption_button_model.h similarity index 75% rename from ash/public/cpp/caption_buttons/caption_button_model.h rename to chromeos/ui/frame/caption_buttons/caption_button_model.h index 33ff4d5..8593203 100644 --- a/ash/public/cpp/caption_buttons/caption_button_model.h +++ b/chromeos/ui/frame/caption_buttons/caption_button_model.h
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_PUBLIC_CPP_CAPTION_BUTTONS_CAPTION_BUTTON_MODEL_H_ -#define ASH_PUBLIC_CPP_CAPTION_BUTTONS_CAPTION_BUTTON_MODEL_H_ +#ifndef CHROMEOS_UI_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_MODEL_H_ +#define CHROMEOS_UI_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_MODEL_H_ #include "ui/views/window/caption_button_types.h" -namespace ash { +namespace chromeos { // CaptionButtonModel describes the state of caption buttons // for each CaptionButtonIcon types. @@ -26,6 +26,6 @@ virtual bool InZoomMode() const = 0; }; -} // namespace ash +} // namespace chromeos -#endif // ASH_PUBLIC_CPP_CAPTION_BUTTONS_CAPTION_BUTTON_MODEL_H_ +#endif // CHROMEOS_UI_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_MODEL_H_
diff --git a/ash/public/cpp/caption_buttons/frame_back_button.cc b/chromeos/ui/frame/caption_buttons/frame_back_button.cc similarity index 93% rename from ash/public/cpp/caption_buttons/frame_back_button.cc rename to chromeos/ui/frame/caption_buttons/frame_back_button.cc index cb2a5ae..f2b9041 100644 --- a/ash/public/cpp/caption_buttons/frame_back_button.cc +++ b/chromeos/ui/frame/caption_buttons/frame_back_button.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/public/cpp/caption_buttons/frame_back_button.h" +#include "chromeos/ui/frame/caption_buttons/frame_back_button.h" #include "chromeos/ui/vector_icons/vector_icons.h" #include "ui/aura/window.h" @@ -15,7 +15,7 @@ #include "ui/views/window/caption_button_layout_constants.h" #include "ui/views/window/frame_caption_button.h" -namespace ash { +namespace chromeos { FrameBackButton::FrameBackButton() : FrameCaptionButton(this, views::CAPTION_BUTTON_ICON_BACK, HTMENU) { @@ -38,4 +38,4 @@ ignore_result(root_window->GetHost()->SendEventToSink(&release_key_event)); } -} // namespace ash +} // namespace chromeos
diff --git a/chromeos/ui/frame/caption_buttons/frame_back_button.h b/chromeos/ui/frame/caption_buttons/frame_back_button.h new file mode 100644 index 0000000..331de34 --- /dev/null +++ b/chromeos/ui/frame/caption_buttons/frame_back_button.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 CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_BACK_BUTTON_H_ +#define CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_BACK_BUTTON_H_ + +#include "base/component_export.h" +#include "ui/views/window/frame_caption_button.h" + +namespace chromeos { + +// A button to send back key events. It's used in Chrome hosted app windows, +// among other places. +class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) FrameBackButton + : public views::FrameCaptionButton, + public views::ButtonListener { + public: + FrameBackButton(); + ~FrameBackButton() override; + + // views::ButtonListener: + void ButtonPressed(Button* sender, const ui::Event& event) override; + + private: + DISALLOW_COPY_AND_ASSIGN(FrameBackButton); +}; + +} // namespace chromeos + +#endif // CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_BACK_BUTTON_H_
diff --git a/ash/public/cpp/caption_buttons/frame_caption_button_container_view.cc b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc similarity index 97% rename from ash/public/cpp/caption_buttons/frame_caption_button_container_view.cc rename to chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc index a28cfc7..59db93c 100644 --- a/ash/public/cpp/caption_buttons/frame_caption_button_container_view.cc +++ b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include <cmath> #include <map> -#include "ash/public/cpp/caption_buttons/caption_button_model.h" -#include "ash/public/cpp/caption_buttons/frame_size_button.h" -#include "ash/public/cpp/caption_buttons/snap_controller.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/numerics/ranges.h" #include "chromeos/ui/base/tablet_state.h" +#include "chromeos/ui/frame/caption_buttons/caption_button_model.h" +#include "chromeos/ui/frame/caption_buttons/frame_size_button.h" +#include "chromeos/ui/frame/caption_buttons/snap_controller.h" #include "ui/aura/window_tree_host.h" #include "ui/base/hit_test.h" #include "ui/base/l10n/l10n_util.h" @@ -31,7 +31,7 @@ #include "ui/views/widget/widget_delegate.h" #include "ui/views/window/frame_caption_button.h" -namespace ash { +namespace chromeos { namespace { @@ -473,7 +473,7 @@ views::FrameCaptionButton* buttons[] = {menu_button_, minimize_button_, size_button_, close_button_}; int min_squared_distance = INT_MAX; - views::FrameCaptionButton* closest_button = NULL; + views::FrameCaptionButton* closest_button = nullptr; for (size_t i = 0; i < base::size(buttons); ++i) { views::FrameCaptionButton* button = buttons[i]; if (!button->GetVisible()) @@ -520,4 +520,4 @@ SnapController::Get()->CommitSnap(frame_->GetNativeWindow(), snap); } -} // namespace ash +} // namespace chromeos
diff --git a/ash/public/cpp/caption_buttons/frame_caption_button_container_view.h b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h similarity index 87% rename from ash/public/cpp/caption_buttons/frame_caption_button_container_view.h rename to chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h index 61cd215..bff904e 100644 --- a/ash/public/cpp/caption_buttons/frame_caption_button_container_view.h +++ b/chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ -#define ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ +#ifndef CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ +#define CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ #include <map> -#include "ash/public/cpp/ash_public_export.h" -#include "ash/public/cpp/caption_buttons/caption_button_model.h" -#include "ash/public/cpp/caption_buttons/frame_size_button_delegate.h" -#include "ash/public/cpp/caption_buttons/snap_controller.h" +#include "base/component_export.h" #include "base/macros.h" +#include "chromeos/ui/frame/caption_buttons/caption_button_model.h" +#include "chromeos/ui/frame/caption_buttons/frame_size_button_delegate.h" +#include "chromeos/ui/frame/caption_buttons/snap_controller.h" #include "ui/views/animation/animation_delegate_views.h" #include "ui/views/controls/button/button.h" #include "ui/views/view.h" @@ -26,11 +26,15 @@ class Widget; } -namespace ash { +namespace chromeos { // Container view for the frame caption buttons. It performs the appropriate // action when a caption button is clicked. -class ASH_PUBLIC_EXPORT FrameCaptionButtonContainerView +// +// NOTE: The associated test (frame_caption_button_container_view_unittest.cc) +// is in //ash because it needs ash test support (AshTestBase and its +// utilities). +class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) FrameCaptionButtonContainerView : public views::View, public views::ButtonListener, public FrameSizeButtonDelegate, @@ -43,7 +47,7 @@ ~FrameCaptionButtonContainerView() override; // For testing. - class ASH_PUBLIC_EXPORT TestApi { + class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) TestApi { public: explicit TestApi(FrameCaptionButtonContainerView* container_view) : container_view_(container_view) {} @@ -166,6 +170,6 @@ DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerView); }; -} // namespace ash +} // namespace chromeos -#endif // ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ +#endif // CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_
diff --git a/ash/public/cpp/caption_buttons/frame_size_button.cc b/chromeos/ui/frame/caption_buttons/frame_size_button.cc similarity index 97% rename from ash/public/cpp/caption_buttons/frame_size_button.cc rename to chromeos/ui/frame/caption_buttons/frame_size_button.cc index e67f494..7a1e1d58 100644 --- a/ash/public/cpp/caption_buttons/frame_size_button.cc +++ b/chromeos/ui/frame/caption_buttons/frame_size_button.cc
@@ -2,21 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/public/cpp/caption_buttons/frame_size_button.h" +#include "chromeos/ui/frame/caption_buttons/frame_size_button.h" #include <memory> -#include "ash/public/cpp/caption_buttons/snap_controller.h" #include "base/i18n/rtl.h" #include "base/metrics/user_metrics.h" #include "chromeos/ui/base/window_properties.h" +#include "chromeos/ui/frame/caption_buttons/snap_controller.h" #include "ui/aura/window.h" #include "ui/aura/window_observer.h" #include "ui/base/hit_test.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/views/widget/widget.h" -namespace ash { +namespace chromeos { namespace { @@ -277,7 +277,7 @@ HitTestButton(closest_button, event_location_in_screen)) { return closest_button; } - return NULL; + return nullptr; } bool FrameSizeButton::CommitSnap(const ui::LocatedEvent& event) { @@ -313,4 +313,4 @@ delegate_->SetButtonsToNormal(animate); } -} // namespace ash +} // namespace chromeos
diff --git a/ash/public/cpp/caption_buttons/frame_size_button.h b/chromeos/ui/frame/caption_buttons/frame_size_button.h similarity index 89% rename from ash/public/cpp/caption_buttons/frame_size_button.h rename to chromeos/ui/frame/caption_buttons/frame_size_button.h index 58023fa..893946f 100644 --- a/ash/public/cpp/caption_buttons/frame_size_button.h +++ b/chromeos/ui/frame/caption_buttons/frame_size_button.h
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_ -#define ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_ +#ifndef CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_ +#define CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_ #include <memory> -#include "ash/public/cpp/ash_public_export.h" -#include "ash/public/cpp/caption_buttons/frame_size_button_delegate.h" +#include "base/component_export.h" #include "base/macros.h" #include "base/timer/timer.h" +#include "chromeos/ui/frame/caption_buttons/frame_size_button_delegate.h" #include "ui/views/window/frame_caption_button.h" -namespace ash { +namespace chromeos { // The maximize/restore button. // When the mouse is pressed over the size button or the size button is touched: @@ -24,7 +24,8 @@ // When the drag terminates, the action for the button underneath the mouse // is executed. For the sake of simplicity, the size button is the event // handler for a click starting on the size button and the entire drag. -class ASH_PUBLIC_EXPORT FrameSizeButton : public views::FrameCaptionButton { +class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) FrameSizeButton + : public views::FrameCaptionButton { public: FrameSizeButton(views::ButtonListener* listener, FrameSizeButtonDelegate* delegate); @@ -103,6 +104,6 @@ DISALLOW_COPY_AND_ASSIGN(FrameSizeButton); }; -} // namespace ash +} // namespace chromeos -#endif // ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_ +#endif // CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_
diff --git a/ash/public/cpp/caption_buttons/frame_size_button_delegate.h b/chromeos/ui/frame/caption_buttons/frame_size_button_delegate.h similarity index 83% rename from ash/public/cpp/caption_buttons/frame_size_button_delegate.h rename to chromeos/ui/frame/caption_buttons/frame_size_button_delegate.h index 7c48f16..8141a775 100644 --- a/ash/public/cpp/caption_buttons/frame_size_button_delegate.h +++ b/chromeos/ui/frame/caption_buttons/frame_size_button_delegate.h
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_ -#define ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_ +#ifndef CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_ +#define CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_ -#include "ash/public/cpp/ash_public_export.h" +#include "base/component_export.h" #include "ui/views/window/caption_button_types.h" namespace gfx { @@ -16,12 +16,12 @@ class FrameCaptionButton; } -namespace ash { +namespace chromeos { enum class SnapDirection; // Delegate interface for FrameSizeButton. -class ASH_PUBLIC_EXPORT FrameSizeButtonDelegate { +class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) FrameSizeButtonDelegate { public: enum Animate { ANIMATE_YES, ANIMATE_NO }; @@ -58,6 +58,6 @@ virtual ~FrameSizeButtonDelegate() {} }; -} // namespace ash +} // namespace chromeos -#endif // ASH_PUBLIC_CPP_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_ +#endif // CHROMEOS_UI_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_
diff --git a/ash/public/cpp/caption_buttons/snap_controller.cc b/chromeos/ui/frame/caption_buttons/snap_controller.cc similarity index 82% rename from ash/public/cpp/caption_buttons/snap_controller.cc rename to chromeos/ui/frame/caption_buttons/snap_controller.cc index 2cf48b9a..3c62788 100644 --- a/ash/public/cpp/caption_buttons/snap_controller.cc +++ b/chromeos/ui/frame/caption_buttons/snap_controller.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/public/cpp/caption_buttons/snap_controller.h" +#include "chromeos/ui/frame/caption_buttons/snap_controller.h" #include "base/check_op.h" -namespace ash { +namespace chromeos { namespace { @@ -29,4 +29,4 @@ g_instance = this; } -} // namespace ash +} // namespace chromeos
diff --git a/ash/public/cpp/caption_buttons/snap_controller.h b/chromeos/ui/frame/caption_buttons/snap_controller.h similarity index 78% rename from ash/public/cpp/caption_buttons/snap_controller.h rename to chromeos/ui/frame/caption_buttons/snap_controller.h index be58f9ec..cd98aa54c 100644 --- a/ash/public/cpp/caption_buttons/snap_controller.h +++ b/chromeos/ui/frame/caption_buttons/snap_controller.h
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_PUBLIC_CPP_CAPTION_BUTTONS_SNAP_CONTROLLER_H_ -#define ASH_PUBLIC_CPP_CAPTION_BUTTONS_SNAP_CONTROLLER_H_ +#ifndef CHROMEOS_UI_FRAME_CAPTION_BUTTONS_SNAP_CONTROLLER_H_ +#define CHROMEOS_UI_FRAME_CAPTION_BUTTONS_SNAP_CONTROLLER_H_ -#include "ash/public/cpp/ash_public_export.h" +#include "base/component_export.h" namespace aura { class Window; } -namespace ash { +namespace chromeos { // The previewed snap state for a window, corresponding to the use of a // PhantomWindowController. @@ -23,7 +23,7 @@ // This interface handles snap actions to be performed on a top level window. // The singleton that implements the interface is provided by Ash. -class ASH_PUBLIC_EXPORT SnapController { +class COMPONENT_EXPORT(CHROMEOS_UI_FRAME) SnapController { public: virtual ~SnapController(); @@ -43,6 +43,6 @@ SnapController(); }; -} // namespace ash +} // namespace chromeos -#endif // ASH_PUBLIC_CPP_CAPTION_BUTTONS_SNAP_CONTROLLER_H_ +#endif // CHROMEOS_UI_FRAME_CAPTION_BUTTONS_SNAP_CONTROLLER_H_
diff --git a/components/arc/session/arc_vm_client_adapter.cc b/components/arc/session/arc_vm_client_adapter.cc index aeca7d62..e5d21a5 100644 --- a/components/arc/session/arc_vm_client_adapter.cc +++ b/components/arc/session/arc_vm_client_adapter.cc
@@ -547,6 +547,13 @@ << "StopArcInstance is called during browser shutdown. Do nothing."; return; } + if (current_cid_ == kInvalidCid) { + // No VM is currently running, avoid calling ConciergeClient::StopVm(). + // TODO(wvk): Once StartMiniArc() is implemented, use a DCHECK here + // instead. + OnArcInstanceStopped(); + return; + } if (should_backup_log) { GetDebugDaemonClient()->BackupArcBugReport(
diff --git a/components/arc/session/arc_vm_client_adapter_unittest.cc b/components/arc/session/arc_vm_client_adapter_unittest.cc index 44d83087..693e7d6 100644 --- a/components/arc/session/arc_vm_client_adapter_unittest.cc +++ b/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -710,7 +710,9 @@ // Tests that StopArcInstance() immediately notifies the observer on failure. TEST_F(ArcVmClientAdapterTest, StopArcInstance_Fail) { + SetValidUserInfo(); StartMiniArc(); + UpgradeArc(true); // Inject failure. vm_tools::concierge::StopVmResponse response; @@ -738,15 +740,11 @@ EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called()); EXPECT_FALSE(arc_instance_stopped_called()); - // Try to stop the VM. StopVm will fail in this case because - // no VM is running. - vm_tools::concierge::StopVmResponse response; - response.set_success(false); - GetTestConciergeClient()->set_stop_vm_response(response); + // Try to stop the VM. No VM is running so StopVm() shouldn't be called. adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/false); run_loop()->Run(); - EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called()); + EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called()); EXPECT_TRUE(arc_instance_stopped_called()); } @@ -802,15 +800,11 @@ EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called()); EXPECT_FALSE(arc_instance_stopped_called()); - // Try to stop the VM. StopVm will fail in this case because - // no VM is running. - vm_tools::concierge::StopVmResponse response; - response.set_success(false); - GetTestConciergeClient()->set_stop_vm_response(response); + // Try to stop the VM. No VM is running so StopVm() shouldn't be called. adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/false); run_loop()->Run(); - EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called()); + EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called()); EXPECT_TRUE(arc_instance_stopped_called()); } @@ -827,15 +821,11 @@ EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called()); EXPECT_FALSE(arc_instance_stopped_called()); - // Try to stop the VM. StopVm will fail in this case because - // no VM is running. - vm_tools::concierge::StopVmResponse response; - response.set_success(false); - GetTestConciergeClient()->set_stop_vm_response(response); + // Try to stop the VM. No VM is running so StopVm() shouldn't be called. adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/false); run_loop()->Run(); - EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called()); + EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called()); EXPECT_TRUE(arc_instance_stopped_called()); } @@ -853,15 +843,11 @@ EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called()); EXPECT_FALSE(arc_instance_stopped_called()); - // Try to stop the VM. StopVm will fail in this case because - // no VM is running. - vm_tools::concierge::StopVmResponse response; - response.set_success(false); - GetTestConciergeClient()->set_stop_vm_response(response); + // Try to stop the VM. No VM is running so StopVm() shouldn't be called. adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/false); run_loop()->Run(); - EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called()); + EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called()); EXPECT_TRUE(arc_instance_stopped_called()); } @@ -876,15 +862,11 @@ EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called()); EXPECT_FALSE(arc_instance_stopped_called()); - // Try to stop the VM. StopVm will fail in this case because - // no VM is running. - vm_tools::concierge::StopVmResponse response; - response.set_success(false); - GetTestConciergeClient()->set_stop_vm_response(response); + // Try to stop the VM. No VM is running so StopVm() shouldn't be called. adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/false); run_loop()->Run(); - EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called()); + EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called()); EXPECT_TRUE(arc_instance_stopped_called()); } @@ -899,15 +881,11 @@ EXPECT_FALSE(GetTestConciergeClient()->start_arc_vm_called()); EXPECT_FALSE(arc_instance_stopped_called()); - // Try to stop the VM. StopVm will fail in this case because - // no VM is running. - vm_tools::concierge::StopVmResponse response; - response.set_success(false); - GetTestConciergeClient()->set_stop_vm_response(response); + // Try to stop the VM. No VM is running so StopVm() shouldn't be called. adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/false); run_loop()->Run(); - EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called()); + EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called()); EXPECT_TRUE(arc_instance_stopped_called()); } @@ -924,15 +902,11 @@ EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called()); EXPECT_FALSE(arc_instance_stopped_called()); - // Try to stop the VM. StopVm will fail in this case because - // no VM is running. - vm_tools::concierge::StopVmResponse response; - response.set_success(false); - GetTestConciergeClient()->set_stop_vm_response(response); + // Try to stop the VM. No VM is running so StopVm() shouldn't be called. adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/false); run_loop()->Run(); - EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called()); + EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called()); EXPECT_TRUE(arc_instance_stopped_called()); } @@ -946,15 +920,11 @@ EXPECT_TRUE(GetTestConciergeClient()->start_arc_vm_called()); EXPECT_FALSE(arc_instance_stopped_called()); - // Try to stop the VM. StopVm will fail in this case because - // no VM is running. - vm_tools::concierge::StopVmResponse response; - response.set_success(false); - GetTestConciergeClient()->set_stop_vm_response(response); + // Try to stop the VM. No VM is running so StopVm() shouldn't be called. adapter()->StopArcInstance(/*on_shutdown=*/false, /*should_backup_log=*/false); run_loop()->Run(); - EXPECT_TRUE(GetTestConciergeClient()->stop_vm_called()); + EXPECT_FALSE(GetTestConciergeClient()->stop_vm_called()); EXPECT_TRUE(arc_instance_stopped_called()); }
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager.cc b/components/autofill/core/browser/payments/credit_card_save_manager.cc index e9e8c20..dc616b85 100644 --- a/components/autofill/core/browser/payments/credit_card_save_manager.cc +++ b/components/autofill/core/browser/payments/credit_card_save_manager.cc
@@ -486,6 +486,8 @@ // should not display the offer-to-save infobar at all. if (!is_mobile_build || show_save_prompt_.value_or(true)) { user_did_accept_upload_prompt_ = false; + if (observer_for_testing_) + observer_for_testing_->OnOfferUploadSave(); client_->ConfirmSaveCreditCardToCloud( upload_request_.card, legal_message_lines_, AutofillClient::SaveCreditCardOptions()
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager.h b/components/autofill/core/browser/payments/credit_card_save_manager.h index cc5131c..a1e7714 100644 --- a/components/autofill/core/browser/payments/credit_card_save_manager.h +++ b/components/autofill/core/browser/payments/credit_card_save_manager.h
@@ -84,6 +84,7 @@ public: virtual ~ObserverForTest() {} virtual void OnOfferLocalSave() {} + virtual void OnOfferUploadSave() {} virtual void OnDecideToRequestUploadSave() {} virtual void OnReceivedGetUploadDetailsResponse() {} virtual void OnSentUploadCardRequest() {}
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn index 2ff08f53..3c27ddd 100644 --- a/components/exo/BUILD.gn +++ b/components/exo/BUILD.gn
@@ -129,6 +129,7 @@ "//chromeos/constants", "//chromeos/crosapi/cpp", "//chromeos/ui/base", + "//chromeos/ui/frame", "//ui/events/ozone/layout", ] sources += [ @@ -302,6 +303,7 @@ "//ash/keyboard/ui", "//ash/public/cpp", "//chromeos/constants", + "//chromeos/ui/frame", "//ui/base:test_support", "//ui/base/cursor/mojom:cursor_type", "//ui/base/dragdrop/mojom:mojom_shared",
diff --git a/components/exo/DEPS b/components/exo/DEPS index 46b7ed2d..9b0c1e4 100644 --- a/components/exo/DEPS +++ b/components/exo/DEPS
@@ -5,6 +5,7 @@ "+chromeos/constants/chromeos_features.h", "+chromeos/crosapi/cpp/crosapi_constants.h", "+chromeos/ui/base/window_state_type.h", + "+chromeos/ui/frame/caption_buttons", "+components/viz/common", "+components/viz/host", "+device/gamepad",
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc index 467443f..5bbc164 100644 --- a/components/exo/client_controlled_shell_surface.cc +++ b/components/exo/client_controlled_shell_surface.cc
@@ -11,7 +11,6 @@ #include "ash/frame/non_client_frame_view_ash.h" #include "ash/frame/wide_frame_view.h" #include "ash/public/cpp/ash_features.h" -#include "ash/public/cpp/caption_buttons/caption_button_model.h" #include "ash/public/cpp/default_frame_header.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h" #include "ash/public/cpp/rounded_corner_decorator.h" @@ -39,6 +38,7 @@ #include "base/trace_event/trace_event.h" #include "base/trace_event/traced_value.h" #include "chromeos/ui/base/window_state_type.h" +#include "chromeos/ui/frame/caption_buttons/caption_button_model.h" #include "components/exo/shell_surface_util.h" #include "components/exo/surface.h" #include "components/exo/wm_helper.h" @@ -214,7 +214,7 @@ return window_state->IsPinned() || window_state->IsTrustedPinned(); } -class CaptionButtonModel : public ash::CaptionButtonModel { +class CaptionButtonModel : public chromeos::CaptionButtonModel { public: CaptionButtonModel(uint32_t visible_button_mask, uint32_t enabled_button_mask) : visible_button_mask_(visible_button_mask),
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc index 1c0e2b7..aafbbd3 100644 --- a/components/exo/client_controlled_shell_surface_unittest.cc +++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -8,8 +8,6 @@ #include "ash/frame/header_view.h" #include "ash/frame/non_client_frame_view_ash.h" #include "ash/frame/wide_frame_view.h" -#include "ash/public/cpp/caption_buttons/caption_button_model.h" -#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/cpp/window_pin_type.h" #include "ash/public/cpp/window_properties.h" @@ -33,6 +31,8 @@ #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "cc/paint/display_item_list.h" +#include "chromeos/ui/frame/caption_buttons/caption_button_model.h" +#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h" #include "components/exo/buffer.h" #include "components/exo/display.h" #include "components/exo/pointer.h" @@ -1503,7 +1503,7 @@ ash::NonClientFrameViewAsh* frame_view = static_cast<ash::NonClientFrameViewAsh*>( shell_surface->GetWidget()->non_client_view()->frame_view()); - ash::FrameCaptionButtonContainerView* container = + chromeos::FrameCaptionButtonContainerView* container = static_cast<ash::HeaderView*>(frame_view->GetHeaderView()) ->caption_button_container(); @@ -1511,7 +1511,7 @@ for (auto visible : kAllButtons) { uint32_t visible_buttons = 1 << visible; shell_surface->SetFrameButtons(visible_buttons, 0); - const ash::CaptionButtonModel* model = container->model(); + const chromeos::CaptionButtonModel* model = container->model(); for (auto not_visible : kAllButtons) { if (not_visible != visible) EXPECT_FALSE(model->IsVisible(not_visible)); @@ -1524,7 +1524,7 @@ for (auto enabled : kAllButtons) { uint32_t enabled_buttons = 1 << enabled; shell_surface->SetFrameButtons(kAllButtonMask, enabled_buttons); - const ash::CaptionButtonModel* model = container->model(); + const chromeos::CaptionButtonModel* model = container->model(); for (auto not_enabled : kAllButtons) { if (not_enabled != enabled) EXPECT_FALSE(model->IsEnabled(not_enabled));
diff --git a/components/feed/feed_feature_list.cc b/components/feed/feed_feature_list.cc index 8065e08..b3fad0a6 100644 --- a/components/feed/feed_feature_list.cc +++ b/components/feed/feed_feature_list.cc
@@ -30,9 +30,6 @@ &kInterestFeedContentSuggestions, "only_set_last_refresh_attempt_on_success", true}; -const base::Feature kInterestFeedFeedback{"InterestFeedFeedback", - base::FEATURE_DISABLED_BY_DEFAULT}; - const base::Feature kReportFeedUserActions{"ReportFeedUserActions", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/feed/feed_feature_list.h b/components/feed/feed_feature_list.h index 3fd0e3cb..462872491 100644 --- a/components/feed/feed_feature_list.h +++ b/components/feed/feed_feature_list.h
@@ -24,8 +24,6 @@ extern const base::FeatureParam<bool> kThrottleBackgroundFetches; extern const base::FeatureParam<bool> kOnlySetLastRefreshAttemptOnSuccess; -extern const base::Feature kInterestFeedFeedback; - // Indicates if user card clicks and views in Chrome's feed should be reported // for personalization. Also enables the feed header menu to manage the feed. extern const base::Feature kReportFeedUserActions;
diff --git a/components/heap_profiling/multi_process/test_driver.cc b/components/heap_profiling/multi_process/test_driver.cc index cf61046..fb67ecb 100644 --- a/components/heap_profiling/multi_process/test_driver.cc +++ b/components/heap_profiling/multi_process/test_driver.cc
@@ -17,6 +17,7 @@ #include "base/stl_util.h" #include "base/test/bind_test_util.h" #include "base/threading/platform_thread.h" +#include "base/trace_event/heap_profiler.h" #include "base/trace_event/heap_profiler_event_filter.h" #include "base/values.h" #include "build/build_config.h"
diff --git a/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc b/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc index 1753703..d65cd6c 100644 --- a/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc +++ b/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
@@ -21,7 +21,6 @@ #include "components/history/core/test/test_history_database.h" #include "components/sync/model/data_batch.h" #include "components/sync/model/mock_model_type_change_processor.h" -#include "components/sync/model/recording_model_type_change_processor.h" #include "components/sync/model/sync_metadata_store.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -37,12 +36,12 @@ using syncer::MetadataBatch; using syncer::MetadataChangeList; using syncer::MockModelTypeChangeProcessor; -using syncer::RecordingModelTypeChangeProcessor; using testing::_; using testing::AllOf; using testing::Mock; using testing::NiceMock; using testing::Pointee; +using testing::Return; namespace history { @@ -81,6 +80,14 @@ return arg.specifics.typed_url().title() == title; } +MATCHER(HasTypedUrlInSpecifics, "") { + return arg.specifics.has_typed_url(); +} + +MATCHER(IsValidStorageKey, "") { + return TypedURLSyncMetadataDatabase::StorageKeyToURLID(arg) > 0; +} + Time SinceEpoch(int64_t microseconds_since_epoch) { return Time::FromDeltaSinceWindowsEpoch( TimeDelta::FromMicroseconds(microseconds_since_epoch)); @@ -300,7 +307,6 @@ ASSERT_TRUE(test_dir_.CreateUniqueTempDir()); fake_history_backend_->Init( false, TestHistoryDatabaseParamsForPath(test_dir_.GetPath())); - mock_processor_.DelegateCallsByDefaultTo(&processor_); std::unique_ptr<TypedURLSyncBridge> bridge = std::make_unique<TypedURLSyncBridge>( fake_history_backend_.get(), fake_history_backend_->db(), @@ -312,13 +318,13 @@ } void TearDown() override { - VerifyProcessorReceivedValidEntityData(); fake_history_backend_->Closing(); } // Starts sync for |typed_url_sync_bridge_| with |initial_data| as the // initial sync data. void StartSyncing(const std::vector<TypedUrlSpecifics>& specifics) { + ON_CALL(mock_processor_, IsTrackingMetadata()).WillByDefault(Return(true)); // Set change processor. const auto error = bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(), @@ -455,13 +461,6 @@ base::BindOnce(&VerifyDataBatch, ExpectedMap(expected))); } - void VerifyProcessorReceivedValidEntityData() { - for (const auto& it : processor_.put_multimap()) { - EXPECT_GT(TypedURLSyncMetadataDatabase::StorageKeyToURLID(it.first), 0); - EXPECT_TRUE(it.second->specifics.has_typed_url()); - } - } - static void DiffVisits(const VisitVector& history_visits, const sync_pb::TypedUrlSpecifics& sync_specifics, std::vector<VisitInfo>* new_visits, @@ -518,12 +517,6 @@ base::ScopedTempDir test_dir_; scoped_refptr<TestHistoryBackend> fake_history_backend_; TypedURLSyncBridge* typed_url_sync_bridge_ = nullptr; - // TODO(crbug.com/791939): should be removed after moving to - // |mock_processor_|. - RecordingModelTypeChangeProcessor processor_; - - // |mock_processor_| is preferred to use instead of |processor_|. The - // |processor_| will be removed in following patches. NiceMock<MockModelTypeChangeProcessor> mock_processor_; }; @@ -791,7 +784,8 @@ WriteToTypedUrlSpecifics(server_row, server_visits, typed_url); // Check username/password url is not synced. - EXPECT_CALL(mock_processor_, Put(_, _, _)); + EXPECT_CALL(mock_processor_, + Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _)); // Make sure there is no crash when merge two urls. StartSyncing({*typed_url}); @@ -816,7 +810,8 @@ sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url(); WriteToTypedUrlSpecifics(row2, visits2, typed_url); - EXPECT_CALL(mock_processor_, Put(_, _, _)); + EXPECT_CALL(mock_processor_, + Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _)); StartSyncing({*typed_url}); // Check that the backend was updated correctly. @@ -844,7 +839,7 @@ urls.push_back(kURL); EntityData entity_data; - EXPECT_CALL(mock_processor_, Put(_, _, _)) + EXPECT_CALL(mock_processor_, Put(IsValidStorageKey(), _, _)) .WillOnce(SaveArgPointeeMove<1>(&entity_data)); StartSyncing(std::vector<TypedUrlSpecifics>()); BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors); @@ -918,7 +913,8 @@ StartSyncing(std::vector<TypedUrlSpecifics>()); - EXPECT_CALL(mock_processor_, Put(_, _, _)); + EXPECT_CALL(mock_processor_, + Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _)); BuildAndPushLocalChanges(1, 0, {kURL}, &url_rows, &visit_vectors); // Check that Put method has been already called. @@ -948,7 +944,8 @@ urls.push_back(kURL); StartSyncing(std::vector<TypedUrlSpecifics>()); - EXPECT_CALL(mock_processor_, Put(_, _, _)); + EXPECT_CALL(mock_processor_, + Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _)); BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors); // Check that Put method has been already called. @@ -1022,7 +1019,9 @@ urls.push_back("http://foo.com/"); StartSyncing(std::vector<TypedUrlSpecifics>()); - EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(4); + EXPECT_CALL(mock_processor_, + Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _)) + .Times(4); BuildAndPushLocalChanges(4, 0, urls, &url_rows, &visit_vectors); // Delete some urls from backend and create deleted row vector. @@ -1088,7 +1087,9 @@ urls.push_back("http://bar.com/"); // Add the URLs into the history db and notify the bridge. - EXPECT_CALL(mock_processor_, Put(_, _, _)).Times(urls.size()); + EXPECT_CALL(mock_processor_, + Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _)) + .Times(urls.size()); EXPECT_CALL(mock_processor_, UntrackEntityForStorageKey(_)).Times(0); BuildAndPushLocalChanges(urls.size(), 0, urls, &url_rows, &visit_vectors); // Store the typed_urls incl. metadata into the bridge's database. @@ -1333,7 +1334,8 @@ urls.push_back(kURL); StartSyncing(std::vector<TypedUrlSpecifics>()); - EXPECT_CALL(mock_processor_, Put(_, _, _)); + EXPECT_CALL(mock_processor_, + Put(IsValidStorageKey(), Pointee(HasTypedUrlInSpecifics()), _)); BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors); Time visit_time = SinceEpoch(3);
diff --git a/components/metrics/generate_expired_histograms_array.gni b/components/metrics/generate_expired_histograms_array.gni index 3560228..e9c04067 100644 --- a/components/metrics/generate_expired_histograms_array.gni +++ b/components/metrics/generate_expired_histograms_array.gni
@@ -145,6 +145,7 @@ "//tools/metrics/histograms/histograms_xml/web_audio/histograms.xml", "//tools/metrics/histograms/histograms_xml/web_core/histograms.xml", "//tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml", + "//tools/metrics/histograms/histograms_xml/weblayer/histograms.xml", "//tools/metrics/histograms/histograms_xml/windows/histograms.xml", "//tools/metrics/histograms/histograms_xml/obsolete_histograms.xml", "//tools/metrics/histograms/enums.xml",
diff --git a/components/mirroring/service/remoting_sender.cc b/components/mirroring/service/remoting_sender.cc index 6676536..2d2dcd0 100644 --- a/components/mirroring/service/remoting_sender.cc +++ b/components/mirroring/service/remoting_sender.cc
@@ -104,6 +104,10 @@ void RemotingSender::ReadFrame(uint32_t size) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!is_reading_); + + if (HadError()) { + return; + } if (!data_pipe_reader_->IsPipeValid()) { VLOG(1) << "Data pipe handle no longer valid."; OnRemotingDataStreamError(); @@ -206,10 +210,16 @@ } void RemotingSender::OnRemotingDataStreamError() { + // NOTE: This method must be idemptotent as it may be called more than once. data_pipe_reader_.reset(); stream_sender_.reset(); if (!error_callback_.is_null()) std::move(error_callback_).Run(); } +bool RemotingSender::HadError() const { + DCHECK_EQ(!data_pipe_reader_, !stream_sender_.is_bound()); + return !data_pipe_reader_; +} + } // namespace mirroring
diff --git a/components/mirroring/service/remoting_sender.h b/components/mirroring/service/remoting_sender.h index 51c7c4d..ac3ac21 100644 --- a/components/mirroring/service/remoting_sender.h +++ b/components/mirroring/service/remoting_sender.h
@@ -81,6 +81,9 @@ void OnRemotingDataStreamError(); + // Returns true if OnRemotingDataStreamError was called. + bool HadError() const; + SEQUENCE_CHECKER(sequence_checker_); const base::TickClock* clock_;
diff --git a/components/payments/content/android/BUILD.gn b/components/payments/content/android/BUILD.gn index 8b86d58..6026e7af 100644 --- a/components/payments/content/android/BUILD.gn +++ b/components/payments/content/android/BUILD.gn
@@ -73,10 +73,40 @@ sources = payments_java_resources } -android_library("java") { +# Minimal target to depend on PaymentDetailsUpdateService. This should be kept +# as small as possible, as it will always be included in chrome's base module. +android_library("service_java") { annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] sources = [ "java/src/org/chromium/components/payments/Address.java", + "java/src/org/chromium/components/payments/PackageManagerDelegate.java", + "java/src/org/chromium/components/payments/PayerData.java", + "java/src/org/chromium/components/payments/PaymentAddressTypeConverter.java", + "java/src/org/chromium/components/payments/PaymentDetailsUpdateService.java", + "java/src/org/chromium/components/payments/PaymentDetailsUpdateServiceHelper.java", + "java/src/org/chromium/components/payments/PaymentFeatureList.java", + "java/src/org/chromium/components/payments/PaymentRequestUpdateEventListener.java", + "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java", + "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperType.java", + ] + deps = [ + "//base:base_java", + "//base:jni_java", + "//components/payments/mojom:mojom_java", + "//content/public/android:content_java", + "//third_party/android_deps:androidx_annotation_annotation_java", + ] + srcjar_deps = [ + ":error_strings_generated_srcjar", + ":payment_details_update_service_aidl", + ] +} + +# TODO(crbug.com/1126301): Rename this back to "java" once references in //clank +# are updated. +android_library("all_java") { + annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] + sources = [ "java/src/org/chromium/components/payments/BasicCardUtils.java", "java/src/org/chromium/components/payments/BrowserPaymentRequest.java", "java/src/org/chromium/components/payments/CanMakePaymentQuery.java", @@ -88,15 +118,9 @@ "java/src/org/chromium/components/payments/MojoPaymentRequestGateKeeper.java", "java/src/org/chromium/components/payments/MojoStructCollection.java", "java/src/org/chromium/components/payments/OriginSecurityChecker.java", - "java/src/org/chromium/components/payments/PackageManagerDelegate.java", - "java/src/org/chromium/components/payments/PayerData.java", - "java/src/org/chromium/components/payments/PaymentAddressTypeConverter.java", "java/src/org/chromium/components/payments/PaymentApp.java", "java/src/org/chromium/components/payments/PaymentAppFactoryParams.java", "java/src/org/chromium/components/payments/PaymentDetailsConverter.java", - "java/src/org/chromium/components/payments/PaymentDetailsUpdateService.java", - "java/src/org/chromium/components/payments/PaymentDetailsUpdateServiceHelper.java", - "java/src/org/chromium/components/payments/PaymentFeatureList.java", "java/src/org/chromium/components/payments/PaymentHandlerHost.java", "java/src/org/chromium/components/payments/PaymentManifestDownloader.java", "java/src/org/chromium/components/payments/PaymentManifestParser.java", @@ -105,7 +129,6 @@ "java/src/org/chromium/components/payments/PaymentRequestLifecycleObserver.java", "java/src/org/chromium/components/payments/PaymentRequestParams.java", "java/src/org/chromium/components/payments/PaymentRequestSpec.java", - "java/src/org/chromium/components/payments/PaymentRequestUpdateEventListener.java", "java/src/org/chromium/components/payments/PaymentUIsObserver.java", "java/src/org/chromium/components/payments/PaymentValidator.java", "java/src/org/chromium/components/payments/SkipToGPayHelper.java", @@ -114,12 +137,11 @@ "java/src/org/chromium/components/payments/UrlUtil.java", "java/src/org/chromium/components/payments/WebAppManifestSection.java", "java/src/org/chromium/components/payments/intent/IsReadyToPayServiceHelper.java", - "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java", - "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperType.java", "java/src/org/chromium/components/payments/intent/WebPaymentIntentHelperTypeConverter.java", ] deps = [ ":java_resources", + ":service_java", "//base:base_java", "//base:jni_java", "//components/autofill/android:autofill_java", @@ -136,15 +158,20 @@ "//url:origin_java", ] srcjar_deps = [ - ":error_strings_generated_srcjar", ":method_strings_generated_srcjar", ":payment_app_type_generated_enum", - ":payment_details_update_service_aidl", ":payments_journey_logger_enum_javagen", ] resources_package = "org.chromium.components.payments" } +java_group("java") { + deps = [ + ":all_java", + ":service_java", + ] +} + android_aidl("payment_details_update_service_aidl") { interface_file = "java/src/org/chromium/components/payments/payment_details_update_service.aidl" sources = [
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn index a12397b..b82908b 100644 --- a/components/performance_manager/BUILD.gn +++ b/components/performance_manager/BUILD.gn
@@ -231,6 +231,7 @@ "performance_manager_tab_helper_unittest.cc", "performance_manager_unittest.cc", "registered_objects_unittest.cc", + "render_process_host_id_unittest.cc", "v8_memory/v8_context_tracker_helpers_unittest.cc", "v8_memory/v8_context_tracker_internal_unittest.cc", "v8_memory/v8_detailed_memory_unittest.cc",
diff --git a/components/performance_manager/DEPS b/components/performance_manager/DEPS index eb9f102..cf77bb8 100644 --- a/components/performance_manager/DEPS +++ b/components/performance_manager/DEPS
@@ -14,4 +14,5 @@ "+third_party/blink/public/mojom/service_worker", "+third_party/blink/public/mojom/tokens", "+third_party/leveldatabase", + "+ui/gfx/geometry", ]
diff --git a/components/performance_manager/graph/frame_node_impl.cc b/components/performance_manager/graph/frame_node_impl.cc index 489ea99..318c310 100644 --- a/components/performance_manager/graph/frame_node_impl.cc +++ b/components/performance_manager/graph/frame_node_impl.cc
@@ -229,6 +229,13 @@ return is_audible_.value(); } +const gfx::Rect& FrameNodeImpl::viewport_intersection() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // The viewport intersection of the main frame is not tracked. + DCHECK(!IsMainFrame()); + return viewport_intersection_.value(); +} + void FrameNodeImpl::SetIsCurrent(bool is_current) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); is_current_.SetAndMaybeNotify(this, is_current); @@ -274,6 +281,14 @@ is_audible_.SetAndMaybeNotify(this, is_audible); } +void FrameNodeImpl::SetViewportIntersection( + const gfx::Rect& viewport_intersection) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // The viewport intersection of the main frame is not tracked. + DCHECK(!IsMainFrame()); + viewport_intersection_.SetAndMaybeNotify(this, viewport_intersection); +} + void FrameNodeImpl::OnNavigationCommitted(const GURL& url, bool same_document) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -497,6 +512,11 @@ return is_audible(); } +const gfx::Rect& FrameNodeImpl::GetViewportIntersection() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return viewport_intersection(); +} + void FrameNodeImpl::AddChildFrame(FrameNodeImpl* child_frame_node) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(child_frame_node);
diff --git a/components/performance_manager/graph/frame_node_impl.h b/components/performance_manager/graph/frame_node_impl.h index 0a4ea6ab..2168ef0 100644 --- a/components/performance_manager/graph/frame_node_impl.h +++ b/components/performance_manager/graph/frame_node_impl.h
@@ -82,6 +82,7 @@ void SetNetworkAlmostIdle() override; void SetLifecycleState(LifecycleState state) override; void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload) override; + void SetViewportIntersection(const gfx::Rect& viewport_intersection) override; void SetOriginTrialFreezePolicy(mojom::InterventionPolicy policy) override; void SetIsAdFrame() override; void SetHadFormInteraction() override; @@ -120,6 +121,7 @@ const PriorityAndReason& priority_and_reason() const; bool had_form_interaction() const; bool is_audible() const; + const gfx::Rect& viewport_intersection() const; // Setters are not thread safe. void SetIsCurrent(bool is_current); @@ -190,6 +192,7 @@ const PriorityAndReason& GetPriorityAndReason() const override; bool HadFormInteraction() const override; bool IsAudible() const override; + const gfx::Rect& GetViewportIntersection() const override; // Properties associated with a Document, which are reset when a // different-document navigation is committed in the frame. @@ -336,6 +339,17 @@ NotifiesOnlyOnChanges<bool, &FrameNodeObserver::OnIsAudibleChanged> is_audible_{false}; + // Tracks the intersection of this frame with the viewport. + // + // Note that the viewport intersection for the main frame is always invalid. + // This is because the main frame always occupies the entirety of the viewport + // so there is no point in tracking it. To avoid programming mistakes, it is + // forbidden to query this property for the main frame. + ObservedProperty::NotifiesOnlyOnChanges< + gfx::Rect, + &FrameNodeObserver::OnViewportIntersectionChanged> + viewport_intersection_; + // Inline storage for ExecutionContext. std::unique_ptr<NodeAttachedData> execution_context_;
diff --git a/components/performance_manager/graph/frame_node_impl_describer.cc b/components/performance_manager/graph/frame_node_impl_describer.cc index 13fc713..cc54525 100644 --- a/components/performance_manager/graph/frame_node_impl_describer.cc +++ b/components/performance_manager/graph/frame_node_impl_describer.cc
@@ -6,6 +6,7 @@ #include <sstream> #include <string> +#include <utility> #include "base/task/task_traits.h" #include "base/values.h" @@ -97,6 +98,8 @@ ret.SetKey("priority", PriorityAndReasonToValue(impl->priority_and_reason_.value())); ret.SetBoolKey("is_audible", impl->is_audible_.value()); + ret.SetStringKey("viewport_intersection", + impl->viewport_intersection_.value().ToString()); return ret; }
diff --git a/components/performance_manager/graph/frame_node_impl_unittest.cc b/components/performance_manager/graph/frame_node_impl_unittest.cc index 163ff81a..1304c1e5 100644 --- a/components/performance_manager/graph/frame_node_impl_unittest.cc +++ b/components/performance_manager/graph/frame_node_impl_unittest.cc
@@ -150,6 +150,7 @@ void(const FrameNode*, const PriorityAndReason& previous_value)); MOCK_METHOD1(OnHadFormInteractionChanged, void(const FrameNode*)); MOCK_METHOD1(OnIsAudibleChanged, void(const FrameNode*)); + MOCK_METHOD1(OnViewportIntersectionChanged, void(const FrameNode*)); MOCK_METHOD1(OnNonPersistentNotificationCreated, void(const FrameNode*)); MOCK_METHOD2(OnFirstContentfulPaint, void(const FrameNode*, base::TimeDelta)); @@ -367,6 +368,27 @@ graph()->RemoveFrameNodeObserver(&obs); } +TEST_F(FrameNodeImplTest, ViewportIntersection) { + auto process = CreateNode<ProcessNodeImpl>(); + auto page = CreateNode<PageNodeImpl>(); + // A child frame node is used because the main frame does not have a viewport + // intersection. + auto main_frame_node = CreateFrameNodeAutoId(process.get(), page.get()); + auto child_frame_node = + CreateFrameNodeAutoId(process.get(), page.get(), main_frame_node.get()); + + MockObserver obs; + graph()->AddFrameNodeObserver(&obs); + + EXPECT_CALL(obs, OnViewportIntersectionChanged(child_frame_node.get())); + + gfx::Rect kViewportIntersection(25, 25, 100, 100); + child_frame_node->SetViewportIntersection(kViewportIntersection); + EXPECT_EQ(child_frame_node->viewport_intersection(), kViewportIntersection); + + graph()->RemoveFrameNodeObserver(&obs); +} + TEST_F(FrameNodeImplTest, FirstContentfulPaint) { auto process = CreateNode<ProcessNodeImpl>(); auto page = CreateNode<PageNodeImpl>(); @@ -386,7 +408,10 @@ auto process = CreateNode<ProcessNodeImpl>(); auto page = CreateNode<PageNodeImpl>(); auto frame_node = CreateFrameNodeAutoId(process.get(), page.get()); + auto child_frame_node = + CreateFrameNodeAutoId(process.get(), page.get(), frame_node.get()); const FrameNode* public_frame_node = frame_node.get(); + const FrameNode* public_child_frame_node = child_frame_node.get(); // Simply test that the public interface impls yield the same result as their // private counterpart. @@ -427,6 +452,10 @@ public_frame_node->IsHoldingIndexedDBLock()); EXPECT_EQ(frame_node->had_form_interaction(), public_frame_node->HadFormInteraction()); + // Use the child frame node to test the viewport intersection because the + // viewport intersection of the main frame is not tracked. + EXPECT_EQ(child_frame_node->viewport_intersection(), + public_child_frame_node->GetViewportIntersection()); } TEST_F(FrameNodeImplTest, VisitChildFrameNodes) {
diff --git a/components/performance_manager/public/graph/frame_node.h b/components/performance_manager/public/graph/frame_node.h index c04079f0..f7ae35a 100644 --- a/components/performance_manager/public/graph/frame_node.h +++ b/components/performance_manager/public/graph/frame_node.h
@@ -13,6 +13,7 @@ #include "components/performance_manager/public/mojom/coordination_unit.mojom.h" #include "components/performance_manager/public/mojom/lifecycle.mojom.h" #include "third_party/blink/public/common/tokens/tokens.h" +#include "ui/gfx/geometry/rect.h" class GURL; @@ -173,6 +174,9 @@ // Returns true if the frame is audible, false otherwise. virtual bool IsAudible() const = 0; + // Returns the intersection of this frame with the viewport. + virtual const gfx::Rect& GetViewportIntersection() const = 0; + // Returns a proxy to the RenderFrameHost associated with this node. The // proxy may only be dereferenced on the UI thread. virtual const RenderFrameHostProxy& GetRenderFrameHostProxy() const = 0; @@ -240,6 +244,9 @@ // Invoked when the IsAudible property changes. virtual void OnIsAudibleChanged(const FrameNode* frame_node) = 0; + // Invoked when a frame's intersection with the viewport changes + virtual void OnViewportIntersectionChanged(const FrameNode* frame_node) = 0; + // Events with no property changes. // Invoked when a non-persistent notification has been issued by the frame. @@ -287,6 +294,7 @@ const PriorityAndReason& previous_value) override {} void OnHadFormInteractionChanged(const FrameNode* frame_node) override {} void OnIsAudibleChanged(const FrameNode* frame_node) override {} + void OnViewportIntersectionChanged(const FrameNode* frame_node) override {} void OnNonPersistentNotificationCreated( const FrameNode* frame_node) override {} void OnFirstContentfulPaint(
diff --git a/components/performance_manager/public/mojom/BUILD.gn b/components/performance_manager/public/mojom/BUILD.gn index 43c1d3f78..5ed1eb9 100644 --- a/components/performance_manager/public/mojom/BUILD.gn +++ b/components/performance_manager/public/mojom/BUILD.gn
@@ -15,5 +15,8 @@ "lifecycle.mojom", ] - public_deps = [ "//mojo/public/mojom/base" ] + public_deps = [ + "//mojo/public/mojom/base", + "//ui/gfx/geometry/mojom", + ] }
diff --git a/components/performance_manager/public/mojom/coordination_unit.mojom b/components/performance_manager/public/mojom/coordination_unit.mojom index 240f02dc..6d845dd9 100644 --- a/components/performance_manager/public/mojom/coordination_unit.mojom +++ b/components/performance_manager/public/mojom/coordination_unit.mojom
@@ -7,6 +7,7 @@ import "mojo/public/mojom/base/process_id.mojom"; import "mojo/public/mojom/base/time.mojom"; import "components/performance_manager/public/mojom/lifecycle.mojom"; +import "ui/gfx/geometry/mojom/geometry.mojom"; // Any new type here needs to be mirrored between coordination_unit_types.h and // coordination_unit.mojom, and have mappings between the two defined in @@ -37,6 +38,7 @@ SetNetworkAlmostIdle(); SetLifecycleState(LifecycleState state); SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload); + // Called the first time a form in this document is interacted with. SetHadFormInteraction(); @@ -48,6 +50,11 @@ SetIsAdFrame(); + // Called when the intersection between this frame and the viewport changes. + // The viewport is the rectangular area of the top-level document that is + // visible. This is used to drive the frame prioritization logic. + SetViewportIntersection(gfx.mojom.Rect viewport_intersection); + // Event signals. // Called when the associated frame has caused a non-persistent notification
diff --git a/components/performance_manager/public/render_process_host_id.h b/components/performance_manager/public/render_process_host_id.h index 8a2f0a8a..45152939 100644 --- a/components/performance_manager/public/render_process_host_id.h +++ b/components/performance_manager/public/render_process_host_id.h
@@ -6,11 +6,33 @@ #define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_RENDER_PROCESS_HOST_ID_H_ #include "base/util/type_safety/id_type.h" +#include "content/public/common/child_process_host.h" namespace performance_manager { +using RenderProcessHostIdBase = + util::IdType<class RenderProcessHostIdTag, + int32_t, + content::ChildProcessHost::kInvalidUniqueID, + 1>; + // A strongly typed wrapper for the id returned by RenderProcessHost::GetID(). -using RenderProcessHostId = util::IdType32<class RenderProcessHostIdTag>; +// +// This uses ChildProcessHost::kInvalidUniqueId (-1) as the default invalid id, +// but also recognizes 0 as an invalid id because there is existing code that +// uses 0 as an invalid value. It starts generating id's at 1. +class RenderProcessHostId : public RenderProcessHostIdBase { + public: + using RenderProcessHostIdBase::RenderProcessHostIdBase; + + // 0 is also an invalid value. + constexpr bool is_null() const { + return RenderProcessHostIdBase::is_null() || this->value() == 0; + } + + // Override operator bool() to call the overridden is_null(). + constexpr explicit operator bool() const { return !is_null(); } +}; } // namespace performance_manager
diff --git a/components/performance_manager/render_process_host_id_unittest.cc b/components/performance_manager/render_process_host_id_unittest.cc new file mode 100644 index 0000000..d9c1763 --- /dev/null +++ b/components/performance_manager/render_process_host_id_unittest.cc
@@ -0,0 +1,39 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/performance_manager/public/render_process_host_id.h" + +#include "content/public/common/child_process_host.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace performance_manager { + +TEST(RenderProcessHostIdTest, InvalidValues) { + RenderProcessHostId default_id; + EXPECT_TRUE(default_id.is_null()); + EXPECT_FALSE(default_id); + + RenderProcessHostId invalid_id(content::ChildProcessHost::kInvalidUniqueID); + EXPECT_TRUE(invalid_id.is_null()); + EXPECT_FALSE(invalid_id); + + RenderProcessHostId zero_id(0); + EXPECT_TRUE(zero_id.is_null()); + EXPECT_FALSE(zero_id); + + EXPECT_EQ(default_id, invalid_id); + EXPECT_NE(default_id, zero_id); + + RenderProcessHostId valid_id(1); + EXPECT_FALSE(valid_id.is_null()); + EXPECT_TRUE(valid_id); +} + +TEST(RenderProcessHostIdTest, Generator) { + RenderProcessHostId::Generator generator; + EXPECT_EQ(generator.GenerateNextId(), RenderProcessHostId(1)); + EXPECT_EQ(generator.GenerateNextId(), RenderProcessHostId(2)); +} + +} // namespace performance_manager
diff --git a/components/performance_manager/v8_memory/v8_context_tracker.cc b/components/performance_manager/v8_memory/v8_context_tracker.cc index 26aae898..a96dded 100644 --- a/components/performance_manager/v8_memory/v8_context_tracker.cc +++ b/components/performance_manager/v8_memory/v8_context_tracker.cc
@@ -12,6 +12,8 @@ namespace performance_manager { namespace v8_memory { +using ProcessData = internal::ProcessData; + //////////////////////////////////////////////////////////////////////////////// // V8ContextTracker::ExecutionContextState implementation: @@ -91,24 +93,54 @@ base::Value V8ContextTracker::DescribeFrameNodeData( const FrameNode* node) const { DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph()); + + size_t v8_context_count = 0; + const auto* ec_data = + data_store_->Get(blink::ExecutionContextToken(node->GetFrameToken())); + if (ec_data) + v8_context_count = ec_data->v8_context_count(); + base::Value dict(base::Value::Type::DICTIONARY); - // TODO(chrisha): Implement me. + dict.SetIntKey("v8_context_count", v8_context_count); return dict; } base::Value V8ContextTracker::DescribeProcessNodeData( const ProcessNode* node) const { DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph()); + + size_t v8_context_count = 0; + size_t detached_v8_context_count = 0; + size_t execution_context_count = 0; + size_t destroyed_execution_context_count = 0; + const auto* process_data = ProcessData::Get(ProcessNodeImpl::FromNode(node)); + if (process_data) { + v8_context_count = process_data->GetV8ContextDataCount(); + detached_v8_context_count = process_data->GetDetachedV8ContextDataCount(); + execution_context_count = process_data->GetExecutionContextDataCount(); + destroyed_execution_context_count = + process_data->GetDestroyedExecutionContextDataCount(); + } + base::Value dict(base::Value::Type::DICTIONARY); - // TODO(chrisha): Implement me. + dict.SetIntKey("v8_context_count", v8_context_count); + dict.SetIntKey("detached_v8_context_count", detached_v8_context_count); + dict.SetIntKey("execution_context_count", execution_context_count); + dict.SetIntKey("destroyed_execution_context_count", + destroyed_execution_context_count); return dict; } base::Value V8ContextTracker::DescribeWorkerNodeData( const WorkerNode* node) const { - DCHECK_ON_GRAPH_SEQUENCE(node->GetGraph()); + size_t v8_context_count = 0; + const auto* ec_data = + data_store_->Get(ToExecutionContextToken(node->GetWorkerToken())); + if (ec_data) + v8_context_count = ec_data->v8_context_count(); + base::Value dict(base::Value::Type::DICTIONARY); - // TODO(chrisha): Implement me. + dict.SetIntKey("v8_context_count", v8_context_count); return dict; }
diff --git a/components/performance_manager/v8_memory/v8_context_tracker_helpers.cc b/components/performance_manager/v8_memory/v8_context_tracker_helpers.cc index 00b61bdd..153e98276 100644 --- a/components/performance_manager/v8_memory/v8_context_tracker_helpers.cc +++ b/components/performance_manager/v8_memory/v8_context_tracker_helpers.cc
@@ -178,5 +178,21 @@ return false; } +void MarkedObjectCount::Mark() { + DCHECK_LT(marked_count_, count_); + ++marked_count_; +} + +void MarkedObjectCount::Decrement(bool marked) { + DCHECK_LT(0u, count_); + if (marked) { + DCHECK_LT(0u, marked_count_); + --marked_count_; + } else { + DCHECK_LT(marked_count_, count_); + } + --count_; +} + } // namespace v8_memory } // namespace performance_manager
diff --git a/components/performance_manager/v8_memory/v8_context_tracker_helpers.h b/components/performance_manager/v8_memory/v8_context_tracker_helpers.h index 0eaca29..6a2aeae 100644 --- a/components/performance_manager/v8_memory/v8_context_tracker_helpers.h +++ b/components/performance_manager/v8_memory/v8_context_tracker_helpers.h
@@ -78,6 +78,61 @@ const V8ContextDescription& description, Graph* graph) WARN_UNUSED_RESULT; +// Small helper class for maintaining a count of objects that are optionally +// "marked". +class MarkedObjectCount { + public: + MarkedObjectCount() = default; + MarkedObjectCount(const MarkedObjectCount&) = delete; + MarkedObjectCount& operator=(const MarkedObjectCount&) = delete; + ~MarkedObjectCount() = default; + + size_t count() const { return count_; } + size_t marked_count() const { return marked_count_; } + + void Increment() { ++count_; } + void Mark(); + void Decrement(bool marked); + + private: + size_t marked_count_ = 0; + size_t count_ = 0; +}; + +// Helper class for maintaining a pair of context counts for both +// ExecutionContexts and V8Contexts. +class ContextCounts { + public: + ContextCounts() = default; + ContextCounts(const ContextCounts&) = delete; + ContextCounts& operator=(const ContextCounts&) = delete; + ~ContextCounts() = default; + + size_t GetExecutionContextDataCount() const { return ec_count_.count(); } + size_t GetDestroyedExecutionContextDataCount() const { + return ec_count_.marked_count(); + } + void IncrementExecutionContextDataCount() { ec_count_.Increment(); } + void MarkExecutionContextDataDestroyed() { ec_count_.Mark(); } + void DecrementExecutionContextDataCount(bool destroyed) { + ec_count_.Decrement(destroyed); + } + + size_t GetV8ContextDataCount() const { return v8_count_.count(); } + size_t GetDetachedV8ContextDataCount() const { + return v8_count_.marked_count(); + } + void IncrementV8ContextDataCount() { v8_count_.Increment(); } + void MarkV8ContextDataDetached() { v8_count_.Mark(); } + void DecrementV8ContextDataCount(bool detached) { + v8_count_.Decrement(detached); + } + + private: + MarkedObjectCount ec_count_; + MarkedObjectCount v8_count_; +}; + } // namespace v8_memory } // namespace performance_manager
diff --git a/components/performance_manager/v8_memory/v8_context_tracker_internal.cc b/components/performance_manager/v8_memory/v8_context_tracker_internal.cc index 7c61b04..7477c7bf 100644 --- a/components/performance_manager/v8_memory/v8_context_tracker_internal.cc +++ b/components/performance_manager/v8_memory/v8_context_tracker_internal.cc
@@ -60,6 +60,13 @@ return ShouldDestroy(); } +bool ExecutionContextData::MarkDestroyed(util::PassKey<ProcessData>) { + if (destroyed) + return false; + destroyed = true; + return true; +} + //////////////////////////////////////////////////////////////////////////////// // RemoteFrameData implementation: @@ -128,6 +135,13 @@ return static_cast<ExecutionContextData*>(execution_context_state); } +bool V8ContextData::MarkDetached(util::PassKey<ProcessData>) { + if (detached) + return false; + detached = true; + return true; +} + //////////////////////////////////////////////////////////////////////////////// // ProcessData implementation: @@ -181,6 +195,7 @@ DCHECK(!ec_data->ShouldDestroy()); DCHECK(!ec_data->IsTracked()); execution_context_datas_.Append(ec_data); + counts_.IncrementExecutionContextDataCount(); } void ProcessData::Add(util::PassKey<V8ContextTrackerDataStore>, @@ -197,6 +212,7 @@ DCHECK_EQ(this, v8_data->process_data()); DCHECK(!v8_data->IsTracked()); v8_context_datas_.Append(v8_data); + counts_.IncrementV8ContextDataCount(); } void ProcessData::Remove(util::PassKey<V8ContextTrackerDataStore>, @@ -205,6 +221,7 @@ DCHECK_EQ(this, ec_data->process_data()); DCHECK(ec_data->IsTracked()); DCHECK(ec_data->ShouldDestroy()); + counts_.DecrementExecutionContextDataCount(ec_data->destroyed); ec_data->RemoveFromList(); } @@ -221,9 +238,26 @@ DCHECK(v8_data); DCHECK_EQ(this, v8_data->process_data()); DCHECK(v8_data->IsTracked()); + counts_.DecrementV8ContextDataCount(v8_data->detached); v8_data->RemoveFromList(); } +bool ProcessData::MarkDestroyed(util::PassKey<V8ContextTrackerDataStore>, + ExecutionContextData* ec_data) { + bool result = ec_data->MarkDestroyed(PassKey()); + if (result) + counts_.MarkExecutionContextDataDestroyed(); + return result; +} + +bool ProcessData::MarkDetached(util::PassKey<V8ContextTrackerDataStore>, + V8ContextData* v8_data) { + bool result = v8_data->MarkDetached(PassKey()); + if (result) + counts_.MarkV8ContextDataDetached(); + return result; +} + //////////////////////////////////////////////////////////////////////////////// // V8ContextTrackerDataStore implementation: @@ -281,11 +315,35 @@ return it->get(); } +void V8ContextTrackerDataStore::MarkDestroyed(ExecutionContextData* ec_data) { + DCHECK(ec_data); + if (ec_data->process_data()->MarkDestroyed(PassKey(), ec_data)) { + DCHECK_LT(destroyed_execution_context_count_, + global_execution_context_datas_.size()); + ++destroyed_execution_context_count_; + } +} + +void V8ContextTrackerDataStore::MarkDetached(V8ContextData* v8_data) { + DCHECK(v8_data); + if (v8_data->process_data()->MarkDetached(PassKey(), v8_data)) { + DCHECK_LT(detached_v8_context_count_, global_v8_context_datas_.size()); + ++detached_v8_context_count_; + } +} + void V8ContextTrackerDataStore::Destroy( const blink::ExecutionContextToken& token) { auto it = global_execution_context_datas_.find(token); DCHECK(it != global_execution_context_datas_.end()); auto* ec_data = it->get(); + if (ec_data->destroyed) { + DCHECK_LT(0u, destroyed_execution_context_count_); + --destroyed_execution_context_count_; + } else { + DCHECK_LT(destroyed_execution_context_count_, + global_execution_context_datas_.size()); + } ec_data->process_data()->Remove(PassKey(), ec_data); global_execution_context_datas_.erase(it); } @@ -302,6 +360,12 @@ auto it = global_v8_context_datas_.find(token); DCHECK(it != global_v8_context_datas_.end()); auto* v8_data = it->get(); + if (v8_data->detached) { + DCHECK_LT(0u, detached_v8_context_count_); + --detached_v8_context_count_; + } else { + DCHECK_LT(detached_v8_context_count_, global_v8_context_datas_.size()); + } v8_data->process_data()->Remove(PassKey(), v8_data); global_v8_context_datas_.erase(it); }
diff --git a/components/performance_manager/v8_memory/v8_context_tracker_internal.h b/components/performance_manager/v8_memory/v8_context_tracker_internal.h index 30adf6a..c5bec6c 100644 --- a/components/performance_manager/v8_memory/v8_context_tracker_internal.h +++ b/components/performance_manager/v8_memory/v8_context_tracker_internal.h
@@ -20,6 +20,7 @@ #include "components/performance_manager/graph/node_attached_data_impl.h" #include "components/performance_manager/graph/process_node_impl.h" #include "components/performance_manager/v8_memory/v8_context_tracker.h" +#include "components/performance_manager/v8_memory/v8_context_tracker_helpers.h" #include "components/performance_manager/v8_memory/v8_context_tracker_types.h" #include "third_party/blink/public/common/tokens/tokens.h" @@ -100,6 +101,10 @@ // transitioned to "ShouldDestroy". WARN_UNUSED_RESULT bool DecrementV8ContextCount(util::PassKey<V8ContextData>); + // Marks this context as destroyed. Returns true if the state changed, false + // if it was already destroyed. + WARN_UNUSED_RESULT bool MarkDestroyed(util::PassKey<ProcessData>); + private: ProcessData* const process_data_; @@ -180,6 +185,10 @@ // Returns the ExecutionContextData associated with this V8ContextData. ExecutionContextData* GetExecutionContextData() const; + // Marks this context as detached. Returns true if the state changed, false + // if it was already detached. + WARN_UNUSED_RESULT bool MarkDetached(util::PassKey<ProcessData>); + private: ProcessData* const process_data_; }; @@ -191,6 +200,8 @@ public: struct Traits : public NodeAttachedDataInMap<ProcessNodeImpl> {}; + using PassKey = util::PassKey<ProcessData>; + explicit ProcessData(const ProcessNodeImpl* process_node); ~ProcessData() override; @@ -217,6 +228,27 @@ RemoteFrameData* rf_data); void Remove(util::PassKey<V8ContextTrackerDataStore>, V8ContextData* v8_data); + // For marking objects detached/destroyed. Returns true if the state + // actually changed, false otherwise. + WARN_UNUSED_RESULT bool MarkDestroyed( + util::PassKey<V8ContextTrackerDataStore>, + ExecutionContextData* ec_data); + WARN_UNUSED_RESULT bool MarkDetached(util::PassKey<V8ContextTrackerDataStore>, + V8ContextData* v8_data); + + size_t GetExecutionContextDataCount() const { + return counts_.GetExecutionContextDataCount(); + } + size_t GetDestroyedExecutionContextDataCount() const { + return counts_.GetDestroyedExecutionContextDataCount(); + } + size_t GetV8ContextDataCount() const { + return counts_.GetV8ContextDataCount(); + } + size_t GetDetachedV8ContextDataCount() const { + return counts_.GetDetachedV8ContextDataCount(); + } + private: // Used to initialize |data_store_| at construction. static V8ContextTrackerDataStore* GetDataStore( @@ -227,6 +259,9 @@ // Pointer to the DataStore that implicitly owns us. V8ContextTrackerDataStore* const data_store_; + // Counts the number of ExecutionContexts and V8Contexts. + ContextCounts counts_; + // List of ExecutionContextDatas associated with this process. base::LinkedList<ExecutionContextData> execution_context_datas_; @@ -262,12 +297,23 @@ RemoteFrameData* Get(const blink::RemoteFrameToken& token); V8ContextData* Get(const blink::V8ContextToken& token); + // For marking objects as detached/destroyed. + void MarkDestroyed(ExecutionContextData* ec_data); + void MarkDetached(V8ContextData* v8_data); + // Destroys objects by token. They must exist ("Get" should return non // nullptr). void Destroy(const blink::ExecutionContextToken& token); void Destroy(const blink::RemoteFrameToken& token); void Destroy(const blink::V8ContextToken& token); + size_t GetDestroyedExecutionContextDataCount() const { + return destroyed_execution_context_count_; + } + size_t GetDetachedV8ContextDataCount() const { + return detached_v8_context_count_; + } + size_t GetExecutionContextDataCount() const { return global_execution_context_datas_.size(); } @@ -279,6 +325,9 @@ } private: + size_t destroyed_execution_context_count_ = 0; + size_t detached_v8_context_count_ = 0; + // Browser wide registry of ExecutionContextData objects. std::set<std::unique_ptr<ExecutionContextData>, ExecutionContextData::Comparator>
diff --git a/components/performance_manager/v8_memory/v8_context_tracker_internal_unittest.cc b/components/performance_manager/v8_memory/v8_context_tracker_internal_unittest.cc index 7af3f748..e4bd742 100644 --- a/components/performance_manager/v8_memory/v8_context_tracker_internal_unittest.cc +++ b/components/performance_manager/v8_memory/v8_context_tracker_internal_unittest.cc
@@ -221,6 +221,75 @@ EXPECT_EQ(0u, data_store()->GetV8ContextDataCount()); } +TEST_F(V8ContextTrackerInternalTest, ContextCounts) { + auto* process_data = ProcessData::GetOrCreate( + static_cast<ProcessNodeImpl*>(mock_graph_.process.get())); + + std::unique_ptr<ExecutionContextData> ec_data = + std::make_unique<ExecutionContextData>( + process_data, mock_graph_.frame->frame_token(), base::nullopt); + auto* raw_ec_data = ec_data.get(); + + std::unique_ptr<V8ContextData> v8_data1 = std::make_unique<V8ContextData>( + process_data, V8ContextDescription(), ec_data.get()); + auto* raw_v8_data1 = v8_data1.get(); + + std::unique_ptr<V8ContextData> v8_data2 = std::make_unique<V8ContextData>( + process_data, V8ContextDescription(), ec_data.get()); + + data_store()->Pass(std::move(ec_data)); + data_store()->Pass(std::move(v8_data1)); + data_store()->Pass(std::move(v8_data2)); + + EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount()); + EXPECT_EQ(0u, data_store()->GetDestroyedExecutionContextDataCount()); + EXPECT_EQ(2u, data_store()->GetV8ContextDataCount()); + EXPECT_EQ(0u, data_store()->GetDetachedV8ContextDataCount()); + EXPECT_EQ(1u, process_data->GetExecutionContextDataCount()); + EXPECT_EQ(0u, process_data->GetDestroyedExecutionContextDataCount()); + EXPECT_EQ(2u, process_data->GetV8ContextDataCount()); + EXPECT_EQ(0u, process_data->GetDetachedV8ContextDataCount()); + + EXPECT_FALSE(raw_ec_data->destroyed); + data_store()->MarkDestroyed(raw_ec_data); + EXPECT_TRUE(raw_ec_data->destroyed); + + EXPECT_FALSE(raw_v8_data1->detached); + data_store()->MarkDetached(raw_v8_data1); + EXPECT_TRUE(raw_v8_data1->detached); + + EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount()); + EXPECT_EQ(1u, data_store()->GetDestroyedExecutionContextDataCount()); + EXPECT_EQ(2u, data_store()->GetV8ContextDataCount()); + EXPECT_EQ(1u, data_store()->GetDetachedV8ContextDataCount()); + EXPECT_EQ(1u, process_data->GetExecutionContextDataCount()); + EXPECT_EQ(1u, process_data->GetDestroyedExecutionContextDataCount()); + EXPECT_EQ(2u, process_data->GetV8ContextDataCount()); + EXPECT_EQ(1u, process_data->GetDetachedV8ContextDataCount()); + + data_store()->Destroy(raw_v8_data1->GetToken()); + + EXPECT_EQ(1u, data_store()->GetExecutionContextDataCount()); + EXPECT_EQ(1u, data_store()->GetDestroyedExecutionContextDataCount()); + EXPECT_EQ(1u, data_store()->GetV8ContextDataCount()); + EXPECT_EQ(0u, data_store()->GetDetachedV8ContextDataCount()); + EXPECT_EQ(1u, process_data->GetExecutionContextDataCount()); + EXPECT_EQ(1u, process_data->GetDestroyedExecutionContextDataCount()); + EXPECT_EQ(1u, process_data->GetV8ContextDataCount()); + EXPECT_EQ(0u, process_data->GetDetachedV8ContextDataCount()); + + process_data->TearDown(); + + EXPECT_EQ(0u, data_store()->GetExecutionContextDataCount()); + EXPECT_EQ(0u, data_store()->GetDestroyedExecutionContextDataCount()); + EXPECT_EQ(0u, data_store()->GetV8ContextDataCount()); + EXPECT_EQ(0u, data_store()->GetDetachedV8ContextDataCount()); + EXPECT_EQ(0u, process_data->GetExecutionContextDataCount()); + EXPECT_EQ(0u, process_data->GetDestroyedExecutionContextDataCount()); + EXPECT_EQ(0u, process_data->GetV8ContextDataCount()); + EXPECT_EQ(0u, process_data->GetDetachedV8ContextDataCount()); +} + namespace { class V8ContextTrackerInternalTearDownOrderTest
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index bc93733..3aaef76 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -11667,11 +11667,9 @@ 'id': 185, 'caption': '''Allow users to redeem offers through Chrome OS Registration''', 'tags': [], - 'desc': '''IT admins for enterprise devices can use this flag to control whether to allow users to redeem offers through Chrome OS Registration. + 'desc': '''Setting the policy to Enabled or leaving it unset lets enterprise device users redeem offers through <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> Registration. - If this policy is set to true or left not set, users will be able to redeem offers through Chrome OS Registration. - - If this policy is set to false, user will not be able to redeem offers.''', + Setting the policy to Disabled means users can't redeem these offers.''', }, { 'name': 'TermsOfServiceURL', @@ -11687,11 +11685,9 @@ 'id': 186, 'caption': '''Set the Terms of Service for a device-local account''', 'tags': [], - 'desc': '''Sets the Terms of Service that the user must accept before starting a device-local account session. + 'desc': '''Setting the policy means <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> downloads the Terms of Service and presents them to users whenever a device-local account session starts. Users can only sign in to the session after accepting the Terms of Service. - If this policy is set, <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> will download the Terms of Service and present them to the user whenever a device-local account session is starting. The user will only be allowed into the session after accepting the Terms of Service. - - If this policy is not set, no Terms of Service are shown. + Leaving the policy unset means no Terms of Service appear. The policy should be set to a URL from which <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> can download the Terms of Service. The Terms of Service must be plain text, served as MIME type text/plain. No markup is allowed.''', }, @@ -13541,9 +13537,9 @@ 'id': 574, 'caption': '''Enforce browser guest mode''', 'tags': [], - 'desc': '''If this policy is set to enabled, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will enforce guest sessions and prevents profile logins. Guest logins are <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> profiles where all windows are in incognito mode. + 'desc': '''Setting the policy to Enabled means <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> enforces guest sessions and prevents profile sign-ins. Guest sign-ins are <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> profiles where windows are in Incognito mode. - If this policy is set to disabled or not set or browser guest mode is disabled by <ph name="BROWSER_GUEST_MODE_ENABLED_POLICY_NAME">BrowserGuestModeEnabled</ph> policy, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will allow using new and existing profiles.''', + Setting the policy to Disabled, leaving it unset, or disabling browser Guest mode (through <ph name="BROWSER_GUEST_MODE_ENABLED_POLICY_NAME">BrowserGuestModeEnabled</ph>) allows the use of new and existing profiles.''', }, { 'name': 'BrowserAddPersonEnabled', @@ -16211,11 +16207,11 @@ 'id': 469, 'caption': '''Allow SMS Messages to be synced from phone to Chromebook.''', 'tags': ['local-data-access', 'google-sharing'], - 'desc': '''If this setting is enabled, users will be allowed to set up their devices to sync SMS messages between their phones and Chromebooks. Note that if this policy is allowed, users must explicitly opt into this feature by completing a setup flow. Once the setup flow is complete, users will be able to send and receive SMS messages on their Chromebooks. + 'desc': '''Setting the policy to Enabled lets users set up their devices to sync their text messages to Chromebooks. Users must explicitly opt in to this feature by completing a setup flow. On completion, users can send and receive texts on their Chromebooks. - If this setting is disabled, users will not be allowed to set up SMS syncing. + Setting the policy to Disabled means users can't set up text syncing. - If this policy is left not set, the default is not allowed for managed users and allowed for non-managed users.''', + Leaving the policy unset means that by default, the feature isn't allowed for managed users but is allowed for other users.''', }, { 'name': 'SmartLockSigninAllowed', @@ -16294,7 +16290,9 @@ 'id': 370, 'caption': '''Allow queries to a Google time service''', 'tags': [], - 'desc': '''Setting this policy to false stops <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> from occasionally sending queries to a Google server to retrieve an accurate timestamp. These queries will be enabled if this policy is set to True or is not set.''', + 'desc': '''Setting the policy to Enabled or leaving it unset means <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> send occasional queries to a Google server to retrieve an accurate timestamp. + + Setting the policy to Disabled stops <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> from sending these queries.''', }, { 'name': 'DeviceSecondFactorAuthentication', @@ -16521,18 +16519,15 @@ 'id': 377, 'caption': '''Whitelist note-taking apps allowed on the <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> lock screen''', 'tags': [], - 'desc': '''Specifies list of apps that can be enabled as a note-taking app on the <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> lock screen. + 'desc': '''This policy is deprecated, please use <ph name="NOTE_TAKING_APPS_LOCK_SCREEN_ALLOWLIST">NoteTakingAppsLockScreenAllowlist</ph> instead. - If the preferred note-taking app is enabled on the lock screen, the lock screen will contain UI element for launching the preferred note taking app. - When launched, the app will be able to create an app window on top of the lock screen, and create data items (notes) in the lock screen context. The app will be able to import created notes to the primary user session, when the session is unlocked. Currently, only Chrome note-taking apps are supported on the lock screen. + Setting the policy specifies the apps that users can turn on as a note-taking app on the <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> lock screen. - If the policy is set, the user will be allowed to enable an app on the lock screen only if the app's extension ID is contained in the policy list value. - As a consequence, setting this policy to an empty list will disable note-taking on the lock screen entirely. - Note that the policy containing an app ID does not necessarily mean that the user will be able to enable the app as a note-taking app on the lock screen - for example, on Chrome 61, the set of available apps is additionally restricted by the platform. + If the preferred app is on the lock screen, a UI element for launching the preferred note-taking app appears on the screen. When launched, the app can create a window on top of the lock screen and create notes in this context. The app can import created notes to the primary user session, when the session is unlocked. Only <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> note-taking apps are supported on the lock screen. - If the policy is left unset, there will be no restrictions on the set of apps the user can enable on the lock screen imposed by the policy. + Setting the policy means users can turn on an app on the lock screen if the app's extension ID is in the policy list value. So, setting it to an empty list will turn off note-taking on the lock screen. The policy with an app ID doesn't necessarily mean that users can turn the app on as a note-taking app on the lock screen. For example, on <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> 61, the set of available apps is also restricted by the platform. - This policy is deprecated, please use <ph name="NOTE_TAKING_APPS_LOCK_SCREEN_ALLOWLIST">NoteTakingAppsLockScreenAllowlist</ph> instead.''' + Leaving the policy unset amounts to no restrictions on the set of apps users can enable on the lock screen imposed by the policy.''' }, { 'name': 'NoteTakingAppsLockScreenAllowlist', @@ -16553,16 +16548,13 @@ 'id': 759, 'caption': '''The list of note-taking apps allowed on the <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> lock screen''', 'tags': [], - 'desc': '''The list of apps allowed on the <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> lock screen. + 'desc': '''Setting the policy specifies the apps that users can turn on as a note-taking app on the <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> lock screen. - If the preferred note-taking app is enabled on the lock screen, the lock screen will contain UI element for launching the preferred note taking app. - When launched, the app will be able to create an app window on top of the lock screen, and create data items (notes) in the lock screen context. The app will be able to import created notes to the primary user session, when the session is unlocked. Currently, only Chrome note-taking apps are supported on the lock screen. + If the preferred app is on the lock screen, a UI element for launching the preferred note-taking app appears on the screen. When launched, the app can create a window on top of the lock screen and create notes in this context. The app can import created notes to the primary user session, when the session is unlocked. Only <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> note-taking apps are supported on the lock screen. - If the policy is set, the user will be allowed to enable an app on the lock screen only if the app's extension ID is contained in the policy list value. - As a consequence, setting this policy to an empty list will disable note-taking on the lock screen entirely. - Note that the policy containing an app ID does not necessarily mean that the user will be able to enable the app as a note-taking app on the lock screen - for example, on Chrome 61, the set of available apps is additionally restricted by the platform. + Setting the policy means users can turn on an app on the lock screen if the app's extension ID is in the policy list value. So, setting it to an empty list will turn off note-taking on the lock screen. The policy with an app ID doesn't necessarily mean that users can turn the app on as a note-taking app on the lock screen. For example, on <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> 61, the set of available apps is also restricted by the platform. - If the policy is left unset, there will be no restrictions on the set of apps the user can enable on the lock screen imposed by the policy.''' + Leaving the policy unset amounts to no restrictions on the set of apps users can enable on the lock screen imposed by the policy."''' }, { 'name': 'CastReceiverEnabled', @@ -20659,11 +20651,9 @@ 'supported_on': ['chrome_os:77-'], 'caption': '''Allow the device to request powerwash''', 'tags': [], - 'desc': ''' - This policy when set to False, does not allow the device to trigger powerwash. An exception is if <ph name="TPM_FIRMWARE_UPDATE_SETTINGS_NAME">TPMFirmwareUpdateSettings</ph> policy is set to a value that allows the TPM firmware update and the TPM firmware was not updated yet. - When set to True, it allows the device to trigger powerwash. - If left unset, it defaults to True, meaning it allows the device to powerwash. - ''' + 'desc': '''Setting the policy to Enabled or leaving it unset lets a device trigger powerwash. + + Setting the policy to Disabled doesn't let a device trigger powerwash. An exception to still allow a powerwash can occur if <ph name="TPM_FIRMWARE_UPDATE_SETTINGS_NAME">TPMFirmwareUpdateSettings</ph> is set to a value that lets the TPM firmware update, but it hasn't updated yet.''' }, { 'name': 'ExternalPrintServers', @@ -20813,13 +20803,7 @@ 'example_value': 1, 'id': 579, 'caption': '''Allow users to manage installed CA certificates.''', - 'desc': '''This policy controls whether user are able to import and remove CA certificates via Certificate Manager. - - If this policy is set to ''Allow users to manage all certificates'' or left not set, users will be able to edit trust settings for all CA certificates, remove user-imported certificates and import certificates. - - If this policy is set to ''Allow users to manage user certificates'', users will be able to manage only user-imported certificates and will not be able to change trust settings of built-in certificates. - - If this policy is set to ''Disallow users to manage certificates'', users will not be able to manage CA certificates, they can only view CA certificates.''', + 'desc': '''Setting the policy to All (0) or leaving it unset lets users edit trust settings for all CA certificates, remove user-imported certificates, and import certificates using Certificate Manager. Setting the policy to UserOnly (1) lets users manage only user-imported certificates, but not change trust settings of built-in certificates. Setting it to None (2) lets users view (not manage) CA certificates.''', }, { 'id': 581, @@ -20845,57 +20829,6 @@ ''' }, { - 'id': 583, - 'name': 'SendFilesForMalwareCheck', - 'type': 'int-enum', - 'owners': ['drubery@chromium.org', 'chrome-safebrowsing-team@chromium.org'], - 'schema': { - 'type': 'integer', - 'enum': [0, 2, 3, 4], - }, - 'items': [ - { - 'name': 'DoNotScan', - 'value': 0, - 'caption': '''Do not scan files''' - }, - { - 'name': 'SendDownloads', - 'value': 2, - 'caption': '''Send user downloads for scanning''' - }, - { - 'name': 'SendUploads', - 'value': 3, - 'caption': '''Send user uploads for scanning''' - }, - { - 'name': 'SendUploadsAndDownloads', - 'value': 4, - 'caption': '''Send user uploads and downloads for scanning''' - }, - ], - 'supported_on': ['chrome.*:78-', 'chrome_os:78-'], - 'future': True, - 'features': { - 'dynamic_refresh': True, - 'per_profile': True, - 'cloud_only': True, - }, - 'example_value': 2, - 'caption': '''Scan users downloads with Safe Browsing''', - 'tags': ['google-sharing', 'admin-sharing'], - 'desc': '''This policy controls the deep scanning of user downloads with Safe Browsing. If unset, or set to the default, 'Do not scan files', user downloads will not be scanned by Safe Browsing. - - If set to 'Send user downloads for scanning', users downloads will be sent over the network to Safe Browsing for malware scanning. - - If set to 'Send user uploads for scanning', users uploads will be sent over the network to Safe Browsing for malware scanning. - - If set to 'Send user uploads and downloads for scanning', behaves according to the rules described under 'Send user uploads for scanning' and 'Send user downloads for scanning'. - - See the <ph name="DELAY_DELIVER_UNTIL_VERDICT_POLICY_NAME">DelayDeliveryUntilVerdict</ph> and <ph name="UNSAFE_EVENTS_REPORTING_ENABLED">UnsafeEventsReportingEnabled</ph> policies for details of how the results of scanning are displayed to the user and admin.''' - }, - { 'name': 'UnsafeEventsReportingEnabled', 'owners': ['rogerta@chromium.org', 'mad@chromium.org'], 'type': 'main', @@ -21127,58 +21060,6 @@ ''' }, { - 'name': 'CheckContentCompliance', - 'owners': ['rogerta@chromium.org', 'mad@chromium.org'], - 'type': 'int-enum', - 'schema': { - 'type': 'integer', - 'enum': [ 0, 1, 2, 3 ], - }, - 'items': [ - { - 'name': 'None', - 'value': 0, - 'caption': '''Don't check for sensitive data protection rule violations''', - }, - { - 'name': 'Check-downloads', - 'value': 1, - 'caption': '''Check sensitive data protection rule violations for downloads''', - }, - { - 'name': 'Check-uploads', - 'value': 2, - 'caption': '''Check sensitive data protection rule violations for uploads''', - }, - { - 'name': 'Check-uploads-and-downloads', - 'value': 3, - 'caption': '''Check sensitive data protection rule violations for uploads and downloads''', - }, - ], - 'example_value': 0, - 'features': { - 'dynamic_refresh': True, - 'per_profile': False, - 'cloud_only': True, - }, - 'id': 589, - 'supported_on': ['chrome.*:78-', 'chrome_os:81-'], - 'future': True, - 'caption': '''Send files for sensitive data protection rule violation inspection''', - 'tags': [], - 'desc': '''Controls how <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> checks data that is uploaded, downloaded, pasted from the clipboard, or dragged and dropped for sensitive data protection rule violations. - - If this policy is not set or set to 'None', <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will not check any data for sensitive data protection rule violations. - - If this policy is set to 'Check downloads' and the user attempts to download a file from a URL in the <ph name="DOMAINS_TO_CHECK_COMPLIANCE_OF_DOWNLOADED_CONTENT_POLICTY_NAME">URLsToCheckComplianceOfDownloadedContent</ph> policy, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will check the data downloaded for compiance with enterprise rules. - - If this policy is set to 'Check uploads' and the user attempts to upload a file to a domain not in the <ph name="DOMAINS_TO_NOT_CHECK_COMPLIANCE_OF_UPLOADED_CONTENT_POLICY_NAME">URLsToNotCheckComplianceOfUploadedContent</ph>, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will check the file uploaded, data pasted from the clipboard, or data dragged and dropped for compiance with enterprise rules. - - If this policy is set to 'Check uploads and downloads', <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> behaves according to the rules described under 'Check downloads' and 'Check uploads'. - ''' - }, - { 'name': 'URLsToCheckComplianceOfDownloadedContent', 'owners': ['rogerta@chromium.org', 'mad@chromium.org'], 'type': 'list', @@ -24529,7 +24410,7 @@ }, ], 'placeholders': [], - 'deleted_policy_ids': [114, 115, 412, 476, 544, 546, 562, 569, 578], + 'deleted_policy_ids': [114, 115, 412, 476, 544, 546, 562, 569, 578, 583, 589], 'deleted_atomic_policy_group_ids': [], 'highest_id_currently_used': 793, 'highest_atomic_group_id_currently_used': 40
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.cc b/components/safe_browsing/core/common/safe_browsing_prefs.cc index e894e93..3573bec 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.cc +++ b/components/safe_browsing/core/common/safe_browsing_prefs.cc
@@ -96,8 +96,6 @@ "safebrowsing.password_protection_warning_trigger"; const char kAdvancedProtectionLastRefreshInUs[] = "safebrowsing.advanced_protection_last_refresh"; -const char kSafeBrowsingSendFilesForMalwareCheck[] = - "safebrowsing.send_files_for_malware_check"; const char kUnsafeEventsReportingEnabled[] = "safebrowsing.unsafe_events_reporting"; const char kBlockLargeFileTransfer[] = @@ -106,7 +104,6 @@ "safebrowsing.delay_delivery_until_verdict"; const char kAllowPasswordProtectedFiles[] = "safebrowsing.allow_password_protected_files"; -const char kCheckContentCompliance[] = "safebrowsing.check_content_compliance"; const char kBlockUnsupportedFiletypes[] = "safebrowsing.block_unsupported_filetypes"; const char kURLsToCheckComplianceOfDownloadedContent[] = @@ -229,8 +226,6 @@ registry->RegisterIntegerPref(prefs::kPasswordProtectionWarningTrigger, PASSWORD_PROTECTION_OFF); registry->RegisterInt64Pref(prefs::kAdvancedProtectionLastRefreshInUs, 0); - registry->RegisterIntegerPref(prefs::kSafeBrowsingSendFilesForMalwareCheck, - DO_NOT_SCAN); registry->RegisterBooleanPref(prefs::kAdvancedProtectionAllowed, true); registry->RegisterIntegerPref( prefs::kSafeBrowsingEnterpriseRealTimeUrlCheckMode, @@ -245,7 +240,6 @@ registry->RegisterIntegerPref( prefs::kAllowPasswordProtectedFiles, AllowPasswordProtectedFilesValues::ALLOW_UPLOADS_AND_DOWNLOADS); - registry->RegisterIntegerPref(prefs::kCheckContentCompliance, CHECK_NONE); registry->RegisterIntegerPref(prefs::kBlockUnsupportedFiletypes, BLOCK_UNSUPPORTED_FILETYPES_NONE); registry->RegisterListPref(prefs::kURLsToCheckComplianceOfDownloadedContent);
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.h b/components/safe_browsing/core/common/safe_browsing_prefs.h index 29672db..df400539 100644 --- a/components/safe_browsing/core/common/safe_browsing_prefs.h +++ b/components/safe_browsing/core/common/safe_browsing_prefs.h
@@ -92,10 +92,6 @@ // microseconds); extern const char kAdvancedProtectionLastRefreshInUs[]; -// Whether or not to send downloads to Safe Browsing for deep scanning. This -// is configured by enterprise policy. -extern const char kSafeBrowsingSendFilesForMalwareCheck[]; - // Boolean that indidicates if Chrome reports unsafe events to Google. extern const char kUnsafeEventsReportingEnabled[]; @@ -111,9 +107,6 @@ // or downloaded or both. extern const char kAllowPasswordProtectedFiles[]; -// Integer that indicates if Chrome checks data for content compliance. -extern const char kCheckContentCompliance[]; - // Integer that indicates if Chrome blocks data that cannot be checked for // content compliance due to unsupported filetypes. extern const char kBlockUnsupportedFiletypes[]; @@ -184,7 +177,7 @@ }; // Enum representing possible values of the SendFilesForMalwareCheck policy. -// This must be kept in sync with policy_templates.json. +// TODO(crbug/1109242): Remove this once tests use connector policies directly. enum SendFilesForMalwareCheckValues { DO_NOT_SCAN = 0, SEND_DOWNLOADS = 2, @@ -194,8 +187,8 @@ SEND_FILES_FOR_MALWARE_CHECK_MAX = SEND_UPLOADS_AND_DOWNLOADS, }; -// Enum representing possible values of the CheckContentCompliance policy. This -// must be kept in sync with policy_templates.json. +// Enum representing possible values of the CheckContentCompliance policy. +// TODO(crbug/1109242): Remove this once tests use connector policies directly. enum CheckContentComplianceValues { CHECK_NONE = 0, CHECK_DOWNLOADS = 1,
diff --git a/components/services/heap_profiling/public/cpp/profiling_client.cc b/components/services/heap_profiling/public/cpp/profiling_client.cc index ff58a17..d39fdb8 100644 --- a/components/services/heap_profiling/public/cpp/profiling_client.cc +++ b/components/services/heap_profiling/public/cpp/profiling_client.cc
@@ -14,6 +14,7 @@ #include "base/sampling_heap_profiler/sampling_heap_profiler.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" +#include "base/trace_event/heap_profiler_allocation_context_tracker.h" #include "base/trace_event/heap_profiler_event_filter.h" #include "base/trace_event/malloc_dump_provider.h" #include "base/trace_event/memory_dump_manager.h"
diff --git a/components/sessions/core/session_service_commands.cc b/components/sessions/core/session_service_commands.cc index c931e3ff..25eb017d 100644 --- a/components/sessions/core/session_service_commands.cc +++ b/components/sessions/core/session_service_commands.cc
@@ -65,7 +65,8 @@ static const SessionCommand::id_type kCommandSetWindowWorkspace2 = 23; static const SessionCommand::id_type kCommandTabNavigationPathPruned = 24; static const SessionCommand::id_type kCommandSetTabGroup = 25; -static const SessionCommand::id_type kCommandSetTabGroupMetadata = 26; +// OBSOLETE Superseded by kCommandSetTabGroupMetadata2. +// static const SessionCommand::id_type kCommandSetTabGroupMetadata = 26; static const SessionCommand::id_type kCommandSetTabGroupMetadata2 = 27; static const SessionCommand::id_type kCommandSetTabGuid = 28; static const SessionCommand::id_type kCommandSetTabUserAgentOverride2 = 29; @@ -635,7 +636,6 @@ break; } - case kCommandSetTabGroupMetadata: case kCommandSetTabGroupMetadata2: { std::unique_ptr<base::Pickle> pickle = command->PayloadAsPickle(); base::PickleIterator iter(*pickle); @@ -652,27 +652,16 @@ if (!iter.ReadString16(&title)) return true; - if (command->id() == kCommandSetTabGroupMetadata) { - SkColor color; - if (!iter.ReadUInt32(&color)) - return true; + uint32_t color_int; + if (!iter.ReadUInt32(&color_int)) + return true; - // crrev.com/c/1968039 changes the color of a tab group from a SkColor - // to a TabGroupColorId. Here we ignore the old SkColor and assign the - // default TabGroupColorId because the fallback is acceptable while - // the tab groups feature isn't yet launched. Once it is, - // kCommandSetTabGroupMetadata will be deprecated in favor of - // kCommandSetTabGroupMetadata2, which properly restores - // TabGroupColorIds. - group->visual_data = tab_groups::TabGroupVisualData( - title, tab_groups::TabGroupColorId::kGrey); - } else { - uint32_t color_int; - if (!iter.ReadUInt32(&color_int)) - return true; - - group->visual_data = tab_groups::TabGroupVisualData(title, color_int); - } + // The |is_collapsed| boolean was added in M88 to save the collapsed + // state, so previous versions may not have this stored. + bool is_collapsed = false; + ignore_result(!iter.ReadBool(&is_collapsed)); + group->visual_data = + tab_groups::TabGroupVisualData(title, color_int, is_collapsed); break; } @@ -963,6 +952,9 @@ WriteTokenToPickle(&pickle, group.token()); pickle.WriteString16(visual_data->title()); pickle.WriteUInt32(static_cast<int>(visual_data->color())); + + // This boolean was added in M88 to save the collapsed state. + pickle.WriteBool(visual_data->is_collapsed()); return std::make_unique<SessionCommand>(kCommandSetTabGroupMetadata2, pickle); }
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn index aaf595f27..c5d19c6a 100644 --- a/components/sync/BUILD.gn +++ b/components/sync/BUILD.gn
@@ -30,6 +30,8 @@ # etc, but currently they all depend on each other. static_library("rest_of_sync") { sources = [ + "engine/commit_and_get_updates_types.cc", + "engine/commit_and_get_updates_types.h", "engine/commit_queue.h", "engine/configure_reason.h", "engine/cycle/commit_counters.cc", @@ -66,8 +68,6 @@ "engine/net/http_bridge.h", "engine/net/http_post_provider_factory.h", "engine/net/http_post_provider_interface.h", - "engine/non_blocking_sync_common.cc", - "engine/non_blocking_sync_common.h", "engine/passive_model_worker.cc", "engine/passive_model_worker.h", "engine/polling_constants.cc", @@ -377,8 +377,6 @@ "model/mock_model_type_change_processor.h", "model/model_type_store_test_util.cc", "model/model_type_store_test_util.h", - "model/recording_model_type_change_processor.cc", - "model/recording_model_type_change_processor.h", "model/stub_model_type_sync_bridge.cc", "model/stub_model_type_sync_bridge.h", "model/sync_change_processor_wrapper_for_test.cc",
diff --git a/components/sync/driver/about_sync_util.cc b/components/sync/driver/about_sync_util.cc index 8ebd6d83..d000a02d 100644 --- a/components/sync/driver/about_sync_util.cc +++ b/components/sync/driver/about_sync_util.cc
@@ -120,9 +120,8 @@ // fields. class Section { public: - explicit Section(const std::string& title) : title_(title) {} - - void MarkSensitive() { is_sensitive_ = true; } + Section(const std::string& title, bool is_sensitive) + : title_(title), is_sensitive_(is_sensitive) {} Stat<bool>* AddBoolStat(const std::string& key) { return AddStat(key, false); @@ -143,6 +142,8 @@ return result; } + bool is_sensitive() { return is_sensitive_; } + private: template <typename T> Stat<T>* AddStat(const std::string& key, const T& default_value) { @@ -161,15 +162,22 @@ public: SectionList() = default; - Section* AddSection(const std::string& title) { - sections_.push_back(std::make_unique<Section>(title)); + // WARNING: If this section includes any Personally Identifiable Information, + // |is_sensitive| should be set to true. + Section* AddSection(const std::string& title, bool is_sensitive) { + sections_.push_back(std::make_unique<Section>(title, is_sensitive)); return sections_.back().get(); } - base::Value ToValue() const { + // If |include_sensitive_data| is true, returns all added sections. Otherwise, + // omits those added with |is_sensitive| set to true. + base::Value ToValue(IncludeSensitiveData include_sensitive_data) const { base::Value result(base::Value::Type::LIST); - for (const std::unique_ptr<Section>& section : sections_) - result.Append(section->ToValue()); + for (const std::unique_ptr<Section>& section : sections_) { + if (include_sensitive_data || !section->is_sensitive()) { + result.Append(section->ToValue()); + } + } return result; } @@ -297,13 +305,15 @@ // which are grouped into sections and populated with the help of the SyncStat // classes defined above. std::unique_ptr<base::DictionaryValue> ConstructAboutInformation( + IncludeSensitiveData include_sensitive_data, SyncService* service, version_info::Channel channel) { auto about_info = std::make_unique<base::DictionaryValue>(); SectionList section_list; - Section* section_summary = section_list.AddSection("Summary"); + Section* section_summary = + section_list.AddSection("Summary", /*is_sensitive=*/false); Stat<std::string>* transport_state = section_summary->AddStringStat("Transport State"); Stat<std::string>* disable_reasons = @@ -318,13 +328,14 @@ section_summary->AddBoolStat("Setup In Progress"); Stat<std::string>* auth_error = section_summary->AddStringStat("Auth Error"); - Section* section_version = section_list.AddSection("Version Info"); + Section* section_version = + section_list.AddSection("Version Info", /*is_sensitive=*/false); Stat<std::string>* client_version = section_version->AddStringStat("Client Version"); Stat<std::string>* server_url = section_version->AddStringStat("Server URL"); - Section* section_identity = section_list.AddSection(kIdentityTitle); - section_identity->MarkSensitive(); + Section* section_identity = + section_list.AddSection(kIdentityTitle, /*is_sensitive=*/true); Stat<std::string>* sync_client_id = section_identity->AddStringStat("Sync Client ID"); Stat<std::string>* invalidator_id = @@ -332,7 +343,8 @@ Stat<std::string>* username = section_identity->AddStringStat("Username"); Stat<bool>* user_is_primary = section_identity->AddBoolStat("Is Primary"); - Section* section_credentials = section_list.AddSection("Credentials"); + Section* section_credentials = + section_list.AddSection("Credentials", /*is_sensitive=*/false); Stat<std::string>* token_request_time = section_credentials->AddStringStat("Requested Token"); Stat<std::string>* token_response_time = @@ -343,7 +355,8 @@ Stat<std::string>* next_token_request = section_credentials->AddStringStat("Next Token Request"); - Section* section_local = section_list.AddSection("Local State"); + Section* section_local = + section_list.AddSection("Local State", /*is_sensitive=*/false); Stat<std::string>* server_connection = section_local->AddStringStat("Server Connection"); Stat<std::string>* last_synced = section_local->AddStringStat("Last Synced"); @@ -355,14 +368,16 @@ Stat<std::string>* local_backend_path = section_local->AddStringStat("Local Backend Path"); - Section* section_network = section_list.AddSection("Network"); + Section* section_network = + section_list.AddSection("Network", /*is_sensitive=*/false); Stat<bool>* is_any_throttled_or_backoff = section_network->AddBoolStat("Throttled or Backoff"); Stat<std::string>* retry_time = section_network->AddStringStat("Retry Time"); Stat<bool>* are_notifications_enabled = section_network->AddBoolStat("Notifications Enabled"); - Section* section_encryption = section_list.AddSection("Encryption"); + Section* section_encryption = + section_list.AddSection("Encryption", /*is_sensitive=*/false); Stat<bool>* is_using_explicit_passphrase = section_encryption->AddBoolStat("Explicit Passphrase"); Stat<bool>* is_passphrase_required = @@ -382,8 +397,8 @@ Stat<std::string>* passphrase_time = section_encryption->AddStringStat("Passphrase Time"); - Section* section_last_session = - section_list.AddSection("Status from Last Completed Session"); + Section* section_last_session = section_list.AddSection( + "Status from Last Completed Session", /*is_sensitive=*/false); Stat<std::string>* session_source = section_last_session->AddStringStat("Sync Source"); Stat<std::string>* get_key_result = @@ -393,7 +408,8 @@ Stat<std::string>* commit_result = section_last_session->AddStringStat("Commit Step Result"); - Section* section_counters = section_list.AddSection("Running Totals"); + Section* section_counters = + section_list.AddSection("Running Totals", /*is_sensitive=*/false); Stat<int>* notifications_received = section_counters->AddIntStat("Notifications Received"); Stat<int>* updates_received = @@ -409,8 +425,8 @@ Stat<int>* conflicts_resolved_server_wins = section_counters->AddIntStat("Conflicts Resolved: Server Wins"); - Section* section_this_cycle = - section_list.AddSection("Transient Counters (this cycle)"); + Section* section_this_cycle = section_list.AddSection( + "Transient Counters (this cycle)", /*is_sensitive=*/false); Stat<int>* encryption_conflicts = section_this_cycle->AddIntStat("Encryption Conflicts"); Stat<int>* hierarchy_conflicts = @@ -421,7 +437,8 @@ section_this_cycle->AddIntStat("Committed Items"); Section* section_that_cycle = section_list.AddSection( - "Transient Counters (last cycle of last completed session)"); + "Transient Counters (last cycle of last completed session)", + /*is_sensitive=*/false); Stat<int>* updates_downloaded = section_that_cycle->AddIntStat("Updates Downloaded"); Stat<int>* committed_count = @@ -433,7 +450,8 @@ if (!service) { transport_state->Set("Sync service does not exist"); - about_info->SetKey(kDetailsKey, section_list.ToValue()); + about_info->SetKey(kDetailsKey, + section_list.ToValue(include_sensitive_data)); return about_info; } @@ -571,7 +589,7 @@ // This list of sections belongs in the 'details' field of the returned // message. - about_info->SetKey(kDetailsKey, section_list.ToValue()); + about_info->SetKey(kDetailsKey, section_list.ToValue(include_sensitive_data)); // The values set from this point onwards do not belong in the // details list.
diff --git a/components/sync/driver/about_sync_util.h b/components/sync/driver/about_sync_util.h index c25ed39..f7ee0b6f 100644 --- a/components/sync/driver/about_sync_util.h +++ b/components/sync/driver/about_sync_util.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/util/type_safety/strong_alias.h" #include "components/signin/public/identity_manager/account_info.h" #include "components/version_info/version_info.h" @@ -65,10 +66,16 @@ extern const char kOnReceivedIncludeSpecificsInitialState[]; extern const char kOnReceivedListOfTypes[]; extern const char kTypes[]; + +using IncludeSensitiveData = + util::StrongAlias<class IncludeSensitiveDataTag, bool>; // This function returns a DictionaryValue which contains all the information // required to populate the 'About' tab of about:sync. // Note that |service| may be null. +// If |include_sensitive_data| is false, Personally Identifiable Information +// won't be included in the return value. std::unique_ptr<base::DictionaryValue> ConstructAboutInformation( + IncludeSensitiveData include_sensitive_data, SyncService* service, version_info::Channel channel);
diff --git a/components/sync/driver/about_sync_util_unittest.cc b/components/sync/driver/about_sync_util_unittest.cc index d8e709ab..db90aff8 100644 --- a/components/sync/driver/about_sync_util_unittest.cc +++ b/components/sync/driver/about_sync_util_unittest.cc
@@ -18,8 +18,8 @@ service.SetDisableReasons( syncer::SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR); - std::unique_ptr<base::DictionaryValue> strings( - ConstructAboutInformation(&service, version_info::Channel::UNKNOWN)); + std::unique_ptr<base::DictionaryValue> strings(ConstructAboutInformation( + IncludeSensitiveData(true), &service, version_info::Channel::UNKNOWN)); EXPECT_TRUE(strings->HasKey("unrecoverable_error_detected")); }
diff --git a/components/sync/driver/glue/sync_engine_backend.cc b/components/sync/driver/glue/sync_engine_backend.cc index 523d5dd..ffed624 100644 --- a/components/sync/driver/glue/sync_engine_backend.cc +++ b/components/sync/driver/glue/sync_engine_backend.cc
@@ -143,8 +143,6 @@ /*types_to_add=*/ControlTypes(), /*types_to_remove=*/ModelTypeSet()); - ModelSafeRoutingInfo routing_info; - registrar_->GetModelSafeRoutingInfo(&routing_info); SDVLOG(1) << "Control Types " << ModelTypeSetToString(new_control_types) << " added; calling ConfigureSyncer"; @@ -469,9 +467,7 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Update the enabled types for the bridge and sync manager. - ModelSafeRoutingInfo routing_info; - registrar_->GetModelSafeRoutingInfo(&routing_info); - ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info); + ModelTypeSet enabled_types = registrar_->GetTypesWithRoutingInfo(); enabled_types.RemoveAll(ProxyTypes()); const ModelTypeSet failed_configuration_types =
diff --git a/components/sync/driver/glue/sync_engine_impl.cc b/components/sync/driver/glue/sync_engine_impl.cc index 463079c..98cd1fb8 100644 --- a/components/sync/driver/glue/sync_engine_impl.cc +++ b/components/sync/driver/glue/sync_engine_impl.cc
@@ -263,14 +263,6 @@ std::move(cb)); } -void SyncEngineImpl::GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) const { - if (IsInitialized()) { - registrar_->GetModelSafeRoutingInfo(out); - } else { - NOTREACHED(); - } -} - void SyncEngineImpl::RequestBufferedProtocolEventsAndEnableForwarding() { sync_task_runner_->PostTask( FROM_HERE,
diff --git a/components/sync/driver/glue/sync_engine_impl.h b/components/sync/driver/glue/sync_engine_impl.h index 5cd8be7..9776192b 100644 --- a/components/sync/driver/glue/sync_engine_impl.h +++ b/components/sync/driver/glue/sync_engine_impl.h
@@ -83,7 +83,6 @@ const Status& GetDetailedStatus() const override; void HasUnsyncedItemsForTest( base::OnceCallback<void(bool)> cb) const override; - void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) const override; void RequestBufferedProtocolEventsAndEnableForwarding() override; void DisableProtocolEventForwarding() override; void OnCookieJarChanged(bool account_mismatch,
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc index 5d57670..421104b 100644 --- a/components/sync/driver/profile_sync_service.cc +++ b/components/sync/driver/profile_sync_service.cc
@@ -1483,17 +1483,12 @@ type_status_header->SetString("num_live", "Live Entries"); type_status_header->SetString("message", "Message"); type_status_header->SetString("state", "State"); - type_status_header->SetString("group_type", "Group Type"); result->Append(std::move(type_status_header)); - ModelSafeRoutingInfo routing_info; - engine_->GetModelSafeRoutingInfo(&routing_info); const ModelTypeSet registered = GetRegisteredDataTypes(); for (ModelType type : registered) { auto type_status = std::make_unique<base::DictionaryValue>(); type_status->SetString("name", ModelTypeToString(type)); - type_status->SetString("group_type", - ModelSafeGroupToString(routing_info[type])); if (data_type_error_map_.find(type) != data_type_error_map_.end()) { const SyncError& error = data_type_error_map_.find(type)->second; @@ -1516,12 +1511,9 @@ } else if (backed_off_types.Has(type)) { type_status->SetString("status", "warning"); type_status->SetString("message", "Backed off"); - } else if (routing_info.find(type) != routing_info.end()) { + } else { type_status->SetString("status", "ok"); type_status->SetString("message", ""); - } else { - type_status->SetString("status", "warning"); - type_status->SetString("message", "Disabled by User"); } const auto& dtc_iter = data_type_controllers_.find(type);
diff --git a/components/sync/driver/resources/about.html b/components/sync/driver/resources/about.html index 8779ed3..30a1f102 100644 --- a/components/sync/driver/resources/about.html +++ b/components/sync/driver/resources/about.html
@@ -55,9 +55,8 @@ <td jscontent="name" width=30%></td> <td jscontent="num_entries" width=10%></td> <td jscontent="num_live" width=10%></td> - <td jscontent="message" width=30%></td> + <td jscontent="message" width=40%></td> <td jscontent="state" width=10%></td> - <td jscontent="group_type" width=10%></td> </tr> </table> </div>
diff --git a/components/sync/engine/non_blocking_sync_common.cc b/components/sync/engine/commit_and_get_updates_types.cc similarity index 96% rename from components/sync/engine/non_blocking_sync_common.cc rename to components/sync/engine/commit_and_get_updates_types.cc index 216d6c6..9a357dc 100644 --- a/components/sync/engine/non_blocking_sync_common.cc +++ b/components/sync/engine/commit_and_get_updates_types.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "base/trace_event/memory_usage_estimator.h"
diff --git a/components/sync/engine/non_blocking_sync_common.h b/components/sync/engine/commit_and_get_updates_types.h similarity index 94% rename from components/sync/engine/non_blocking_sync_common.h rename to components/sync/engine/commit_and_get_updates_types.h index 4e773e3..c2489d7 100644 --- a/components/sync/engine/non_blocking_sync_common.h +++ b/components/sync/engine/commit_and_get_updates_types.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_SYNC_ENGINE_NON_BLOCKING_SYNC_COMMON_H_ -#define COMPONENTS_SYNC_ENGINE_NON_BLOCKING_SYNC_COMMON_H_ +#ifndef COMPONENTS_SYNC_ENGINE_COMMIT_AND_GET_UPDATES_TYPES_H_ +#define COMPONENTS_SYNC_ENGINE_COMMIT_AND_GET_UPDATES_TYPES_H_ #include <stdint.h> @@ -114,4 +114,4 @@ } // namespace syncer -#endif // COMPONENTS_SYNC_ENGINE_NON_BLOCKING_SYNC_COMMON_H_ +#endif // COMPONENTS_SYNC_ENGINE_COMMIT_AND_GET_UPDATES_TYPES_H_
diff --git a/components/sync/engine/commit_queue.h b/components/sync/engine/commit_queue.h index 65e1cc6..cef7bcbc 100644 --- a/components/sync/engine/commit_queue.h +++ b/components/sync/engine/commit_queue.h
@@ -5,7 +5,7 @@ #ifndef COMPONENTS_SYNC_ENGINE_COMMIT_QUEUE_H_ #define COMPONENTS_SYNC_ENGINE_COMMIT_QUEUE_H_ -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" namespace syncer {
diff --git a/components/sync/engine/data_type_activation_response.h b/components/sync/engine/data_type_activation_response.h index 8f151b3..b543f539 100644 --- a/components/sync/engine/data_type_activation_response.h +++ b/components/sync/engine/data_type_activation_response.h
@@ -10,8 +10,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine/model_type_processor.h" -#include "components/sync/engine/non_blocking_sync_common.h" #include "components/sync/protocol/model_type_state.pb.h" namespace syncer {
diff --git a/components/sync/engine/fake_sync_engine.cc b/components/sync/engine/fake_sync_engine.cc index 75dc3bfc..25230807 100644 --- a/components/sync/engine/fake_sync_engine.cc +++ b/components/sync/engine/fake_sync_engine.cc
@@ -75,8 +75,6 @@ void FakeSyncEngine::HasUnsyncedItemsForTest( base::OnceCallback<void(bool)> cb) const {} -void FakeSyncEngine::GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) const {} - void FakeSyncEngine::RequestBufferedProtocolEventsAndEnableForwarding() {} void FakeSyncEngine::DisableProtocolEventForwarding() {}
diff --git a/components/sync/engine/fake_sync_engine.h b/components/sync/engine/fake_sync_engine.h index 1826359..dd1f5c6 100644 --- a/components/sync/engine/fake_sync_engine.h +++ b/components/sync/engine/fake_sync_engine.h
@@ -72,8 +72,6 @@ void HasUnsyncedItemsForTest( base::OnceCallback<void(bool)> cb) const override; - void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) const override; - void RequestBufferedProtocolEventsAndEnableForwarding() override; void DisableProtocolEventForwarding() override;
diff --git a/components/sync/engine/mock_sync_engine.h b/components/sync/engine/mock_sync_engine.h index 2d8cfdc..b47d486a 100644 --- a/components/sync/engine/mock_sync_engine.h +++ b/components/sync/engine/mock_sync_engine.h
@@ -51,7 +51,6 @@ MOCK_CONST_METHOD0(GetDetailedStatus, const SyncStatus&()); MOCK_CONST_METHOD1(HasUnsyncedItemsForTest, void(base::OnceCallback<void(bool)>)); - MOCK_CONST_METHOD1(GetModelSafeRoutingInfo, void(ModelSafeRoutingInfo*)); MOCK_METHOD0(RequestBufferedProtocolEventsAndEnableForwarding, void()); MOCK_METHOD0(DisableProtocolEventForwarding, void()); MOCK_METHOD1(ClearServerData, void(base::OnceClosure));
diff --git a/components/sync/engine/model_safe_worker.cc b/components/sync/engine/model_safe_worker.cc index 841ee4a..dfa9d28c 100644 --- a/components/sync/engine/model_safe_worker.cc +++ b/components/sync/engine/model_safe_worker.cc
@@ -7,63 +7,15 @@ #include <utility> #include "base/bind.h" -#include "base/json/json_writer.h" #include "base/threading/thread_restrictions.h" -#include "base/values.h" namespace syncer { -std::unique_ptr<base::DictionaryValue> ModelSafeRoutingInfoToValue( - const ModelSafeRoutingInfo& routing_info) { - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - for (auto it = routing_info.begin(); it != routing_info.end(); ++it) { - dict->SetString(ModelTypeToString(it->first), - ModelSafeGroupToString(it->second)); - } - return dict; -} - -std::string ModelSafeRoutingInfoToString( - const ModelSafeRoutingInfo& routing_info) { - std::string json; - base::JSONWriter::Write(*ModelSafeRoutingInfoToValue(routing_info), &json); - return json; -} - -ModelTypeSet GetRoutingInfoTypes(const ModelSafeRoutingInfo& routing_info) { - ModelTypeSet types; - for (auto it = routing_info.begin(); it != routing_info.end(); ++it) { - types.Put(it->first); - } - return types; -} - -ModelSafeGroup GetGroupForModelType(const ModelType type, - const ModelSafeRoutingInfo& routes) { - auto it = routes.find(type); - if (it == routes.end()) { - if (type != UNSPECIFIED && type != TOP_LEVEL_FOLDER) - DVLOG(1) << "Entry does not belong to active ModelSafeGroup!"; - return GROUP_PASSIVE; - } - return it->second; -} - -std::string ModelSafeGroupToString(ModelSafeGroup group) { - switch (group) { - case GROUP_PASSIVE: - return "Group Passive"; - case GROUP_NON_BLOCKING: - return "Group Non Blocking"; - } - NOTREACHED(); - return "Invalid"; -} - ModelSafeWorker::ModelSafeWorker() : work_done_or_abandoned_(base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED) { } + ModelSafeWorker::~ModelSafeWorker() {} void ModelSafeWorker::RequestStop() {
diff --git a/components/sync/engine/model_safe_worker.h b/components/sync/engine/model_safe_worker.h index 5ad91f2..d9df664c 100644 --- a/components/sync/engine/model_safe_worker.h +++ b/components/sync/engine/model_safe_worker.h
@@ -18,10 +18,6 @@ #include "components/sync/base/model_type.h" #include "components/sync/base/syncer_error.h" -namespace base { -class DictionaryValue; -} // namespace base - namespace syncer { using WorkCallback = base::OnceCallback<SyncerError(void)>; @@ -38,8 +34,6 @@ // SyncBackendRegistrar involvement. }; -std::string ModelSafeGroupToString(ModelSafeGroup group); - // TODO(crbug.com/1102835): This class is a remainder from the old Directory // implementation and should be removed. // @@ -99,23 +93,6 @@ DISALLOW_COPY_AND_ASSIGN(ModelSafeWorker); }; -// A map that details which ModelSafeGroup each ModelType -// belongs to. Routing info can change in response to the user enabling / -// disabling sync for certain types, as well as model association completions. -using ModelSafeRoutingInfo = std::map<ModelType, ModelSafeGroup>; - -// Caller takes ownership of return value. -std::unique_ptr<base::DictionaryValue> ModelSafeRoutingInfoToValue( - const ModelSafeRoutingInfo& routing_info); - -std::string ModelSafeRoutingInfoToString( - const ModelSafeRoutingInfo& routing_info); - -ModelTypeSet GetRoutingInfoTypes(const ModelSafeRoutingInfo& routing_info); - -ModelSafeGroup GetGroupForModelType(const ModelType type, - const ModelSafeRoutingInfo& routes); - } // namespace syncer #endif // COMPONENTS_SYNC_ENGINE_MODEL_SAFE_WORKER_H_
diff --git a/components/sync/engine/model_safe_worker_unittest.cc b/components/sync/engine/model_safe_worker_unittest.cc index e498aa5e..13e06f3 100644 --- a/components/sync/engine/model_safe_worker_unittest.cc +++ b/components/sync/engine/model_safe_worker_unittest.cc
@@ -84,34 +84,6 @@ } // namespace -TEST_F(ModelSafeWorkerTest, ModelSafeRoutingInfoToValue) { - ModelSafeRoutingInfo routing_info; - routing_info[BOOKMARKS] = GROUP_PASSIVE; - routing_info[APPS] = GROUP_NON_BLOCKING; - base::DictionaryValue expected_value; - expected_value.SetString("Apps", "Group Non Blocking"); - expected_value.SetString("Bookmarks", "Group Passive"); - std::unique_ptr<base::DictionaryValue> value( - ModelSafeRoutingInfoToValue(routing_info)); - EXPECT_TRUE(value->Equals(&expected_value)); -} - -TEST_F(ModelSafeWorkerTest, ModelSafeRoutingInfoToString) { - ModelSafeRoutingInfo routing_info; - routing_info[APPS] = GROUP_NON_BLOCKING; - routing_info[BOOKMARKS] = GROUP_PASSIVE; - EXPECT_EQ("{\"Apps\":\"Group Non Blocking\",\"Bookmarks\":\"Group Passive\"}", - ModelSafeRoutingInfoToString(routing_info)); -} - -TEST_F(ModelSafeWorkerTest, GetRoutingInfoTypes) { - ModelSafeRoutingInfo routing_info; - routing_info[BOOKMARKS] = GROUP_PASSIVE; - routing_info[PASSWORDS] = GROUP_NON_BLOCKING; - const ModelTypeSet expected_types(BOOKMARKS, PASSWORDS); - EXPECT_EQ(expected_types, GetRoutingInfoTypes(routing_info)); -} - TEST_F(ModelSafeWorkerTest, DoWorkAndWaitUntilDone) { bool did_work = false; DoWorkAndWaitUntilDoneOnSyncThread(base::BindOnce(
diff --git a/components/sync/engine/model_type_processor.h b/components/sync/engine/model_type_processor.h index 8470ac2..8d048360 100644 --- a/components/sync/engine/model_type_processor.h +++ b/components/sync/engine/model_type_processor.h
@@ -8,7 +8,7 @@ #include <memory> #include "base/callback_forward.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/protocol/model_type_state.pb.h" namespace syncer {
diff --git a/components/sync/engine/sync_backend_registrar.cc b/components/sync/engine/sync_backend_registrar.cc index 0f7b470..bcfefee 100644 --- a/components/sync/engine/sync_backend_registrar.cc +++ b/components/sync/engine/sync_backend_registrar.cc
@@ -57,7 +57,7 @@ // Although this can re-set types in GROUP_NON_BLOCKING, this should be // idempotent. - last_configured_types_ = GetRoutingInfoTypes(routing_info_); + last_configured_types_ = GetTypesWithRoutingInfoNoLock(); } void SyncBackendRegistrar::AddRestoredDataType(ModelType type) { @@ -96,14 +96,11 @@ routing_info_.erase(type); } - // TODO(akalin): Use SVLOG/SLOG if we add any more logging. DVLOG(1) << name_ << ": Adding types " << ModelTypeSetToString(types_to_add) << " (with newly-added types " << ModelTypeSetToString(newly_added_types) << ") and removing types " - << ModelTypeSetToString(types_to_remove) - << " to get new routing info " - << ModelSafeRoutingInfoToString(routing_info_); - last_configured_types_ = GetRoutingInfoTypes(routing_info_); + << ModelTypeSetToString(types_to_remove); + last_configured_types_ = GetTypesWithRoutingInfoNoLock(); return newly_added_types; } @@ -129,25 +126,17 @@ } } -void SyncBackendRegistrar::GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) { +ModelTypeSet SyncBackendRegistrar::GetTypesWithRoutingInfo() const { base::AutoLock lock(lock_); - ModelSafeRoutingInfo copy(routing_info_); - out->swap(copy); + return GetTypesWithRoutingInfoNoLock(); } -bool SyncBackendRegistrar::IsCurrentThreadSafeForModel( - ModelType model_type) const { - lock_.AssertAcquired(); - ModelSafeGroup group = GetGroupForModelType(model_type, routing_info_); - DCHECK_NE(GROUP_NON_BLOCKING, group); - - if (group == GROUP_PASSIVE) { - return IsControlType(model_type); +ModelTypeSet SyncBackendRegistrar::GetTypesWithRoutingInfoNoLock() const { + ModelTypeSet types; + for (const auto& model_type_and_group : routing_info_) { + types.Put(model_type_and_group.first); } - - auto it = workers_.find(group); - DCHECK(it != workers_.end()); - return it->second->IsOnModelSequence(); + return types; } SyncBackendRegistrar::~SyncBackendRegistrar() {
diff --git a/components/sync/engine/sync_backend_registrar.h b/components/sync/engine/sync_backend_registrar.h index b190694..bf4c07a 100644 --- a/components/sync/engine/sync_backend_registrar.h +++ b/components/sync/engine/sync_backend_registrar.h
@@ -83,18 +83,20 @@ void RequestWorkerStopOnUIThread(); void GetWorkers(std::vector<scoped_refptr<ModelSafeWorker>>* out); - void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out); + + // Returns the set of currently enabled types. + ModelTypeSet GetTypesWithRoutingInfo() const; private: + // Same as GetTypesWithRoutingInfo() but callers are responsible for holding + // |lock_|. + ModelTypeSet GetTypesWithRoutingInfoNoLock() const; + // Add a worker for |group| to the worker map if one is successfully created // by |worker_factory|. void MaybeAddWorker(ModelSafeWorkerFactory worker_factory, ModelSafeGroup group); - // Return true if |model_type| lives on the current thread. Must be - // called with |lock_| held. May be called on any thread. - bool IsCurrentThreadSafeForModel(ModelType model_type) const; - // Returns model safe group that should be assigned to type when it is first // configured (before activation). ModelSafeGroup GetInitialGroupForType(ModelType type) const; @@ -112,7 +114,7 @@ std::map<ModelSafeGroup, scoped_refptr<ModelSafeWorker>> workers_; // Maps ModelType to ModelSafeGroup. - ModelSafeRoutingInfo routing_info_; + std::map<ModelType, ModelSafeGroup> routing_info_; // The types that were enabled as of the last configuration. Updated on each // call to ConfigureDataTypes as well as SetInitialTypes.
diff --git a/components/sync/engine/sync_backend_registrar_unittest.cc b/components/sync/engine/sync_backend_registrar_unittest.cc index 6497683e..faea0f5f 100644 --- a/components/sync/engine/sync_backend_registrar_unittest.cc +++ b/components/sync/engine/sync_backend_registrar_unittest.cc
@@ -39,10 +39,9 @@ sync_thread_.FlushForTesting(); } - void ExpectRoutingInfo(const ModelSafeRoutingInfo& expected_routing_info) { - ModelSafeRoutingInfo actual_routing_info; - registrar_->GetModelSafeRoutingInfo(&actual_routing_info); - EXPECT_EQ(expected_routing_info, actual_routing_info); + void ExpectRoutingInfo(ModelTypeSet expected_routing_info_types) { + EXPECT_EQ(expected_routing_info_types, + registrar_->GetTypesWithRoutingInfo()); } size_t GetWorkersSize() { @@ -78,7 +77,7 @@ registrar()->SetInitialTypes(ModelTypeSet()); EXPECT_FALSE(registrar()->IsNigoriEnabled()); EXPECT_EQ(1u, GetWorkersSize()); - ExpectRoutingInfo(ModelSafeRoutingInfo()); + ExpectRoutingInfo(ModelTypeSet()); } TEST_F(SyncBackendRegistrarTest, ConstructorNonEmpty) { @@ -89,7 +88,7 @@ EXPECT_EQ(ModelTypeSet(NIGORI), registrar()->GetLastConfiguredTypes()); // Bookmarks dropped because it is in ModelSafeGroup::GROUP_NON_BLOCKING. // Passwords dropped because of no password store. - ExpectRoutingInfo({{NIGORI, GROUP_PASSIVE}}); + ExpectRoutingInfo({NIGORI}); } TEST_F(SyncBackendRegistrarTest, ConstructorNonEmptyReversedInitialization) { @@ -100,7 +99,7 @@ EXPECT_EQ(ModelTypeSet(NIGORI), registrar()->GetLastConfiguredTypes()); // Bookmarks dropped because it is in ModelSafeGroup::GROUP_NON_BLOCKING. // Passwords dropped because of no password store. - ExpectRoutingInfo({{NIGORI, GROUP_PASSIVE}}); + ExpectRoutingInfo({NIGORI}); } TEST_F(SyncBackendRegistrarTest, ConfigureDataTypes) { @@ -110,21 +109,19 @@ // Add. const ModelTypeSet types1(BOOKMARKS, NIGORI, AUTOFILL); EXPECT_EQ(types1, registrar()->ConfigureDataTypes(types1, ModelTypeSet())); - ExpectRoutingInfo({{BOOKMARKS, GROUP_NON_BLOCKING}, - {NIGORI, GROUP_PASSIVE}, - {AUTOFILL, GROUP_PASSIVE}}); + ExpectRoutingInfo({BOOKMARKS, NIGORI, AUTOFILL}); EXPECT_EQ(types1, registrar()->GetLastConfiguredTypes()); // Add and remove. const ModelTypeSet types2(PREFERENCES, THEMES); EXPECT_EQ(types2, registrar()->ConfigureDataTypes(types2, types1)); - ExpectRoutingInfo({{PREFERENCES, GROUP_PASSIVE}, {THEMES, GROUP_PASSIVE}}); + ExpectRoutingInfo({PREFERENCES, THEMES}); EXPECT_EQ(types2, registrar()->GetLastConfiguredTypes()); // Remove. EXPECT_TRUE(registrar()->ConfigureDataTypes(ModelTypeSet(), types2).Empty()); - ExpectRoutingInfo(ModelSafeRoutingInfo()); + ExpectRoutingInfo(ModelTypeSet()); EXPECT_EQ(ModelTypeSet(), registrar()->GetLastConfiguredTypes()); } @@ -134,12 +131,12 @@ registrar()->RegisterDataType(AUTOFILL); registrar()->RegisterDataType(BOOKMARKS); - ExpectRoutingInfo(ModelSafeRoutingInfo()); + ExpectRoutingInfo(ModelTypeSet()); // Simulate that initial sync was already done for AUTOFILL. registrar()->AddRestoredDataType(AUTOFILL); // It should be added to routing info and set of configured types. EXPECT_EQ(ModelTypeSet(AUTOFILL), registrar()->GetLastConfiguredTypes()); - ExpectRoutingInfo({{AUTOFILL, GROUP_NON_BLOCKING}}); + ExpectRoutingInfo({AUTOFILL}); // Configure two data types. Initial sync wasn't done for BOOKMARKS so // it should be included in types to be downloaded. @@ -148,8 +145,7 @@ registrar()->ConfigureDataTypes(types_to_add, ModelTypeSet()); EXPECT_EQ(ModelTypeSet(BOOKMARKS), newly_added_types); EXPECT_EQ(types_to_add, registrar()->GetLastConfiguredTypes()); - ExpectRoutingInfo( - {{AUTOFILL, GROUP_NON_BLOCKING}, {BOOKMARKS, GROUP_NON_BLOCKING}}); + ExpectRoutingInfo({AUTOFILL, BOOKMARKS}); } } // namespace
diff --git a/components/sync/engine/sync_engine.h b/components/sync/engine/sync_engine.h index 1bb9ec1..5471e39b 100644 --- a/components/sync/engine/sync_engine.h +++ b/components/sync/engine/sync_engine.h
@@ -156,8 +156,6 @@ base::OnceCallback<void(bool)> cb) const = 0; - virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) const = 0; - // Requests that the backend forward to the fronent any protocol events in // its buffer and begin forwarding automatically from now on. Repeated calls // to this function may result in the same events being emitted several
diff --git a/components/sync/engine_impl/commit_contribution.h b/components/sync/engine_impl/commit_contribution.h index 55e24cd..b31117d 100644 --- a/components/sync/engine_impl/commit_contribution.h +++ b/components/sync/engine_impl/commit_contribution.h
@@ -8,7 +8,7 @@ #include <stddef.h> #include "components/sync/base/syncer_error.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine_impl/cycle/status_controller.h" #include "components/sync/protocol/sync.pb.h"
diff --git a/components/sync/engine_impl/commit_contribution_impl.cc b/components/sync/engine_impl/commit_contribution_impl.cc index 4889948..188ddd4 100644 --- a/components/sync/engine_impl/commit_contribution_impl.cc +++ b/components/sync/engine_impl/commit_contribution_impl.cc
@@ -11,7 +11,7 @@ #include "base/values.h" #include "components/sync/base/time.h" #include "components/sync/base/unique_position.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine_impl/model_type_worker.h" #include "components/sync/protocol/proto_value_conversions.h"
diff --git a/components/sync/engine_impl/commit_contribution_impl.h b/components/sync/engine_impl/commit_contribution_impl.h index f7535300..52a7af7c 100644 --- a/components/sync/engine_impl/commit_contribution_impl.h +++ b/components/sync/engine_impl/commit_contribution_impl.h
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "components/sync/base/passphrase_enums.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine_impl/commit_contribution.h" #include "components/sync/engine_impl/cycle/data_type_debug_info_emitter.h" #include "components/sync/protocol/sync.pb.h"
diff --git a/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc b/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc index ee6db92..17a5186 100644 --- a/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc +++ b/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc
@@ -13,14 +13,13 @@ const base::FilePath& persistent_file) : loopback_server_(persistent_file) {} -LoopbackConnectionManager::~LoopbackConnectionManager() {} +LoopbackConnectionManager::~LoopbackConnectionManager() = default; -bool LoopbackConnectionManager::PostBufferToPath( +HttpResponse LoopbackConnectionManager::PostBufferToPath( const std::string& buffer_in, const std::string& path, const std::string& access_token, - std::string* buffer_out, - HttpResponse* http_response) { + std::string* buffer_out) { buffer_out->clear(); sync_pb::ClientToServerMessage message; @@ -28,22 +27,23 @@ DCHECK(parsed) << "Unable to parse the ClientToServerMessage."; sync_pb::ClientToServerResponse client_to_server_response; - http_response->http_status_code = + HttpResponse http_response = HttpResponse::Uninitialized(); + http_response.http_status_code = loopback_server_.HandleCommand(message, &client_to_server_response); if (client_to_server_response.IsInitialized()) { *buffer_out = client_to_server_response.SerializeAsString(); } - DCHECK_GE(http_response->http_status_code, 0); + DCHECK_GE(http_response.http_status_code, 0); - if (http_response->http_status_code != net::HTTP_OK) { - http_response->server_status = HttpResponse::SYNC_SERVER_ERROR; - return false; + if (http_response.http_status_code != net::HTTP_OK) { + http_response.server_status = HttpResponse::SYNC_SERVER_ERROR; + } else { + http_response.server_status = HttpResponse::SERVER_CONNECTION_OK; } - http_response->server_status = HttpResponse::SERVER_CONNECTION_OK; - return true; + return http_response; } } // namespace syncer
diff --git a/components/sync/engine_impl/loopback_server/loopback_connection_manager.h b/components/sync/engine_impl/loopback_server/loopback_connection_manager.h index e354114..6e78daf5 100644 --- a/components/sync/engine_impl/loopback_server/loopback_connection_manager.h +++ b/components/sync/engine_impl/loopback_server/loopback_connection_manager.h
@@ -23,11 +23,10 @@ private: // Overridden ServerConnectionManager functions. - bool PostBufferToPath(const std::string& buffer_in, - const std::string& path, - const std::string& access_token, - std::string* buffer_out, - HttpResponse* http_response) override; + HttpResponse PostBufferToPath(const std::string& buffer_in, + const std::string& path, + const std::string& access_token, + std::string* buffer_out) override; // The loopback server that will handle the requests locally. LoopbackServer loopback_server_;
diff --git a/components/sync/engine_impl/model_type_registry.h b/components/sync/engine_impl/model_type_registry.h index ab9f7de..f617dc5e 100644 --- a/components/sync/engine_impl/model_type_registry.h +++ b/components/sync/engine_impl/model_type_registry.h
@@ -14,9 +14,9 @@ #include "base/memory/weak_ptr.h" #include "components/sync/base/model_type.h" #include "components/sync/base/passphrase_enums.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine/model_safe_worker.h" #include "components/sync/engine/model_type_connector.h" -#include "components/sync/engine/non_blocking_sync_common.h" #include "components/sync/engine/sync_encryption_handler.h" #include "components/sync/engine_impl/nudge_handler.h"
diff --git a/components/sync/engine_impl/model_type_worker.h b/components/sync/engine_impl/model_type_worker.h index 3b481bb..3d3c0858 100644 --- a/components/sync/engine_impl/model_type_worker.h +++ b/components/sync/engine_impl/model_type_worker.h
@@ -19,8 +19,8 @@ #include "components/sync/base/cancelation_observer.h" #include "components/sync/base/model_type.h" #include "components/sync/base/passphrase_enums.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine/commit_queue.h" -#include "components/sync/engine/non_blocking_sync_common.h" #include "components/sync/engine/sync_encryption_handler.h" #include "components/sync/engine_impl/commit_contributor.h" #include "components/sync/engine_impl/cycle/data_type_debug_info_emitter.h"
diff --git a/components/sync/engine_impl/net/server_connection_manager.cc b/components/sync/engine_impl/net/server_connection_manager.cc index 545a906d..7b74540 100644 --- a/components/sync/engine_impl/net/server_connection_manager.cc +++ b/components/sync/engine_impl/net/server_connection_manager.cc
@@ -75,9 +75,13 @@ // static HttpResponse HttpResponse::ForHttpError(int http_status_code) { HttpResponse response; - response.server_status = http_status_code == net::HTTP_UNAUTHORIZED - ? SYNC_AUTH_ERROR - : SYNC_SERVER_ERROR; + if (http_status_code == net::HTTP_OK) { + response.server_status = SERVER_CONNECTION_OK; + } else if (http_status_code == net::HTTP_UNAUTHORIZED) { + response.server_status = SYNC_AUTH_ERROR; + } else { + response.server_status = SYNC_SERVER_ERROR; + } response.http_status_code = http_status_code; return response; } @@ -140,17 +144,16 @@ ServerConnectionEvent(server_response_.server_status)); } -bool ServerConnectionManager::PostBufferWithCachedAuth( +HttpResponse ServerConnectionManager::PostBufferWithCachedAuth( const std::string& buffer_in, - std::string* buffer_out, - HttpResponse* http_response) { + std::string* buffer_out) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::string path = MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_)); - bool result = PostBufferToPath(buffer_in, path, access_token_, buffer_out, - http_response); - SetServerResponse(*http_response); - return result; + HttpResponse http_response = + PostBufferToPath(buffer_in, path, access_token_, buffer_out); + SetServerResponse(http_response); + return http_response; } void ServerConnectionManager::AddListener(
diff --git a/components/sync/engine_impl/net/server_connection_manager.h b/components/sync/engine_impl/net/server_connection_manager.h index 0b7af61..70acc88 100644 --- a/components/sync/engine_impl/net/server_connection_manager.h +++ b/components/sync/engine_impl/net/server_connection_manager.h
@@ -64,6 +64,7 @@ static HttpResponse Uninitialized(); static HttpResponse ForNetError(int net_error_code); static HttpResponse ForIoError(); + // TODO(crbug.com/951350): Rename to ForHttpStatusCode. static HttpResponse ForHttpError(int http_status_code); static HttpResponse ForSuccess(); @@ -95,13 +96,10 @@ ServerConnectionManager(); virtual ~ServerConnectionManager(); - // POSTS buffer_in and reads a http_response into buffer_out. - // Uses our currently set access token in our headers. - // - // Returns true if executed successfully. - bool PostBufferWithCachedAuth(const std::string& buffer_in, - std::string* buffer_out, - HttpResponse* http_response); + // POSTs |buffer_in| and reads the body of the response into |buffer_out|. + // Uses the currently set access token in the headers. + HttpResponse PostBufferWithCachedAuth(const std::string& buffer_in, + std::string* buffer_out); void AddListener(ServerConnectionEventListener* listener); void RemoveListener(ServerConnectionEventListener* listener); @@ -145,11 +143,10 @@ // Internal PostBuffer base function which subclasses are expected to // implement. - virtual bool PostBufferToPath(const std::string& buffer_in, - const std::string& path, - const std::string& access_token, - std::string* buffer_out, - HttpResponse* http_response) = 0; + virtual HttpResponse PostBufferToPath(const std::string& buffer_in, + const std::string& path, + const std::string& access_token, + std::string* buffer_out) = 0; void ClearAccessToken();
diff --git a/components/sync/engine_impl/net/sync_server_connection_manager.cc b/components/sync/engine_impl/net/sync_server_connection_manager.cc index 1f5b051..9933a72 100644 --- a/components/sync/engine_impl/net/sync_server_connection_manager.cc +++ b/components/sync/engine_impl/net/sync_server_connection_manager.cc
@@ -49,17 +49,11 @@ CancelationSignal* cancelation_signal); ~Connection() override; - // TODO(crbug.com/951350): Return the HttpResponse by value. It's not - // obvious what the boolean return value means. (True means success or HTTP - // error, false means canceled or network error.) - bool Init(const std::string& connection_url, - int sync_server_port, - const std::string& access_token, - const std::string& payload, - HttpResponse* response); - bool ReadBufferResponse(std::string* buffer_out, - HttpResponse* response, - bool require_response); + HttpResponse Init(const std::string& connection_url, + int sync_server_port, + const std::string& access_token, + const std::string& payload); + bool ReadBufferResponse(std::string* buffer_out, HttpResponse* response); bool ReadDownloadResponse(HttpResponse* response, std::string* buffer_out); // CancelationObserver overrides. @@ -95,11 +89,10 @@ Connection::~Connection() = default; -bool Connection::Init(const std::string& connection_url, - int sync_server_port, - const std::string& access_token, - const std::string& payload, - HttpResponse* response) { +HttpResponse Connection::Init(const std::string& connection_url, + int sync_server_port, + const std::string& access_token, + const std::string& payload) { post_provider_->SetURL(connection_url.c_str(), sync_server_port); if (!access_token.empty()) { @@ -113,55 +106,45 @@ payload.data()); // Issue the POST, blocking until it finishes. - int net_error_code = 0; - int http_status_code = 0; if (!cancelation_signal_->TryRegisterHandler(this)) { // Return early because cancelation signal was signaled. // TODO(crbug.com/951350): Introduce an extra status code for canceled? - response->server_status = HttpResponse::CONNECTION_UNAVAILABLE; - return false; + return HttpResponse::ForNetError(0); } base::ScopedClosureRunner auto_unregister(base::BindOnce( &CancelationSignal::UnregisterHandler, base::Unretained(cancelation_signal_), base::Unretained(this))); + int net_error_code = 0; + int http_status_code = 0; if (!post_provider_->MakeSynchronousPost(&net_error_code, &http_status_code)) { DCHECK_NE(net_error_code, net::OK); DVLOG(1) << "Http POST failed, error returns: " << net_error_code; - response->server_status = HttpResponse::CONNECTION_UNAVAILABLE; - response->net_error_code = net_error_code; - return false; + return HttpResponse::ForNetError(net_error_code); } // We got a server response, copy over response codes and content. - response->http_status_code = http_status_code; - response->content_length = + HttpResponse response = HttpResponse::ForHttpError(http_status_code); + response.content_length = static_cast<int64_t>(post_provider_->GetResponseContentLength()); - response->payload_length = + response.payload_length = static_cast<int64_t>(post_provider_->GetResponseContentLength()); - if (response->http_status_code == net::HTTP_OK) - response->server_status = HttpResponse::SERVER_CONNECTION_OK; - else if (response->http_status_code == net::HTTP_UNAUTHORIZED) - response->server_status = HttpResponse::SYNC_AUTH_ERROR; - else - response->server_status = HttpResponse::SYNC_SERVER_ERROR; - // Write the content into our buffer. + // Write the content into the buffer. buffer_.assign(post_provider_->GetResponseContent(), post_provider_->GetResponseContentLength()); - return true; + return response; } bool Connection::ReadBufferResponse(std::string* buffer_out, - HttpResponse* response, - bool require_response) { + HttpResponse* response) { if (net::HTTP_OK != response->http_status_code) { response->server_status = HttpResponse::SYNC_SERVER_ERROR; return false; } - if (require_response && (1 > response->content_length)) + if (response->content_length <= 0) return false; const int64_t bytes_read = @@ -218,23 +201,20 @@ SyncServerConnectionManager::~SyncServerConnectionManager() = default; -bool SyncServerConnectionManager::PostBufferToPath( +HttpResponse SyncServerConnectionManager::PostBufferToPath( const std::string& buffer_in, const std::string& path, const std::string& access_token, - std::string* buffer_out, - HttpResponse* http_response) { + std::string* buffer_out) { if (access_token.empty()) { - http_response->server_status = HttpResponse::SYNC_AUTH_ERROR; // Print a log to distinguish this "known failure" from others. DVLOG(1) << "ServerConnectionManager forcing SYNC_AUTH_ERROR due to missing" " access token"; - return false; + return HttpResponse::ForHttpError(net::HTTP_UNAUTHORIZED); } if (cancelation_signal_->IsSignalled()) { - http_response->server_status = HttpResponse::CONNECTION_UNAVAILABLE; - return false; + return HttpResponse::ForNetError(0); } auto connection = std::make_unique<Connection>(post_provider_factory_.get(), @@ -243,21 +223,19 @@ // Note that |post| may be aborted by now, which will just cause Init to fail // with CONNECTION_UNAVAILABLE. - bool ok = connection->Init(connection_url, sync_server_port_, access_token, - buffer_in, http_response); + HttpResponse http_response = connection->Init( + connection_url, sync_server_port_, access_token, buffer_in); - if (http_response->server_status == HttpResponse::SYNC_AUTH_ERROR) { + if (http_response.server_status == HttpResponse::SYNC_AUTH_ERROR) { ClearAccessToken(); } - if (!ok || net::HTTP_OK != http_response->http_status_code) - return false; - - if (connection->ReadBufferResponse(buffer_out, http_response, true)) { - http_response->server_status = HttpResponse::SERVER_CONNECTION_OK; - return true; + if (http_response.server_status != HttpResponse::SERVER_CONNECTION_OK) { + return http_response; } - return false; + + connection->ReadBufferResponse(buffer_out, &http_response); + return http_response; } } // namespace syncer
diff --git a/components/sync/engine_impl/net/sync_server_connection_manager.h b/components/sync/engine_impl/net/sync_server_connection_manager.h index 1e436fa1..0df5eed 100644 --- a/components/sync/engine_impl/net/sync_server_connection_manager.h +++ b/components/sync/engine_impl/net/sync_server_connection_manager.h
@@ -32,11 +32,10 @@ ~SyncServerConnectionManager() override; protected: - bool PostBufferToPath(const std::string& buffer_in, - const std::string& path, - const std::string& access_token, - std::string* buffer_out, - HttpResponse* http_response) override; + HttpResponse PostBufferToPath(const std::string& buffer_in, + const std::string& path, + const std::string& access_token, + std::string* buffer_out) override; private: FRIEND_TEST_ALL_PREFIXES(SyncServerConnectionManagerTest, VeryEarlyAbortPost);
diff --git a/components/sync/engine_impl/net/sync_server_connection_manager_unittest.cc b/components/sync/engine_impl/net/sync_server_connection_manager_unittest.cc index c692d4f..f531004 100644 --- a/components/sync/engine_impl/net/sync_server_connection_manager_unittest.cc +++ b/components/sync/engine_impl/net/sync_server_connection_manager_unittest.cc
@@ -72,12 +72,9 @@ "server", 0, true, std::make_unique<BlockingHttpPostFactory>(), &signal); std::string buffer_out; - HttpResponse http_response = HttpResponse::Uninitialized(); + HttpResponse http_response = + server.PostBufferToPath("", "/testpath", "testauth", &buffer_out); - bool result = server.PostBufferToPath("", "/testpath", "testauth", - &buffer_out, &http_response); - - EXPECT_FALSE(result); EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE, http_response.server_status); } @@ -87,14 +84,12 @@ SyncServerConnectionManager server( "server", 0, true, std::make_unique<BlockingHttpPostFactory>(), &signal); - std::string buffer_out; - HttpResponse http_response = HttpResponse::Uninitialized(); signal.Signal(); - bool result = server.PostBufferToPath("", "/testpath", "testauth", - &buffer_out, &http_response); + std::string buffer_out; + HttpResponse http_response = + server.PostBufferToPath("", "/testpath", "testauth", &buffer_out); - EXPECT_FALSE(result); EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE, http_response.server_status); } @@ -112,12 +107,9 @@ TestTimeouts::tiny_timeout()); std::string buffer_out; - HttpResponse http_response = HttpResponse::Uninitialized(); + HttpResponse http_response = + server.PostBufferToPath("", "/testpath", "testauth", &buffer_out); - bool result = server.PostBufferToPath("", "/testpath", "testauth", - &buffer_out, &http_response); - - EXPECT_FALSE(result); EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE, http_response.server_status); abort_thread.Stop(); } @@ -179,12 +171,9 @@ std::make_unique<FailingHttpPostFactory>(net::ERR_TIMED_OUT), &signal); std::string buffer_out; - HttpResponse http_response = HttpResponse::Uninitialized(); + HttpResponse http_response = + server.PostBufferToPath("", "/testpath", "testauth", &buffer_out); - bool result = server.PostBufferToPath("", "/testpath", "testauth", - &buffer_out, &http_response); - - EXPECT_FALSE(result); EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE, http_response.server_status); }
diff --git a/components/sync/engine_impl/syncer_proto_util.cc b/components/sync/engine_impl/syncer_proto_util.cc index ddb08eb..d0d032c 100644 --- a/components/sync/engine_impl/syncer_proto_util.cc +++ b/components/sync/engine_impl/syncer_proto_util.cc
@@ -356,11 +356,11 @@ const base::Time start_time = base::Time::Now(); + // Fills in buffer_out. std::string buffer_out; - HttpResponse http_response = HttpResponse::Uninitialized(); - - // Fills in buffer_out and http_response. - if (!scm->PostBufferWithCachedAuth(buffer_in, &buffer_out, &http_response)) { + HttpResponse http_response = + scm->PostBufferWithCachedAuth(buffer_in, &buffer_out); + if (http_response.server_status != HttpResponse::SERVER_CONNECTION_OK) { LOG(WARNING) << "Error posting from syncer:" << http_response; return false; }
diff --git a/components/sync/engine_impl/syncer_proto_util_unittest.cc b/components/sync/engine_impl/syncer_proto_util_unittest.cc index b45c0de2..ff83fb3 100644 --- a/components/sync/engine_impl/syncer_proto_util_unittest.cc +++ b/components/sync/engine_impl/syncer_proto_util_unittest.cc
@@ -214,27 +214,26 @@ class DummyConnectionManager : public ServerConnectionManager { public: - DummyConnectionManager() : send_error_(false) {} + DummyConnectionManager() = default; - bool PostBufferToPath(const std::string& buffer_in, - const std::string& path, - const std::string& access_token, - std::string* buffer_out, - HttpResponse* response) override { + HttpResponse PostBufferToPath(const std::string& buffer_in, + const std::string& path, + const std::string& access_token, + std::string* buffer_out) override { if (send_error_) { - return false; + return HttpResponse::ForIoError(); } sync_pb::ClientToServerResponse client_to_server_response; client_to_server_response.SerializeToString(buffer_out); - return true; + return HttpResponse::ForSuccess(); } void set_send_error(bool send) { send_error_ = send; } private: - bool send_error_; + bool send_error_ = false; }; TEST_F(SyncerProtoUtilTest, PostAndProcessHeaders) {
diff --git a/components/sync/model/fake_model_type_sync_bridge.h b/components/sync/model/fake_model_type_sync_bridge.h index 354da8a..d4606095 100644 --- a/components/sync/model/fake_model_type_sync_bridge.h +++ b/components/sync/model/fake_model_type_sync_bridge.h
@@ -11,7 +11,7 @@ #include <unordered_set> #include "base/optional.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/model/entity_data.h" #include "components/sync/model/metadata_batch.h" #include "components/sync/model/model_error.h"
diff --git a/components/sync/model/model_type_sync_bridge.h b/components/sync/model/model_type_sync_bridge.h index 9c16529..eacd8a72 100644 --- a/components/sync/model/model_type_sync_bridge.h +++ b/components/sync/model/model_type_sync_bridge.h
@@ -11,7 +11,7 @@ #include "base/callback.h" #include "base/optional.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/model/entity_change.h" #include "components/sync/model/model_type_change_processor.h"
diff --git a/components/sync/model/recording_model_type_change_processor.cc b/components/sync/model/recording_model_type_change_processor.cc deleted file mode 100644 index 8a36f00..0000000 --- a/components/sync/model/recording_model_type_change_processor.cc +++ /dev/null
@@ -1,64 +0,0 @@ -// 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/sync/model/recording_model_type_change_processor.h" - -#include <utility> - -#include "base/bind.h" -#include "base/memory/ptr_util.h" -#include "components/sync/model/fake_model_type_sync_bridge.h" -#include "components/sync/model/metadata_batch.h" - -namespace syncer { - -RecordingModelTypeChangeProcessor::RecordingModelTypeChangeProcessor() {} - -RecordingModelTypeChangeProcessor::~RecordingModelTypeChangeProcessor() {} - -void RecordingModelTypeChangeProcessor::Put( - const std::string& storage_key, - std::unique_ptr<EntityData> entity_data, - MetadataChangeList* metadata_changes) { - put_multimap_.insert(std::make_pair(storage_key, std::move(entity_data))); -} - -void RecordingModelTypeChangeProcessor::Delete( - const std::string& storage_key, - MetadataChangeList* metadata_changes) { - delete_set_.insert(storage_key); -} - -void RecordingModelTypeChangeProcessor::UpdateStorageKey( - const EntityData& entity_data, - const std::string& storage_key, - MetadataChangeList* metadata_change_list) { - update_multimap_.insert(std::make_pair( - storage_key, FakeModelTypeSyncBridge::CopyEntityData(entity_data))); -} - -void RecordingModelTypeChangeProcessor::UntrackEntityForStorageKey( - const std::string& storage_key) { - untrack_for_storage_key_set_.insert(storage_key); -} - -void RecordingModelTypeChangeProcessor::UntrackEntityForClientTagHash( - const ClientTagHash& client_tag_hash) { - untrack_for_client_tag_hash_set_.insert(client_tag_hash); -} - -void RecordingModelTypeChangeProcessor::ModelReadyToSync( - std::unique_ptr<MetadataBatch> batch) { - std::swap(metadata_, batch); -} - -bool RecordingModelTypeChangeProcessor::IsTrackingMetadata() { - return true; -} - -std::string RecordingModelTypeChangeProcessor::TrackedAccountId() { - return ""; -} - -} // namespace syncer
diff --git a/components/sync/model/recording_model_type_change_processor.h b/components/sync/model/recording_model_type_change_processor.h deleted file mode 100644 index 97a9f4c..0000000 --- a/components/sync/model/recording_model_type_change_processor.h +++ /dev/null
@@ -1,75 +0,0 @@ -// 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_SYNC_MODEL_RECORDING_MODEL_TYPE_CHANGE_PROCESSOR_H_ -#define COMPONENTS_SYNC_MODEL_RECORDING_MODEL_TYPE_CHANGE_PROCESSOR_H_ - -#include <map> -#include <memory> -#include <set> -#include <string> - -#include "components/sync/base/client_tag_hash.h" -#include "components/sync/model/fake_model_type_change_processor.h" -#include "components/sync/model/model_type_sync_bridge.h" - -namespace syncer { - -// Augmented FakeModelTypeChangeProcessor that accumulates all instructions in -// members that can then be accessed for verification. -class RecordingModelTypeChangeProcessor : public FakeModelTypeChangeProcessor { - public: - RecordingModelTypeChangeProcessor(); - ~RecordingModelTypeChangeProcessor() override; - - // FakeModelTypeChangeProcessor overrides. - void Put(const std::string& storage_key, - std::unique_ptr<EntityData> entity_data, - MetadataChangeList* metadata_changes) override; - void Delete(const std::string& storage_key, - MetadataChangeList* metadata_changes) override; - void UpdateStorageKey(const EntityData& entity_data, - const std::string& storage_key, - MetadataChangeList* metadata_change_list) override; - void UntrackEntityForStorageKey(const std::string& storage_key) override; - void UntrackEntityForClientTagHash( - const ClientTagHash& client_tag_hash) override; - void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) override; - bool IsTrackingMetadata() override; - std::string TrackedAccountId() override; - - const std::multimap<std::string, std::unique_ptr<EntityData>>& put_multimap() - const { - return put_multimap_; - } - - const std::multimap<std::string, std::unique_ptr<EntityData>>& - update_multimap() const { - return update_multimap_; - } - - const std::set<std::string>& delete_set() const { return delete_set_; } - - const std::set<std::string>& untrack_for_storage_key_set() const { - return untrack_for_storage_key_set_; - } - - const std::set<ClientTagHash>& untrack_for_client_tag_hash_set() const { - return untrack_for_client_tag_hash_set_; - } - - MetadataBatch* metadata() const { return metadata_.get(); } - - private: - std::multimap<std::string, std::unique_ptr<EntityData>> put_multimap_; - std::multimap<std::string, std::unique_ptr<EntityData>> update_multimap_; - std::set<std::string> delete_set_; - std::set<std::string> untrack_for_storage_key_set_; - std::set<ClientTagHash> untrack_for_client_tag_hash_set_; - std::unique_ptr<MetadataBatch> metadata_; -}; - -} // namespace syncer - -#endif // COMPONENTS_SYNC_MODEL_RECORDING_MODEL_TYPE_CHANGE_PROCESSOR_H_
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.h b/components/sync/model_impl/client_tag_based_model_type_processor.h index 2cfa68e..198584085 100644 --- a/components/sync/model_impl/client_tag_based_model_type_processor.h +++ b/components/sync/model_impl/client_tag_based_model_type_processor.h
@@ -17,8 +17,8 @@ #include "components/sync/base/client_tag_hash.h" #include "components/sync/base/model_type.h" #include "components/sync/base/sync_stop_metadata_fate.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine/model_type_processor.h" -#include "components/sync/engine/non_blocking_sync_common.h" #include "components/sync/model/data_batch.h" #include "components/sync/model/data_type_activation_request.h" #include "components/sync/model/metadata_batch.h"
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc index e0f8289c..1c59dd49 100644 --- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc +++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -21,8 +21,8 @@ #include "components/sync/base/model_type.h" #include "components/sync/base/sync_mode.h" #include "components/sync/base/time.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine/data_type_activation_response.h" -#include "components/sync/engine/non_blocking_sync_common.h" #include "components/sync/model/conflict_resolution.h" #include "components/sync/model/data_type_activation_request.h" #include "components/sync/model/fake_model_type_sync_bridge.h"
diff --git a/components/sync/model_impl/client_tag_based_remote_update_handler.h b/components/sync/model_impl/client_tag_based_remote_update_handler.h index cf16911..d6ffa72 100644 --- a/components/sync/model_impl/client_tag_based_remote_update_handler.h +++ b/components/sync/model_impl/client_tag_based_remote_update_handler.h
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "base/optional.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/model/conflict_resolution.h" #include "components/sync/model/entity_change.h" #include "components/sync/model/model_error.h"
diff --git a/components/sync/model_impl/in_memory_metadata_change_list.h b/components/sync/model_impl/in_memory_metadata_change_list.h index a816e76e..23ce471 100644 --- a/components/sync/model_impl/in_memory_metadata_change_list.h +++ b/components/sync/model_impl/in_memory_metadata_change_list.h
@@ -9,7 +9,7 @@ #include <memory> #include <string> -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/model/metadata_change_list.h" #include "components/sync/protocol/entity_metadata.pb.h" #include "components/sync/protocol/model_type_state.pb.h"
diff --git a/components/sync/model_impl/processor_entity.cc b/components/sync/model_impl/processor_entity.cc index fa8c2bc..b2de6b6 100644 --- a/components/sync/model_impl/processor_entity.cc +++ b/components/sync/model_impl/processor_entity.cc
@@ -15,7 +15,7 @@ #include "components/sync/base/client_tag_hash.h" #include "components/sync/base/sync_base_switches.h" #include "components/sync/base/time.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/protocol/proto_memory_estimations.h" namespace syncer {
diff --git a/components/sync/model_impl/processor_entity_tracker.h b/components/sync/model_impl/processor_entity_tracker.h index 998cd3f..90023c9 100644 --- a/components/sync/model_impl/processor_entity_tracker.h +++ b/components/sync/model_impl/processor_entity_tracker.h
@@ -12,7 +12,7 @@ #include <vector> #include "components/sync/base/client_tag_hash.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/protocol/entity_metadata.pb.h" #include "components/sync/protocol/model_type_state.pb.h"
diff --git a/components/sync/model_impl/processor_entity_unittest.cc b/components/sync/model_impl/processor_entity_unittest.cc index af7e9817..b73264f82 100644 --- a/components/sync/model_impl/processor_entity_unittest.cc +++ b/components/sync/model_impl/processor_entity_unittest.cc
@@ -11,7 +11,7 @@ #include "components/sync/base/client_tag_hash.h" #include "components/sync/base/model_type.h" #include "components/sync/base/time.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/protocol/sync.pb.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/sync/test/engine/mock_connection_manager.cc b/components/sync/test/engine/mock_connection_manager.cc index 691fe25..6b5a53f6 100644 --- a/components/sync/test/engine/mock_connection_manager.cc +++ b/components/sync/test/engine/mock_connection_manager.cc
@@ -13,6 +13,7 @@ #include "components/sync/engine_impl/syncer_proto_util.h" #include "components/sync/protocol/bookmark_specifics.pb.h" #include "net/base/net_errors.h" +#include "net/http/http_status_code.h" #include "testing/gtest/include/gtest/gtest.h" using std::find; @@ -65,27 +66,29 @@ mid_commit_observer_ = observer; } -bool MockConnectionManager::PostBufferToPath(const std::string& buffer_in, - const std::string& path, - const std::string& access_token, - std::string* buffer_out, - HttpResponse* http_response) { +HttpResponse MockConnectionManager::PostBufferToPath( + const std::string& buffer_in, + const std::string& path, + const std::string& access_token, + std::string* buffer_out) { ClientToServerMessage post; if (!post.ParseFromString(buffer_in)) { ADD_FAILURE(); - return false; + // Note: Here and below, ForIoError() is chosen somewhat arbitrarily, since + // HttpResponse doesn't have any better-fitting type of error. + return HttpResponse::ForIoError(); } if (!post.has_protocol_version()) { ADD_FAILURE(); - return false; + return HttpResponse::ForIoError(); } if (!post.has_api_key()) { ADD_FAILURE(); - return false; + return HttpResponse::ForIoError(); } if (!post.has_bag_of_chips()) { ADD_FAILURE(); - return false; + return HttpResponse::ForIoError(); } requests_.push_back(post); @@ -94,29 +97,25 @@ client_to_server_response.Clear(); if (access_token.empty()) { - http_response->server_status = HttpResponse::SYNC_AUTH_ERROR; - return false; + return HttpResponse::ForNetError(net::HTTP_UNAUTHORIZED); } if (access_token != kValidAccessToken) { // Simulate server-side auth failure. - http_response->server_status = HttpResponse::SYNC_AUTH_ERROR; ClearAccessToken(); + return HttpResponse::ForNetError(net::HTTP_UNAUTHORIZED); } if (--countdown_to_postbuffer_fail_ == 0) { // Fail as countdown hits zero. - http_response->server_status = HttpResponse::SYNC_SERVER_ERROR; - return false; + return HttpResponse::ForHttpError(net::HTTP_BAD_REQUEST); } if (!server_reachable_) { - http_response->server_status = HttpResponse::CONNECTION_UNAVAILABLE; - return false; + return HttpResponse::ForNetError(net::ERR_FAILED); } // Default to an ok connection. - http_response->server_status = HttpResponse::SERVER_CONNECTION_OK; client_to_server_response.set_error_code(SyncEnums::SUCCESS); const string current_store_birthday = store_birthday(); client_to_server_response.set_store_birthday(current_store_birthday); @@ -126,9 +125,8 @@ client_to_server_response.set_error_message("Merry Unbirthday!"); client_to_server_response.SerializeToString(buffer_out); store_birthday_sent_ = true; - return true; + return HttpResponse::ForSuccess(); } - bool result = true; EXPECT_TRUE(!store_birthday_sent_ || post.has_store_birthday() || post.message_contents() == ClientToServerMessage::CLEAR_SERVER_DATA); @@ -136,21 +134,21 @@ if (post.message_contents() == ClientToServerMessage::COMMIT) { if (!ProcessCommit(&post, &client_to_server_response)) { - return false; + return HttpResponse::ForIoError(); } } else if (post.message_contents() == ClientToServerMessage::GET_UPDATES) { if (!ProcessGetUpdates(&post, &client_to_server_response)) { - return false; + return HttpResponse::ForIoError(); } } else if (post.message_contents() == ClientToServerMessage::CLEAR_SERVER_DATA) { if (!ProcessClearServerData(&post, &client_to_server_response)) { - return false; + return HttpResponse::ForIoError(); } } else { EXPECT_TRUE(false) << "Unknown/unsupported ClientToServerMessage"; - return false; + return HttpResponse::ForIoError(); } { @@ -187,7 +185,7 @@ mid_commit_observer_->Observe(); } - return result; + return HttpResponse::ForSuccess(); } sync_pb::GetUpdatesResponse* MockConnectionManager::GetUpdateResponse() {
diff --git a/components/sync/test/engine/mock_connection_manager.h b/components/sync/test/engine/mock_connection_manager.h index 9753123c..ed9e0f6 100644 --- a/components/sync/test/engine/mock_connection_manager.h +++ b/components/sync/test/engine/mock_connection_manager.h
@@ -39,11 +39,10 @@ ~MockConnectionManager() override; // Overridden ServerConnectionManager functions. - bool PostBufferToPath(const std::string& buffer_in, - const std::string& path, - const std::string& access_token, - std::string* buffer_out, - HttpResponse* http_response) override; + HttpResponse PostBufferToPath(const std::string& buffer_in, + const std::string& path, + const std::string& access_token, + std::string* buffer_out) override; // Control of commit response. // NOTE: Commit callback is invoked only once then reset.
diff --git a/components/sync/test/engine/mock_model_type_processor.h b/components/sync/test/engine/mock_model_type_processor.h index a4f04a8..71f904d 100644 --- a/components/sync/test/engine/mock_model_type_processor.h +++ b/components/sync/test/engine/mock_model_type_processor.h
@@ -16,8 +16,8 @@ #include "base/callback.h" #include "base/macros.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine/model_type_processor.h" -#include "components/sync/engine/non_blocking_sync_common.h" #include "components/sync/protocol/model_type_state.pb.h" namespace syncer {
diff --git a/components/sync/test/engine/mock_model_type_worker.h b/components/sync/test/engine/mock_model_type_worker.h index 18ebe92..799e607 100644 --- a/components/sync/test/engine/mock_model_type_worker.h +++ b/components/sync/test/engine/mock_model_type_worker.h
@@ -18,9 +18,9 @@ #include "base/memory/weak_ptr.h" #include "components/sync/base/client_tag_hash.h" #include "components/sync/base/model_type.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/engine/commit_queue.h" #include "components/sync/engine/model_type_processor.h" -#include "components/sync/engine/non_blocking_sync_common.h" #include "components/sync/protocol/model_type_state.pb.h" #include "components/sync/protocol/sync.pb.h"
diff --git a/components/sync/test/engine/single_type_mock_server.h b/components/sync/test/engine/single_type_mock_server.h index 2f06642..33072f6 100644 --- a/components/sync/test/engine/single_type_mock_server.h +++ b/components/sync/test/engine/single_type_mock_server.h
@@ -15,7 +15,7 @@ #include "base/macros.h" #include "components/sync/base/client_tag_hash.h" #include "components/sync/base/model_type.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" namespace syncer {
diff --git a/components/sync_bookmarks/bookmark_local_changes_builder.h b/components/sync_bookmarks/bookmark_local_changes_builder.h index ee5ededa..9380205 100644 --- a/components/sync_bookmarks/bookmark_local_changes_builder.h +++ b/components/sync_bookmarks/bookmark_local_changes_builder.h
@@ -7,7 +7,7 @@ #include <vector> -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" namespace bookmarks { class BookmarkModel;
diff --git a/components/sync_bookmarks/bookmark_model_merger.h b/components/sync_bookmarks/bookmark_model_merger.h index acb1e53..ac289da 100644 --- a/components/sync_bookmarks/bookmark_model_merger.h +++ b/components/sync_bookmarks/bookmark_model_merger.h
@@ -13,7 +13,7 @@ #include "base/macros.h" #include "components/sync/base/unique_position.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" namespace bookmarks { class BookmarkModel;
diff --git a/components/sync_bookmarks/bookmark_model_observer_impl.cc b/components/sync_bookmarks/bookmark_model_observer_impl.cc index 2d1011c..dc644fd 100644 --- a/components/sync_bookmarks/bookmark_model_observer_impl.cc +++ b/components/sync_bookmarks/bookmark_model_observer_impl.cc
@@ -13,7 +13,7 @@ #include "components/sync/base/hash_util.h" #include "components/sync/base/unique_position.h" #include "components/sync/driver/sync_driver_switches.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync_bookmarks/bookmark_specifics_conversions.h" #include "components/sync_bookmarks/switches.h"
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.h b/components/sync_bookmarks/bookmark_remote_updates_handler.h index 8b501ff..e62e828 100644 --- a/components/sync_bookmarks/bookmark_remote_updates_handler.h +++ b/components/sync_bookmarks/bookmark_remote_updates_handler.h
@@ -9,7 +9,7 @@ #include <string> #include <vector> -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync_bookmarks/synced_bookmark_tracker.h" namespace bookmarks {
diff --git a/components/sync_sessions/session_sync_bridge_unittest.cc b/components/sync_sessions/session_sync_bridge_unittest.cc index 5cc4e622..86e2478f 100644 --- a/components/sync_sessions/session_sync_bridge_unittest.cc +++ b/components/sync_sessions/session_sync_bridge_unittest.cc
@@ -19,7 +19,7 @@ #include "components/prefs/testing_pref_service.h" #include "components/sync/base/client_tag_hash.h" #include "components/sync/base/sync_prefs.h" -#include "components/sync/engine/non_blocking_sync_common.h" +#include "components/sync/engine/commit_and_get_updates_types.h" #include "components/sync/model/data_batch.h" #include "components/sync/model/data_type_activation_request.h" #include "components/sync/model/metadata_batch.h"
diff --git a/components/timers/alarm_timer_chromeos.cc b/components/timers/alarm_timer_chromeos.cc index af98c065..bd3947c 100644 --- a/components/timers/alarm_timer_chromeos.cc +++ b/components/timers/alarm_timer_chromeos.cc
@@ -17,6 +17,7 @@ #include "base/memory/ptr_util.h" #include "base/pending_task.h" #include "base/task/common/task_annotator.h" +#include "base/trace_event/task_execution_macros.h" #include "base/trace_event/trace_event.h" namespace timers {
diff --git a/components/tracing/test/trace_event_perftest.cc b/components/tracing/test/trace_event_perftest.cc index 5f93f59c..c2317ce5 100644 --- a/components/tracing/test/trace_event_perftest.cc +++ b/components/tracing/test/trace_event_perftest.cc
@@ -11,6 +11,7 @@ #include "base/run_loop.h" #include "base/test/task_environment.h" #include "base/threading/thread.h" +#include "base/trace_event/task_execution_macros.h" #include "base/trace_event/trace_event.h" #include "base/trace_event/traced_value.h" #include "perf_test_helpers.h"
diff --git a/components/viz/common/quads/shared_quad_state.h b/components/viz/common/quads/shared_quad_state.h index 91bd287..97681e500 100644 --- a/components/viz/common/quads/shared_quad_state.h +++ b/components/viz/common/quads/shared_quad_state.h
@@ -34,7 +34,7 @@ ~SharedQuadState(); void SetAll(const gfx::Transform& quad_to_target_transform, - const gfx::Rect& layer_rect, + const gfx::Rect& quad_layer_rect, const gfx::Rect& visible_layer_rect, const gfx::RRectF& rounded_corner_bounds, const gfx::Rect& clip_rect,
diff --git a/components/viz/service/display/overlay_ca_unittest.cc b/components/viz/service/display/overlay_ca_unittest.cc index 4983910c..a97d4c94 100644 --- a/components/viz/service/display/overlay_ca_unittest.cc +++ b/components/viz/service/display/overlay_ca_unittest.cc
@@ -95,8 +95,7 @@ class CATestOverlayProcessor : public OverlayProcessorMac { public: CATestOverlayProcessor() - : OverlayProcessorMac(true /* could_overlay */, - true /* enable_ca_overlay */) {} + : OverlayProcessorMac(true /* enable_ca_overlay */) {} }; std::unique_ptr<AggregatedRenderPass> CreateRenderPass() {
diff --git a/components/viz/service/display/overlay_processor_android.cc b/components/viz/service/display/overlay_processor_android.cc index 8550036..8c1ab6b 100644 --- a/components/viz/service/display/overlay_processor_android.cc +++ b/components/viz/service/display/overlay_processor_android.cc
@@ -20,14 +20,8 @@ OverlayProcessorAndroid::OverlayProcessorAndroid( gpu::SharedImageManager* shared_image_manager, gpu::MemoryTracker* memory_tracker, - gpu::GpuTaskSchedulerHelper* gpu_task_scheduler, - bool enable_overlay) - : OverlayProcessorUsingStrategy(), - gpu_task_scheduler_(gpu_task_scheduler), - overlay_enabled_(enable_overlay) { - if (!overlay_enabled_) - return; - + gpu::GpuTaskSchedulerHelper* gpu_task_scheduler) + : OverlayProcessorUsingStrategy(), gpu_task_scheduler_(gpu_task_scheduler) { // In unittests, we don't have the gpu_task_scheduler_ set up, but still want // to test ProcessForOverlays functionalities where we are making overlay // candidates correctly. @@ -90,7 +84,7 @@ } bool OverlayProcessorAndroid::IsOverlaySupported() const { - return overlay_enabled_; + return true; } bool OverlayProcessorAndroid::NeedsSurfaceDamageRectList() const {
diff --git a/components/viz/service/display/overlay_processor_android.h b/components/viz/service/display/overlay_processor_android.h index 0bf0f43..b01b089 100644 --- a/components/viz/service/display/overlay_processor_android.h +++ b/components/viz/service/display/overlay_processor_android.h
@@ -34,8 +34,7 @@ public: OverlayProcessorAndroid(gpu::SharedImageManager* shared_image_manager, gpu::MemoryTracker* memory_tracker, - gpu::GpuTaskSchedulerHelper* gpu_task_scheduler, - bool enable_overlay); + gpu::GpuTaskSchedulerHelper* gpu_task_scheduler); ~OverlayProcessorAndroid() override; bool IsOverlaySupported() const override; @@ -79,7 +78,6 @@ PromotionHintInfoMap promotion_hint_info_map_; gpu::GpuTaskSchedulerHelper* gpu_task_scheduler_; - const bool overlay_enabled_; // This class is created, accessed, and destroyed on the gpu thread. std::unique_ptr<OverlayProcessorOnGpu> processor_on_gpu_;
diff --git a/components/viz/service/display/overlay_processor_interface.cc b/components/viz/service/display/overlay_processor_interface.cc index c22926e..e8b0800 100644 --- a/components/viz/service/display/overlay_processor_interface.cc +++ b/components/viz/service/display/overlay_processor_interface.cc
@@ -88,25 +88,34 @@ gpu::SharedImageInterface* shared_image_interface, const RendererSettings& renderer_settings, const DebugRendererSettings* debug_settings) { -#if defined(OS_APPLE) - bool could_overlay = - output_surface->GetSurfaceHandle() != gpu::kNullSurfaceHandle; - could_overlay &= output_surface->capabilities().supports_surfaceless; - bool enable_ca_overlay = could_overlay && renderer_settings.allow_overlays; + // If we are offscreen, we don't have overlay support. + // TODO(vasilyt): WebView would have a kNullSurfaceHandle. Make sure when + // overlay for WebView is enabled, this check still works. + if (surface_handle == gpu::kNullSurfaceHandle) + return std::make_unique<OverlayProcessorStub>(); - return std::make_unique<OverlayProcessorMac>(could_overlay, - enable_ca_overlay); +#if defined(OS_APPLE) + DCHECK(capabilities.supports_surfaceless); + + return std::make_unique<OverlayProcessorMac>( + renderer_settings.allow_overlays); #elif defined(OS_WIN) + if (!capabilities.supports_dc_layers) + return std::make_unique<OverlayProcessorStub>(); + return std::make_unique<OverlayProcessorWin>( output_surface, std::make_unique<DCLayerOverlayProcessor>( debug_settings, /*allowed_yuv_overlay_count=*/1)); #elif defined(USE_OZONE) if (!features::IsUsingOzonePlatform()) return std::make_unique<OverlayProcessorStub>(); - bool overlay_enabled = surface_handle != gpu::kNullSurfaceHandle; - overlay_enabled &= !renderer_settings.overlay_strategies.empty(); + + // In tests and Ozone/X11, we do not expect surfaceless surface support. + if (!capabilities.supports_surfaceless) + return std::make_unique<OverlayProcessorStub>(); + std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates; - if (overlay_enabled) { + if (!renderer_settings.overlay_strategies.empty()) { auto* overlay_manager = ui::OzonePlatform::GetInstance()->GetOverlayManager(); overlay_candidates = @@ -114,19 +123,18 @@ } gpu::SharedImageInterface* sii = nullptr; - if (overlay_enabled && features::ShouldUseRealBuffersForPageFlipTest()) { + if (features::ShouldUseRealBuffersForPageFlipTest()) { sii = shared_image_interface; CHECK(shared_image_interface); } return std::make_unique<OverlayProcessorOzone>( - overlay_enabled, std::move(overlay_candidates), + std::move(overlay_candidates), std::move(renderer_settings.overlay_strategies), sii); #elif defined(OS_ANDROID) - bool overlay_enabled = surface_handle != gpu::kNullSurfaceHandle; if (capabilities.supports_surfaceless) { // This is for Android SurfaceControl case. - return std::make_unique<OverlayProcessorSurfaceControl>(overlay_enabled); + return std::make_unique<OverlayProcessorSurfaceControl>(); } else { // When SurfaceControl is enabled, any resource backed by // an AHardwareBuffer can be marked as an overlay candidate but it requires @@ -134,10 +142,11 @@ // native window backed GLSurface, the overlay processing code will // incorrectly assume these resources can be overlaid. So we disable all // overlay processing for this OutputSurface. - overlay_enabled &= !capabilities.android_surface_control_feature_enabled; + if (capabilities.android_surface_control_feature_enabled) + return std::make_unique<OverlayProcessorStub>(); + return std::make_unique<OverlayProcessorAndroid>( - shared_image_manager, memory_tracker, gpu_task_scheduler, - overlay_enabled); + shared_image_manager, memory_tracker, gpu_task_scheduler); } #else // Default return std::make_unique<OverlayProcessorStub>();
diff --git a/components/viz/service/display/overlay_processor_mac.cc b/components/viz/service/display/overlay_processor_mac.cc index a7cbd3a..22298611 100644 --- a/components/viz/service/display/overlay_processor_mac.cc +++ b/components/viz/service/display/overlay_processor_mac.cc
@@ -15,17 +15,14 @@ #include "ui/gfx/geometry/rect_conversions.h" namespace viz { -OverlayProcessorMac::OverlayProcessorMac(bool could_overlay, - bool enable_ca_overlay) - : could_overlay_(could_overlay), - enable_ca_overlay_(enable_ca_overlay), +OverlayProcessorMac::OverlayProcessorMac(bool enable_ca_overlay) + : enable_ca_overlay_(enable_ca_overlay), ca_layer_overlay_processor_(std::make_unique<CALayerOverlayProcessor>()) { } OverlayProcessorMac::OverlayProcessorMac( std::unique_ptr<CALayerOverlayProcessor> ca_layer_overlay_processor) - : could_overlay_(true), - enable_ca_overlay_(true), + : enable_ca_overlay_(true), ca_layer_overlay_processor_(std::move(ca_layer_overlay_processor)) {} OverlayProcessorMac::~OverlayProcessorMac() = default; @@ -35,7 +32,7 @@ } bool OverlayProcessorMac::IsOverlaySupported() const { - return could_overlay_; + return true; } gfx::Rect OverlayProcessorMac::GetPreviousFrameOverlaysBoundingRect() const {
diff --git a/components/viz/service/display/overlay_processor_mac.h b/components/viz/service/display/overlay_processor_mac.h index f37747e5..5afdb25 100644 --- a/components/viz/service/display/overlay_processor_mac.h +++ b/components/viz/service/display/overlay_processor_mac.h
@@ -27,7 +27,7 @@ public: using CandidateList = CALayerOverlayList; - OverlayProcessorMac(bool could_overlay, bool enable_ca_overlay); + explicit OverlayProcessorMac(bool enable_ca_overlay); // For testing. explicit OverlayProcessorMac( std::unique_ptr<CALayerOverlayProcessor> ca_layer_overlay_processor); @@ -67,7 +67,6 @@ base::Optional<OutputSurfaceOverlayPlane>* output_surface_plane) override; private: - const bool could_overlay_; const bool enable_ca_overlay_; gfx::Rect ca_overlay_damage_rect_; gfx::Rect previous_frame_full_bounding_rect_;
diff --git a/components/viz/service/display/overlay_processor_ozone.cc b/components/viz/service/display/overlay_processor_ozone.cc index b4a7ea7..8094b2d 100644 --- a/components/viz/service/display/overlay_processor_ozone.cc +++ b/components/viz/service/display/overlay_processor_ozone.cc
@@ -71,37 +71,32 @@ // |available_strategies| is a list of overlay strategies that should be // initialized by InitializeStrategies. OverlayProcessorOzone::OverlayProcessorOzone( - bool overlay_enabled, std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates, std::vector<OverlayStrategy> available_strategies, gpu::SharedImageInterface* shared_image_interface) : OverlayProcessorUsingStrategy(), - overlay_enabled_(overlay_enabled), overlay_candidates_(std::move(overlay_candidates)), available_strategies_(std::move(available_strategies)), shared_image_interface_(shared_image_interface) { - if (overlay_enabled_) { - for (OverlayStrategy strategy : available_strategies_) { - switch (strategy) { - case OverlayStrategy::kFullscreen: - strategies_.push_back( - std::make_unique<OverlayStrategyFullscreen>(this)); - break; - case OverlayStrategy::kSingleOnTop: - strategies_.push_back( - std::make_unique<OverlayStrategySingleOnTop>(this)); - break; - case OverlayStrategy::kUnderlay: - strategies_.push_back( - std::make_unique<OverlayStrategyUnderlay>(this)); - break; - case OverlayStrategy::kUnderlayCast: - strategies_.push_back( - std::make_unique<OverlayStrategyUnderlayCast>(this)); - break; - default: - NOTREACHED(); - } + for (OverlayStrategy strategy : available_strategies_) { + switch (strategy) { + case OverlayStrategy::kFullscreen: + strategies_.push_back( + std::make_unique<OverlayStrategyFullscreen>(this)); + break; + case OverlayStrategy::kSingleOnTop: + strategies_.push_back( + std::make_unique<OverlayStrategySingleOnTop>(this)); + break; + case OverlayStrategy::kUnderlay: + strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this)); + break; + case OverlayStrategy::kUnderlayCast: + strategies_.push_back( + std::make_unique<OverlayStrategyUnderlayCast>(this)); + break; + default: + NOTREACHED(); } } } @@ -109,7 +104,7 @@ OverlayProcessorOzone::~OverlayProcessorOzone() = default; bool OverlayProcessorOzone::IsOverlaySupported() const { - return overlay_enabled_; + return true; } bool OverlayProcessorOzone::NeedsSurfaceDamageRectList() const {
diff --git a/components/viz/service/display/overlay_processor_ozone.h b/components/viz/service/display/overlay_processor_ozone.h index 24909784..3f0e055 100644 --- a/components/viz/service/display/overlay_processor_ozone.h +++ b/components/viz/service/display/overlay_processor_ozone.h
@@ -18,7 +18,6 @@ : public OverlayProcessorUsingStrategy { public: OverlayProcessorOzone( - bool overlay_enabled, std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates, std::vector<OverlayStrategy> available_strategies, gpu::SharedImageInterface* shared_image_interface); @@ -45,8 +44,6 @@ bool SetNativePixmapForCandidate(ui::OverlaySurfaceCandidate* candidate, const gpu::Mailbox& mailbox); - const bool overlay_enabled_; - std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates_; const std::vector<OverlayStrategy> available_strategies_; gpu::SharedImageInterface* const shared_image_interface_;
diff --git a/components/viz/service/display/overlay_processor_surface_control.cc b/components/viz/service/display/overlay_processor_surface_control.cc index f78d2f3..b285cd8d 100644 --- a/components/viz/service/display/overlay_processor_surface_control.cc +++ b/components/viz/service/display/overlay_processor_surface_control.cc
@@ -30,19 +30,16 @@ } // namespace -OverlayProcessorSurfaceControl::OverlayProcessorSurfaceControl( - bool enable_overlay) - : OverlayProcessorUsingStrategy(), overlay_enabled_(enable_overlay) { - if (overlay_enabled_) { - strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>( - this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates)); - } +OverlayProcessorSurfaceControl::OverlayProcessorSurfaceControl() + : OverlayProcessorUsingStrategy() { + strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>( + this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates)); } OverlayProcessorSurfaceControl::~OverlayProcessorSurfaceControl() {} bool OverlayProcessorSurfaceControl::IsOverlaySupported() const { - return overlay_enabled_; + return true; } bool OverlayProcessorSurfaceControl::NeedsSurfaceDamageRectList() const {
diff --git a/components/viz/service/display/overlay_processor_surface_control.h b/components/viz/service/display/overlay_processor_surface_control.h index d71c1be..a265576c 100644 --- a/components/viz/service/display/overlay_processor_surface_control.h +++ b/components/viz/service/display/overlay_processor_surface_control.h
@@ -13,7 +13,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorSurfaceControl : public OverlayProcessorUsingStrategy { public: - explicit OverlayProcessorSurfaceControl(bool enable_overlay); + OverlayProcessorSurfaceControl(); ~OverlayProcessorSurfaceControl() override; bool IsOverlaySupported() const override; @@ -32,7 +32,6 @@ const OverlayCandidate& overlay) const override; private: - const bool overlay_enabled_; gfx::OverlayTransform display_transform_ = gfx::OVERLAY_TRANSFORM_NONE; gfx::Size viewport_size_; };
diff --git a/components/viz/service/display/overlay_processor_surface_control_unittest.cc b/components/viz/service/display/overlay_processor_surface_control_unittest.cc index 960abca..9f1b80f 100644 --- a/components/viz/service/display/overlay_processor_surface_control_unittest.cc +++ b/components/viz/service/display/overlay_processor_surface_control_unittest.cc
@@ -20,7 +20,7 @@ OverlayCandidateList candidates; candidates.push_back(candidate); - OverlayProcessorSurfaceControl processor(true); + OverlayProcessorSurfaceControl processor; processor.CheckOverlaySupport(nullptr, &candidates); EXPECT_TRUE(candidates.at(0).overlay_handled); EXPECT_RECTF_EQ(candidates.at(0).display_rect, gfx::RectF(10.f, 10.f)); @@ -37,7 +37,7 @@ OverlayCandidateList candidates; candidates.push_back(candidate); - OverlayProcessorSurfaceControl processor(true); + OverlayProcessorSurfaceControl processor; processor.CheckOverlaySupport(nullptr, &candidates); EXPECT_TRUE(candidates.at(0).overlay_handled); EXPECT_RECTF_EQ(candidates.at(0).display_rect, @@ -56,7 +56,7 @@ OverlayCandidateList candidates; candidates.push_back(candidate); - OverlayProcessorSurfaceControl processor(true); + OverlayProcessorSurfaceControl processor; processor.CheckOverlaySupport(nullptr, &candidates); EXPECT_TRUE(candidates.at(0).overlay_handled); EXPECT_RECTF_EQ(candidates.at(0).display_rect, @@ -75,7 +75,7 @@ OverlayCandidateList candidates; candidates.push_back(candidate); - OverlayProcessorSurfaceControl processor(true); + OverlayProcessorSurfaceControl processor; processor.CheckOverlaySupport(nullptr, &candidates); EXPECT_TRUE(candidates.at(0).overlay_handled); EXPECT_RECTF_EQ(candidates.at(0).display_rect, @@ -92,7 +92,7 @@ OverlayCandidateList candidates; candidates.push_back(candidate); - OverlayProcessorSurfaceControl processor(true); + OverlayProcessorSurfaceControl processor; processor.SetViewportSize(gfx::Size(100, 200)); processor.SetDisplayTransformHint(gfx::OVERLAY_TRANSFORM_ROTATE_90); @@ -116,7 +116,7 @@ base::Optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane> overlay_plane = candidate; - OverlayProcessorSurfaceControl processor(true); + OverlayProcessorSurfaceControl processor; processor.SetViewportSize(gfx::Size(100, 200)); processor.SetDisplayTransformHint(gfx::OVERLAY_TRANSFORM_ROTATE_90); processor.AdjustOutputSurfaceOverlay(&overlay_plane); @@ -130,7 +130,7 @@ candidate.transform = gfx::OVERLAY_TRANSFORM_ROTATE_90; candidate.overlay_handled = false; - OverlayProcessorSurfaceControl processor(true); + OverlayProcessorSurfaceControl processor; processor.SetViewportSize(gfx::Size(100, 200)); processor.SetDisplayTransformHint(gfx::OVERLAY_TRANSFORM_ROTATE_90);
diff --git a/components/viz/service/display/overlay_processor_win.cc b/components/viz/service/display/overlay_processor_win.cc index 9cc749b..718863c 100644 --- a/components/viz/service/display/overlay_processor_win.cc +++ b/components/viz/service/display/overlay_processor_win.cc
@@ -27,13 +27,14 @@ OutputSurface* output_surface, std::unique_ptr<DCLayerOverlayProcessor> dc_layer_overlay_processor) : output_surface_(output_surface), - supports_dc_layers_(output_surface->capabilities().supports_dc_layers), - dc_layer_overlay_processor_(std::move(dc_layer_overlay_processor)) {} + dc_layer_overlay_processor_(std::move(dc_layer_overlay_processor)) { + DCHECK(output_surface_->capabilities().supports_dc_layers); +} OverlayProcessorWin::~OverlayProcessorWin() = default; bool OverlayProcessorWin::IsOverlaySupported() const { - return supports_dc_layers_; + return true; } gfx::Rect OverlayProcessorWin::GetPreviousFrameOverlaysBoundingRect() const { @@ -85,9 +86,6 @@ return; } - if (!supports_dc_layers_) - return; - dc_layer_overlay_processor_->Process( resource_provider, gfx::RectF(root_render_pass->output_rect), render_passes, damage_rect, surface_damage_rect_list, candidates);
diff --git a/components/viz/service/display/overlay_processor_win.h b/components/viz/service/display/overlay_processor_win.h index bb77144..fd5bacf2 100644 --- a/components/viz/service/display/overlay_processor_win.h +++ b/components/viz/service/display/overlay_processor_win.h
@@ -70,8 +70,6 @@ private: OutputSurface* const output_surface_; - // Whether direct composition layers are supported by the output surface. - const bool supports_dc_layers_; // Whether direct composition layers are being used with SetEnableDCLayers(). bool using_dc_layers_ = false; // Number of frames since the last time direct composition layers were used.
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 73620ae3..2c9160ce 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -2585,10 +2585,13 @@ overlay->rpdq = nullptr; gfx::Transform target_to_device = current_frame()->window_matrix * current_frame()->projection_matrix; - const gfx::Rect* scissor = is_scissor_enabled_ ? &scissor_rect_ : nullptr; - + // Use nullptr scissor, so we can always render the whole render pass in an + // overlay backing. + // TODO(penghuang): reusing overlay backing from previous frame to avoid + // reproducing the overlay backing if the render pass content quad properties + // and content are not changed. DrawQuadParams params = CalculateDrawQuadParams( - target_to_device, scissor, quad, /*draw_region=*/nullptr); + target_to_device, /*scissor=*/nullptr, quad, /*draw_region=*/nullptr); DrawRPDQParams rpdq_params = CalculateRPDQParams(quad, ¶ms); // |filter_bounds| is the content space bounds that includes any filtered
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc index 73c56d47..2a8379f 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -527,7 +527,6 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Make sure there is no unsubmitted PaintFrame or PaintRenderPass. DCHECK(!current_paint_); - DCHECK(resource_sync_tokens_.empty()); SkSurfaceCharacterization characterization = CreateSkSurfaceCharacterization( size, BufferFormat(format), mipmap, std::move(color_space), @@ -706,6 +705,9 @@ void SkiaOutputSurfaceImpl::ScheduleOverlays( OverlayList overlays, std::vector<gpu::SyncToken> sync_tokens) { + std::move(resource_sync_tokens_.begin(), resource_sync_tokens_.end(), + std::back_inserter(sync_tokens)); + resource_sync_tokens_.clear(); auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::ScheduleOverlays, base::Unretained(impl_on_gpu_.get()), std::move(overlays),
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index ea3dbb3..88312d56 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -2304,12 +2304,8 @@ "media/session/pepper_playback_observer.h", "media/session/pepper_player_delegate.cc", "media/session/pepper_player_delegate.h", - "pepper_flash_settings_helper_impl.cc", - "pepper_flash_settings_helper_impl.h", "plugin_content_origin_allowlist.cc", "plugin_content_origin_allowlist.h", - "plugin_data_remover_impl.cc", - "plugin_data_remover_impl.h", "plugin_list.cc", "plugin_list.h", "plugin_private_storage_helper.cc",
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index 52d124e2..e75aa84d 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -583,18 +583,34 @@ } if (status.HasExclusionReason( net::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)) { - blockedReasons->push_back( - Network::SetCookieBlockedReasonEnum::SameSiteStrict); + if (status.HasDowngradeWarning()) { + blockedReasons->push_back( + Network::SetCookieBlockedReasonEnum::SchemefulSameSiteStrict); + } else { + blockedReasons->push_back( + Network::SetCookieBlockedReasonEnum::SameSiteStrict); + } } if (status.HasExclusionReason( net::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)) { - blockedReasons->push_back(Network::SetCookieBlockedReasonEnum::SameSiteLax); + if (status.HasDowngradeWarning()) { + blockedReasons->push_back( + Network::SetCookieBlockedReasonEnum::SchemefulSameSiteLax); + } else { + blockedReasons->push_back( + Network::SetCookieBlockedReasonEnum::SameSiteLax); + } } if (status.HasExclusionReason( net::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX)) { - blockedReasons->push_back( - Network::SetCookieBlockedReasonEnum::SameSiteUnspecifiedTreatedAsLax); + if (status.HasDowngradeWarning()) { + blockedReasons->push_back(Network::SetCookieBlockedReasonEnum:: + SchemefulSameSiteUnspecifiedTreatedAsLax); + } else { + blockedReasons->push_back( + Network::SetCookieBlockedReasonEnum::SameSiteUnspecifiedTreatedAsLax); + } } if (status.HasExclusionReason( net::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE)) { @@ -658,17 +674,33 @@ } if (status.HasExclusionReason( net::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)) { - blockedReasons->push_back(Network::CookieBlockedReasonEnum::SameSiteStrict); + if (status.HasDowngradeWarning()) { + blockedReasons->push_back( + Network::CookieBlockedReasonEnum::SchemefulSameSiteStrict); + } else { + blockedReasons->push_back( + Network::CookieBlockedReasonEnum::SameSiteStrict); + } } if (status.HasExclusionReason( net::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)) { - blockedReasons->push_back(Network::CookieBlockedReasonEnum::SameSiteLax); + if (status.HasDowngradeWarning()) { + blockedReasons->push_back( + Network::CookieBlockedReasonEnum::SchemefulSameSiteLax); + } else { + blockedReasons->push_back(Network::CookieBlockedReasonEnum::SameSiteLax); + } } if (status.HasExclusionReason( net::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX)) { - blockedReasons->push_back( - Network::CookieBlockedReasonEnum::SameSiteUnspecifiedTreatedAsLax); + if (status.HasDowngradeWarning()) { + blockedReasons->push_back(Network::CookieBlockedReasonEnum:: + SchemefulSameSiteUnspecifiedTreatedAsLax); + } else { + blockedReasons->push_back( + Network::CookieBlockedReasonEnum::SameSiteUnspecifiedTreatedAsLax); + } } if (status.HasExclusionReason( net::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE)) {
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index 87309e34..388682f2 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc
@@ -82,9 +82,8 @@ #include "third_party/blink/public/common/loader/referrer_utils.h" #include "third_party/blink/public/common/loader/throttling_url_loader.h" -#if defined(USE_X11) +#if defined(OS_LINUX) #include "base/nix/xdg_util.h" -#include "ui/base/ui_base_features.h" #endif namespace content { @@ -219,7 +218,7 @@ } }; -#if defined(USE_X11) +#if defined(OS_LINUX) base::FilePath GetTemporaryDownloadDirectory() { std::unique_ptr<base::Environment> env(base::Environment::Create()); return base::nix::GetXDGDirectory(env.get(), "XDG_DATA_HOME", ".local/share"); @@ -560,13 +559,12 @@ base::FilePath DownloadManagerImpl::GetDefaultDownloadDirectory() { base::FilePath default_download_directory; -#if defined(USE_X11) +#if defined(OS_LINUX) // TODO(thomasanderson,crbug.com/784010): Remove this when all Linux // distros with versions of GTK lower than 3.14.7 are no longer // supported. This should happen when support for Ubuntu Trusty and // Debian Jessie are removed. - if (!features::IsUsingOzonePlatform()) - default_download_directory = GetTemporaryDownloadDirectory(); + default_download_directory = GetTemporaryDownloadDirectory(); #endif if (delegate_ && default_download_directory.empty()) {
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc index 5781160..91bf615 100644 --- a/content/browser/download/download_manager_impl_unittest.cc +++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -47,7 +47,6 @@ #include "content/public/test/test_browser_context.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/ui_base_features.h" #include "url/origin.h" using base::test::RunOnceCallback; @@ -608,16 +607,17 @@ EXPECT_CALL(GetMockDownloadManagerDelegate(), GetNextId_(_)) .WillOnce(RunOnceCallback<0>(local_id)); - // TODO(https://crbug.com/1109690): figure out what to do for Ozone/Linux. - // Probably, this can be removed. - bool should_call_get_save_dir = true; -#if defined(USE_X11) - should_call_get_save_dir = features::IsUsingOzonePlatform(); + // TODO(thomasanderson,crbug.com/784010): Remove this when all Linux + // distros with versions of GTK lower than 3.14.7 are no longer + // supported. This should happen when support for Ubuntu Trusty and + // Debian Jessie are removed. +#if defined(OS_LINUX) + // Doing nothing will set the default download directory to null. + EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _)).Times(0); +#else + EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _)); #endif - if (should_call_get_save_dir) { - // Doing nothing will set the default download directory to null. - EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _)); - } + EXPECT_CALL(GetMockDownloadManagerDelegate(), ApplicationClientIdForFileScanning()) .WillRepeatedly(Return("client-id")); @@ -650,16 +650,17 @@ EXPECT_CALL(GetMockDownloadManagerDelegate(), GetNextId_(_)) .WillOnce(RunOnceCallback<0>(download::DownloadItem::kInvalidId)); - // TODO(https://crbug.com/1109690): figure out what to do for Ozone/Linux. - // Probably, this can be removed. - bool should_call_get_save_dir = true; -#if defined(USE_X11) - should_call_get_save_dir = features::IsUsingOzonePlatform(); + // TODO(thomasanderson,crbug.com/784010): Remove this when all Linux + // distros with versions of GTK lower than 3.14.7 are no longer + // supported. This should happen when support for Ubuntu Trusty and + // Debian Jessie are removed. +#if defined(OS_LINUX) + // Doing nothing will set the default download directory to null. + EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _)).Times(0); +#else + EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _)); #endif - if (should_call_get_save_dir) { - // Doing nothing will set the default download directory to null. - EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _)); - } + EXPECT_CALL(GetMockDownloadManagerDelegate(), ApplicationClientIdForFileScanning()) .WillRepeatedly(Return("client-id"));
diff --git a/content/browser/origin_trials/origin_trials_browsertest.cc b/content/browser/origin_trials/origin_trials_browsertest.cc index e2fb5098..ea2d34a 100644 --- a/content/browser/origin_trials/origin_trials_browsertest.cc +++ b/content/browser/origin_trials/origin_trials_browsertest.cc
@@ -188,8 +188,10 @@ EXPECT_FALSE(HasTrialEnabled(GetFrameByName("same-origin"))); EXPECT_FALSE(HasTrialEnabled(GetFrameByName("cross-origin"))); - if (disable_site_isolation_) - ASSERT_EQ(1, RenderProcessHost::GetCurrentRenderProcessCountForTesting()); + // With site isolation, the cross-site iframe on |main_url_| will get its own + // process. Otherwise, we'll only get one main frame process. + ASSERT_EQ(AreAllSitesIsolatedForTesting() ? 2 : 1, + RenderProcessHost::GetCurrentRenderProcessCountForTesting()); // OT does not persist when we navigated away. NavigateViaRenderer(shell()->web_contents(),
diff --git a/content/browser/pepper_flash_settings_helper_impl.cc b/content/browser/pepper_flash_settings_helper_impl.cc deleted file mode 100644 index 691edbe..0000000 --- a/content/browser/pepper_flash_settings_helper_impl.cc +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/pepper_flash_settings_helper_impl.h" - -#include "base/files/file_path.h" -#include "content/browser/plugin_service_impl.h" -#include "content/public/browser/browser_thread.h" -#include "ipc/ipc_channel_handle.h" - -namespace content { - -// static -scoped_refptr<PepperFlashSettingsHelper> PepperFlashSettingsHelper::Create() { - return new PepperFlashSettingsHelperImpl(); -} - -PepperFlashSettingsHelperImpl::PepperFlashSettingsHelperImpl() { -} - -PepperFlashSettingsHelperImpl::~PepperFlashSettingsHelperImpl() { -} - -void PepperFlashSettingsHelperImpl::OpenChannelToBroker( - const base::FilePath& path, - OpenChannelCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - if (!callback) - return; - if (callback_) - std::move(callback).Run(false, IPC::ChannelHandle()); - - // Balanced in OnPpapiChannelOpened(). We need to keep this object around - // until then. - AddRef(); - - callback_ = std::move(callback); - PluginServiceImpl* plugin_service = PluginServiceImpl::GetInstance(); - plugin_service->OpenChannelToPpapiBroker(0, 0, path, this); -} - -void PepperFlashSettingsHelperImpl::GetPpapiChannelInfo( - base::ProcessHandle* renderer_handle, - int* renderer_id) { - *renderer_handle = base::kNullProcessHandle; - *renderer_id = 0; -} - -void PepperFlashSettingsHelperImpl::OnPpapiChannelOpened( - const IPC::ChannelHandle& channel_handle, - base::ProcessId /* plugin_pid */, - int /* plugin_child_id */) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(callback_); - - if (channel_handle.is_mojo_channel_handle()) - std::move(callback_).Run(true, channel_handle); - else - std::move(callback_).Run(false, IPC::ChannelHandle()); - - // Balance the AddRef() call in Initialize(). - Release(); -} - -bool PepperFlashSettingsHelperImpl::Incognito() { - return false; -} - -} // namespace content
diff --git a/content/browser/pepper_flash_settings_helper_impl.h b/content/browser/pepper_flash_settings_helper_impl.h deleted file mode 100644 index e121732..0000000 --- a/content/browser/pepper_flash_settings_helper_impl.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_PEPPER_FLASH_SETTINGS_HELPER_IMPL_H_ -#define CONTENT_BROWSER_PEPPER_FLASH_SETTINGS_HELPER_IMPL_H_ - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "content/browser/ppapi_plugin_process_host.h" -#include "content/public/browser/pepper_flash_settings_helper.h" - -namespace content { - -class CONTENT_EXPORT PepperFlashSettingsHelperImpl - : public PepperFlashSettingsHelper, - public PpapiPluginProcessHost::BrokerClient { - public: - PepperFlashSettingsHelperImpl(); - - // PepperFlashSettingsHelper implementation. - void OpenChannelToBroker(const base::FilePath& path, - OpenChannelCallback callback) override; - - // PpapiPluginProcessHost::BrokerClient implementation. - void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle, - int* renderer_id) override; - void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle, - base::ProcessId plugin_pid, - int plugin_child_id) override; - bool Incognito() override; - - protected: - ~PepperFlashSettingsHelperImpl() override; - - private: - OpenChannelCallback callback_; - DISALLOW_COPY_AND_ASSIGN(PepperFlashSettingsHelperImpl); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_PEPPER_FLASH_SETTINGS_HELPER_IMPL_H_
diff --git a/content/browser/plugin_data_remover_impl.cc b/content/browser/plugin_data_remover_impl.cc deleted file mode 100644 index 7bead7f..0000000 --- a/content/browser/plugin_data_remover_impl.cc +++ /dev/null
@@ -1,265 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/plugin_data_remover_impl.h" - -#include <stdint.h> - -#include <limits> - -#include "base/bind.h" -#include "base/sequenced_task_runner_helpers.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/waitable_event.h" -#include "base/version.h" -#include "build/build_config.h" -#include "content/browser/plugin_service_impl.h" -#include "content/common/child_process_host_impl.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/common/child_process_host.h" -#include "content/public/common/content_constants.h" -#include "content/public/common/pepper_plugin_info.h" -#include "ppapi/proxy/ppapi_messages.h" - -namespace content { - -namespace { - -// The minimum Flash Player version that implements NPP_ClearSiteData. -const char kMinFlashVersion[] = "10.3"; -const int64_t kRemovalTimeoutMs = 10000; -const uint64_t kClearAllData = 0; - -} // namespace - -// static -PluginDataRemover* PluginDataRemover::Create(BrowserContext* browser_context) { - return new PluginDataRemoverImpl(browser_context); -} - -// static -void PluginDataRemover::GetSupportedPlugins( - std::vector<WebPluginInfo>* supported_plugins) { - bool allow_wildcard = false; - std::vector<WebPluginInfo> plugins; - PluginService::GetInstance()->GetPluginInfoArray( - GURL(), kFlashPluginSwfMimeType, allow_wildcard, &plugins, nullptr); - base::Version min_version(kMinFlashVersion); - for (auto it = plugins.begin(); it != plugins.end(); ++it) { - base::Version version; - WebPluginInfo::CreateVersionFromString(it->version, &version); - if (version.IsValid() && min_version.CompareTo(version) == -1) - supported_plugins->push_back(*it); - } -} - -class PluginDataRemoverImpl::Context - : public PpapiPluginProcessHost::BrokerClient, - public IPC::Listener, - public base::RefCountedThreadSafe<Context, - BrowserThread::DeleteOnIOThread> { - public: - Context(base::Time begin_time, BrowserContext* browser_context) - : event_(new base::WaitableEvent( - base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED)), - begin_time_(begin_time), - is_removing_(false), - browser_context_path_(browser_context->GetPath()) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - } - - void Init(const std::string& mime_type) { - GetIOThreadTaskRunner({})->PostTask( - FROM_HERE, base::BindOnce(&Context::InitOnIOThread, this, mime_type)); - GetIOThreadTaskRunner({})->PostDelayedTask( - FROM_HERE, base::BindOnce(&Context::OnTimeout, this), - base::TimeDelta::FromMilliseconds(kRemovalTimeoutMs)); - } - - void InitOnIOThread(const std::string& mime_type) { - PluginServiceImpl* plugin_service = PluginServiceImpl::GetInstance(); - - // Get the plugin file path. - std::vector<WebPluginInfo> plugins; - plugin_service->GetPluginInfoArray(GURL(), mime_type, false, &plugins, - nullptr); - - if (plugins.empty()) { - // May be empty for some tests and on the CrOS login OOBE screen. - event_->Signal(); - return; - } - - base::FilePath plugin_path = plugins[0].path; - - const PepperPluginInfo* pepper_info = - plugin_service->GetRegisteredPpapiPluginInfo(plugin_path); - if (!pepper_info) { - event_->Signal(); - return; - } - - DCHECK_CURRENTLY_ON(BrowserThread::IO); - is_removing_ = true; - - // Balanced in OnPpapiChannelOpened. - AddRef(); - plugin_name_ = pepper_info->name; - // Use the broker since we run this function outside the sandbox. - plugin_service->OpenChannelToPpapiBroker(0, 0, plugin_path, this); - } - - // Called when a timeout happens in order not to block the client - // indefinitely. - void OnTimeout() { - LOG_IF(ERROR, is_removing_) << "Timed out"; - SignalDone(); - } - - bool Incognito() override { return false; } - - // PpapiPluginProcessHost::BrokerClient implementation. - void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle, - int* renderer_id) override { - *renderer_handle = base::kNullProcessHandle; - *renderer_id = 0; - } - - void OnPpapiChannelOpened(const IPC::ChannelHandle& channel_handle, - base::ProcessId /* peer_pid */, - int /* child_id */) override { - if (channel_handle.is_mojo_channel_handle()) - ConnectToChannel(channel_handle); - - // Balancing the AddRef call. - Release(); - } - - // IPC::Listener methods. - bool OnMessageReceived(const IPC::Message& message) override { - IPC_BEGIN_MESSAGE_MAP(Context, message) - IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult, - OnPpapiClearSiteDataResult) - IPC_MESSAGE_UNHANDLED_ERROR() - IPC_END_MESSAGE_MAP() - - return true; - } - - void OnChannelError() override { - if (is_removing_) { - NOTREACHED() << "Channel error"; - SignalDone(); - } - } - - base::WaitableEvent* event() { return event_.get(); } - - private: - friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>; - friend class base::DeleteHelper<Context>; - ~Context() override {} - - IPC::Message* CreatePpapiClearSiteDataMsg(uint64_t max_age) { - base::FilePath profile_path = - browser_context_path_.Append(kPepperDataDirname); - // TODO(vtl): This "duplicates" logic in webkit/plugins/ppapi/file_path.cc - // (which prepends the plugin name to the relative part of the path - // instead, with the absolute, profile-dependent part being enforced by - // the browser). -#if defined(OS_WIN) - base::FilePath plugin_data_path = - profile_path.Append(base::FilePath(base::UTF8ToUTF16(plugin_name_))); -#else - base::FilePath plugin_data_path = - profile_path.Append(base::FilePath(plugin_name_)); -#endif // defined(OS_WIN) - return new PpapiMsg_ClearSiteData(0u, plugin_data_path, std::string(), - kClearAllData, max_age); - } - - // Connects the client side of a newly opened plugin channel. - void ConnectToChannel(const IPC::ChannelHandle& handle) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - // If we timed out, don't bother connecting. - if (!is_removing_) - return; - - DCHECK(!channel_.get()); - channel_ = IPC::Channel::CreateClient(handle, this, - base::ThreadTaskRunnerHandle::Get()); - if (!channel_->Connect()) { - NOTREACHED() << "Couldn't connect to plugin"; - SignalDone(); - return; - } - - uint64_t max_age = begin_time_.is_null() - ? std::numeric_limits<uint64_t>::max() - : (base::Time::Now() - begin_time_).InSeconds(); - - IPC::Message* msg = CreatePpapiClearSiteDataMsg(max_age); - if (!channel_->Send(msg)) { - NOTREACHED() << "Couldn't send ClearSiteData message"; - SignalDone(); - return; - } - } - - // Handles the PpapiHostMsg_ClearSiteDataResult message. - void OnPpapiClearSiteDataResult(uint32_t request_id, bool success) { - DCHECK_EQ(0u, request_id); - LOG_IF(ERROR, !success) << "ClearSiteData returned error"; - SignalDone(); - } - - // Signals that we are finished with removing data (successful or not). This - // method is safe to call multiple times. - void SignalDone() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!is_removing_) - return; - is_removing_ = false; - event_->Signal(); - } - - std::unique_ptr<base::WaitableEvent> event_; - // The point in time from which on we remove data. - base::Time begin_time_; - bool is_removing_; - - // Path for the current profile. Must be retrieved on the UI thread from the - // browser context when we start so we can use it later on the I/O thread. - base::FilePath browser_context_path_; - - // The name of the plugin. Use only on the I/O thread. - std::string plugin_name_; - - // The channel is NULL until we have opened a connection to the plugin - // process. - std::unique_ptr<IPC::Channel> channel_; -}; - - -PluginDataRemoverImpl::PluginDataRemoverImpl(BrowserContext* browser_context) - : mime_type_(kFlashPluginSwfMimeType), - browser_context_(browser_context) { -} - -PluginDataRemoverImpl::~PluginDataRemoverImpl() { -} - -base::WaitableEvent* PluginDataRemoverImpl::StartRemoving( - base::Time begin_time) { - DCHECK(!context_.get()); - context_ = new Context(begin_time, browser_context_); - context_->Init(mime_type_); - return context_->event(); -} - -} // namespace content
diff --git a/content/browser/plugin_data_remover_impl.h b/content/browser/plugin_data_remover_impl.h deleted file mode 100644 index 7baa087..0000000 --- a/content/browser/plugin_data_remover_impl.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_PLUGIN_DATA_REMOVER_IMPL_H_ -#define CONTENT_BROWSER_PLUGIN_DATA_REMOVER_IMPL_H_ - -#include <string> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/time/time.h" -#include "content/public/browser/plugin_data_remover.h" - -namespace content { - -class CONTENT_EXPORT PluginDataRemoverImpl : public PluginDataRemover { - public: - explicit PluginDataRemoverImpl(BrowserContext* browser_context); - ~PluginDataRemoverImpl() override; - - // PluginDataRemover implementation: - base::WaitableEvent* StartRemoving(base::Time begin_time) override; - - // The plugin whose data should be removed (usually Flash) is specified via - // its MIME type. This method sets a different MIME type in order to call a - // different plugin (for example in tests). - void set_mime_type(const std::string& mime_type) { mime_type_ = mime_type; } - - private: - class Context; - - std::string mime_type_; - - // The browser context for the profile. - BrowserContext* browser_context_; - - // This allows this object to be deleted on the UI thread while it's still - // being used on the IO thread. - scoped_refptr<Context> context_; - - DISALLOW_COPY_AND_ASSIGN(PluginDataRemoverImpl); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_PLUGIN_DATA_REMOVER_IMPL_H_
diff --git a/content/browser/portal/OWNERS b/content/browser/portal/OWNERS index bf4f802..1c33ce23 100644 --- a/content/browser/portal/OWNERS +++ b/content/browser/portal/OWNERS
@@ -1,3 +1,3 @@ file://third_party/blink/renderer/core/html/portal/OWNERS -# COMPONENT: Blink>HTML>Portal +# COMPONENT: Blink>Portals
diff --git a/content/browser/renderer_host/input/synthetic_mouse_driver.cc b/content/browser/renderer_host/input/synthetic_mouse_driver.cc index f8a4a16..e677bb6a 100644 --- a/content/browser/renderer_host/input/synthetic_mouse_driver.cc +++ b/content/browser/renderer_host/input/synthetic_mouse_driver.cc
@@ -4,6 +4,7 @@ #include "content/browser/renderer_host/input/synthetic_mouse_driver.h" +#include "build/build_config.h" #include "content/browser/renderer_host/input/synthetic_gesture_target.h" #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h" @@ -35,16 +36,16 @@ float force, const base::TimeTicks& timestamp) { DCHECK_EQ(index, 0); + blink::WebMouseEvent::Button pressed_button = + SyntheticPointerActionParams::GetWebMouseEventButton(button); + click_count_ = ComputeClickCount(timestamp, pressed_button, x, y); int modifiers = SyntheticPointerActionParams::GetWebMouseEventModifier(button); mouse_event_ = blink::SyntheticWebMouseEventBuilder::Build( blink::WebInputEvent::Type::kMouseDown, x, y, modifiers | key_modifiers | last_modifiers_, mouse_event_.pointer_type); - mouse_event_.button = - SyntheticPointerActionParams::GetWebMouseEventButton(button); + mouse_event_.button = pressed_button; last_modifiers_ = modifiers | last_modifiers_; - bool is_repeated_click = IsRepeatedClickEvent(timestamp, x, y); - click_count_ = is_repeated_click ? 2 : 1; mouse_event_.click_count = click_count_; last_mouse_click_time_ = timestamp; last_x_ = x; @@ -125,27 +126,38 @@ return true; } -bool SyntheticMouseDriver::IsRepeatedClickEvent( +int SyntheticMouseDriver::ComputeClickCount( const base::TimeTicks& timestamp, + blink::WebMouseEvent::Button pressed_button, float x, float y) { const int kDoubleClickTimeMS = 500; const int kDoubleClickRange = 4; if (click_count_ == 0) - return false; + return 1; base::TimeDelta time_difference = timestamp - last_mouse_click_time_; if (time_difference.InMilliseconds() > kDoubleClickTimeMS) - return false; + return 1; if (std::abs(x - last_x_) > kDoubleClickRange / 2) - return false; + return 1; if (std::abs(y - last_y_) > kDoubleClickRange / 2) - return false; + return 1; - return true; + if (mouse_event_.button != pressed_button) + return 1; + + ++click_count_; +#if !defined(OS_MAC) && !defined(OS_WIN) + // On Mac and Windows, we keep incresing the click count, but on the other + // platforms, we reset the count to 1 when it is greater than 3. + if (click_count_ > 3) + click_count_ = 1; +#endif + return click_count_; } } // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_mouse_driver.h b/content/browser/renderer_host/input/synthetic_mouse_driver.h index 145323f6..a0c9e0f9 100644 --- a/content/browser/renderer_host/input/synthetic_mouse_driver.h +++ b/content/browser/renderer_host/input/synthetic_mouse_driver.h
@@ -57,7 +57,10 @@ unsigned last_modifiers_ = 0; private: - bool IsRepeatedClickEvent(const base::TimeTicks& timestamp, float x, float y); + int ComputeClickCount(const base::TimeTicks& timestamp, + blink::WebMouseEvent::Button pressed_button, + float x, + float y); int click_count_ = 0; base::TimeTicks last_mouse_click_time_ = base::TimeTicks::Now(); float last_x_ = 0;
diff --git a/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc b/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc index 0da2a6a4..e9ccbcc 100644 --- a/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc +++ b/content/browser/renderer_host/input/synthetic_pointer_action_unittest.cc
@@ -5,6 +5,7 @@ #include "content/browser/renderer_host/input/synthetic_pointer_action.h" #include "base/bind.h" #include "base/time/time.h" +#include "build/build_config.h" #include "content/browser/renderer_host/input/synthetic_gesture.h" #include "content/browser/renderer_host/input/synthetic_gesture_target.h" #include "testing/gtest/include/gtest/gtest.h" @@ -301,9 +302,10 @@ SyntheticPointerActionParams::PointerActionType::PRESS || param.pointer_action_type() == SyntheticPointerActionParams::PointerActionType::RELEASE) { - if (click_count_ != 1) { - return testing::AssertionFailure() << "Pointer click count was " - << click_count_ << ", expected 1."; + if (click_count_ < 1) { + return testing::AssertionFailure() + << "Pointer click count was " << click_count_ << ", expected " + << "greater or equal to 1."; } } @@ -390,7 +392,7 @@ protected: template <typename MockGestureTarget> void CreateSyntheticPointerActionTarget() { - target_.reset(new MockGestureTarget()); + target_ = std::make_unique<MockGestureTarget>(); synthetic_pointer_driver_ = SyntheticPointerDriver::Create( target_->GetDefaultSyntheticGestureSourceType()); } @@ -468,7 +470,7 @@ param_list4.push_back(param1); param_list4.push_back(param2); params_.PushPointerActionParamsList(param_list4); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerTouchActionTarget* pointer_touch_target = @@ -539,7 +541,7 @@ // Send a touch release for the second finger and not move the first finger. params_.PushPointerActionParamsList(param_list3); } - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerTouchActionTarget* pointer_touch_target = @@ -607,7 +609,7 @@ param_list3.push_back(param1); param_list3.push_back(param2); params_.PushPointerActionParamsList(param_list3); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerTouchActionTarget* pointer_touch_target = @@ -646,7 +648,7 @@ param.set_pointer_id(0); param.set_position(gfx::PointF(54, 89)); params_.PushPointerActionParams(param); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); EXPECT_EQ(0, num_success_); @@ -656,7 +658,7 @@ SyntheticPointerActionParams::PointerActionType::RELEASE); params_ = SyntheticPointerActionListParams(); params_.PushPointerActionParams(param); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); EXPECT_EQ(0, num_success_); @@ -668,7 +670,7 @@ params_ = SyntheticPointerActionListParams(); params_.PushPointerActionParams(param); params_.PushPointerActionParams(param); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerTouchActionTarget* pointer_touch_target = @@ -710,7 +712,7 @@ SyntheticPointerActionParams param4 = SyntheticPointerActionParams( SyntheticPointerActionParams::PointerActionType::RELEASE); params_.PushPointerActionParams(param4); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerMouseActionTarget* pointer_mouse_target = @@ -781,7 +783,7 @@ SyntheticPointerActionParams::PointerActionType::RELEASE); param6.set_button(SyntheticPointerActionParams::Button::LEFT); params_.PushPointerActionParams(param6); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerMouseActionTarget* pointer_mouse_target = @@ -851,7 +853,7 @@ param3.set_button(SyntheticPointerActionParams::Button::LEFT); param3.set_key_modifiers(6); params_.PushPointerActionParams(param3); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerMouseActionTarget* pointer_mouse_target = @@ -904,7 +906,7 @@ param3.set_key_modifiers(6); param3.set_timestamp(timestamp + base::TimeDelta::FromSeconds(3)); params_.PushPointerActionParams(param3); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerMouseActionTarget* pointer_mouse_target = @@ -936,7 +938,7 @@ SyntheticPointerActionParams param = SyntheticPointerActionParams( SyntheticPointerActionParams::PointerActionType::RELEASE); params_.PushPointerActionParams(param); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); EXPECT_EQ(1, num_success_); @@ -955,7 +957,7 @@ // Cannot send a mouse down again without releasing the mouse button. params_.PushPointerActionParams(param); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerMouseActionTarget* pointer_mouse_target = @@ -996,7 +998,7 @@ SyntheticPointerActionParams param4 = SyntheticPointerActionParams( SyntheticPointerActionParams::PointerActionType::LEAVE); params_.PushPointerActionParams(param4); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); MockSyntheticPointerPenActionTarget* pointer_pen_target = @@ -1034,13 +1036,304 @@ TEST_F(SyntheticPointerActionTest, EmptyParams) { CreateSyntheticPointerActionTarget<MockSyntheticPointerPenActionTarget>(); - pointer_action_.reset(new SyntheticPointerAction(params_)); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); ForwardSyntheticPointerAction(); EXPECT_EQ(1, num_success_); EXPECT_EQ(0, num_failure_); } +TEST_F(SyntheticPointerActionTest, PointerMouseActionIncreaseClickCount) { + CreateSyntheticPointerActionTarget<MockSyntheticPointerMouseActionTarget>(); + + // Send a mouse move. + SyntheticPointerActionParams param1 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::MOVE); + param1.set_position(gfx::PointF(189, 62)); + params_.PushPointerActionParams(param1); + + // Send a mouse down. + SyntheticPointerActionParams param2 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PRESS); + param2.set_position(gfx::PointF(189, 62)); + params_.PushPointerActionParams(param2); + + // Send a mouse up. + SyntheticPointerActionParams param3 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE); + params_.PushPointerActionParams(param3); + + // Send a second mouse down. + SyntheticPointerActionParams param4 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PRESS); + param4.set_position(gfx::PointF(189, 62)); + params_.PushPointerActionParams(param4); + + // Send a second mouse up. + SyntheticPointerActionParams param5 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE); + params_.PushPointerActionParams(param5); + + // Send a third mouse down. + SyntheticPointerActionParams param6 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PRESS); + param6.set_position(gfx::PointF(189, 62)); + params_.PushPointerActionParams(param6); + + // Send a third mouse up. + SyntheticPointerActionParams param7 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE); + params_.PushPointerActionParams(param7); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); + + // Send a fourth mouse down. + SyntheticPointerActionParams param8 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PRESS); + param8.set_position(gfx::PointF(189, 62)); + params_.PushPointerActionParams(param8); + + // Send a fourth mouse up. + SyntheticPointerActionParams param9 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE); + params_.PushPointerActionParams(param9); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); + + ForwardSyntheticPointerAction(); + MockSyntheticPointerMouseActionTarget* pointer_mouse_target = + static_cast<MockSyntheticPointerMouseActionTarget*>(target_.get()); + EXPECT_EQ(1, num_success_); + EXPECT_EQ(0, num_failure_); + std::vector<SyntheticPointerActionParams::Button> buttons; + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param1, 0, buttons)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(2, num_success_); + EXPECT_EQ(0, num_failure_); + buttons.push_back(SyntheticPointerActionParams::Button::LEFT); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param2, 1, buttons, SyntheticPointerActionParams::Button::LEFT)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(3, num_success_); + EXPECT_EQ(0, num_failure_); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param3, 1, buttons, SyntheticPointerActionParams::Button::LEFT)); + buttons.pop_back(); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(4, num_success_); + EXPECT_EQ(0, num_failure_); + buttons.push_back(SyntheticPointerActionParams::Button::LEFT); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param4, 2, buttons, SyntheticPointerActionParams::Button::LEFT)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(5, num_success_); + EXPECT_EQ(0, num_failure_); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param5, 2, buttons, SyntheticPointerActionParams::Button::LEFT)); + buttons.pop_back(); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(6, num_success_); + EXPECT_EQ(0, num_failure_); + buttons.push_back(SyntheticPointerActionParams::Button::LEFT); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param6, 3, buttons, SyntheticPointerActionParams::Button::LEFT)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(7, num_success_); + EXPECT_EQ(0, num_failure_); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param7, 3, buttons, SyntheticPointerActionParams::Button::LEFT)); + buttons.pop_back(); + + int click_count = 4; +#if !defined(OS_MAC) && !defined(OS_WIN) + click_count = 1; +#endif + ForwardSyntheticPointerAction(); + EXPECT_EQ(8, num_success_); + EXPECT_EQ(0, num_failure_); + buttons.push_back(SyntheticPointerActionParams::Button::LEFT); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param8, click_count, buttons, + SyntheticPointerActionParams::Button::LEFT)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(9, num_success_); + EXPECT_EQ(0, num_failure_); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param9, click_count, buttons, + SyntheticPointerActionParams::Button::LEFT)); +} + +TEST_F(SyntheticPointerActionTest, PointerMouseActionResetCountOnOtherButton) { + CreateSyntheticPointerActionTarget<MockSyntheticPointerMouseActionTarget>(); + + // Send a mouse move. + SyntheticPointerActionParams param1 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::MOVE); + param1.set_position(gfx::PointF(189, 62)); + params_.PushPointerActionParams(param1); + + // Send a mouse down. + SyntheticPointerActionParams param2 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PRESS); + param2.set_position(gfx::PointF(189, 62)); + params_.PushPointerActionParams(param2); + + // Send a mouse up. + SyntheticPointerActionParams param3 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE); + params_.PushPointerActionParams(param3); + + // Send a second mouse down with another button. + SyntheticPointerActionParams param4 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PRESS); + param4.set_position(gfx::PointF(189, 62)); + param4.set_button(SyntheticPointerActionParams::Button::MIDDLE); + params_.PushPointerActionParams(param4); + + // Send a second mouse up. + SyntheticPointerActionParams param5 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE); + param5.set_button(SyntheticPointerActionParams::Button::MIDDLE); + params_.PushPointerActionParams(param5); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); + + ForwardSyntheticPointerAction(); + MockSyntheticPointerMouseActionTarget* pointer_mouse_target = + static_cast<MockSyntheticPointerMouseActionTarget*>(target_.get()); + EXPECT_EQ(1, num_success_); + EXPECT_EQ(0, num_failure_); + std::vector<SyntheticPointerActionParams::Button> buttons; + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param1, 0, buttons)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(2, num_success_); + EXPECT_EQ(0, num_failure_); + buttons.push_back(SyntheticPointerActionParams::Button::LEFT); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param2, 1, buttons, SyntheticPointerActionParams::Button::LEFT)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(3, num_success_); + EXPECT_EQ(0, num_failure_); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param3, 1, buttons, SyntheticPointerActionParams::Button::LEFT)); + buttons.pop_back(); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(4, num_success_); + EXPECT_EQ(0, num_failure_); + buttons.push_back(SyntheticPointerActionParams::Button::MIDDLE); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param4, 1, buttons, SyntheticPointerActionParams::Button::MIDDLE)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(5, num_success_); + EXPECT_EQ(0, num_failure_); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param5, 1, buttons, SyntheticPointerActionParams::Button::MIDDLE)); +} + +TEST_F(SyntheticPointerActionTest, PointerMouseActionResetCountAfterMove) { + CreateSyntheticPointerActionTarget<MockSyntheticPointerMouseActionTarget>(); + + // Send a mouse move. + SyntheticPointerActionParams param1 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::MOVE); + param1.set_position(gfx::PointF(189, 62)); + params_.PushPointerActionParams(param1); + + // Send a mouse down. + SyntheticPointerActionParams param2 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PRESS); + param2.set_position(gfx::PointF(189, 62)); + params_.PushPointerActionParams(param2); + + // Send a mouse up. + SyntheticPointerActionParams param3 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE); + params_.PushPointerActionParams(param3); + + // Send a second mouse down close to the last one. + SyntheticPointerActionParams param4 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PRESS); + param4.set_position(gfx::PointF(190, 60)); + params_.PushPointerActionParams(param4); + + // Send a second mouse up. + SyntheticPointerActionParams param5 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE); + params_.PushPointerActionParams(param5); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); + + // Send a third mouse down far enough from the last one. + SyntheticPointerActionParams param6 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::PRESS); + param6.set_position(gfx::PointF(290, 60)); + params_.PushPointerActionParams(param6); + + // Send a third mouse up. + SyntheticPointerActionParams param7 = SyntheticPointerActionParams( + SyntheticPointerActionParams::PointerActionType::RELEASE); + params_.PushPointerActionParams(param7); + pointer_action_ = std::make_unique<SyntheticPointerAction>(params_); + + ForwardSyntheticPointerAction(); + MockSyntheticPointerMouseActionTarget* pointer_mouse_target = + static_cast<MockSyntheticPointerMouseActionTarget*>(target_.get()); + EXPECT_EQ(1, num_success_); + EXPECT_EQ(0, num_failure_); + std::vector<SyntheticPointerActionParams::Button> buttons; + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param1, 0, buttons)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(2, num_success_); + EXPECT_EQ(0, num_failure_); + buttons.push_back(SyntheticPointerActionParams::Button::LEFT); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param2, 1, buttons, SyntheticPointerActionParams::Button::LEFT)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(3, num_success_); + EXPECT_EQ(0, num_failure_); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param3, 1, buttons, SyntheticPointerActionParams::Button::LEFT)); + buttons.pop_back(); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(4, num_success_); + EXPECT_EQ(0, num_failure_); + buttons.push_back(SyntheticPointerActionParams::Button::LEFT); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param4, 2, buttons, SyntheticPointerActionParams::Button::LEFT)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(5, num_success_); + EXPECT_EQ(0, num_failure_); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param5, 2, buttons, SyntheticPointerActionParams::Button::LEFT)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(6, num_success_); + EXPECT_EQ(0, num_failure_); + buttons.push_back(SyntheticPointerActionParams::Button::LEFT); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param6, 1, buttons, SyntheticPointerActionParams::Button::LEFT)); + + ForwardSyntheticPointerAction(); + EXPECT_EQ(7, num_success_); + EXPECT_EQ(0, num_failure_); + EXPECT_TRUE(pointer_mouse_target->SyntheticMouseActionDispatchedCorrectly( + param7, 1, buttons, SyntheticPointerActionParams::Button::LEFT)); +} + } // namespace } // namespace content
diff --git a/content/browser/xr/service/browser_xr_runtime_impl.cc b/content/browser/xr/service/browser_xr_runtime_impl.cc index 3f224fa..1f5bda7 100644 --- a/content/browser/xr/service/browser_xr_runtime_impl.cc +++ b/content/browser/xr/service/browser_xr_runtime_impl.cc
@@ -117,14 +117,6 @@ device::mojom::VRDisplayInfoPtr ret = device::mojom::VRDisplayInfo::New(); - // Maximum 1000km translation. - if (info->stage_parameters && - IsValidTransform(info->stage_parameters->mojo_from_floor, 1000000)) { - ret->stage_parameters = device::mojom::VRStageParameters::New( - info->stage_parameters->mojo_from_floor, - info->stage_parameters->bounds); - } - ret->left_eye = ValidateEyeParameters(info->left_eye.get()); ret->right_eye = ValidateEyeParameters(info->right_eye.get()); return ret;
diff --git a/content/ppapi_plugin/BUILD.gn b/content/ppapi_plugin/BUILD.gn index e196670..48c2a739 100644 --- a/content/ppapi_plugin/BUILD.gn +++ b/content/ppapi_plugin/BUILD.gn
@@ -27,8 +27,6 @@ ] sources = [ - "broker_process_dispatcher.cc", - "broker_process_dispatcher.h", "plugin_process_dispatcher.cc", "plugin_process_dispatcher.h", "ppapi_blink_platform_impl.cc",
diff --git a/content/ppapi_plugin/broker_process_dispatcher.cc b/content/ppapi_plugin/broker_process_dispatcher.cc deleted file mode 100644 index 6293949..0000000 --- a/content/ppapi_plugin/broker_process_dispatcher.cc +++ /dev/null
@@ -1,347 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/ppapi_plugin/broker_process_dispatcher.h" - -#include <stddef.h> - -#include <memory> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" -#include "content/child/child_process.h" -#include "ppapi/c/pp_bool.h" -#include "ppapi/c/private/ppp_flash_browser_operations.h" -#include "ppapi/proxy/ppapi_messages.h" - -namespace content { -namespace { - -// How long we wait before releasing the broker process. -const int kBrokerReleaseTimeSeconds = 30; - -std::string ConvertPluginDataPath(const base::FilePath& plugin_data_path) { - // The string is always 8-bit, convert on Windows. -#if defined(OS_WIN) - return base::WideToUTF8(plugin_data_path.value()); -#else - return plugin_data_path.value(); -#endif -} - -struct GetPermissionSettingsContext { - GetPermissionSettingsContext( - const base::WeakPtr<BrokerProcessDispatcher> in_dispatcher, - uint32_t in_request_id) - : dispatcher(in_dispatcher), request_id(in_request_id) {} - - base::WeakPtr<BrokerProcessDispatcher> dispatcher; - uint32_t request_id; -}; - -void GetPermissionSettingsCallback( - void* user_data, - PP_Bool success, - PP_Flash_BrowserOperations_Permission default_permission, - uint32_t site_count, - const PP_Flash_BrowserOperations_SiteSetting sites[]) { - std::unique_ptr<GetPermissionSettingsContext> context( - reinterpret_cast<GetPermissionSettingsContext*>(user_data)); - - if (!context->dispatcher.get()) - return; - - ppapi::FlashSiteSettings site_vector; - if (success) { - site_vector.reserve(site_count); - for (uint32_t i = 0; i < site_count; ++i) { - if (!sites[i].site) { - success = PP_FALSE; - break; - } - site_vector.push_back( - ppapi::FlashSiteSetting(sites[i].site, sites[i].permission)); - } - - if (!success) - site_vector.clear(); - } - context->dispatcher->OnGetPermissionSettingsCompleted( - context->request_id, PP_ToBool(success), default_permission, site_vector); -} - -} // namespace - -BrokerProcessDispatcher::BrokerProcessDispatcher( - PP_GetInterface_Func get_plugin_interface, - PP_ConnectInstance_Func connect_instance, - bool peer_is_browser) - : ppapi::proxy::BrokerSideDispatcher(connect_instance), - get_plugin_interface_(get_plugin_interface), - flash_browser_operations_1_3_(nullptr), - flash_browser_operations_1_2_(nullptr), - flash_browser_operations_1_0_(nullptr), - peer_is_browser_(peer_is_browser) { - if (get_plugin_interface) { - flash_browser_operations_1_0_ = - static_cast<const PPP_Flash_BrowserOperations_1_0*>( - get_plugin_interface_(PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_0)); - - flash_browser_operations_1_2_ = - static_cast<const PPP_Flash_BrowserOperations_1_2*>( - get_plugin_interface_(PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_2)); - - flash_browser_operations_1_3_ = - static_cast<const PPP_Flash_BrowserOperations_1_3*>( - get_plugin_interface_(PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_3)); - } -} - -BrokerProcessDispatcher::~BrokerProcessDispatcher() { - DVLOG(1) << "BrokerProcessDispatcher::~BrokerProcessDispatcher()"; - // Don't free the process right away. This timer allows the child process - // to be re-used if the user rapidly goes to a new page that requires this - // plugin. This is the case for common plugins where they may be used on a - // source and destination page of a navigation. We don't want to tear down - // and re-start processes each time in these cases. - process_ref_.ReleaseWithDelay( - base::TimeDelta::FromSeconds(kBrokerReleaseTimeSeconds)); -} - -bool BrokerProcessDispatcher::OnMessageReceived(const IPC::Message& msg) { - if (BrokerSideDispatcher::OnMessageReceived(msg)) - return true; - - if (!peer_is_browser_) { - // We might want to consider killing the peer instead is we see problems in - // the future. - return false; - } - - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(BrokerProcessDispatcher, msg) - IPC_MESSAGE_HANDLER(PpapiMsg_GetSitesWithData, OnGetSitesWithData) - IPC_MESSAGE_HANDLER(PpapiMsg_ClearSiteData, OnClearSiteData) - IPC_MESSAGE_HANDLER(PpapiMsg_DeauthorizeContentLicenses, - OnDeauthorizeContentLicenses) - IPC_MESSAGE_HANDLER(PpapiMsg_GetPermissionSettings, - OnGetPermissionSettings) - IPC_MESSAGE_HANDLER(PpapiMsg_SetDefaultPermission, OnSetDefaultPermission) - IPC_MESSAGE_HANDLER(PpapiMsg_SetSitePermission, OnSetSitePermission) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void BrokerProcessDispatcher::OnGetPermissionSettingsCompleted( - uint32_t request_id, - bool success, - PP_Flash_BrowserOperations_Permission default_permission, - const ppapi::FlashSiteSettings& sites) { - Send(new PpapiHostMsg_GetPermissionSettingsResult( - request_id, success, default_permission, sites)); -} - -void BrokerProcessDispatcher::OnGetSitesWithData( - uint32_t request_id, - const base::FilePath& plugin_data_path) { - std::vector<std::string> sites; - GetSitesWithData(plugin_data_path, &sites); - Send(new PpapiHostMsg_GetSitesWithDataResult(request_id, sites)); -} - -void BrokerProcessDispatcher::OnClearSiteData( - uint32_t request_id, - const base::FilePath& plugin_data_path, - const std::string& site, - uint64_t flags, - uint64_t max_age) { - Send(new PpapiHostMsg_ClearSiteDataResult( - request_id, ClearSiteData(plugin_data_path, site, flags, max_age))); -} - -void BrokerProcessDispatcher::OnDeauthorizeContentLicenses( - uint32_t request_id, - const base::FilePath& plugin_data_path) { - Send(new PpapiHostMsg_DeauthorizeContentLicensesResult( - request_id, DeauthorizeContentLicenses(plugin_data_path))); -} - -void BrokerProcessDispatcher::OnGetPermissionSettings( - uint32_t request_id, - const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type) { - if (flash_browser_operations_1_3_) { - std::string data_str = ConvertPluginDataPath(plugin_data_path); - // The GetPermissionSettingsContext object will be deleted in - // GetPermissionSettingsCallback(). - flash_browser_operations_1_3_->GetPermissionSettings( - data_str.c_str(), setting_type, &GetPermissionSettingsCallback, - new GetPermissionSettingsContext(AsWeakPtr(), request_id)); - return; - } - - if (flash_browser_operations_1_2_) { - std::string data_str = ConvertPluginDataPath(plugin_data_path); - // The GetPermissionSettingsContext object will be deleted in - // GetPermissionSettingsCallback(). - flash_browser_operations_1_2_->GetPermissionSettings( - data_str.c_str(), setting_type, &GetPermissionSettingsCallback, - new GetPermissionSettingsContext(AsWeakPtr(), request_id)); - return; - } - - OnGetPermissionSettingsCompleted( - request_id, false, PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT, - ppapi::FlashSiteSettings()); - return; -} - -void BrokerProcessDispatcher::OnSetDefaultPermission( - uint32_t request_id, - const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific) { - Send(new PpapiHostMsg_SetDefaultPermissionResult( - request_id, - SetDefaultPermission(plugin_data_path, setting_type, permission, - clear_site_specific))); -} - -void BrokerProcessDispatcher::OnSetSitePermission( - uint32_t request_id, - const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites) { - Send(new PpapiHostMsg_SetSitePermissionResult( - request_id, SetSitePermission(plugin_data_path, setting_type, sites))); -} - -void BrokerProcessDispatcher::GetSitesWithData( - const base::FilePath& plugin_data_path, - std::vector<std::string>* site_vector) { - std::string data_str = ConvertPluginDataPath(plugin_data_path); - if (flash_browser_operations_1_3_) { - char** sites = nullptr; - flash_browser_operations_1_3_->GetSitesWithData(data_str.c_str(), &sites); - if (!sites) - return; - - for (size_t i = 0; sites[i]; ++i) - site_vector->push_back(sites[i]); - - flash_browser_operations_1_3_->FreeSiteList(sites); - } -} - -bool BrokerProcessDispatcher::ClearSiteData( - const base::FilePath& plugin_data_path, - const std::string& site, - uint64_t flags, - uint64_t max_age) { - std::string data_str = ConvertPluginDataPath(plugin_data_path); - if (flash_browser_operations_1_3_) { - flash_browser_operations_1_3_->ClearSiteData( - data_str.c_str(), site.empty() ? nullptr : site.c_str(), flags, - max_age); - return true; - } - - // TODO(viettrungluu): Remove this (and the 1.0 interface) sometime after M21 - // goes to Stable. - if (flash_browser_operations_1_2_) { - flash_browser_operations_1_2_->ClearSiteData( - data_str.c_str(), site.empty() ? nullptr : site.c_str(), flags, - max_age); - return true; - } - - if (flash_browser_operations_1_0_) { - flash_browser_operations_1_0_->ClearSiteData( - data_str.c_str(), site.empty() ? nullptr : site.c_str(), flags, - max_age); - return true; - } - - return false; -} - -bool BrokerProcessDispatcher::DeauthorizeContentLicenses( - const base::FilePath& plugin_data_path) { - if (flash_browser_operations_1_3_) { - std::string data_str = ConvertPluginDataPath(plugin_data_path); - return PP_ToBool(flash_browser_operations_1_3_->DeauthorizeContentLicenses( - data_str.c_str())); - } - - if (flash_browser_operations_1_2_) { - std::string data_str = ConvertPluginDataPath(plugin_data_path); - return PP_ToBool(flash_browser_operations_1_2_->DeauthorizeContentLicenses( - data_str.c_str())); - } - - return false; -} - -bool BrokerProcessDispatcher::SetDefaultPermission( - const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific) { - if (flash_browser_operations_1_3_) { - std::string data_str = ConvertPluginDataPath(plugin_data_path); - return PP_ToBool(flash_browser_operations_1_3_->SetDefaultPermission( - data_str.c_str(), setting_type, permission, - PP_FromBool(clear_site_specific))); - } - - if (flash_browser_operations_1_2_) { - std::string data_str = ConvertPluginDataPath(plugin_data_path); - return PP_ToBool(flash_browser_operations_1_2_->SetDefaultPermission( - data_str.c_str(), setting_type, permission, - PP_FromBool(clear_site_specific))); - } - - return false; -} - -bool BrokerProcessDispatcher::SetSitePermission( - const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites) { - if (sites.empty()) - return true; - - std::string data_str = ConvertPluginDataPath(plugin_data_path); - std::unique_ptr<PP_Flash_BrowserOperations_SiteSetting[]> site_array( - new PP_Flash_BrowserOperations_SiteSetting[sites.size()]); - - for (size_t i = 0; i < sites.size(); ++i) { - site_array[i].site = sites[i].site.c_str(); - site_array[i].permission = sites[i].permission; - } - - if (flash_browser_operations_1_3_) { - PP_Bool result = flash_browser_operations_1_3_->SetSitePermission( - data_str.c_str(), setting_type, - static_cast<uint32_t>(sites.size()), site_array.get()); - - return PP_ToBool(result); - } - - if (flash_browser_operations_1_2_) { - PP_Bool result = flash_browser_operations_1_2_->SetSitePermission( - data_str.c_str(), setting_type, - static_cast<uint32_t>(sites.size()), site_array.get()); - - return PP_ToBool(result); - } - - return false; -} - -} // namespace content
diff --git a/content/ppapi_plugin/broker_process_dispatcher.h b/content/ppapi_plugin/broker_process_dispatcher.h deleted file mode 100644 index 95401dd0..0000000 --- a/content/ppapi_plugin/broker_process_dispatcher.h +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_PPAPI_PLUGIN_BROKER_PROCESS_DISPATCHER_H_ -#define CONTENT_PPAPI_PLUGIN_BROKER_PROCESS_DISPATCHER_H_ - -#include <stdint.h> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "content/child/scoped_child_process_reference.h" -#include "ppapi/c/ppp.h" -#include "ppapi/proxy/broker_dispatcher.h" -#include "ppapi/shared_impl/ppp_flash_browser_operations_shared.h" - -namespace content { - -// Wrapper around a BrokerDispatcher that provides the necessary integration -// for plugin process management. This class is to avoid direct dependencies -// from the PPAPI proxy on the Chrome multiprocess infrastructure. -class BrokerProcessDispatcher - : public ppapi::proxy::BrokerSideDispatcher, - public base::SupportsWeakPtr<BrokerProcessDispatcher> { - public: - BrokerProcessDispatcher(PP_GetInterface_Func get_plugin_interface, - PP_ConnectInstance_Func connect_instance, - bool peer_is_browser); - ~BrokerProcessDispatcher() override; - - // IPC::Listener overrides. - bool OnMessageReceived(const IPC::Message& msg) override; - - void OnGetPermissionSettingsCompleted( - uint32_t request_id, - bool success, - PP_Flash_BrowserOperations_Permission default_permission, - const ppapi::FlashSiteSettings& sites); - - private: - void OnGetSitesWithData(uint32_t request_id, - const base::FilePath& plugin_data_path); - void OnClearSiteData(uint32_t request_id, - const base::FilePath& plugin_data_path, - const std::string& site, - uint64_t flags, - uint64_t max_age); - void OnDeauthorizeContentLicenses(uint32_t request_id, - const base::FilePath& plugin_data_path); - void OnGetPermissionSettings( - uint32_t request_id, - const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type); - void OnSetDefaultPermission( - uint32_t request_id, - const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific); - void OnSetSitePermission(uint32_t request_id, - const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites); - - // Returns a list of sites that have data stored. - void GetSitesWithData(const base::FilePath& plugin_data_path, - std::vector<std::string>* sites); - - // Requests that the plugin clear data, returning true on success. - bool ClearSiteData(const base::FilePath& plugin_data_path, - const std::string& site, - uint64_t flags, - uint64_t max_age); - - bool DeauthorizeContentLicenses(const base::FilePath& plugin_data_path); - bool SetDefaultPermission(const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - bool clear_site_specific); - bool SetSitePermission(const base::FilePath& plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - const ppapi::FlashSiteSettings& sites); - - ScopedChildProcessReference process_ref_; - - PP_GetInterface_Func get_plugin_interface_; - - const PPP_Flash_BrowserOperations_1_3* flash_browser_operations_1_3_; - const PPP_Flash_BrowserOperations_1_2* flash_browser_operations_1_2_; - const PPP_Flash_BrowserOperations_1_0* flash_browser_operations_1_0_; - - bool peer_is_browser_; - - DISALLOW_COPY_AND_ASSIGN(BrokerProcessDispatcher); -}; - -} // namespace content - -#endif // CONTENT_PPAPI_PLUGIN_BROKER_PROCESS_DISPATCHER_H_
diff --git a/content/ppapi_plugin/ppapi_plugin_main.cc b/content/ppapi_plugin/ppapi_plugin_main.cc index dc737cbc..7a6d15d 100644 --- a/content/ppapi_plugin/ppapi_plugin_main.cc +++ b/content/ppapi_plugin/ppapi_plugin_main.cc
@@ -23,7 +23,6 @@ #include "content/public/common/main_function_params.h" #include "ipc/ipc_sender.h" #include "ppapi/proxy/plugin_globals.h" -#include "ppapi/proxy/proxy_module.h" #include "services/tracing/public/cpp/trace_startup.h" #include "ui/base/ui_base_switches.h"
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc index a20df3c..99075d5 100644 --- a/content/ppapi_plugin/ppapi_thread.cc +++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -28,7 +28,6 @@ #include "components/discardable_memory/client/client_discardable_shared_memory_manager.h" #include "content/child/browser_font_resource_trusted.h" #include "content/child/child_process.h" -#include "content/ppapi_plugin/broker_process_dispatcher.h" #include "content/ppapi_plugin/plugin_process_dispatcher.h" #include "content/ppapi_plugin/ppapi_blink_platform_impl.h" #include "content/public/common/content_client.h" @@ -483,24 +482,13 @@ ppapi::proxy::ProxyChannel* dispatcher = nullptr; bool init_result = false; - if (is_broker_) { - bool peer_is_browser = renderer_pid == base::kNullProcessId; - BrokerProcessDispatcher* broker_dispatcher = - new BrokerProcessDispatcher(plugin_entry_points_.get_interface, - connect_instance_func_, peer_is_browser); - init_result = broker_dispatcher->InitBrokerWithChannel( - this, renderer_pid, pipe.handle0.release(), false); - dispatcher = broker_dispatcher; - } else { - DCHECK_NE(base::kNullProcessId, renderer_pid); - PluginProcessDispatcher* plugin_dispatcher = - new PluginProcessDispatcher(plugin_entry_points_.get_interface, - permissions_, - incognito); - init_result = plugin_dispatcher->InitPluginWithChannel( - this, renderer_pid, pipe.handle0.release(), false); - dispatcher = plugin_dispatcher; - } + DCHECK(!is_broker_); + DCHECK_NE(base::kNullProcessId, renderer_pid); + PluginProcessDispatcher* plugin_dispatcher = new PluginProcessDispatcher( + plugin_entry_points_.get_interface, permissions_, incognito); + init_result = plugin_dispatcher->InitPluginWithChannel( + this, renderer_pid, pipe.handle0.release(), false); + dispatcher = plugin_dispatcher; if (!init_result) { delete dispatcher;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 0247ea6..dc37ade 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -927,6 +927,23 @@ "RetryGetVideoCaptureDeviceInfos", base::FEATURE_DISABLED_BY_DEFAULT}; #endif // defined(OS_MAC) +#if !defined(OS_WIN) && !defined(OS_FUCHSIA) && !defined(OS_IOS) +// If the JavaScript on a WebUI page has an error (such as an unhandled +// exception), report that error back the crash reporting infrastructure, same +// as we do for program crashes. +const base::Feature kSendWebUIJavaScriptErrorReports{ + "SendWebUIJavaScriptErrorReports", base::FEATURE_DISABLED_BY_DEFAULT}; +// Parameter: Should we send the error reports to the production server? If +// false, we send to the staging server, which is useful for developers (doesn't +// pollute the report database). +const char kSendWebUIJavaScriptErrorReportsSendToProductionVariation[] = + "send_webui_js_errors_to_production"; +const base::FeatureParam<bool> + kWebUIJavaScriptErrorReportsSendToProductionParam{ + &kSendWebUIJavaScriptErrorReports, + kSendWebUIJavaScriptErrorReportsSendToProductionVariation, true}; +#endif + #if defined(WEBRTC_USE_PIPEWIRE) // Controls whether the PipeWire support for screen capturing is enabled on the // Wayland display server.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 6b63a6e..6442d713 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -197,6 +197,14 @@ CONTENT_EXPORT extern const base::Feature kRetryGetVideoCaptureDeviceInfos; #endif // defined(OS_MAC) +#if !defined(OS_WIN) && !defined(OS_FUCHSIA) && !defined(OS_IOS) +CONTENT_EXPORT extern const base::Feature kSendWebUIJavaScriptErrorReports; +CONTENT_EXPORT extern const char + kSendWebUIJavaScriptErrorReportsSendToProductionVariation[]; +CONTENT_EXPORT extern const base::FeatureParam<bool> + kWebUIJavaScriptErrorReportsSendToProductionParam; +#endif + #if defined(WEBRTC_USE_PIPEWIRE) CONTENT_EXPORT extern const base::Feature kWebRtcPipeWireCapturer; #endif // defined(WEBRTC_USE_PIPEWIRE)
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc index e328190..3aabc5a7 100644 --- a/content/renderer/media/media_factory.cc +++ b/content/renderer/media/media_factory.cc
@@ -402,11 +402,8 @@ std::vector<std::unique_ptr<BatchingMediaLog::EventHandler>> handlers; handlers.push_back(std::make_unique<RenderMediaEventHandler>()); - - if (base::FeatureList::IsEnabled(media::kMediaInspectorLogging)) { - handlers.push_back( - std::make_unique<InspectorMediaEventHandler>(inspector_context)); - } + handlers.push_back( + std::make_unique<InspectorMediaEventHandler>(inspector_context)); // This must be created for every new WebMediaPlayer, each instance generates // a new player id which is used to collate logs on the browser side. @@ -699,11 +696,8 @@ std::vector<std::unique_ptr<BatchingMediaLog::EventHandler>> handlers; handlers.push_back(std::make_unique<RenderMediaEventHandler>()); - - if (base::FeatureList::IsEnabled(media::kMediaInspectorLogging)) { - handlers.push_back( - std::make_unique<InspectorMediaEventHandler>(inspector_context)); - } + handlers.push_back( + std::make_unique<InspectorMediaEventHandler>(inspector_context)); // This must be created for every new WebMediaPlayer, each instance generates // a new player id which is used to collate logs on the browser side.
diff --git a/content/renderer/pepper/plugin_module.cc b/content/renderer/pepper/plugin_module.cc index 763d35fd..a42968ec 100644 --- a/content/renderer/pepper/plugin_module.cc +++ b/content/renderer/pepper/plugin_module.cc
@@ -107,7 +107,6 @@ #include "ppapi/c/private/ppb_file_ref_private.h" #include "ppapi/c/private/ppb_find_private.h" #include "ppapi/c/private/ppb_flash_font_file.h" -#include "ppapi/c/private/ppb_flash_fullscreen.h" #include "ppapi/c/private/ppb_host_resolver_private.h" #include "ppapi/c/private/ppb_instance_private.h" #include "ppapi/c/private/ppb_isolated_file_system_private.h"
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc index a900e21f..913c517 100644 --- a/content/renderer/render_widget_unittest.cc +++ b/content/renderer/render_widget_unittest.cc
@@ -97,23 +97,6 @@ IPC::TestSink* sink() { return &sink_; } - std::unique_ptr<cc::LayerTreeFrameSink> AllocateNewLayerTreeFrameSink() - override { - std::unique_ptr<cc::FakeLayerTreeFrameSink> sink = - cc::FakeLayerTreeFrameSink::Create3d(); - last_created_frame_sink_ = sink.get(); - return sink; - } - - // The returned pointer is valid after RequestNewLayerTreeFrameSink() occurs, - // until another call to RequestNewLayerTreeFrameSink() happens. It's okay to - // use this pointer on the main thread because this class causes the - // compositor to run in single thread mode by returning a null from - // GetCompositorImplThreadTaskRunner(). - cc::FakeLayerTreeFrameSink* last_created_frame_sink() { - return last_created_frame_sink_; - } - protected: bool Send(IPC::Message* msg) override { sink_.OnMessageReceived(*msg); @@ -124,7 +107,6 @@ private: IPC::TestSink sink_; static int next_routing_id_; - cc::FakeLayerTreeFrameSink* last_created_frame_sink_ = nullptr; DISALLOW_COPY_AND_ASSIGN(InteractiveRenderWidget); }; @@ -189,16 +171,6 @@ InteractiveRenderWidget* widget() const { return widget_.get(); } - blink::WebFrameWidget* frame_widget() const { return web_frame_widget_; } - - const base::HistogramTester& histogram_tester() const { - return histogram_tester_; - } - - cc::FakeLayerTreeFrameSink* GetFrameSink() { - return widget_->last_created_frame_sink(); - } - private: base::test::TaskEnvironment task_environment_; RenderProcess render_process_; @@ -211,7 +183,6 @@ FakeCompositorDependencies compositor_deps_; std::unique_ptr<AgentSchedulingGroup> agent_scheduling_group_; std::unique_ptr<InteractiveRenderWidget> widget_; - base::HistogramTester histogram_tester_; const bool is_for_nested_main_frame_; }; @@ -245,127 +216,4 @@ EXPECT_FALSE(layer_tree_host->is_external_pinch_gesture_active_for_testing()); } -#if defined(OS_ANDROID) -TEST_F(RenderWidgetUnittest, ForceSendMetadataOnInput) { - cc::LayerTreeHost* layer_tree_host = widget()->layer_tree_host(); - // We should not have any force send metadata requests at start. - EXPECT_FALSE(layer_tree_host->TakeForceSendMetadataRequest()); - // ShowVirtualKeyboard will trigger a text input state update. - widget()->GetWebWidget()->ShowVirtualKeyboard(); - // We should now have a force send metadata request. - EXPECT_TRUE(layer_tree_host->TakeForceSendMetadataRequest()); -} -#endif // !defined(OS_ANDROID) - -class NotifySwapTimesRenderWidgetUnittest : public RenderWidgetUnittest { - public: - void SetUp() override { - RenderWidgetUnittest::SetUp(); - - viz::ParentLocalSurfaceIdAllocator allocator; - - // TODO(danakj): This usually happens through - // RenderWidget::UpdateVisualProperties() and we are cutting past that for - // some reason. - allocator.GenerateId(); - widget()->layer_tree_host()->SetViewportRectAndScale( - gfx::Rect(200, 100), 1.f, allocator.GetCurrentLocalSurfaceId()); - - auto root_layer = cc::SolidColorLayer::Create(); - root_layer->SetBounds(gfx::Size(200, 100)); - root_layer->SetBackgroundColor(SK_ColorGREEN); - widget()->layer_tree_host()->SetRootLayer(root_layer); - - auto color_layer = cc::SolidColorLayer::Create(); - color_layer->SetBounds(gfx::Size(100, 100)); - root_layer->AddChild(color_layer); - color_layer->SetBackgroundColor(SK_ColorRED); - } - - // |swap_to_presentation| determines how long after swap should presentation - // happen. This can be negative, positive, or zero. If zero, an invalid (null) - // presentation time is used. - void CompositeAndWaitForPresentation(base::TimeDelta swap_to_presentation) { - base::RunLoop swap_run_loop; - base::RunLoop presentation_run_loop; - - // Register callbacks for swap time and presentation time. - base::TimeTicks swap_time; - frame_widget()->NotifySwapAndPresentationTime( - base::BindOnce( - [](base::OnceClosure swap_quit_closure, base::TimeTicks* swap_time, - blink::WebSwapResult result, base::TimeTicks timestamp) { - DCHECK(!timestamp.is_null()); - *swap_time = timestamp; - std::move(swap_quit_closure).Run(); - }, - swap_run_loop.QuitClosure(), &swap_time), - base::BindOnce( - [](base::OnceClosure presentation_quit_closure, - blink::WebSwapResult result, base::TimeTicks timestamp) { - DCHECK(!timestamp.is_null()); - std::move(presentation_quit_closure).Run(); - }, - presentation_run_loop.QuitClosure())); - - // Composite and wait for the swap to complete. - widget()->layer_tree_host()->Composite(base::TimeTicks::Now(), - /*raster=*/true); - swap_run_loop.Run(); - - // Present and wait for it to complete. - viz::FrameTimingDetails timing_details; - if (!swap_to_presentation.is_zero()) { - timing_details.presentation_feedback = gfx::PresentationFeedback( - /*presentation_time=*/swap_time + swap_to_presentation, - base::TimeDelta::FromMilliseconds(16), 0); - } - GetFrameSink()->NotifyDidPresentCompositorFrame(1, timing_details); - presentation_run_loop.Run(); - } -}; - -TEST_F(NotifySwapTimesRenderWidgetUnittest, PresentationTimestampValid) { - base::HistogramTester histograms; - - CompositeAndWaitForPresentation(base::TimeDelta::FromMilliseconds(2)); - - EXPECT_THAT(histograms.GetAllSamples( - "PageLoad.Internal.Renderer.PresentationTime.Valid"), - testing::ElementsAre(base::Bucket(true, 1))); - EXPECT_THAT( - histograms.GetAllSamples( - "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime"), - testing::ElementsAre(base::Bucket(2, 1))); -} - -TEST_F(NotifySwapTimesRenderWidgetUnittest, PresentationTimestampInvalid) { - base::HistogramTester histograms; - - CompositeAndWaitForPresentation(base::TimeDelta()); - - EXPECT_THAT(histograms.GetAllSamples( - "PageLoad.Internal.Renderer.PresentationTime.Valid"), - testing::ElementsAre(base::Bucket(false, 1))); - EXPECT_THAT( - histograms.GetAllSamples( - "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime"), - testing::IsEmpty()); -} - -TEST_F(NotifySwapTimesRenderWidgetUnittest, - PresentationTimestampEarlierThanSwaptime) { - base::HistogramTester histograms; - - CompositeAndWaitForPresentation(base::TimeDelta::FromMilliseconds(-2)); - - EXPECT_THAT(histograms.GetAllSamples( - "PageLoad.Internal.Renderer.PresentationTime.Valid"), - testing::ElementsAre(base::Bucket(false, 1))); - EXPECT_THAT( - histograms.GetAllSamples( - "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime"), - testing::IsEmpty()); -} - } // namespace content
diff --git a/content/test/portal/OWNERS b/content/test/portal/OWNERS index bf4f802..1c33ce23 100644 --- a/content/test/portal/OWNERS +++ b/content/test/portal/OWNERS
@@ -1,3 +1,3 @@ file://third_party/blink/renderer/core/html/portal/OWNERS -# COMPONENT: Blink>HTML>Portal +# COMPONENT: Blink>Portals
diff --git a/content/web_test/browser/web_test_control_host.cc b/content/web_test/browser/web_test_control_host.cc index e6b609b9..f18312b 100644 --- a/content/web_test/browser/web_test_control_host.cc +++ b/content/web_test/browser/web_test_control_host.cc
@@ -1065,6 +1065,10 @@ } } +void WebTestControlHost::RenderViewDeleted(RenderViewHost* render_view_host) { + main_window_render_view_hosts_.erase(render_view_host); +} + void WebTestControlHost::RenderProcessHostDestroyed( RenderProcessHost* render_process_host) { render_process_host_observer_.Remove(render_process_host);
diff --git a/content/web_test/browser/web_test_control_host.h b/content/web_test/browser/web_test_control_host.h index 3d4f487..e5813b02 100644 --- a/content/web_test/browser/web_test_control_host.h +++ b/content/web_test/browser/web_test_control_host.h
@@ -159,6 +159,7 @@ void DidUpdateFaviconURL( RenderFrameHost* render_frame_host, const std::vector<blink::mojom::FaviconURLPtr>& candidates) override; + void RenderViewDeleted(RenderViewHost* render_view_host) override; // RenderProcessHostObserver implementation. void RenderProcessHostDestroyed(
diff --git a/device/bluetooth/adapter.cc b/device/bluetooth/adapter.cc index 13f0a70..28b68c2 100644 --- a/device/bluetooth/adapter.cc +++ b/device/bluetooth/adapter.cc
@@ -89,6 +89,7 @@ void Adapter::RegisterAdvertisement(const device::BluetoothUUID& service_uuid, const std::vector<uint8_t>& service_data, + bool use_scan_response, RegisterAdvertisementCallback callback) { auto advertisement_data = std::make_unique<device::BluetoothAdvertisement::Data>( @@ -98,10 +99,38 @@ uuid_list->push_back(service_uuid.value()); advertisement_data->set_service_uuids(std::move(uuid_list)); - auto service_data_map = - std::make_unique<device::BluetoothAdvertisement::ServiceData>(); - service_data_map->emplace(service_uuid.value(), service_data); - advertisement_data->set_service_data(std::move(service_data_map)); + if (!use_scan_response) { + auto service_data_map = + std::make_unique<device::BluetoothAdvertisement::ServiceData>(); + service_data_map->emplace(service_uuid.value(), service_data); + advertisement_data->set_service_data(std::move(service_data_map)); + } else { + // Require the service uuid to be in 128-bit format. + DCHECK_EQ(service_uuid.format(), + device::BluetoothUUID::Format::kFormat128Bit); + auto scan_response_data_map = + std::make_unique<device::BluetoothAdvertisement::ScanResponseData>(); + // Start with the original scan response data. + std::vector<uint8_t> scan_response_data(service_data.begin(), + service_data.end()); + // Now insert in front of the service data the identifying 2-bytes of the + // service id assuming this is a valid 16-bit uuid. For example, the uuid: + // 0000fef3-0000-1000-8000-00805f9b34fb can be uniquely defined by two bytes + // ****fef3-****-****-****-************ the rest is the same for all 16-bit + // uuids as defined by the Bluetooth spec. We insert them in little endian + // ordering 0xf3 first, then 0xfe in for this example. + auto service_id_bytes = service_uuid.GetBytes(); + // Take bytes 2 and 3. + auto id_bytes = base::make_span(service_id_bytes).subspan(2, 2); + // Add them in reverse order (little endian). + scan_response_data.insert(scan_response_data.begin(), id_bytes.rbegin(), + id_bytes.rend()); + // The platform API only supports AD Type 0x16 "Service Data" which assumes + // as 16-bit service id. + scan_response_data_map->emplace(0x16, scan_response_data); + advertisement_data->set_scan_response_data( + std::move(scan_response_data_map)); + } auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); adapter_->RegisterAdvertisement(
diff --git a/device/bluetooth/adapter.h b/device/bluetooth/adapter.h index f9d113a..df4868b 100644 --- a/device/bluetooth/adapter.h +++ b/device/bluetooth/adapter.h
@@ -40,6 +40,7 @@ AddObserverCallback callback) override; void RegisterAdvertisement(const device::BluetoothUUID& service_uuid, const std::vector<uint8_t>& service_data, + bool use_scan_response, RegisterAdvertisementCallback callback) override; void SetDiscoverable(bool discoverable, SetDiscoverableCallback callback) override;
diff --git a/device/bluetooth/adapter_unittest.cc b/device/bluetooth/adapter_unittest.cc index e6e98d0..21d0d7b 100644 --- a/device/bluetooth/adapter_unittest.cc +++ b/device/bluetooth/adapter_unittest.cc
@@ -21,7 +21,7 @@ namespace { -const char kServiceId[] = "00000000-0000-0000-0000-000000000001"; +const char kServiceId[] = "0000abcd-0000-0000-0000-000000000001"; const char kDeviceServiceDataStr[] = "ServiceData"; std::vector<uint8_t> GetByteVector(const std::string& str) { @@ -36,9 +36,7 @@ device::BluetoothAdapter::CreateAdvertisementCallback callback, device::BluetoothAdapter::AdvertisementErrorCallback error_callback) override { - last_register_advertisement_args_ = - std::make_pair(*advertisement_data->service_uuids(), - *advertisement_data->service_data()); + last_advertisement_data_ = std::move(advertisement_data); if (should_advertisement_registration_succeed_) { std::move(callback).Run( @@ -51,9 +49,8 @@ } bool should_advertisement_registration_succeed_ = true; - base::Optional<std::pair<device::BluetoothAdvertisement::UUIDList, - device::BluetoothAdvertisement::ServiceData>> - last_register_advertisement_args_; + std::unique_ptr<device::BluetoothAdvertisement::Data> + last_advertisement_data_; protected: ~MockBluetoothAdapterWithAdvertisements() override = default; @@ -80,7 +77,7 @@ } protected: - void VerifyRegisterAdvertisement(bool should_succeed) { + void RegisterAdvertisement(bool should_succeed, bool use_scan_data) { mock_bluetooth_adapter_->should_advertisement_registration_succeed_ = should_succeed; @@ -90,21 +87,46 @@ base::RunLoop run_loop; adapter_->RegisterAdvertisement( device::BluetoothUUID(kServiceId), service_data, + /*use_scan_data=*/use_scan_data, base::BindLambdaForTesting([&](mojo::PendingRemote<mojom::Advertisement> pending_advertisement) { EXPECT_EQ(should_succeed, pending_advertisement.is_valid()); run_loop.Quit(); })); run_loop.Run(); + } - auto& uuid_list = - mock_bluetooth_adapter_->last_register_advertisement_args_->first; - EXPECT_EQ(1u, uuid_list.size()); - EXPECT_EQ(kServiceId, uuid_list[0]); - EXPECT_EQ( - service_data, - mock_bluetooth_adapter_->last_register_advertisement_args_->second.at( - kServiceId)); + void VerifyAdvertisement() { + auto service_data = GetByteVector(kDeviceServiceDataStr); + auto uuid_list = + mock_bluetooth_adapter_->last_advertisement_data_->service_uuids(); + EXPECT_EQ(1u, uuid_list->size()); + EXPECT_EQ(kServiceId, (*uuid_list)[0]); + auto last_service_data = + mock_bluetooth_adapter_->last_advertisement_data_->service_data(); + EXPECT_EQ(service_data, last_service_data->at(kServiceId)); + EXPECT_FALSE(mock_bluetooth_adapter_->last_advertisement_data_ + ->scan_response_data()); + } + + void VerifyAdvertisementWithScanData() { + auto service_data = GetByteVector(kDeviceServiceDataStr); + auto uuid_list = + mock_bluetooth_adapter_->last_advertisement_data_->service_uuids(); + EXPECT_EQ(1u, uuid_list->size()); + EXPECT_EQ(kServiceId, (*uuid_list)[0]); + EXPECT_FALSE( + mock_bluetooth_adapter_->last_advertisement_data_->service_data()); + auto last_scan_response_data = + mock_bluetooth_adapter_->last_advertisement_data_->scan_response_data(); + ASSERT_TRUE(base::Contains(*last_scan_response_data, 0x16)); + const auto& raw_data = (*last_scan_response_data)[0x16]; + // First two bytes should be the identifying bits of the kServiceId UUID. + // They should be in litten endian order (reversed). + EXPECT_EQ(0xCD, raw_data[0]); + EXPECT_EQ(0xAB, raw_data[1]); + EXPECT_EQ(service_data, + std::vector<uint8_t>(raw_data.begin() + 2, raw_data.end())); } scoped_refptr<NiceMock<MockBluetoothAdapterWithAdvertisements>> @@ -116,11 +138,18 @@ }; TEST_F(AdapterTest, TestRegisterAdvertisement_Success) { - VerifyRegisterAdvertisement(/*should_succeed=*/true); + RegisterAdvertisement(/*should_succeed=*/true, /*use_scan_data=*/false); + VerifyAdvertisement(); } TEST_F(AdapterTest, TestRegisterAdvertisement_Error) { - VerifyRegisterAdvertisement(/*should_succeed=*/false); + RegisterAdvertisement(/*should_succeed=*/false, /*use_scan_data=*/false); + VerifyAdvertisement(); +} + +TEST_F(AdapterTest, TestRegisterAdvertisement_ScanResponseData) { + RegisterAdvertisement(/*should_succeed=*/true, /*use_scan_data=*/true); + VerifyAdvertisementWithScanData(); } } // namespace bluetooth
diff --git a/device/bluetooth/public/mojom/adapter.mojom b/device/bluetooth/public/mojom/adapter.mojom index 5d7fc04a..5de5b4ee 100644 --- a/device/bluetooth/public/mojom/adapter.mojom +++ b/device/bluetooth/public/mojom/adapter.mojom
@@ -147,6 +147,16 @@ // Requests the adapter to broadcast a BLE advertisement on |service_id| with // the associated packet |service_data|. Returns null if advertisement is not // registered successfully. + // + // When |use_scan_response| is true, the |service_data| is added to the scan + // response instead of the initial advertisement. A few assumptions are made: + // + // 1) The |service_id| provided is a valid 16-bit UUID in 128-bit format. + // The identifying 16-bits will be extracted for the short service id used + // in the scan response. + // 2) The Ad Type is assumed to be 0x16 as that is all that is supported by + // the Platform right now. + // // Important notes: // * This method registers a "non-connectable" advertisement. Any future // effort to allow this API to support "connectable" advertisements would @@ -157,8 +167,8 @@ // as Chrome OS does. Non-Chrome OS clients of this API are responsible for // understanding their host OS's and/or hardware's limitations. [Sync] - RegisterAdvertisement(UUID service_id, array<uint8> service_data) => - (pending_remote<Advertisement>? advertisement); + RegisterAdvertisement(UUID service_id, array<uint8> service_data, + bool use_scan_response) => (pending_remote<Advertisement>? advertisement); // Requests the local device to make itself discoverable to nearby remote // devices.
diff --git a/device/fido/cable/v2_authenticator.cc b/device/fido/cable/v2_authenticator.cc index e4b2e7d..d4fc1161 100644 --- a/device/fido/cable/v2_authenticator.cc +++ b/device/fido/cable/v2_authenticator.cc
@@ -72,7 +72,7 @@ // communication. This specifies a Google service and the short domain need is // necessary to fit within a BLE advert. constexpr uint32_t kTunnelServer = device::cablev2::tunnelserver::EncodeDomain( - "xyi3", + "ua5v", device::cablev2::tunnelserver::TLD::COM); struct MakeCredRequest {
diff --git a/device/fido/cable/v2_handshake.cc b/device/fido/cable/v2_handshake.cc index ca826be..e0e8565 100644 --- a/device/fido/cable/v2_handshake.cc +++ b/device/fido/cable/v2_handshake.cc
@@ -93,7 +93,7 @@ std::string DecodeDomain(uint32_t domain) { static const char kBase32Chars[33] = "abcdefghijklmnopqrstuvwxyz234567"; - std::string ret; + std::string ret = "cable."; ret.push_back(kBase32Chars[(domain >> 17) & 0x1f]); ret.push_back(kBase32Chars[(domain >> 12) & 0x1f]); ret.push_back(kBase32Chars[(domain >> 7) & 0x1f]);
diff --git a/device/fido/cable/v2_handshake_unittest.cc b/device/fido/cable/v2_handshake_unittest.cc index c3c6945d..321e169 100644 --- a/device/fido/cable/v2_handshake_unittest.cc +++ b/device/fido/cable/v2_handshake_unittest.cc
@@ -22,7 +22,7 @@ tunnelserver::EncodeDomain("abcd", tunnelserver::TLD::NET); uint8_t tunnel_id[16] = {0}; const GURL url = tunnelserver::GetNewTunnelURL(encoded, tunnel_id); - EXPECT_TRUE(url.spec().find("//abcd.net/") != std::string::npos) << url; + EXPECT_TRUE(url.spec().find("//cable.abcd.net/") != std::string::npos) << url; } TEST(CableV2Encoding, EIDToFromComponents) {
diff --git a/device/vr/android/arcore/arcore.h b/device/vr/android/arcore/arcore.h index 629ef1b8..317c2698 100644 --- a/device/vr/android/arcore/arcore.h +++ b/device/vr/android/arcore/arcore.h
@@ -25,6 +25,14 @@ public: virtual ~ArCore() = default; + // Represents an inclusive range from min to max. (This is different from + // base::Interval which excludes the top end of the range, resulting in an + // empty interval if min==max.) + struct MinMaxRange { + float min; + float max; + }; + // Initializes the runtime and returns whether it was successful. // If successful, the runtime must be paused when this method returns. virtual bool Initialize( @@ -32,6 +40,10 @@ const std::unordered_set<device::mojom::XRSessionFeature>& enabled_features) = 0; + // Returns the target framerate range in Hz. Actual capture frame rate will + // vary within this range, i.e. lower in low light to increase exposure time. + virtual MinMaxRange GetTargetFramerateRange() = 0; + virtual void SetDisplayGeometry( const gfx::Size& frame_size, display::Display::Rotation display_rotation) = 0;
diff --git a/device/vr/android/arcore/arcore_gl.cc b/device/vr/android/arcore/arcore_gl.cc index 177ac5b..ba48093 100644 --- a/device/vr/android/arcore/arcore_gl.cc +++ b/device/vr/android/arcore/arcore_gl.cc
@@ -49,6 +49,18 @@ const gfx::Size kDefaultFrameSize = {1, 1}; const display::Display::Rotation kDefaultRotation = display::Display::ROTATE_0; +// When scheduling calls to GetFrameData, leave some safety margin to run a bit +// early. For the ARCore Update calculation, need to leave time for the update +// itself to finish, not counting time blocked waiting for a frame to be +// available. For the render completion calculation, the margin compensates for +// variations in rendering time. Express this as a fraction of the frame time, +// on the theory that devices capable of 60fps would tend to be faster than +// ones running at 30fps. +const float kScheduleFrametimeMarginForUpdate = 0.2f; +const float kScheduleFrametimeMarginForRender = 0.2f; + +const int kSampleWindowSize = 3; + gfx::Transform GetContentTransform(const gfx::RectF& bounds) { // Calculate the transform matrix from quad coordinates (range 0..1 with // origin at bottom left of the quad) to texture lookup UV coordinates (also @@ -72,7 +84,10 @@ ArCoreGl::ArCoreGl(std::unique_ptr<ArImageTransport> ar_image_transport) : gl_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), ar_image_transport_(std::move(ar_image_transport)), - webxr_(std::make_unique<vr::WebXrPresentationState>()) { + webxr_(std::make_unique<vr::WebXrPresentationState>()), + average_animate_time_(kSampleWindowSize), + average_process_time_(kSampleWindowSize), + average_render_time_(kSampleWindowSize) { DVLOG(1) << __func__; } @@ -279,6 +294,17 @@ FinishRenderingFrame(); } + // If there is still a rendering frame (we didn't wait for it), check + // if it's complete. If yes, collect its statistics now so that the GPU + // time estimate for the upcoming frame is up to date. + if (webxr_->HaveRenderingFrame()) { + auto* frame = webxr_->GetRenderingFrame(); + if (frame->render_completion_fence && + frame->render_completion_fence->HasCompleted()) { + FinishRenderingFrame(); + } + } + DVLOG(3) << __func__ << ": should_update_display_geometry_=" << should_update_display_geometry_ << ", transfer_size_=" << transfer_size_.ToString() @@ -361,9 +387,19 @@ base::TimeTicks arcore_update_started = base::TimeTicks::Now(); mojom::VRPosePtr pose = arcore_->Update(&camera_updated); base::TimeTicks now = base::TimeTicks::Now(); - base::TimeDelta frame_timestamp = arcore_->GetFrameTimestamp(); + last_arcore_update_time_ = now; - DVLOG(3) << __func__ << ": frame_timestamp=" << frame_timestamp; + // Track the camera frame timestamp interval in preparation for handling with + // frame rate variations within ARCore's configured frame rate range. Not yet + // used for timing purposes since we currently only request 30fps. (Note that + // the frame timestamp has an unspecified and camera-specific time base.) + base::TimeDelta frame_timestamp = arcore_->GetFrameTimestamp(); + if (!last_arcore_frame_timestamp_.is_zero()) { + base::TimeDelta delta = frame_timestamp - last_arcore_frame_timestamp_; + TRACE_COUNTER1("xr", "ARCore camera frame interval (ms)", + delta.InMilliseconds()); + } + last_arcore_frame_timestamp_ = frame_timestamp; base::TimeDelta arcore_update_elapsed = now - arcore_update_started; TRACE_COUNTER1("gpu", "ARCore update elapsed (ms)", @@ -394,11 +430,21 @@ *floor_height_estimate_ != new_floor_height_estimate) { floor_height_estimate_ = new_floor_height_estimate; - frame_data->stage_parameters_updated = true; - frame_data->stage_parameters = mojom::VRStageParameters::New(); - frame_data->stage_parameters->mojo_from_floor = gfx::Transform(); - frame_data->stage_parameters->mojo_from_floor.Translate3d( + if (!stage_parameters_) { + stage_parameters_ = mojom::VRStageParameters::New(); + } + stage_parameters_->mojo_from_floor = gfx::Transform(); + stage_parameters_->mojo_from_floor.Translate3d( 0, (-1 * *floor_height_estimate_), 0); + + stage_parameters_id_++; + } + + // Only send updates to the stage parameters if the session's stage parameters + // id is different. + frame_data->stage_parameters_id = stage_parameters_id_; + if (!options || options->stage_parameters_id != stage_parameters_id_) { + frame_data->stage_parameters = stage_parameters_.Clone(); } frame_data->frame_id = webxr_->StartFrameAnimating(); @@ -461,6 +507,8 @@ vr::WebXrFrame* animating_frame = webxr_->GetAnimatingFrame(); animating_frame->time_js_submit = base::TimeTicks::Now(); + average_animate_time_.AddSample(animating_frame->time_js_submit - + animating_frame->time_pose); if (animating_frame->index != frame_index) { DVLOG(1) << __func__ << ": wrong frame index, got " << frame_index @@ -487,16 +535,100 @@ } // We're done with the camera image for this frame, post a task to start the - // next ARCore update if we had deferred it. + // next animating frame and its ARCore update if we had deferred it. if (pending_getframedata_) { - // Run this now, not as a posted task. Starting the next frame update is a - // high priority to ensure JavaScript has as much time as possible available - // for setting up the next frame in parallel to the current one completing - // rendering. - std::move(pending_getframedata_).Run(); + ScheduleGetFrameData(); } } +base::TimeDelta ArCoreGl::EstimatedArCoreFrameTime() { + // Currently, the frame time is used for scheduling heuristics where it's + // safest to use the shortest-expected frame time which corresponds to the max + // framerate from ARCore's configured range. At the moment we're requesting + // 30fps from ARCore and expecting a single-value range. Revisit this estimate + // (i.e. based on camera timestamp difference) when adding 60fps modes which + // may result in ranges such as 30-60fps. + return base::TimeDelta::FromSecondsD(1.0f / + arcore_->GetTargetFramerateRange().min); +} + +base::TimeDelta ArCoreGl::WaitTimeForArCoreUpdate() { + // ARCore update will block if called before a new camera frame is available. + // Estimate when this is. + base::TimeDelta frametime = EstimatedArCoreFrameTime(); + base::TimeTicks next_update = last_arcore_update_time_ + frametime; + base::TimeTicks now = base::TimeTicks::Now(); + base::TimeDelta wait = + next_update - now - kScheduleFrametimeMarginForUpdate * frametime; + return wait; +} + +base::TimeDelta ArCoreGl::WaitTimeForRenderCompletion() { + DCHECK(webxr_->HaveRenderingFrame()); + + // If there's a current rendering frame, estimate when it's going to finish + // rendering, then try to schedule the next update to match. + auto* rendering_frame = webxr_->GetRenderingFrame(); + base::TimeDelta avg_animate = average_animate_time_.GetAverage(); + base::TimeDelta avg_render = average_render_time_.GetAverage(); + + // The time averages may not have any samples yet, in that case they return + // zero. That's OK, it just means we expect them to finish immediately and + // don't delay. + base::TimeTicks expected_render_complete = + rendering_frame->time_copied + avg_render; + base::TimeDelta render_margin = + kScheduleFrametimeMarginForRender * EstimatedArCoreFrameTime(); + base::TimeTicks now = base::TimeTicks::Now(); + base::TimeDelta render_wait = expected_render_complete - now - render_margin; + + // Once the next frame starts animating, we won't be able to finish processing + // it until the current frame finishes rendering. If rendering is slower than + // the animating (JS processing) time, increase the delay to compensate. + if (avg_animate < avg_render) { + render_wait += avg_render - avg_animate; + } + return render_wait; +} + +void ArCoreGl::ScheduleGetFrameData() { + DCHECK(pending_getframedata_); + + base::TimeDelta delay = base::TimeDelta(); + if (!last_arcore_update_time_.is_null()) { + base::TimeDelta update_wait = WaitTimeForArCoreUpdate(); + if (update_wait > delay) { + delay = update_wait; + } + + if (webxr_->HaveRenderingFrame()) { + base::TimeDelta render_wait = WaitTimeForRenderCompletion(); + if (render_wait > delay) { + delay = render_wait; + } + } + } + TRACE_COUNTER1("xr", "ARCore schedule delay (ms)", delay.InMilliseconds()); + if (delay.is_zero()) { + // If there's no wait time, run immediately, not as posted task, to minimize + // delay. There shouldn't be any pending work we'd need to yield for. + RunPendingGetFrameData(); + } else { + // Run the next frame update as a posted task. This uses a helper method + // since it's not safe to have a closure owned by the task runner, see + // comments on pending_getframedata_ in the header file. + gl_thread_task_runner_->PostDelayedTask( + FROM_HERE, + base::BindOnce(&ArCoreGl::RunPendingGetFrameData, + weak_ptr_factory_.GetWeakPtr()), + delay); + } +} + +void ArCoreGl::RunPendingGetFrameData() { + std::move(pending_getframedata_).Run(); +} + void ArCoreGl::FinishRenderingFrame() { DCHECK(webxr_->HaveRenderingFrame()); vr::WebXrFrame* frame = webxr_->GetRenderingFrame(); @@ -535,18 +667,47 @@ static_cast<gl::GLFenceAndroidNativeFenceSync*>( frame->render_completion_fence.get()) ->GetStatusChangeTime(); + base::TimeTicks now = base::TimeTicks::Now(); if (completion_time.is_null()) { // The fence status change time is best effort and may be unavailable. // In that case, use wallclock time. DVLOG(3) << __func__ << ": got null completion time, using wallclock"; - completion_time = base::TimeTicks::Now(); + completion_time = now; } base::TimeDelta pose_to_submit = frame->time_js_submit - frame->time_pose; base::TimeDelta submit_to_swap = completion_time - frame->time_js_submit; TRACE_COUNTER2("gpu", "WebXR frame time (ms)", "javascript", - pose_to_submit.InMilliseconds(), "processing", + pose_to_submit.InMilliseconds(), "post-submit", submit_to_swap.InMilliseconds()); + + average_render_time_.AddSample(completion_time - frame->time_copied); + + // Add Animating/Processing/Rendering async annotations to event traces. + + // Trace IDs need to be unique. Since frame->index is an 8-bit wrapping value, + // use a separate arbitrary value. This is the only place we create this kind + // of trace, so there's no need to keep the ID in sync with other code + // locations. Use a static value so that IDs don't get reused across sessions. + static uint32_t frame_id_for_tracing = 0; + uint32_t trace_id = ++frame_id_for_tracing; + + TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1( + "xr", "Animating", trace_id, frame->time_pose, "frame", frame->index); + TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP1("xr", "Animating", trace_id, + frame->time_js_submit, "frame", + frame->index); + + TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1("xr", "Processing", trace_id, + frame->time_js_submit, + "frame", frame->index); + TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP1( + "xr", "Processing", trace_id, frame->time_copied, "frame", frame->index); + + TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1( + "xr", "Rendering", trace_id, frame->time_copied, "frame", frame->index); + TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP1( + "xr", "Rendering", trace_id, completion_time, "frame", frame->index); } void ArCoreGl::SubmitFrameMissing(int16_t frame_index, @@ -607,7 +768,6 @@ } void ArCoreGl::TransitionProcessingFrameToRendering() { - webxr_->GetProcessingFrame()->time_copied = base::TimeTicks::Now(); if (webxr_->HaveRenderingFrame()) { // It's possible, though unlikely, that the previous rendering frame hasn't // finished yet, for example if an unusually slow frame is followed by an @@ -618,6 +778,14 @@ DVLOG(3) << __func__ << ": wait for previous rendering frame to complete"; FinishRenderingFrame(); } + + DCHECK(!webxr_->HaveRenderingFrame()); + DCHECK(webxr_->HaveProcessingFrame()); + auto* frame = webxr_->GetProcessingFrame(); + frame->time_copied = base::TimeTicks::Now(); + average_process_time_.AddSample(frame->time_copied - frame->time_js_submit); + + frame->render_completion_fence = nullptr; webxr_->TransitionFrameProcessingToRendering(); // We finished processing a frame, unblock a potentially waiting next frame.
diff --git a/device/vr/android/arcore/arcore_gl.h b/device/vr/android/arcore/arcore_gl.h index 2bde2e5..1f668eb4 100644 --- a/device/vr/android/arcore/arcore_gl.h +++ b/device/vr/android/arcore/arcore_gl.h
@@ -19,6 +19,7 @@ #include "device/vr/public/mojom/isolated_xr_service.mojom.h" #include "device/vr/public/mojom/vr_service.mojom.h" #include "device/vr/util/fps_meter.h" +#include "device/vr/util/sliding_average.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/pending_associated_receiver.h" #include "mojo/public/cpp/bindings/pending_associated_remote.h" @@ -180,6 +181,11 @@ void GetRenderedFrameStats(); void FinishRenderingFrame(); + base::TimeDelta EstimatedArCoreFrameTime(); + base::TimeDelta WaitTimeForArCoreUpdate(); + base::TimeDelta WaitTimeForRenderCompletion(); + void ScheduleGetFrameData(); + void RunPendingGetFrameData(); bool IsFeatureEnabled(mojom::XRSessionFeature feature); @@ -251,6 +257,13 @@ bool restrict_frame_data_ = false; + base::TimeTicks last_arcore_update_time_; + base::TimeDelta last_arcore_frame_timestamp_; + + device::SlidingTimeDeltaAverage average_animate_time_; + device::SlidingTimeDeltaAverage average_process_time_; + device::SlidingTimeDeltaAverage average_render_time_; + FPSMeter fps_meter_; mojo::Receiver<mojom::XRFrameDataProvider> frame_data_receiver_{this}; @@ -275,6 +288,9 @@ mojom::VRDisplayInfoPtr display_info_; bool display_info_changed_ = false; + mojom::VRStageParametersPtr stage_parameters_; + uint32_t stage_parameters_id_; + // Currently estimated floor height. base::Optional<float> floor_height_estimate_;
diff --git a/device/vr/android/arcore/arcore_impl.cc b/device/vr/android/arcore/arcore_impl.cc index 7b1d8fb..41548e0d 100644 --- a/device/vr/android/arcore/arcore_impl.cc +++ b/device/vr/android/arcore/arcore_impl.cc
@@ -430,7 +430,7 @@ return true; } -bool ArCoreImpl::ConfigureCamera(ArSession* ar_session) const { +bool ArCoreImpl::ConfigureCamera(ArSession* ar_session) { internal::ScopedArCoreObject<ArCameraConfigFilter*> camera_config_filter; ArCameraConfigFilter_create( ar_session, internal::ScopedArCoreObject<ArCameraConfigFilter*>::Receiver( @@ -522,11 +522,16 @@ ArCameraConfig_getDepthSensorUsage(ar_session, camera_config.get(), &depth_sensor_usage); + int32_t min_fps, max_fps; + ArCameraConfig_getFpsRange(ar_session, camera_config.get(), &min_fps, + &max_fps); + DVLOG(3) << __func__ << ": matching camera config found, texture dimensions=" << tex_width << "x" << tex_height << ", image dimensions= " << img_width << "x" << img_height - << ", depth sensor usage=" << depth_sensor_usage; + << ", depth sensor usage=" << depth_sensor_usage + << ", min_fps=" << min_fps << ", max_fps=" << max_fps; } #endif @@ -601,6 +606,11 @@ } }); + int32_t fps_min, fps_max; + ArCameraConfig_getFpsRange(ar_session, best_config->get(), &fps_min, + &fps_max); + target_framerate_range_ = {fps_min, fps_max}; + #if DCHECK_IS_ON() { int32_t tex_width, tex_height; @@ -617,7 +627,9 @@ DVLOG(3) << __func__ << ": selected camera config with texture dimensions=" << tex_width << "x" << tex_height << ", image dimensions=" << img_width << "x" - << img_height << ", depth sensor usage=" << depth_sensor_usage; + << img_height << ", depth sensor usage=" << depth_sensor_usage + << ", min_fps=" << target_framerate_range_.min + << ", max_fps=" << target_framerate_range_.max; } #endif @@ -630,6 +642,10 @@ return true; } +ArCore::MinMaxRange ArCoreImpl::GetTargetFramerateRange() { + return target_framerate_range_; +} + void ArCoreImpl::SetCameraTexture(uint32_t camera_texture_id) { DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid());
diff --git a/device/vr/android/arcore/arcore_impl.h b/device/vr/android/arcore/arcore_impl.h index bc6f50d..43a5539 100644 --- a/device/vr/android/arcore/arcore_impl.h +++ b/device/vr/android/arcore/arcore_impl.h
@@ -110,6 +110,7 @@ base::android::ScopedJavaLocalRef<jobject> application_context, const std::unordered_set<device::mojom::XRSessionFeature>& enabled_features) override; + MinMaxRange GetTargetFramerateRange() override; void SetDisplayGeometry(const gfx::Size& frame_size, display::Display::Rotation display_rotation) override; void SetCameraTexture(uint32_t camera_texture_id) override; @@ -190,6 +191,9 @@ internal::ScopedArCoreObject<ArSession*> arcore_session_; internal::ScopedArCoreObject<ArFrame*> arcore_frame_; + // Target framerate reflecting the current camera configuration. + MinMaxRange target_framerate_range_ = {30.f, 30.f}; + // ArCore light estimation data internal::ScopedArCoreObject<ArLightEstimate*> arcore_light_estimate_; @@ -291,7 +295,7 @@ // Helper, attempts to configure ArSession's camera for use. Note that this is // happening during initialization, before arcore_session_ is set. // Returns true if configuration succeeded, false otherwise. - bool ConfigureCamera(ArSession* ar_session) const; + bool ConfigureCamera(ArSession* ar_session); // Must be last. base::WeakPtrFactory<ArCoreImpl> weak_ptr_factory_{this};
diff --git a/device/vr/android/arcore/arcore_shim.cc b/device/vr/android/arcore/arcore_shim.cc index f289044..c07a0f1 100644 --- a/device/vr/android/arcore/arcore_shim.cc +++ b/device/vr/android/arcore/arcore_shim.cc
@@ -31,6 +31,7 @@ DO(ArCameraConfig_destroy) \ DO(ArCameraConfig_getDepthSensorUsage) \ DO(ArCameraConfig_getFacingDirection) \ + DO(ArCameraConfig_getFpsRange) \ DO(ArCameraConfig_getImageDimensions) \ DO(ArCameraConfig_getTextureDimensions) \ DO(ArCameraConfigFilter_create) \ @@ -275,6 +276,14 @@ session, camera_config, out_facing); } +void ArCameraConfig_getFpsRange(const ArSession* session, + const ArCameraConfig* camera_config, + int32_t* out_min_fps, + int32_t* out_max_fps) { + return g_arcore_api->impl_ArCameraConfig_getFpsRange( + session, camera_config, out_min_fps, out_max_fps); +} + void ArCameraConfig_getImageDimensions(const ArSession* session, const ArCameraConfig* camera_config, int32_t* out_width,
diff --git a/device/vr/openxr/openxr_render_loop.cc b/device/vr/openxr/openxr_render_loop.cc index de8f53b..f9bc09f 100644 --- a/device/vr/openxr/openxr_render_loop.cc +++ b/device/vr/openxr/openxr_render_loop.cc
@@ -58,21 +58,14 @@ frame_data->pose->position = position; } + UpdateStageParameters(); + bool updated_eye_parameters = UpdateEyeParameters(); if (updated_eye_parameters) { frame_data->left_eye = current_display_info_->left_eye.Clone(); frame_data->right_eye = current_display_info_->right_eye.Clone(); - } - bool updated_stage_parameters = UpdateStageParameters(); - if (updated_stage_parameters) { - frame_data->stage_parameters_updated = true; - frame_data->stage_parameters = - current_display_info_->stage_parameters.Clone(); - } - - if (updated_eye_parameters || updated_stage_parameters) { main_thread_task_runner_->PostTask( FROM_HERE, base::BindOnce(on_display_info_changed_, current_display_info_.Clone())); @@ -241,38 +234,21 @@ return changed; } -bool OpenXrRenderLoop::UpdateStageParameters() { - bool changed = false; +void OpenXrRenderLoop::UpdateStageParameters() { XrExtent2Df stage_bounds; gfx::Transform local_from_stage; if (openxr_->GetStageParameters(&stage_bounds, &local_from_stage)) { - if (!current_display_info_->stage_parameters) { - current_display_info_->stage_parameters = mojom::VRStageParameters::New(); - changed = true; - } - - if (current_stage_bounds_.width != stage_bounds.width || - current_stage_bounds_.height != stage_bounds.height) { - current_display_info_->stage_parameters->bounds = - vr_utils::GetStageBoundsFromSize(stage_bounds.width, - stage_bounds.height); - changed = true; - } - + mojom::VRStageParametersPtr stage_parameters = + mojom::VRStageParameters::New(); // mojo_from_local is identity, as is stage_from_floor, so we can directly - // compare and assign local_from_stage and mojo_from_floor. - if (current_display_info_->stage_parameters->mojo_from_floor != - local_from_stage) { - current_display_info_->stage_parameters->mojo_from_floor = - local_from_stage; - changed = true; - } - } else if (current_display_info_->stage_parameters) { - current_display_info_->stage_parameters = nullptr; - changed = true; + // assign local_from_stage and mojo_from_floor. + stage_parameters->mojo_from_floor = local_from_stage; + stage_parameters->bounds = vr_utils::GetStageBoundsFromSize( + stage_bounds.width, stage_bounds.height); + SetStageParameters(std::move(stage_parameters)); + } else { + SetStageParameters(nullptr); } - - return changed; } } // namespace device
diff --git a/device/vr/openxr/openxr_render_loop.h b/device/vr/openxr/openxr_render_loop.h index 2082cf1..030544b 100644 --- a/device/vr/openxr/openxr_render_loop.h +++ b/device/vr/openxr/openxr_render_loop.h
@@ -45,14 +45,13 @@ bool UpdateEye(const XrView& view_head, const gfx::Size& view_size, mojom::VREyeParametersPtr* eye) const; - bool UpdateStageParameters(); + void UpdateStageParameters(); // Owned by OpenXrStatics XrInstance instance_; std::unique_ptr<OpenXrApiWrapper> openxr_; std::unique_ptr<OpenXRInputHelper> input_helper_; - XrExtent2Df current_stage_bounds_; base::RepeatingCallback<void(mojom::VRDisplayInfoPtr)> on_display_info_changed_;
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom index b355f51..fb35307 100644 --- a/device/vr/public/mojom/vr_service.mojom +++ b/device/vr/public/mojom/vr_service.mojom
@@ -316,7 +316,6 @@ }; struct VRDisplayInfo { - VRStageParameters? stage_parameters; // Parameters required to distort a scene for viewing in a VR headset. Only // required for devices which have the can_present capability. VREyeParameters? left_eye; @@ -647,8 +646,9 @@ // periodically. However, setting the stage parameters to null is perfectly // valid in some cases (e.g. we've lost tracking), so we can't just use // whether they are present or not to indicate that they have been updated - // so we have an extra flag to indicate to us that they have been updated. - bool stage_parameters_updated; + // so we compare IDs against the value sent in the XRFrameDataRequestOptions + // to determine when updates are needed. + uint32 stage_parameters_id; VRStageParameters? stage_parameters; // Detected plane information. Only present if plane detection is enabled. @@ -898,6 +898,12 @@ // Controls whether |XRFrameData.light_estimation_data| should be populated // by the request to |XRFrameDataProvider.GetFrameData()|. bool include_lighting_estimation_data; + + // The ID of the last known stage parameters set sent to the requesting + // session. The XRFrameData should only send new stage parameters if it has + // a higher ID. (Zero would indicate that the stage parameters should always + // sent.) + uint32 stage_parameters_id; }; // Provides the necessary functionality for a WebXR session to get data for
diff --git a/device/vr/windows/compositor_base.cc b/device/vr/windows/compositor_base.cc index b2bdc98..4d3b5d8 100644 --- a/device/vr/windows/compositor_base.cc +++ b/device/vr/windows/compositor_base.cc
@@ -289,6 +289,20 @@ } } +void XRCompositorCommon::SetStageParameters( + mojom::VRStageParametersPtr stage_parameters) { + // If the stage parameters are identical no need to update them. + if ((!current_stage_parameters_ && !stage_parameters) || + (current_stage_parameters_ && stage_parameters && + current_stage_parameters_.Equals(stage_parameters))) { + return; + } + + // If they have changed, increment the ID and save the new parameters. + stage_parameters_id_++; + current_stage_parameters_ = std::move(stage_parameters); +} + void XRCompositorCommon::Init() {} void XRCompositorCommon::StartPendingFrame() { @@ -338,6 +352,14 @@ pending_frame_->webxr_has_pose_ = true; pending_frame_->sent_frame_data_time_ = base::TimeTicks::Now(); + // If the stage parameters have been updated since the last frame that was + // sent, send the updated values. + pending_frame_->frame_data_->stage_parameters_id = stage_parameters_id_; + if (options->stage_parameters_id != stage_parameters_id_) { + pending_frame_->frame_data_->stage_parameters = + current_stage_parameters_.Clone(); + } + // Yield here to let the event queue process pending mojo messages, // specifically the next gamepad callback request that's likely to // have been sent during WaitGetPoses.
diff --git a/device/vr/windows/compositor_base.h b/device/vr/windows/compositor_base.h index 375fc124..ea3288e 100644 --- a/device/vr/windows/compositor_base.h +++ b/device/vr/windows/compositor_base.h
@@ -80,6 +80,7 @@ protected: virtual bool UsesInputEventing(); void SetVisibilityState(mojom::XRVisibilityState visibility_state); + void SetStageParameters(mojom::VRStageParametersPtr stage_parameters); #if defined(OS_WIN) D3D11TextureHelper texture_helper_; #endif @@ -185,6 +186,8 @@ mojo::Receiver<mojom::ImmersiveOverlay> overlay_receiver_{this}; mojom::XRVisibilityState visibility_state_ = mojom::XRVisibilityState::VISIBLE; + mojom::VRStageParametersPtr current_stage_parameters_; + uint32_t stage_parameters_id_; DISALLOW_COPY_AND_ASSIGN(XRCompositorCommon); };
diff --git a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc index 77d83ab1..1d411e7 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc +++ b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
@@ -727,16 +727,12 @@ // SpatialStageFrameOfReference.CurrentChanged to also re-calculate this. bool changed = false; if (stage_transform_needs_updating_) { - if (!(stage_origin_ && anchor_origin_) && - current_display_info_->stage_parameters) { + if (!(stage_origin_ && anchor_origin_) && current_stage_parameters_) { changed = true; - current_display_info_->stage_parameters = nullptr; + current_stage_parameters_ = nullptr; } else if (stage_origin_ && anchor_origin_) { changed = true; - current_display_info_->stage_parameters = nullptr; - - mojom::VRStageParametersPtr stage_parameters = - mojom::VRStageParameters::New(); + current_stage_parameters_ = nullptr; Matrix4x4 stage_to_origin; if (!stage_origin_->TryGetTransformTo(anchor_origin_.get(), @@ -748,18 +744,17 @@ return changed; } - stage_parameters->mojo_from_floor = + current_stage_parameters_ = mojom::VRStageParameters::New(); + current_stage_parameters_->mojo_from_floor = ConvertToGfxTransform(stage_to_origin); - - current_display_info_->stage_parameters = std::move(stage_parameters); } stage_transform_needs_updating_ = false; } EnsureStageBounds(); - if (bounds_updated_ && current_display_info_->stage_parameters) { - current_display_info_->stage_parameters->bounds = bounds_; + if (bounds_updated_ && current_stage_parameters_) { + current_stage_parameters_->bounds = bounds_; changed = true; bounds_updated_ = false; } @@ -860,8 +855,7 @@ bool stage_parameters_updated = UpdateStageParameters(); if (stage_parameters_updated) { - ret->stage_parameters_updated = true; - ret->stage_parameters = current_display_info_->stage_parameters.Clone(); + SetStageParameters(current_stage_parameters_.Clone()); } if (send_new_display_info || stage_parameters_updated) {
diff --git a/device/vr/windows_mixed_reality/mixed_reality_renderloop.h b/device/vr/windows_mixed_reality/mixed_reality_renderloop.h index 512478b..e00a557f 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_renderloop.h +++ b/device/vr/windows_mixed_reality/mixed_reality_renderloop.h
@@ -103,6 +103,7 @@ std::unique_ptr<MixedRealityWindow> window_; mojom::VRDisplayInfoPtr current_display_info_; + mojom::VRStageParametersPtr current_stage_parameters_; base::RepeatingCallback<void(mojom::VRDisplayInfoPtr)> on_display_info_changed_;
diff --git a/fuchsia/engine/browser/accessibility_bridge.cc b/fuchsia/engine/browser/accessibility_bridge.cc index 8463885..04b51c1 100644 --- a/fuchsia/engine/browser/accessibility_bridge.cc +++ b/fuchsia/engine/browser/accessibility_bridge.cc
@@ -220,9 +220,8 @@ // deleted are already gone, which means that all updates collected here in // |to_update_| are going to be executed after |to_delete_|. for (const ui::AXTreeObserver::Change& change : changes) { - ui::AXNodeData ax_data = change.node->data(); - ax_data.id = ConvertToFuchsiaNodeId(change.node->id(), root_id_); - to_update_.push_back(AXNodeDataToSemanticNode(ax_data)); + to_update_.push_back( + AXNodeDataToSemanticNode(change.node->data(), root_id_)); } // TODO(https://crbug.com/1134737): Separate updates of atomic updates and // don't allow all of them to be in the same commit.
diff --git a/fuchsia/engine/browser/ax_tree_converter.cc b/fuchsia/engine/browser/ax_tree_converter.cc index da2b25e0..7aca168 100644 --- a/fuchsia/engine/browser/ax_tree_converter.cc +++ b/fuchsia/engine/browser/ax_tree_converter.cc
@@ -175,11 +175,12 @@ return fuchsia_actions; } -std::vector<uint32_t> ConvertChildIds(std::vector<int32_t> ids) { +std::vector<uint32_t> ConvertChildIds(std::vector<int32_t> ids, + int32_t ax_root_id) { std::vector<uint32_t> child_ids; child_ids.reserve(ids.size()); for (auto i : ids) { - child_ids.push_back(base::checked_cast<uint32_t>(i)); + child_ids.push_back(ConvertToFuchsiaNodeId(i, ax_root_id)); } return child_ids; } @@ -207,14 +208,15 @@ } // namespace fuchsia::accessibility::semantics::Node AXNodeDataToSemanticNode( - const ui::AXNodeData& node) { + const ui::AXNodeData& node, + int32_t ax_root_id) { fuchsia::accessibility::semantics::Node fuchsia_node; - fuchsia_node.set_node_id(base::checked_cast<uint32_t>(node.id)); + fuchsia_node.set_node_id(ConvertToFuchsiaNodeId(node.id, ax_root_id)); fuchsia_node.set_role(AxRoleToFuchsiaSemanticRole(node.role)); fuchsia_node.set_states(ConvertStates(node)); fuchsia_node.set_attributes(ConvertAttributes(node)); fuchsia_node.set_actions(ConvertActions(node)); - fuchsia_node.set_child_ids(ConvertChildIds(node.child_ids)); + fuchsia_node.set_child_ids(ConvertChildIds(node.child_ids, ax_root_id)); fuchsia_node.set_location(ConvertBoundingBox(node.relative_bounds.bounds)); if (node.relative_bounds.transform) { fuchsia_node.set_transform(
diff --git a/fuchsia/engine/browser/ax_tree_converter.h b/fuchsia/engine/browser/ax_tree_converter.h index bdb8e6e..5b3a5835 100644 --- a/fuchsia/engine/browser/ax_tree_converter.h +++ b/fuchsia/engine/browser/ax_tree_converter.h
@@ -16,7 +16,7 @@ // present. Those that are will be converted. The Fuchsia SemanticsManager // accepts partial updates, so |node| does not require all fields to be set. WEB_ENGINE_EXPORT fuchsia::accessibility::semantics::Node -AXNodeDataToSemanticNode(const ui::AXNodeData& node); +AXNodeDataToSemanticNode(const ui::AXNodeData& node, int32_t ax_root_id); // Converts Fuchsia action of type |fuchsia_action| to an ax::mojom::Action of // type |mojom_action|. Function will return true if |fuchsia_action| is
diff --git a/fuchsia/engine/browser/ax_tree_converter_unittest.cc b/fuchsia/engine/browser/ax_tree_converter_unittest.cc index 00c9a9ec..40b9068 100644 --- a/fuchsia/engine/browser/ax_tree_converter_unittest.cc +++ b/fuchsia/engine/browser/ax_tree_converter_unittest.cc
@@ -42,9 +42,7 @@ base::StringPiece description, ax::mojom::CheckedState checked_state) { ui::AXNodeData node; - // Important! ID must be set to zero here because its default value (-1), will - // fail when getting converted to an unsigned int (Fuchsia's ID format). - node.id = 0; + node.id = 2; node.role = role; node.AddAction(action); node.AddIntAttribute(ax::mojom::IntAttribute::kCheckedState, @@ -129,10 +127,7 @@ auto& source_node_data = nodes.first; auto& expected_node = nodes.second; - auto converted_node = AXNodeDataToSemanticNode(source_node_data); - EXPECT_EQ(ConvertToFuchsiaNodeId(source_node_data.id, kRootId), - converted_node.node_id()); - + auto converted_node = AXNodeDataToSemanticNode(source_node_data, kRootId); EXPECT_TRUE(fidl::Equals(converted_node, expected_node)); } @@ -145,16 +140,15 @@ source_node_data.role = ax::mojom::Role::kImage; source_node_data.AddStringAttribute(ax::mojom::StringAttribute::kValue, kValue1); - auto converted_node = AXNodeDataToSemanticNode(source_node_data); - EXPECT_EQ(static_cast<uint32_t>(source_node_data.id), - converted_node.node_id()); + auto converted_node = AXNodeDataToSemanticNode(source_node_data, kRootId); Node expected_node; - expected_node.set_node_id(static_cast<uint32_t>(source_node_data.id)); + expected_node.set_node_id( + ConvertToFuchsiaNodeId(source_node_data.id, kRootId)); expected_node.set_actions( std::vector<Action>{Action::SET_FOCUS, Action::SET_VALUE}); expected_node.set_child_ids( - std::vector<uint32_t>{static_cast<uint32_t>(kChildId1)}); + std::vector<uint32_t>{ConvertToFuchsiaNodeId(kChildId1, kRootId)}); expected_node.set_role(Role::IMAGE); States states; states.set_hidden(false); @@ -178,9 +172,7 @@ ax::mojom::Role::kHeader, ax::mojom::Action::kSetValue, std::vector<int32_t>{kChildId1, kChildId2, kChildId3}, relative_bounds, kLabel1, kDescription1, ax::mojom::CheckedState::kFalse); - auto converted_node = AXNodeDataToSemanticNode(source_node_data); - EXPECT_EQ(static_cast<uint32_t>(source_node_data.id), - converted_node.node_id()); + auto converted_node = AXNodeDataToSemanticNode(source_node_data, kRootId); Attributes attributes; attributes.set_label(kLabel1); @@ -206,13 +198,13 @@ auto modified_node_data = source_node_data; modified_node_data.AddStringAttribute(ax::mojom::StringAttribute::kName, kLabel2); - converted_node = AXNodeDataToSemanticNode(modified_node_data); + converted_node = AXNodeDataToSemanticNode(modified_node_data, kRootId); EXPECT_FALSE(fidl::Equals(converted_node, expected_node)); // The same as above, this time changing |child_ids|. modified_node_data = source_node_data; modified_node_data.child_ids = std::vector<int32_t>{}; - converted_node = AXNodeDataToSemanticNode(modified_node_data); + converted_node = AXNodeDataToSemanticNode(modified_node_data, kRootId); EXPECT_FALSE(fidl::Equals(converted_node, expected_node)); } @@ -228,7 +220,7 @@ expected_node.mutable_actions()->begin(), fuchsia::accessibility::semantics::Action::DEFAULT); - auto converted_node = AXNodeDataToSemanticNode(source_node_data); + auto converted_node = AXNodeDataToSemanticNode(source_node_data, kRootId); EXPECT_EQ(ConvertToFuchsiaNodeId(source_node_data.id, kRootId), converted_node.node_id()); @@ -255,39 +247,39 @@ node.id = 0; node.role = ax::mojom::Role::kButton; EXPECT_EQ(fuchsia::accessibility::semantics::Role::BUTTON, - AXNodeDataToSemanticNode(node).role()); + AXNodeDataToSemanticNode(node, kRootId).role()); node.role = ax::mojom::Role::kCheckBox; EXPECT_EQ(fuchsia::accessibility::semantics::Role::CHECK_BOX, - AXNodeDataToSemanticNode(node).role()); + AXNodeDataToSemanticNode(node, kRootId).role()); node.role = ax::mojom::Role::kHeader; EXPECT_EQ(fuchsia::accessibility::semantics::Role::HEADER, - AXNodeDataToSemanticNode(node).role()); + AXNodeDataToSemanticNode(node, kRootId).role()); node.role = ax::mojom::Role::kImage; EXPECT_EQ(fuchsia::accessibility::semantics::Role::IMAGE, - AXNodeDataToSemanticNode(node).role()); + AXNodeDataToSemanticNode(node, kRootId).role()); node.role = ax::mojom::Role::kLink; EXPECT_EQ(fuchsia::accessibility::semantics::Role::LINK, - AXNodeDataToSemanticNode(node).role()); + AXNodeDataToSemanticNode(node, kRootId).role()); node.role = ax::mojom::Role::kRadioButton; EXPECT_EQ(fuchsia::accessibility::semantics::Role::RADIO_BUTTON, - AXNodeDataToSemanticNode(node).role()); + AXNodeDataToSemanticNode(node, kRootId).role()); node.role = ax::mojom::Role::kSlider; EXPECT_EQ(fuchsia::accessibility::semantics::Role::SLIDER, - AXNodeDataToSemanticNode(node).role()); + AXNodeDataToSemanticNode(node, kRootId).role()); node.role = ax::mojom::Role::kTextField; EXPECT_EQ(fuchsia::accessibility::semantics::Role::TEXT_FIELD, - AXNodeDataToSemanticNode(node).role()); + AXNodeDataToSemanticNode(node, kRootId).role()); node.role = ax::mojom::Role::kStaticText; EXPECT_EQ(fuchsia::accessibility::semantics::Role::STATIC_TEXT, - AXNodeDataToSemanticNode(node).role()); + AXNodeDataToSemanticNode(node, kRootId).role()); } } // namespace
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index d51c538..e81d54d9 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -1562,12 +1562,6 @@ validators_.g_l_state.AddValue(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT); } -#if !defined(OS_MAC) - if (workarounds_.ignore_egl_sync_failures) { - gl::GLFenceEGL::SetIgnoreFailures(); - } -#endif - if (workarounds_.avoid_egl_image_target_texture_reuse) { TextureDefinition::AvoidEGLTargetTextureReuse(); }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 2d5ca43..455f452 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -3955,8 +3955,7 @@ // always enabled and there is no way to disable it. // Therefore, it seems OK to also always enable it on top of Desktop GL for // both ES2 and ES3 contexts. - if (!workarounds().disable_texture_cube_map_seamless && - gl_version_info().IsAtLeastGL(3, 2)) { + if (gl_version_info().IsAtLeastGL(3, 2)) { api()->glEnableFn(GL_TEXTURE_CUBE_MAP_SEAMLESS); } @@ -6404,7 +6403,7 @@ state_.viewport_width, state_.viewport_height); } - if (workarounds().restore_scissor_on_fbo_change || supports_dc_layers_) { + if (supports_dc_layers_) { // The driver forgets the correct scissor when modifying the FBO binding. gfx::Vector2d scissor_offset = GetBoundFramebufferDrawOffset(); api()->glScissorFn(state_.scissor_x + scissor_offset.x(), @@ -6412,12 +6411,6 @@ state_.scissor_width, state_.scissor_height); } - if (workarounds().restore_scissor_on_fbo_change) { - // crbug.com/222018 - Also on QualComm, the flush here avoids flicker, - // it's unclear how this bug works. - api()->glFlushFn(); - } - if (workarounds().force_update_scissor_state_when_binding_fbo0 && GetBoundDrawFramebufferServiceId() == 0) { // The theory is that FBO0 keeps some internal (in HW regs maybe?) scissor
diff --git a/gpu/command_buffer/service/skia_utils.cc b/gpu/command_buffer/service/skia_utils.cc index aad43a38..c8f00902 100644 --- a/gpu/command_buffer/service/skia_utils.cc +++ b/gpu/command_buffer/service/skia_utils.cc
@@ -61,7 +61,7 @@ auto* fence_helper = context_state->vk_context_provider()->GetDeviceQueue()->GetFenceHelper(); fence_helper->EnqueueCleanupTaskForSubmittedWork(base::BindOnce( - [](const sk_sp<GrContext>& gr_context, sk_sp<T> sk_object, + [](const sk_sp<GrDirectContext>& gr_context, sk_sp<T> sk_object, gpu::VulkanDeviceQueue* device_queue, bool is_lost) {}, sk_ref_sp(context_state->gr_context()), std::move(sk_object))); #endif @@ -180,8 +180,9 @@ auto* fence_helper = context_state->vk_context_provider()->GetDeviceQueue()->GetFenceHelper(); fence_helper->EnqueueCleanupTaskForSubmittedWork(base::BindOnce( - [](const sk_sp<GrContext>& gr_context, GrBackendTexture backend_texture, - gpu::VulkanDeviceQueue* device_queue, bool is_lost) { + [](const sk_sp<GrDirectContext>& gr_context, + GrBackendTexture backend_texture, gpu::VulkanDeviceQueue* device_queue, + bool is_lost) { if (!gr_context->abandoned()) gr_context->deleteBackendTexture(std::move(backend_texture)); },
diff --git a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc index 4bde2434..5b7a3855 100644 --- a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc +++ b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
@@ -604,13 +604,7 @@ GLManager::Options options; options.context_type = CONTEXT_TYPE_OPENGLES3; options.size = gfx::Size(64, 64); - GpuDriverBugWorkarounds workarounds; -#if defined(OS_MAC) - // Sampling of seamless integer cube map texture has bug on Intel GEN7 gpus - // on Mac OSX, see crbug.com/658930. - workarounds.disable_texture_cube_map_seamless = true; -#endif - gl_.InitializeWithWorkarounds(options, workarounds); + gl_.Initialize(options); width_ = 8; height_ = 8;
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json index 0f76791..0696765 100644 --- a/gpu/config/gpu_driver_bug_list.json +++ b/gpu/config/gpu_driver_bug_list.json
@@ -947,19 +947,6 @@ ] }, { - "id": 129, - "comment": "TODO(dshwang): Fix ANGLE crash. crbug.com/518889", - "description": "ANGLE crash on glReadPixels from incomplete cube map texture", - "cr_bugs": [518889], - "os": { - "type": "win" - }, - "gl_renderer": "ANGLE.*", - "features": [ - "force_cube_complete" - ] - }, - { "id": 130, "description": "NVIDIA fails glReadPixels from incomplete cube map texture", "cr_bugs": [518889], @@ -1096,17 +1083,6 @@ "disabled_extensions": ["GL_EXT_sRGB"] }, { - "id": 141, - "cr_bugs": [570897], - "description": "Framebuffer discarding can hurt performance on non-tilers", - "os": { - "type": "win" - }, - "features": [ - "disable_discard_framebuffer" - ] - }, - { "id": 142, "cr_bugs": [563714], "description": "Pack parameters work incorrectly with pack buffer bound", @@ -3444,6 +3420,9 @@ "id": 343, "description": "Disable using GPU backed resource for imageBitmap from video on d3d9", "cr_bugs": [1098445, 1105923], + "os": { + "type": "win" + }, "gl_renderer": ".*Direct3D9.*", "features": [ "disable_imagebitmap_from_video_using_gpu"
diff --git a/gpu/config/gpu_driver_bug_workarounds.cc b/gpu/config/gpu_driver_bug_workarounds.cc index edd956b..707e5f6 100644 --- a/gpu/config/gpu_driver_bug_workarounds.cc +++ b/gpu/config/gpu_driver_bug_workarounds.cc
@@ -31,8 +31,6 @@ if (workarounds->max_copy_texture_chromium_size_1048576) workarounds->max_copy_texture_chromium_size = 1048576; - if (workarounds->max_copy_texture_chromium_size_262144) - workarounds->max_copy_texture_chromium_size = 262144; if (workarounds->max_3d_array_texture_size_1024) workarounds->max_3d_array_texture_size = 1024;
diff --git a/gpu/config/gpu_workaround_list.txt b/gpu/config/gpu_workaround_list.txt index 19576d1..5233bf15 100644 --- a/gpu/config/gpu_workaround_list.txt +++ b/gpu/config/gpu_workaround_list.txt
@@ -48,7 +48,6 @@ disable_program_caching_for_transform_feedback disable_program_disk_cache disable_software_to_accelerated_canvas_upgrade -disable_texture_cube_map_seamless disable_texture_storage disable_timestamp_queries disable_vp_scaling @@ -79,7 +78,6 @@ force_update_scissor_state_when_binding_fbo0 get_frag_data_info_bug gl_clear_broken -ignore_egl_sync_failures init_gl_position_in_vertex_shader init_one_cube_map_level_before_copyteximage init_texture_max_anisotropy @@ -88,7 +86,6 @@ limit_d3d11_video_decoder_to_11_0 max_3d_array_texture_size_1024 max_copy_texture_chromium_size_1048576 -max_copy_texture_chromium_size_262144 max_msaa_sample_count_2 max_msaa_sample_count_4 max_texture_size_limit_4096 @@ -125,7 +122,6 @@ use_copyteximage2d_instead_of_readpixels_on_multisampled_textures use_empty_video_hdr_metadata use_eqaa_storage_samples_2 -use_es2_for_oopr use_gpu_driver_workaround_for_testing use_intermediary_for_copy_texture_image use_non_zero_size_for_client_side_stream_buffers
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg index 794a6d19..e5c48ea4 100644 --- a/infra/config/generated/cr-buildbucket.cfg +++ b/infra/config/generated/cr-buildbucket.cfg
@@ -27946,17 +27946,13 @@ cipd_version: "refs/heads/master" cmd: "recipes" } - properties: "{\"$build/goma\":{\"use_luci_auth\":true},\"$depot_tools/osx_sdk\":{\"sdk_version\":\"9a235\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"tryserver.chromium.mac\",\"recipe\":\"chromium_upload_clang\"}" + properties: "{\"$build/goma\":{\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"tryserver.chromium.mac\",\"recipe\":\"chromium_upload_clang\"}" execution_timeout_secs: 21600 expiration_secs: 7200 caches { name: "win_toolchain" path: "win_toolchain" } - caches { - name: "xcode_mac_9a235" - path: "xcode_mac_9a235.app" - } build_numbers: YES service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" task_template_canary_percentage {
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star index e82f77f..6ada4194 100644 --- a/infra/config/subprojects/chromium/try.star +++ b/infra/config/subprojects/chromium/try.star
@@ -1198,20 +1198,9 @@ try_.chromium_mac_builder( name = "mac_upload_clang", builderless = False, - caches = [ - swarming.cache( - name = "xcode_mac_9a235", - path = "xcode_mac_9a235.app", - ), - ], executable = "recipe:chromium_upload_clang", execution_timeout = 6 * time.hour, goma_backend = None, # Does not use Goma. - properties = { - "$depot_tools/osx_sdk": { - "sdk_version": "9a235", - }, - }, ) try_.chromium_mac_ios_builder(
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn index 0d8e07f..24b0f66 100644 --- a/ios/chrome/app/application_delegate/BUILD.gn +++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -203,6 +203,7 @@ "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/main", "//ios/chrome/browser/ui/main:scene", + "//ios/chrome/browser/ui/ntp:util", "//ios/chrome/browser/ui/safe_mode", "//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util:multiwindow_util",
diff --git a/ios/chrome/app/application_delegate/metrics_mediator.mm b/ios/chrome/app/application_delegate/metrics_mediator.mm index a099cec9..56f16685 100644 --- a/ios/chrome/app/application_delegate/metrics_mediator.mm +++ b/ios/chrome/app/application_delegate/metrics_mediator.mm
@@ -32,6 +32,7 @@ #import "ios/chrome/browser/ui/main/browser_interface_provider.h" #import "ios/chrome/browser/ui/main/connection_information.h" #import "ios/chrome/browser/ui/main/scene_state.h" +#import "ios/chrome/browser/ui/ntp/ntp_util.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #include "ios/chrome/common/app_group/app_group_metrics_mainapp.h" #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" @@ -110,6 +111,10 @@ + (void)recordNumTabAtStartup:(int)numTabs; // Logs the number of tabs with UMAHistogramCount100 and allows testing. + (void)recordNumTabAtResume:(int)numTabs; +// Logs the number of NTP tabs with UMAHistogramCount100 and allows testing. ++ (void)recordNumNTPTabAtStartup:(int)numTabs; +// Logs the number of NTP tabs with UMAHistogramCount100 and allows testing. ++ (void)recordNumNTPTabAtResume:(int)numTabs; @end @@ -150,6 +155,7 @@ (id<StartupInformation>)startupInformation connectedScenes:(NSArray<SceneState*>*)scenes { int numTabs = 0; + int numNTPTabs = 0; for (SceneState* scene in scenes) { if (!scene.interfaceProvider) { // The scene might not yet be initiated. @@ -157,14 +163,23 @@ // counted in sessions instead of scenes. continue; } - numTabs += scene.interfaceProvider.mainInterface.browser->GetWebStateList() - ->count(); + + const WebStateList* web_state_list = + scene.interfaceProvider.mainInterface.browser->GetWebStateList(); + numTabs += web_state_list->count(); + for (int i = 0; i < web_state_list->count(); i++) { + if (IsURLNewTabPage(web_state_list->GetWebStateAt(i)->GetVisibleURL())) { + numNTPTabs++; + } + } } if (startupInformation.isColdStart) { [self recordNumTabAtStartup:numTabs]; + [self recordNumNTPTabAtStartup:numNTPTabs]; } else { [self recordNumTabAtResume:numTabs]; + [self recordNumNTPTabAtResume:numNTPTabs]; } if (UIAccessibilityIsVoiceOverRunning()) { @@ -427,6 +442,14 @@ base::UmaHistogramCounts100("Tabs.CountAtResume", numTabs); } ++ (void)recordNumNTPTabAtStartup:(int)numTabs { + base::UmaHistogramCounts100("Tabs.NTPCountAtStartup", numTabs); +} + ++ (void)recordNumNTPTabAtResume:(int)numTabs { + base::UmaHistogramCounts100("Tabs.NTPCountAtResume", numTabs); +} + - (void)setBreakpadUploadingEnabled:(BOOL)enableUploading { breakpad_helper::SetUploadingEnabled(enableUploading); }
diff --git a/ios/chrome/app/application_delegate/metrics_mediator_testing.h b/ios/chrome/app/application_delegate/metrics_mediator_testing.h index 1e470ef..5fad2be6 100644 --- a/ios/chrome/app/application_delegate/metrics_mediator_testing.h +++ b/ios/chrome/app/application_delegate/metrics_mediator_testing.h
@@ -15,6 +15,8 @@ - (BOOL)isMetricsReportingEnabledWifiOnly; + (void)recordNumTabAtStartup:(int)numTabs; + (void)recordNumTabAtResume:(int)numTabs; ++ (void)recordNumNTPTabAtStartup:(int)numTabs; ++ (void)recordNumNTPTabAtResume:(int)numTabs; @end #endif // IOS_CHROME_APP_APPLICATION_DELEGATE_METRICS_MEDIATOR_TESTING_H_
diff --git a/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm b/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm index 121fcd3d..8174380 100644 --- a/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm +++ b/ios/chrome/app/application_delegate/metrics_mediator_unittest.mm
@@ -10,6 +10,7 @@ #include "components/metrics/metrics_service.h" #import "ios/chrome/app/application_delegate/startup_information.h" #include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/chrome_url_constants.h" #import "ios/chrome/browser/main/test_browser.h" #import "ios/chrome/browser/metrics/previous_session_info.h" #import "ios/chrome/browser/metrics/previous_session_info_private.h" @@ -132,36 +133,55 @@ // A block that takes as arguments the caller and the arguments from // UserActivityHandler +handleStartupParameters and returns nothing. -typedef void (^logLaunchMetricsBlock)(id, const char*, int); +typedef void (^LogLaunchMetricsBlock)(id, const char*, int); class MetricsMediatorLogLaunchTest : public PlatformTest { protected: - MetricsMediatorLogLaunchTest() : has_been_called_(FALSE) {} + MetricsMediatorLogLaunchTest() + : num_tabs_has_been_called_(FALSE), + num_ntp_tabs_has_been_called_(FALSE) {} void initiateMetricsMediator(BOOL coldStart, int tabCount) { - swizzle_block_ = [^(id self, int numTab) { - has_been_called_ = YES; + num_tabs_swizzle_block_ = [^(id self, int numTab) { + num_tabs_has_been_called_ = YES; + // Tests. + EXPECT_EQ(tabCount, numTab); + } copy]; + num_ntp_tabs_swizzle_block_ = [^(id self, int numTab) { + num_ntp_tabs_has_been_called_ = YES; // Tests. EXPECT_EQ(tabCount, numTab); } copy]; if (coldStart) { - uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( + tabs_uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( [MetricsMediator class], @selector(recordNumTabAtStartup:), - swizzle_block_)); + num_tabs_swizzle_block_)); + ntp_tabs_uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( + [MetricsMediator class], @selector(recordNumNTPTabAtStartup:), + num_ntp_tabs_swizzle_block_)); } else { - uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( + tabs_uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( [MetricsMediator class], @selector(recordNumTabAtResume:), - swizzle_block_)); + num_tabs_swizzle_block_)); + ntp_tabs_uma_histogram_swizzler_.reset(new ScopedBlockSwizzler( + [MetricsMediator class], @selector(recordNumNTPTabAtResume:), + num_ntp_tabs_swizzle_block_)); } } - void verifySwizzleHasBeenCalled() { EXPECT_TRUE(has_been_called_); } + void verifySwizzleHasBeenCalled() { + EXPECT_TRUE(num_tabs_has_been_called_); + EXPECT_TRUE(num_ntp_tabs_has_been_called_); + } web::WebTaskEnvironment task_environment_; NSArray<FakeSceneState*>* connected_scenes_; - __block BOOL has_been_called_; - logLaunchMetricsBlock swizzle_block_; - std::unique_ptr<ScopedBlockSwizzler> uma_histogram_swizzler_; + __block BOOL num_tabs_has_been_called_; + __block BOOL num_ntp_tabs_has_been_called_; + LogLaunchMetricsBlock num_tabs_swizzle_block_; + LogLaunchMetricsBlock num_ntp_tabs_swizzle_block_; + std::unique_ptr<ScopedBlockSwizzler> tabs_uma_histogram_swizzler_; + std::unique_ptr<ScopedBlockSwizzler> ntp_tabs_uma_histogram_swizzler_; std::set<std::unique_ptr<TestBrowser>> browsers_; }; @@ -173,9 +193,12 @@ initiateMetricsMediator(coldStart, 23); // 23 tabs across three scenes. connected_scenes_ = [FakeSceneState sceneArrayWithCount:3]; - [connected_scenes_[0] appendWebStatesWithURL:GURL() count:9]; - [connected_scenes_[1] appendWebStatesWithURL:GURL() count:9]; - [connected_scenes_[2] appendWebStatesWithURL:GURL() count:5]; + [connected_scenes_[0] appendWebStatesWithURL:GURL(kChromeUINewTabURL) + count:9]; + [connected_scenes_[1] appendWebStatesWithURL:GURL(kChromeUINewTabURL) + count:9]; + [connected_scenes_[2] appendWebStatesWithURL:GURL(kChromeUINewTabURL) + count:5]; // Mark one of the scenes as active. connected_scenes_[0].activationLevel = SceneActivationLevelForegroundActive; @@ -211,11 +234,15 @@ initiateMetricsMediator(coldStart, 32); // 32 tabs across five scenes. connected_scenes_ = [FakeSceneState sceneArrayWithCount:5]; - [connected_scenes_[0] appendWebStatesWithURL:GURL() count:8]; - [connected_scenes_[1] appendWebStatesWithURL:GURL() count:8]; + [connected_scenes_[0] appendWebStatesWithURL:GURL(kChromeUINewTabURL) + count:8]; + [connected_scenes_[1] appendWebStatesWithURL:GURL(kChromeUINewTabURL) + count:8]; // Scene 2 has zero tabs. - [connected_scenes_[3] appendWebStatesWithURL:GURL() count:8]; - [connected_scenes_[4] appendWebStatesWithURL:GURL() count:8]; + [connected_scenes_[3] appendWebStatesWithURL:GURL(kChromeUINewTabURL) + count:8]; + [connected_scenes_[4] appendWebStatesWithURL:GURL(kChromeUINewTabURL) + count:8]; id startupInformation = [OCMockObject mockForProtocol:@protocol(StartupInformation)];
diff --git a/ios/chrome/browser/crash_report/BUILD.gn b/ios/chrome/browser/crash_report/BUILD.gn index 537b110..62923d5 100644 --- a/ios/chrome/browser/crash_report/BUILD.gn +++ b/ios/chrome/browser/crash_report/BUILD.gn
@@ -75,7 +75,6 @@ "//ios/chrome/browser/sessions:restoration_agent", "//ios/chrome/browser/sessions:serialisation", "//ios/chrome/browser/sessions:session_service", - "//ios/chrome/browser/ui/infobars:feature_flags", "//ios/chrome/browser/ui/main:scene_state_header", "//ios/chrome/browser/ui/util:multiwindow_util", "//ios/chrome/browser/web:tab_id_tab_helper",
diff --git a/ios/chrome/browser/crash_report/crash_restore_helper.mm b/ios/chrome/browser/crash_report/crash_restore_helper.mm index b404aec..d9ce0fa 100644 --- a/ios/chrome/browser/crash_report/crash_restore_helper.mm +++ b/ios/chrome/browser/crash_report/crash_restore_helper.mm
@@ -21,7 +21,6 @@ #include "components/strings/grit/components_strings.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/crash_report/breakpad_helper.h" -#include "ios/chrome/browser/infobars/confirm_infobar_controller.h" #include "ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #include "ios/chrome/browser/infobars/infobar_manager_impl.h" @@ -34,7 +33,6 @@ #import "ios/chrome/browser/sessions/session_restoration_browser_agent.h" #import "ios/chrome/browser/sessions/session_service_ios.h" #import "ios/chrome/browser/sessions/session_window_ios.h" -#import "ios/chrome/browser/ui/infobars/infobar_feature.h" #import "ios/chrome/browser/ui/main/scene_state.h" #import "ios/chrome/browser/ui/main/scene_state_browser_agent.h" #import "ios/chrome/browser/ui/util/multi_window_support.h" @@ -170,14 +168,8 @@ std::unique_ptr<ConfirmInfoBarDelegate> delegate( new SessionCrashedInfoBarDelegate(crash_restore_helper)); - std::unique_ptr<infobars::InfoBar> infobar; - if (IsCrashRestoreInfobarMessagesUIEnabled()) { - infobar = ::CreateHighPriorityConfirmInfoBar(std::move(delegate)); - } else { - ConfirmInfoBarController* controller = [[ConfirmInfoBarController alloc] - initWithInfoBarDelegate:delegate.get()]; - infobar = std::make_unique<InfoBarIOS>(controller, std::move(delegate)); - } + std::unique_ptr<infobars::InfoBar> infobar = + ::CreateHighPriorityConfirmInfoBar(std::move(delegate)); return !!infobar_manager->AddInfoBar(std::move(infobar)); }
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm index 062b18e..feff53e 100644 --- a/ios/chrome/browser/flags/about_flags.mm +++ b/ios/chrome/browser/flags/about_flags.mm
@@ -434,10 +434,6 @@ flag_descriptions::kEmbedderBlockRestoreUrlName, flag_descriptions::kEmbedderBlockRestoreUrlDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEmbedderBlockRestoreUrl)}, - {"messages-confirm-infobars", - flag_descriptions::kConfirmInfobarMessagesUIName, - flag_descriptions::kConfirmInfobarMessagesUIDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(kConfirmInfobarMessagesUI)}, {"disable-progress-bar-animation", flag_descriptions::kDisableProgressBarAnimationName, flag_descriptions::kDisableProgressBarAnimationDescription, @@ -466,20 +462,12 @@ {"use-js-error-page", flag_descriptions::kUseJSForErrorPageName, flag_descriptions::kUseJSForErrorPageDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(web::features::kUseJSForErrorPage)}, - {"messages-download-infobar", - flag_descriptions::kDownloadInfobarMessagesUIName, - flag_descriptions::kDownloadInfobarMessagesUIDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(kDownloadInfobarMessagesUI)}, {"desktop-version-default", flag_descriptions::kDefaultToDesktopOnIPadName, flag_descriptions::kDefaultToDesktopOnIPadDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(web::features::kUseDefaultUserAgentInWebClient)}, {"mobile-google-srp", flag_descriptions::kMobileGoogleSRPName, flag_descriptions::kMobileGoogleSRPDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(web::kMobileGoogleSRP)}, - {"messages-crash-restore-infobars", - flag_descriptions::kCrashRestoreInfobarMessagesUIName, - flag_descriptions::kCrashRestoreInfobarMessagesUIDescription, - flags_ui::kOsIos, FEATURE_VALUE_TYPE(kCrashRestoreInfobarMessagesUI)}, {"infobar-overlay-ui", flag_descriptions::kInfobarOverlayUIName, flag_descriptions::kInfobarOverlayUIDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kInfobarOverlayUI)}, @@ -579,10 +567,6 @@ {"illustrated-empty-states", flag_descriptions::kIllustratedEmptyStatesName, flag_descriptions::kIllustratedEmptyStatesDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kIllustratedEmptyStates)}, - {"messages-block-popup-infobars", - flag_descriptions::kBlockPopupInfobarMessagesUIName, - flag_descriptions::kBlockPopupInfobarMessagesUIDescription, - flags_ui::kOsIos, FEATURE_VALUE_TYPE(kBlockPopupInfobarMessagesUI)}, {"enable-native-context-menus", flag_descriptions::kEnableNativeContextMenusName, flag_descriptions::kEnableNativeContextMenusDescription, flags_ui::kOsIos,
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc index 2728798..0ccf38c4 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -115,12 +115,6 @@ "When enabled, Autofill logic uses unique numeric renderer IDs instead " "of string form and field identifiers in form filling logic."; -const char kBlockPopupInfobarMessagesUIName[] = - "Block Popup Infobars Messages UI"; -const char kBlockPopupInfobarMessagesUIDescription[] = - "When enabled Block Popup Infobars use the new Messages UI. " - "IOSInfobarUIReboot needs to be enabled as well for this to work."; - extern const char kLogBreadcrumbsName[] = "Log Breadcrumb Events"; extern const char kLogBreadcrumbsDescription[] = "When enabled, breadcrumb events will be logged."; @@ -144,15 +138,6 @@ "When enabled collections are presented using the new iOS13 card " "style."; -const char kConfirmInfobarMessagesUIName[] = "Confirm Infobars Messages UI"; -const char kConfirmInfobarMessagesUIDescription[] = - "When enabled Confirm Infobars use the new Messages UI."; - -const char kCrashRestoreInfobarMessagesUIName[] = - "Crash Restore Infobars Messages UI"; -const char kCrashRestoreInfobarMessagesUIDescription[] = - "When enabled Crash Restore Infobars use the new Messages UI."; - const char kCreditCardScannerName[] = "Enable the 'Use Camera' button"; const char kCreditCardScannerDescription[] = "Allow a user to scan a credit card using the credit card camera scanner." @@ -203,10 +188,6 @@ "When enabled, replaces articles feed with new content Suggestion Feed in " "the NTP."; -const char kDownloadInfobarMessagesUIName[] = "Download Infobars Messages UI"; -const char kDownloadInfobarMessagesUIDescription[] = - "When enabled Downloads use the new Messages UI."; - const char kDragAndDropName[] = "Drag and Drop"; const char kDragAndDropDescription[] = "Enable support for drag and drop.";
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h index 4ea0fa28c..5726cfb 100644 --- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -89,11 +89,6 @@ extern const char kAutofillUseRendererIDsName[]; extern const char kAutofillUseRendererIDsDescription[]; -// Title and description for the flag that enables Messages UI on -// Block Popup Infobars. -extern const char kBlockPopupInfobarMessagesUIName[]; -extern const char kBlockPopupInfobarMessagesUIDescription[]; - // Title and description for the flag that controls whether event breadcrumbs // are captured. extern const char kLogBreadcrumbsName[]; @@ -114,16 +109,6 @@ extern const char kCollectionsCardPresentationStyleName[]; extern const char kCollectionsCardPresentationStyleDescription[]; -// Title and description for the flag that enables Messages UI on -// ConfirmInfobars. -extern const char kConfirmInfobarMessagesUIName[]; -extern const char kConfirmInfobarMessagesUIDescription[]; - -// Title and description for the flag that enables Messages UI on -// Crash Restore Infobars. -extern const char kCrashRestoreInfobarMessagesUIName[]; -extern const char kCrashRestoreInfobarMessagesUIDescription[]; - // Title and description for the flag to scan a new credit card using the // camera. extern const char kCreditCardScannerName[]; @@ -170,10 +155,6 @@ extern const char kDiscoverFeedInNtpName[]; extern const char kDiscoverFeedInNtpDescription[]; -// Title and description for the flag to enable the Messages UI for downloads. -extern const char kDownloadInfobarMessagesUIName[]; -extern const char kDownloadInfobarMessagesUIDescription[]; - // Title and description for the flag to enable drag and drop. extern const char kDragAndDropName[]; extern const char kDragAndDropDescription[];
diff --git a/ios/chrome/browser/infobars/BUILD.gn b/ios/chrome/browser/infobars/BUILD.gn index 19bbcb64..28d2263 100644 --- a/ios/chrome/browser/infobars/BUILD.gn +++ b/ios/chrome/browser/infobars/BUILD.gn
@@ -5,9 +5,6 @@ source_set("infobars") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "confirm_infobar_controller+protected.h", - "confirm_infobar_controller.h", - "confirm_infobar_controller.mm", "infobar_container_ios.h", "infobar_container_ios.mm", "infobar_controller+protected.h",
diff --git a/ios/chrome/browser/infobars/confirm_infobar_controller+protected.h b/ios/chrome/browser/infobars/confirm_infobar_controller+protected.h deleted file mode 100644 index af13e0e..0000000 --- a/ios/chrome/browser/infobars/confirm_infobar_controller+protected.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_INFOBARS_CONFIRM_INFOBAR_CONTROLLER_PROTECTED_H_ -#define IOS_CHROME_BROWSER_INFOBARS_CONFIRM_INFOBAR_CONTROLLER_PROTECTED_H_ - -#import "ios/chrome/browser/infobars/confirm_infobar_controller.h" - -@class ConfirmInfoBarView; - -@interface ConfirmInfoBarController () - -// Overrides superclass property. -@property(nonatomic, readwrite) ConfirmInfoBarView* view; - -// Action for any of the user defined buttons. -- (void)infoBarButtonDidPress:(id)sender; -// Action for any of the user defined links. -- (void)infobarLinkDidPress:(NSUInteger)tag; -// Updates the label on the provided view. -- (void)updateInfobarLabel:(ConfirmInfoBarView*)view; - -@end - -#endif // IOS_CHROME_BROWSER_INFOBARS_CONFIRM_INFOBAR_CONTROLLER_PROTECTED_H_
diff --git a/ios/chrome/browser/infobars/confirm_infobar_controller.h b/ios/chrome/browser/infobars/confirm_infobar_controller.h deleted file mode 100644 index c705f615..0000000 --- a/ios/chrome/browser/infobars/confirm_infobar_controller.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_INFOBARS_CONFIRM_INFOBAR_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_INFOBARS_CONFIRM_INFOBAR_CONTROLLER_H_ - -#import "ios/chrome/browser/infobars/infobar_controller.h" - -class ConfirmInfoBarDelegate; - -@interface ConfirmInfoBarController : InfoBarController - -- (instancetype)initWithInfoBarDelegate:(ConfirmInfoBarDelegate*)infoBarDelegate - NS_DESIGNATED_INITIALIZER; - -@end - -#endif // IOS_CHROME_BROWSER_INFOBARS_CONFIRM_INFOBAR_CONTROLLER_H_
diff --git a/ios/chrome/browser/infobars/confirm_infobar_controller.mm b/ios/chrome/browser/infobars/confirm_infobar_controller.mm deleted file mode 100644 index 36189584..0000000 --- a/ios/chrome/browser/infobars/confirm_infobar_controller.mm +++ /dev/null
@@ -1,169 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/infobars/confirm_infobar_controller.h" - -#include "base/mac/foundation_util.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "components/infobars/core/confirm_infobar_delegate.h" -#import "ios/chrome/browser/infobars/infobar_controller+protected.h" -#include "ios/chrome/browser/infobars/infobar_controller_delegate.h" -#import "ios/chrome/browser/ui/infobars/confirm_infobar_view.h" -#include "ui/gfx/image/image.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -// UI Tags for the infobar elements. -typedef NS_ENUM(NSInteger, ConfirmInfoBarUITags) { - OK = 1, - CANCEL, - CLOSE, - TITLE_LINK -}; - -} // namespace - -#pragma mark - ConfirmInfoBarController - -@interface ConfirmInfoBarController () - -// Overrides superclass property. -@property(nonatomic, readonly) ConfirmInfoBarDelegate* infoBarDelegate; - -@property(nonatomic, weak) ConfirmInfoBarView* infoBarView; - -@end - -@implementation ConfirmInfoBarController - -@dynamic infoBarDelegate; -@synthesize infoBarView = _infoBarView; - -#pragma mark - -#pragma mark InfoBarController - -- (instancetype)initWithInfoBarDelegate: - (ConfirmInfoBarDelegate*)infoBarDelegate { - return [super initWithInfoBarDelegate:infoBarDelegate]; -} - -- (UIView*)infobarView { - ConfirmInfoBarView* infoBarView = - [[ConfirmInfoBarView alloc] initWithFrame:CGRectZero]; - _infoBarView = infoBarView; - // Model data. - gfx::Image modelIcon = self.infoBarDelegate->GetIcon(); - int buttons = self.infoBarDelegate->GetButtons(); - NSString* buttonOK = nil; - if (buttons & ConfirmInfoBarDelegate::BUTTON_OK) { - buttonOK = base::SysUTF16ToNSString(self.infoBarDelegate->GetButtonLabel( - ConfirmInfoBarDelegate::BUTTON_OK)); - } - NSString* buttonCancel = nil; - if (buttons & ConfirmInfoBarDelegate::BUTTON_CANCEL) { - buttonCancel = - base::SysUTF16ToNSString(self.infoBarDelegate->GetButtonLabel( - ConfirmInfoBarDelegate::BUTTON_CANCEL)); - } - - [infoBarView addCloseButtonWithTag:ConfirmInfoBarUITags::CLOSE - target:self - action:@selector(infoBarButtonDidPress:)]; - - // Optional left icon. - if (!modelIcon.IsEmpty()) - [infoBarView addLeftIcon:modelIcon.ToUIImage()]; - - // Optional message. - [self updateInfobarLabel:infoBarView]; - - if (buttonOK && buttonCancel) { - [infoBarView addButton1:buttonOK - tag1:ConfirmInfoBarUITags::OK - button2:buttonCancel - tag2:ConfirmInfoBarUITags::CANCEL - target:self - action:@selector(infoBarButtonDidPress:)]; - } else if (buttonOK) { - [infoBarView addButton:buttonOK - tag:ConfirmInfoBarUITags::OK - target:self - action:@selector(infoBarButtonDidPress:)]; - } else { - // No buttons, only message. - DCHECK(!self.infoBarDelegate->GetMessageText().empty() && !buttonCancel); - } - return infoBarView; -} - -- (void)updateInfobarLabel:(ConfirmInfoBarView*)view { - if (!self.infoBarDelegate->GetMessageText().length()) - return; - if (self.infoBarDelegate->GetLinkText().length()) { - base::string16 msgLink = base::SysNSStringToUTF16([[view class] - stringAsLink:base::SysUTF16ToNSString( - self.infoBarDelegate->GetLinkText()) - tag:ConfirmInfoBarUITags::TITLE_LINK]); - base::string16 messageText = self.infoBarDelegate->GetMessageText(); - base::ReplaceFirstSubstringAfterOffset( - &messageText, 0, self.infoBarDelegate->GetLinkText(), msgLink); - - __weak ConfirmInfoBarController* weakSelf = self; - [view addLabel:base::SysUTF16ToNSString(messageText) - action:^(NSUInteger tag) { - [weakSelf infobarLinkDidPress:tag]; - }]; - } else { - NSString* label = - base::SysUTF16ToNSString(self.infoBarDelegate->GetMessageText()); - [view addLabel:label]; - } -} - -#pragma mark - Handling of User Events - -- (void)infoBarButtonDidPress:(id)sender { - if ([self shouldIgnoreUserInteraction]) - return; - - NSUInteger buttonId = base::mac::ObjCCastStrict<UIButton>(sender).tag; - switch (buttonId) { - case ConfirmInfoBarUITags::OK: - if (self.infoBarDelegate->Accept()) { - self.delegate->RemoveInfoBar(); - } - break; - case ConfirmInfoBarUITags::CANCEL: - if (self.infoBarDelegate->Cancel()) { - self.delegate->RemoveInfoBar(); - } - break; - case ConfirmInfoBarUITags::CLOSE: - self.infoBarDelegate->InfoBarDismissed(); - self.delegate->RemoveInfoBar(); - break; - default: - NOTREACHED() << "Unexpected button pressed"; - break; - } -} - -// Title link was clicked. -- (void)infobarLinkDidPress:(NSUInteger)tag { - if ([self shouldIgnoreUserInteraction]) - return; - - DCHECK(tag == ConfirmInfoBarUITags::TITLE_LINK); - if (self.infoBarDelegate->LinkClicked( - WindowOpenDisposition::NEW_FOREGROUND_TAB)) { - self.delegate->RemoveInfoBar(); - } -} - -@end
diff --git a/ios/chrome/browser/infobars/infobar_utils.mm b/ios/chrome/browser/infobars/infobar_utils.mm index 5e80059e..8e88ae3e 100644 --- a/ios/chrome/browser/infobars/infobar_utils.mm +++ b/ios/chrome/browser/infobars/infobar_utils.mm
@@ -8,7 +8,6 @@ #include <utility> #include "components/infobars/core/confirm_infobar_delegate.h" -#include "ios/chrome/browser/infobars/confirm_infobar_controller.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #import "ios/chrome/browser/infobars/infobar_type.h" #import "ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.h" @@ -20,7 +19,6 @@ std::unique_ptr<infobars::InfoBar> CreateConfirmInfoBar( std::unique_ptr<ConfirmInfoBarDelegate> delegate) { - if (IsConfirmInfobarMessagesUIEnabled()) { // TODO(crbug.com/927064): Coordinators shouldn't be created at this level, // we should probably send only the delegate and have the presenting // Coordinator create the right Coordinator using that delegate. @@ -29,11 +27,6 @@ badgeSupport:NO type:InfobarType::kInfobarTypeConfirm]; return std::make_unique<InfoBarIOS>(coordinator, std::move(delegate)); - } else { - ConfirmInfoBarController* controller = [[ConfirmInfoBarController alloc] - initWithInfoBarDelegate:delegate.get()]; - return std::make_unique<InfoBarIOS>(controller, std::move(delegate)); - } } std::unique_ptr<infobars::InfoBar> CreateHighPriorityConfirmInfoBar(
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn index 2ec28a5f..6e35605b 100644 --- a/ios/chrome/browser/passwords/BUILD.gn +++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -21,8 +21,6 @@ "ios_chrome_password_manager_driver.mm", "ios_chrome_password_store_factory.cc", "ios_chrome_password_store_factory.h", - "ios_password_infobar_controller.h", - "ios_password_infobar_controller.mm", "ios_password_requirements_service_factory.cc", "ios_password_requirements_service_factory.h", "notify_auto_signin_view_controller.h",
diff --git a/ios/chrome/browser/passwords/ios_password_infobar_controller.h b/ios/chrome/browser/passwords/ios_password_infobar_controller.h deleted file mode 100644 index 2daf092..0000000 --- a/ios/chrome/browser/passwords/ios_password_infobar_controller.h +++ /dev/null
@@ -1,14 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_PASSWORDS_IOS_PASSWORD_INFOBAR_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_PASSWORDS_IOS_PASSWORD_INFOBAR_CONTROLLER_H_ - -#import "ios/chrome/browser/infobars/confirm_infobar_controller.h" - -@interface IOSPasswordInfoBarController : ConfirmInfoBarController - -@end - -#endif // IOS_CHROME_BROWSER_PASSWORDS_IOS_PASSWORD_INFOBAR_CONTROLLER_H_
diff --git a/ios/chrome/browser/passwords/ios_password_infobar_controller.mm b/ios/chrome/browser/passwords/ios_password_infobar_controller.mm deleted file mode 100644 index 85e9e1f5..0000000 --- a/ios/chrome/browser/passwords/ios_password_infobar_controller.mm +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/passwords/ios_password_infobar_controller.h" - -#import "ios/chrome/browser/infobars/confirm_infobar_controller+protected.h" -#import "ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h" -#import "ios/chrome/browser/ui/infobars/confirm_infobar_view.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@implementation IOSPasswordInfoBarController - -- (void)updateInfobarLabel:(ConfirmInfoBarView*)view { - [super updateInfobarLabel:view]; - - auto* delegate = static_cast<IOSChromePasswordManagerInfoBarDelegate*>( - self.infoBarDelegate); - NSString* message = delegate->GetDetailsMessageText(); - if (!message.length) - return; - - [view addFooterLabel:message]; -} - -@end
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm index 97710bcb..88be70b 100644 --- a/ios/chrome/browser/passwords/password_controller.mm +++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -54,7 +54,6 @@ #import "ios/chrome/browser/infobars/infobar_type.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h" -#import "ios/chrome/browser/passwords/ios_password_infobar_controller.h" #import "ios/chrome/browser/passwords/notify_auto_signin_view_controller.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
diff --git a/ios/chrome/browser/snapshots/BUILD.gn b/ios/chrome/browser/snapshots/BUILD.gn index 4d0d494e..d0743b1 100644 --- a/ios/chrome/browser/snapshots/BUILD.gn +++ b/ios/chrome/browser/snapshots/BUILD.gn
@@ -26,12 +26,9 @@ ] deps = [ "//base", - "//components/infobars/core", "//ios/chrome/browser/browser_state", - "//ios/chrome/browser/infobars", "//ios/chrome/browser/main:public", "//ios/chrome/browser/ui:feature_flags", - "//ios/chrome/browser/ui/infobars:feature_flags", "//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util:multiwindow_util", "//ios/chrome/browser/web:tab_id_tab_helper",
diff --git a/ios/chrome/browser/snapshots/snapshot_tab_helper.h b/ios/chrome/browser/snapshots/snapshot_tab_helper.h index 0fda90f..3409333 100644 --- a/ios/chrome/browser/snapshots/snapshot_tab_helper.h +++ b/ios/chrome/browser/snapshots/snapshot_tab_helper.h
@@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observer.h" -#include "components/infobars/core/infobar_manager.h" #include "ios/web/public/web_state_observer.h" #import "ios/web/public/web_state_user_data.h" @@ -23,8 +22,7 @@ } // SnapshotTabHelper allows capturing and retrival for web page snapshots. -class SnapshotTabHelper : public infobars::InfoBarManager::Observer, - public web::WebStateObserver, +class SnapshotTabHelper : public web::WebStateObserver, public web::WebStateUserData<SnapshotTabHelper> { public: ~SnapshotTabHelper() override; @@ -92,25 +90,13 @@ web::PageLoadCompletionStatus load_completion_status) override; void WebStateDestroyed(web::WebState* web_state) override; - // infobars::InfoBarManager::Observer implementation. - void OnInfoBarAdded(infobars::InfoBar* infobar) override; - void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override; - void OnInfoBarReplaced(infobars::InfoBar* old_infobar, - infobars::InfoBar* new_infobar) override; - void OnManagerShuttingDown(infobars::InfoBarManager* manager) override; - web::WebState* web_state_ = nullptr; NSString* tab_id_ = nil; SnapshotGenerator* snapshot_generator_ = nil; - infobars::InfoBarManager* infobar_manager_ = nullptr; // Manages this object as an observer of |web_state_|. ScopedObserver<web::WebState, web::WebStateObserver> web_state_observer_; - // Manages this object as an observer of infobars. - ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer> - infobar_observer_; - bool ignore_next_load_ = false; // True if |web_state_| was loading at the time of the last call to
diff --git a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm index 5014db5..aea2441 100644 --- a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm +++ b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
@@ -8,12 +8,8 @@ #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/task/post_task.h" -#include "components/infobars/core/infobar.h" -#include "components/infobars/core/infobar_delegate.h" -#include "ios/chrome/browser/infobars/infobar_manager_impl.h" #import "ios/chrome/browser/snapshots/snapshot_cache.h" #import "ios/chrome/browser/snapshots/snapshot_generator.h" -#import "ios/chrome/browser/ui/infobars/infobar_feature.h" #include "ios/chrome/browser/ui/util/ui_util.h" #include "ios/web/public/thread/web_task_traits.h" #include "ios/web/public/thread/web_thread.h" @@ -117,19 +113,12 @@ : web_state_(web_state), tab_id_([tab_id copy]), web_state_observer_(this), - infobar_observer_(this), weak_ptr_factory_(this) { DCHECK(web_state_); DCHECK(tab_id_.length > 0); snapshot_generator_ = [[SnapshotGenerator alloc] initWithWebState:web_state_ tabID:tab_id_]; web_state_observer_.Add(web_state_); - - // Supports missing InfoBarManager to make testing easier. - infobar_manager_ = InfoBarManagerImpl::FromWebState(web_state_); - if (infobar_manager_) { - infobar_observer_.Add(infobar_manager_); - } } void SnapshotTabHelper::PageLoaded( @@ -190,49 +179,4 @@ tab_id_ = nil; } -void SnapshotTabHelper::OnInfoBarAdded(infobars::InfoBar* infobar) { - // TODO(crbug.com/961343): Remove snapshotting for infobars when - // MessagesUI is permanent for all infobars. - if (!IsConfirmInfobarMessagesUIEnabled()) { - UpdateSnapshotWithCallback(nil); - } -} - -void SnapshotTabHelper::OnInfoBarRemoved(infobars::InfoBar* infobar, - bool animate) { - // TODO(crbug.com/961343): Remove snapshotting for infobars when - // MessagesUI is permanent for all infobars. - if (!IsConfirmInfobarMessagesUIEnabled()) { - UpdateSnapshotWithCallback(nil); - } -} - -void SnapshotTabHelper::OnInfoBarReplaced(infobars::InfoBar* old_infobar, - infobars::InfoBar* new_infobar) { - // TODO(crbug.com/961343): Remove snapshotting for infobars when - // MessagesUI is permanent for all infobars. - // TODO(crbug.com/1018285): Rapid blocking of javascript popups can cause a - // crash as simultaneous snapshots are triggered. Do not take snapshots when - // consecutive infobars are popup blocking infobars. - infobars::InfoBarDelegate::InfoBarIdentifier - popup_blocked_infobar_identifier = - infobars::InfoBarDelegate::POPUP_BLOCKED_INFOBAR_DELEGATE_MOBILE; - bool consecutive_popup_blocked_infobars = - old_infobar->delegate()->GetIdentifier() == - popup_blocked_infobar_identifier && - new_infobar->delegate()->GetIdentifier() == - popup_blocked_infobar_identifier; - if (!consecutive_popup_blocked_infobars && - !IsConfirmInfobarMessagesUIEnabled()) { - UpdateSnapshotWithCallback(nil); - } -} - -void SnapshotTabHelper::OnManagerShuttingDown( - infobars::InfoBarManager* manager) { - DCHECK_EQ(infobar_manager_, manager); - infobar_observer_.Remove(manager); - infobar_manager_ = nullptr; -} - WEB_STATE_USER_DATA_KEY_IMPL(SnapshotTabHelper)
diff --git a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm index 7537b64e..95fc9e6 100644 --- a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm +++ b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm
@@ -10,7 +10,6 @@ #include "base/memory/ptr_util.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/infobars/confirm_infobar_controller.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #include "ios/chrome/browser/infobars/infobar_utils.h" #include "ios/chrome/browser/signin/authentication_service.h"
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm index c64f612..01db2a2 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -730,15 +730,11 @@ [[ToolbarCoordinatorAdaptor alloc] initWithDispatcher:self.dispatcher]; self.toolbarInterface = _toolbarCoordinatorAdaptor; - // TODO(crbug.com/1024288): Remove these lines along the legacy code - // removal. - if (!IsDownloadInfobarMessagesUIEnabled()) { - _downloadManagerCoordinator = [[DownloadManagerCoordinator alloc] - initWithBaseViewController:_browserContainerViewController - browser:browser]; - _downloadManagerCoordinator.presenter = - [[VerticalAnimationContainer alloc] init]; - } + _downloadManagerCoordinator = [[DownloadManagerCoordinator alloc] + initWithBaseViewController:_browserContainerViewController + browser:browser]; + _downloadManagerCoordinator.presenter = + [[VerticalAnimationContainer alloc] init]; _webStateDelegate.reset(new web::WebStateDelegateBridge(self)); _inNewTabAnimation = NO; @@ -2171,14 +2167,11 @@ [self.sideSwipeController addHorizontalGesturesToView:self.view]; - // TODO(crbug.com/1024288): Remove these lines along the legacy code removal. - if (!IsDownloadInfobarMessagesUIEnabled()) { // DownloadManagerCoordinator is already created. DCHECK(_downloadManagerCoordinator); _downloadManagerCoordinator.bottomMarginHeightAnchor = [NamedGuide guideWithName:kSecondaryToolbarGuide view:self.contentArea] .heightAnchor; - } self.bubblePresenter = [[BubblePresenter alloc] initWithBrowserState:self.browserState @@ -2667,13 +2660,10 @@ OfflinePageTabHelper::CreateForWebState( webState, ReadingListModelFactory::GetForBrowserState(self.browserState)); - // TODO(crbug.com/1024288): Remove these lines along the legacy code removal. - if (!IsDownloadInfobarMessagesUIEnabled()) { // DownloadManagerTabHelper cannot function without delegate. DCHECK(_downloadManagerCoordinator); DownloadManagerTabHelper::CreateForWebState(webState, _downloadManagerCoordinator); - } NewTabPageTabHelper::FromWebState(webState)->SetDelegate(self);
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm b/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm index ebdc6e8..5155c3c 100644 --- a/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm
@@ -11,7 +11,6 @@ #include "base/test/task_environment.h" #include "components/infobars/core/infobar_feature.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" -#include "ios/chrome/browser/infobars/confirm_infobar_controller.h" #include "ios/chrome/browser/infobars/infobar_badge_tab_helper.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #include "ios/chrome/browser/infobars/infobar_manager_impl.h" @@ -42,11 +41,6 @@ #error "This file requires ARC support." #endif -// Exposed for testing. -@interface InfobarContainerCoordinator (Testing) -@property(nonatomic, assign) BOOL legacyContainerFullscrenSupportDisabled; -@end - // Test ContainerCoordinatorPositioner. @interface TestContainerCoordinatorPositioner : NSObject <InfobarPositioner> @property(nonatomic, strong) UIView* baseView; @@ -123,17 +117,7 @@ [scoped_key_window_.Get() setRootViewController:base_view_controller_]; positioner_.baseView = base_view_controller_.view; infobar_container_coordinator_.positioner = positioner_; - infobar_container_coordinator_.legacyContainerFullscrenSupportDisabled = - YES; [infobar_container_coordinator_ start]; - - // Setup the Legacy InfobarController and InfobarDelegate. - TestInfoBarDelegate* test_legacy_infobar_delegate = - new TestInfoBarDelegate(@"Legacy Infobar"); - legacy_controller_ = [[ConfirmInfoBarController alloc] - initWithInfoBarDelegate:test_legacy_infobar_delegate]; - legacy_infobar_delegate_ = - std::unique_ptr<ConfirmInfoBarDelegate>(test_legacy_infobar_delegate); } ~InfobarContainerCoordinatorTest() override { @@ -222,13 +206,6 @@ WebStateOpener()); } - // Adds a Legacy Infobar to the InfobarManager, triggering an InfobarBanner - // presentation. - void AddLegacyInfobar() { - GetInfobarManager()->AddInfoBar(std::make_unique<InfoBarIOS>( - legacy_controller_, std::move(legacy_infobar_delegate_))); - } - // Returns InfoBarManager attached to web_state_. infobars::InfoBarManager* GetInfobarManager() { return InfoBarManagerImpl::FromWebState( @@ -247,8 +224,6 @@ InfobarPasswordCoordinator* second_coordinator_; InfobarConfirmCoordinator* confirm_coordinator_; std::unique_ptr<IOSChromeSavePasswordInfoBarDelegate> infobar_delegate_; - ConfirmInfoBarController* legacy_controller_; - std::unique_ptr<ConfirmInfoBarDelegate> legacy_infobar_delegate_; ScopedKeyWindow scoped_window_; WKWebView* web_view_ = nil; CRWWebViewContentView* content_view_ = nil; @@ -322,64 +297,6 @@ InfobarBannerPresentationState::Presented); } -// Tests that a legacy Infobar can be presented and -// infobarBannerState is still NotPresented. -TEST_F(InfobarContainerCoordinatorTest, TestLegacyInfobarPresentation) { - EXPECT_FALSE([infobar_container_coordinator_ - isInfobarPresentingForWebState:browser_->GetWebStateList() - ->GetActiveWebState()]); - ASSERT_EQ(infobar_container_coordinator_.infobarBannerState, - InfobarBannerPresentationState::NotPresented); - AddLegacyInfobar(); - EXPECT_NE(infobar_container_coordinator_.infobarBannerState, - InfobarBannerPresentationState::Presented); - EXPECT_TRUE([infobar_container_coordinator_ - isInfobarPresentingForWebState:browser_->GetWebStateList() - ->GetActiveWebState()]); -} - -// Tests that the presentation of a LegacyInfobar doesn't dismiss the previously -// presented InfobarBanner. -TEST_F(InfobarContainerCoordinatorTest, - TestInfobarBannerPresentationBeforeLegacyPresentation) { - EXPECT_NE(infobar_container_coordinator_.infobarBannerState, - InfobarBannerPresentationState::Presented); - AddInfobar(/*high_priority_presentation=*/false); - ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( - base::test::ios::kWaitForUIElementTimeout, ^bool { - return infobar_container_coordinator_.infobarBannerState == - InfobarBannerPresentationState::Presented; - })); - ASSERT_EQ(infobar_container_coordinator_.infobarBannerState, - InfobarBannerPresentationState::Presented); - AddLegacyInfobar(); - EXPECT_EQ(infobar_container_coordinator_.infobarBannerState, - InfobarBannerPresentationState::Presented); -} - -// Tests that a presented LegacyInfobar doesn't interfere with presenting an -// InfobarBanner. -TEST_F(InfobarContainerCoordinatorTest, - TestInfobarBannerPresentationAfterLegacyPresentation) { - EXPECT_FALSE([infobar_container_coordinator_ - isInfobarPresentingForWebState:browser_->GetWebStateList() - ->GetActiveWebState()]); - AddLegacyInfobar(); - ASSERT_TRUE([infobar_container_coordinator_ - isInfobarPresentingForWebState:browser_->GetWebStateList() - ->GetActiveWebState()]); - ASSERT_NE(infobar_container_coordinator_.infobarBannerState, - InfobarBannerPresentationState::Presented); - AddInfobar(/*high_priority_presentation=*/false); - ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( - base::test::ios::kWaitForUIElementTimeout, ^bool { - return infobar_container_coordinator_.infobarBannerState == - InfobarBannerPresentationState::Presented; - })); - ASSERT_EQ(infobar_container_coordinator_.infobarBannerState, - InfobarBannerPresentationState::Presented); -} - // Tests that the InfobarBanner is dismissed when changing Webstates. TEST_F(InfobarContainerCoordinatorTest, TestInfobarBannerDismissAtWebStateChange) {
diff --git a/ios/chrome/browser/ui/infobars/infobar_feature.h b/ios/chrome/browser/ui/infobars/infobar_feature.h index 94bd72d..21aca604 100644 --- a/ios/chrome/browser/ui/infobars/infobar_feature.h +++ b/ios/chrome/browser/ui/infobars/infobar_feature.h
@@ -13,32 +13,6 @@ // directly. extern const base::Feature kInfobarOverlayUI; -// Feature to choose whether Confirm Infobars use the new Messages UI or the -// legacy one. Also, in order for it to work kIOSInfobarUIReboot needs to be -// enabled. -// Use IsConfirmInfobarMessagesUIEnabled() instead of this constant directly. -extern const base::Feature kConfirmInfobarMessagesUI; - -// Feature to choose whether Confirm Infobars use the new Messages UI or the -// legacy one. Also, in order for it to work kIOSInfobarUIReboot needs to be -// enabled. -// Use IsCrashRestoreInfobarMessagesUIEnabled() instead of this constant -// directly. -extern const base::Feature kCrashRestoreInfobarMessagesUI; - -// Feature to choose whether Block Popup Infobars use the new Messages UI or the -// legacy one. Also, in order for it to work kIOSInfobarUIReboot needs to be -// enabled. -// Use IsBlockPopupInfobarMessagesUIEnabled() instead of this constant -// directly. -extern const base::Feature kBlockPopupInfobarMessagesUI; - -// Feature to choose whether Downloads uses the new Messages UI or the -// legacy one. Also, in order for it to work kIOSInfobarUIReboot needs to be -// enabled. -// Use IsDownloadInfobarMessagesUIEnabled() instead of this constant directly. -extern const base::Feature kDownloadInfobarMessagesUI; - // Feature to choose whether Save Card Infobar uses the new Messages UI or the // legacy one. Also, in order for it to work kIOSInfobarUIReboot needs to be // enabled. @@ -63,18 +37,6 @@ // Whether the Messages Infobar UI is presented using OverlayPresenter. bool IsInfobarOverlayUIEnabled(); -// Whether the Confirm Infobar Messages UI is enabled. -bool IsConfirmInfobarMessagesUIEnabled(); - -// Whether the Crash Restore Infobar Messages UI is enabled. -bool IsCrashRestoreInfobarMessagesUIEnabled(); - -// Whether the Block Popup Infobar Messages UI is enabled. -bool IsBlockPopupInfobarMessagesUIEnabled(); - -// Whether the Download Infobar Messages UI is enabled. -bool IsDownloadInfobarMessagesUIEnabled(); - // Whether the SaveCard Infobar Messages UI is enabled. bool IsSaveCardInfobarMessagesUIEnabled();
diff --git a/ios/chrome/browser/ui/infobars/infobar_feature.mm b/ios/chrome/browser/ui/infobars/infobar_feature.mm index 808693b..72395882 100644 --- a/ios/chrome/browser/ui/infobars/infobar_feature.mm +++ b/ios/chrome/browser/ui/infobars/infobar_feature.mm
@@ -18,27 +18,6 @@ // Feature enabled by default since it will always be checked along // kIOSInfobarUIReboot, effectively working as a kill switch. Meaning that if // kIOSInfobarUIReboot is not enabled this feature won't work. -const base::Feature kConfirmInfobarMessagesUI{"ConfirmInfobarMessagesUI", - base::FEATURE_ENABLED_BY_DEFAULT}; - -// Feature enabled by default since it will always be checked along -// kIOSInfobarUIReboot, effectively working as a kill switch. Meaning that if -// kIOSInfobarUIReboot is not enabled this feature won't work. -const base::Feature kCrashRestoreInfobarMessagesUI{ - "CrashRestoreInfobarMessagesUI", base::FEATURE_ENABLED_BY_DEFAULT}; - -// Feature enabled by default since it will always be checked along -// kIOSInfobarUIReboot, effectively working as a kill switch. Meaning that if -// kIOSInfobarUIReboot is not enabled this feature won't work. -const base::Feature kBlockPopupInfobarMessagesUI{ - "BlockPopupInfobarMessagesUI", base::FEATURE_ENABLED_BY_DEFAULT}; - -const base::Feature kDownloadInfobarMessagesUI{ - "DownloadInfobarMessagesUI", base::FEATURE_DISABLED_BY_DEFAULT}; - -// Feature enabled by default since it will always be checked along -// kIOSInfobarUIReboot, effectively working as a kill switch. Meaning that if -// kIOSInfobarUIReboot is not enabled this feature won't work. const base::Feature kSaveCardInfobarMessagesUI{ "SaveCardInfobarMessagesUI", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -60,26 +39,6 @@ base::FeatureList::IsEnabled(kInfobarOverlayUI); } -bool IsConfirmInfobarMessagesUIEnabled() { - return base::FeatureList::IsEnabled(kConfirmInfobarMessagesUI) && - IsInfobarUIRebootEnabled(); -} - -bool IsCrashRestoreInfobarMessagesUIEnabled() { - return base::FeatureList::IsEnabled(kCrashRestoreInfobarMessagesUI) && - IsInfobarUIRebootEnabled(); -} - -bool IsBlockPopupInfobarMessagesUIEnabled() { - return base::FeatureList::IsEnabled(kBlockPopupInfobarMessagesUI) && - IsInfobarUIRebootEnabled(); -} - -bool IsDownloadInfobarMessagesUIEnabled() { - return base::FeatureList::IsEnabled(kDownloadInfobarMessagesUI) && - IsInfobarUIRebootEnabled(); -} - bool IsSaveCardInfobarMessagesUIEnabled() { return base::FeatureList::IsEnabled(kSaveCardInfobarMessagesUI) && IsInfobarUIRebootEnabled();
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn index fbf17999..245a451c 100644 --- a/ios/chrome/browser/web/BUILD.gn +++ b/ios/chrome/browser/web/BUILD.gn
@@ -253,7 +253,6 @@ "//ios/chrome/browser/ssl", "//ios/chrome/browser/ui:feature_flags", "//ios/chrome/browser/ui/elements", - "//ios/chrome/browser/ui/infobars:feature_flags", "//ios/chrome/browser/ui/infobars/coordinators", "//ios/chrome/browser/ui/util", "//ios/chrome/browser/web:feature_flags",
diff --git a/ios/chrome/browser/web/blocked_popup_tab_helper.mm b/ios/chrome/browser/web/blocked_popup_tab_helper.mm index f4caf98..650f9a1 100644 --- a/ios/chrome/browser/web/blocked_popup_tab_helper.mm +++ b/ios/chrome/browser/web/blocked_popup_tab_helper.mm
@@ -19,12 +19,10 @@ #include "components/infobars/core/infobar.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "ios/chrome/browser/infobars/confirm_infobar_controller.h" #include "ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h" #include "ios/chrome/browser/infobars/infobar_ios.h" #include "ios/chrome/browser/infobars/infobar_manager_impl.h" #import "ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.h" -#import "ios/chrome/browser/ui/infobars/infobar_feature.h" #include "ios/chrome/grit/ios_strings.h" #include "ios/web/public/navigation/referrer.h" #include "net/base/mac/url_conversions.h" @@ -164,24 +162,18 @@ std::make_unique<BlockPopupInfoBarDelegate>(GetBrowserState(), web_state_, popups_)); - std::unique_ptr<infobars::InfoBar> infobar; - if (IsBlockPopupInfobarMessagesUIEnabled()) { InfobarConfirmCoordinator* coordinator = [[InfobarConfirmCoordinator alloc] initWithInfoBarDelegate:delegate.get() badgeSupport:NO type:InfobarType::kInfobarTypeConfirm]; - infobar = std::make_unique<InfoBarIOS>(coordinator, std::move(delegate)); - } else { - ConfirmInfoBarController* controller = [[ConfirmInfoBarController alloc] - initWithInfoBarDelegate:delegate.get()]; - infobar = std::make_unique<InfoBarIOS>(controller, std::move(delegate)); - } + std::unique_ptr<infobars::InfoBar> infobar = + std::make_unique<InfoBarIOS>(coordinator, std::move(delegate)); - if (infobar_) { - infobar_ = infobar_manager->ReplaceInfoBar(infobar_, std::move(infobar)); - } else { - infobar_ = infobar_manager->AddInfoBar(std::move(infobar)); - } + if (infobar_) { + infobar_ = infobar_manager->ReplaceInfoBar(infobar_, std::move(infobar)); + } else { + infobar_ = infobar_manager->AddInfoBar(std::move(infobar)); + } [ConfirmInfobarMetricsRecorder recordConfirmInfobarEvent:MobileMessagesConfirmInfobarEvents::Presented forInfobarConfirmType:InfobarConfirmType::
diff --git a/ios/components/webui/sync_internals/sync_internals_message_handler.mm b/ios/components/webui/sync_internals/sync_internals_message_handler.mm index 1b886159..81e902cc 100644 --- a/ios/components/webui/sync_internals/sync_internals_message_handler.mm +++ b/ios/components/webui/sync_internals/sync_internals_message_handler.mm
@@ -267,10 +267,12 @@ } void SyncInternalsMessageHandler::SendAboutInfo() { - syncer::SyncService* sync_service = GetSyncService(); + // This class serves to display debug information to the user, so it's fine to + // include sensitive data in ConstructAboutInformation(). std::unique_ptr<base::DictionaryValue> value = - syncer::sync_ui_util::ConstructAboutInformation(sync_service, - web_ui::GetChannel()); + syncer::sync_ui_util::ConstructAboutInformation( + syncer::sync_ui_util::IncludeSensitiveData(true), GetSyncService(), + web_ui::GetChannel()); DispatchEvent(syncer::sync_ui_util::kOnAboutInfoUpdated, *value); }
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 3f33a1e..15e08b5 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -740,10 +740,6 @@ const base::Feature kMediaFeedsSafeSearch{"MediaFeedsSafeSearch", base::FEATURE_ENABLED_BY_DEFAULT}; -// Send events to devtools rather than to chrome://media-internals -const base::Feature kMediaInspectorLogging{"MediaInspectorLogging", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Enables experimental local learning for media. Used in the context of media // capabilities only. Adds reporting only; does not change media behavior. const base::Feature kMediaLearningExperiment{"MediaLearningExperiment",
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index 0f47b38..905aedcc 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -153,7 +153,6 @@ MEDIA_EXPORT extern const base::Feature kMediaFeeds; MEDIA_EXPORT extern const base::Feature kMediaFeedsBackgroundFetching; MEDIA_EXPORT extern const base::Feature kMediaFeedsSafeSearch; -MEDIA_EXPORT extern const base::Feature kMediaInspectorLogging; MEDIA_EXPORT extern const base::Feature kMediaLearningExperiment; MEDIA_EXPORT extern const base::Feature kMediaLearningFramework; MEDIA_EXPORT extern const base::Feature kMediaLearningSmoothnessExperiment;
diff --git a/media/gpu/v4l2/v4l2_image_processor_backend.cc b/media/gpu/v4l2/v4l2_image_processor_backend.cc index 064b893..29d80a4 100644 --- a/media/gpu/v4l2/v4l2_image_processor_backend.cc +++ b/media/gpu/v4l2/v4l2_image_processor_backend.cc
@@ -664,13 +664,15 @@ bool V4L2ImageProcessorBackend::ApplyCrop(const gfx::Rect& visible_rect, enum v4l2_buf_type type) { - struct v4l2_rect rect {}; + struct v4l2_rect rect; + memset(&rect, 0, sizeof(rect)); rect.left = visible_rect.x(); rect.top = visible_rect.y(); rect.width = visible_rect.width(); rect.height = visible_rect.height(); - struct v4l2_selection selection_arg {}; + struct v4l2_selection selection_arg; + memset(&selection_arg, 0, sizeof(selection_arg)); // Multiplanar buffer types are messed up in S_SELECTION API, so all drivers // don't necessarily work with MPLANE types. This issue is resolved with // kernel 4.13. As we use kernel < 4.13 today, we use single planar buffer @@ -686,7 +688,8 @@ rect = selection_arg.r; } else { DVLOGF(2) << "Fallback to VIDIOC_S/G_CROP"; - struct v4l2_crop crop {}; + struct v4l2_crop crop; + memset(&crop, 0, sizeof(crop)); crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; crop.c = rect; if (device_->Ioctl(VIDIOC_S_CROP, &crop) != 0) { @@ -711,7 +714,8 @@ const gfx::Size& size, const gfx::Rect& visible_rect, enum v4l2_buf_type type) { - v4l2_format format{}; + struct v4l2_format format; + memset(&format, 0, sizeof(format)); format.type = type; if (device_->Ioctl(VIDIOC_G_FMT, &format) != 0) { VPLOGF(1) << "ioctl() failed: VIDIOC_G_FMT";
diff --git a/media/gpu/vaapi/fuzzers/jpeg_decoder/BUILD.gn b/media/gpu/vaapi/fuzzers/jpeg_decoder/BUILD.gn index 97155c5..37b7d6f 100644 --- a/media/gpu/vaapi/fuzzers/jpeg_decoder/BUILD.gn +++ b/media/gpu/vaapi/fuzzers/jpeg_decoder/BUILD.gn
@@ -6,15 +6,11 @@ import("//third_party/protobuf/proto_library.gni") proto_library("jpeg_decoder_fuzzer_input") { - sources = [ - "jpeg_decoder_fuzzer_input.proto", - ] + sources = [ "jpeg_decoder_fuzzer_input.proto" ] } fuzzer_test("vaapi_jpeg_decoder_fuzzertest") { - sources = [ - "jpeg_decoder_fuzzertest.cc", - ] + sources = [ "jpeg_decoder_fuzzertest.cc" ] deps = [ ":jpeg_decoder_fuzzer_input", "//base", @@ -25,6 +21,7 @@ "//media/gpu:video_frame_mapper", "//media/gpu/chromeos", "//media/gpu/vaapi", + "//media/gpu/vaapi:common", "//media/parsers", "//third_party/libprotobuf-mutator", "//ui/gfx/geometry",
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc index 1abed03..7b534d41 100644 --- a/net/base/mime_util.cc +++ b/net/base/mime_util.cc
@@ -194,6 +194,9 @@ {"application/rss+xml", "rss"}, {"application/vnd.android.package-archive", "apk"}, {"application/vnd.mozilla.xul+xml", "xul"}, + {"application/vnd.ms-excel", "xls"}, + {"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "xlsx"}, {"application/x-gzip", "gz,tgz"}, {"application/x-mpegurl", "m3u8"}, {"application/x-shockwave-flash", "swf,swl"},
diff --git a/ppapi/BUILD.gn b/ppapi/BUILD.gn index bbd15084..9dc7901 100644 --- a/ppapi/BUILD.gn +++ b/ppapi/BUILD.gn
@@ -175,10 +175,6 @@ "tests/test_crypto.h", "tests/test_file_chooser.cc", "tests/test_file_chooser.h", - "tests/test_flash_fullscreen.cc", - "tests/test_flash_fullscreen.h", - "tests/test_flash_fullscreen_for_browser_ui.cc", - "tests/test_flash_fullscreen_for_browser_ui.h", "tests/test_net_address_private.cc", "tests/test_net_address_private.h", "tests/test_pdf.cc",
diff --git a/ppapi/api/private/ppb_flash_fullscreen.idl b/ppapi/api/private/ppb_flash_fullscreen.idl deleted file mode 100644 index 1ea7715..0000000 --- a/ppapi/api/private/ppb_flash_fullscreen.idl +++ /dev/null
@@ -1,45 +0,0 @@ -/* Copyright (c) 2012 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -/** - * This file defines the <code>PPB_FlashFullscreen</code> interface. - */ - -label Chrome { - M23 = 1.0 -}; - -interface PPB_FlashFullscreen { - /** - * Checks whether the plugin instance is currently in fullscreen mode. - */ - PP_Bool IsFullscreen( - [in] PP_Instance instance); - - /** - * Switches the plugin instance to/from fullscreen mode. Returns PP_TRUE on - * success, PP_FALSE on failure. - * - * This does not unbind the current Graphics2D or Graphics3D. Pending flushes - * and swapbuffers will execute as if the resource was off-screen. The - * transition is asynchronous. During the transition, IsFullscreen will - * return PP_FALSE, and no Graphics2D or Graphics3D can be bound. The - * transition ends at the next DidChangeView when going into fullscreen mode. - * The transition out of fullscreen mode is synchronous. - */ - PP_Bool SetFullscreen( - [in] PP_Instance instance, - [in] PP_Bool fullscreen); - - /** - * Gets the size of the screen in pixels. When going fullscreen, the instance - * will be resized to that size. - */ - PP_Bool GetScreenSize( - [in] PP_Instance instance, - [out] PP_Size size); -}; -
diff --git a/ppapi/api/private/ppp_flash_browser_operations.idl b/ppapi/api/private/ppp_flash_browser_operations.idl deleted file mode 100644 index eb1e9625..0000000 --- a/ppapi/api/private/ppp_flash_browser_operations.idl +++ /dev/null
@@ -1,170 +0,0 @@ -/* Copyright 2012 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/** - * This file contains the <code>PPP_Flash_BrowserOperations</code> interface. - */ - -label Chrome { - M20 = 1.0, - M21 = 1.2, - M22 = 1.3 -}; - -[assert_size(4)] -enum PP_Flash_BrowserOperations_SettingType { - PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC = 0, - PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING = 1, - PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_LAST = PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING -}; - -[assert_size(4)] -enum PP_Flash_BrowserOperations_Permission { - // This value is only used with <code>SetSitePermission()</code>. - PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT = 0, - PP_FLASH_BROWSEROPERATIONS_PERMISSION_ALLOW = 1, - PP_FLASH_BROWSEROPERATIONS_PERMISSION_BLOCK = 2, - PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK = 3, - PP_FLASH_BROWSEROPERATIONS_PERMISSION_LAST = PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK -}; - -struct PP_Flash_BrowserOperations_SiteSetting { - cstr_t site; - PP_Flash_BrowserOperations_Permission permission; -}; - -typedef void PPB_Flash_BrowserOperations_GetSettingsCallback( - [inout] mem_t user_data, - [in] PP_Bool success, - [in] PP_Flash_BrowserOperations_Permission default_permission, - [in] uint32_t site_count, - [in, size_is(site_count)] PP_Flash_BrowserOperations_SiteSetting[] sites); - -/** - * This interface allows the browser to request the plugin do things. - */ -interface PPP_Flash_BrowserOperations { - /** - * This function allows the plugin to implement the "Clear site data" feature. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin data is - * stored. On UTF16 systems (Windows), this will be encoded as UTF-8. It will - * be an absolute path and will not have a directory separator (slash) at the - * end. - * @param[in] site String specifying which site to clear the data for. This - * will be null to clear data for all sites. - * @param[in] flags Currently always 0 in Chrome to clear all data. This may - * be extended in the future to clear only specific types of data. - * @param[in] max_age The maximum age in seconds to clear data for. This - * allows the plugin to implement "clear past hour" and "clear past data", - * etc. - * - * @return PP_TRUE on success, PP_FALSE on failure. - * - * See also the NPP_ClearSiteData function in NPAPI. - * https://wiki.mozilla.org/NPAPI:ClearSiteData - */ - PP_Bool ClearSiteData([in] str_t plugin_data_path, - [in] str_t site, - [in] uint64_t flags, - [in] uint64_t max_age); - - /** - * Requests the plugin to deauthorize content licenses. It prevents Flash from - * playing protected content, such as movies and music the user may have - * rented or purchased. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin settings are stored. - * - * @return <code>PP_TRUE</code> on success, <code>PP_FALSE</code> on failure. - */ - [version=1.2] - PP_Bool DeauthorizeContentLicenses([in] str_t plugin_data_path); - - /** - * Gets permission settings. <code>callback</code> will be called exactly once - * to return the settings. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin settings are stored. - * @param[in] setting_type What type of setting to retrieve. - * @param[in] callback The callback to return retrieved data. - * @param[inout] user_data An opaque pointer that will be passed to - * <code>callback</code>. - */ - [version=1.2] - void GetPermissionSettings( - [in] str_t plugin_data_path, - [in] PP_Flash_BrowserOperations_SettingType setting_type, - [in] PPB_Flash_BrowserOperations_GetSettingsCallback callback, - [inout] mem_t user_data); - - /** - * Sets default permission. It applies to all sites except those with - * site-specific settings. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin settings are stored. - * @param[in] setting_type What type of setting to set. - * @param[in] permission The default permission. - * @param[in] clear_site_specific Whether to remove all site-specific - * settings. - * - * @return <code>PP_TRUE</code> on success, <code>PP_FALSE</code> on failure. - */ - [version=1.2] - PP_Bool SetDefaultPermission( - [in] str_t plugin_data_path, - [in] PP_Flash_BrowserOperations_SettingType setting_type, - [in] PP_Flash_BrowserOperations_Permission permission, - [in] PP_Bool clear_site_specific); - - /** - * Sets site-specific permission. If a site has already got site-specific - * permission and it is not in <code>sites</code>, it won't be affected. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin settings are stored. - * @param[in] setting_type What type of setting to set. - * @param[in] site_count How many items are there in <code>sites</code>. - * @param[in] sites The site-specific settings. If a site is specified with - * <code>PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT</code> permission, it - * will be removed from the site-specific list. - * - * @return <code>PP_TRUE</code> on success, <code>PP_FALSE</code> on failure. - */ - [version=1.2] - PP_Bool SetSitePermission( - [in] str_t plugin_data_path, - [in] PP_Flash_BrowserOperations_SettingType setting_type, - [in] uint32_t site_count, - [in, size_is(site_count)] PP_Flash_BrowserOperations_SiteSetting[] sites); - - /** - * Returns a list of sites that have stored data, for use with the - * "Clear site data" feature. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin data is stored. - * @param[out] sites A NULL-terminated array of sites that have stored data. - * Use FreeSiteList on the array when done. - * - * See also the NPP_GetSitesWithData function in NPAPI: - * https://wiki.mozilla.org/NPAPI:ClearSiteData - */ - [version=1.3] - void GetSitesWithData([in] str_t plugin_data_path, - [out] str_t[] sites); - - /** - * Frees the list of sites returned by GetSitesWithData. - * - * @param[in] sites A NULL-terminated array of strings. - */ - [version=1.3] - void FreeSiteList([inout] str_t[] sites); -};
diff --git a/ppapi/c/BUILD.gn b/ppapi/c/BUILD.gn index 065dbfe..885152ae 100644 --- a/ppapi/c/BUILD.gn +++ b/ppapi/c/BUILD.gn
@@ -120,7 +120,6 @@ "private/ppb_file_ref_private.h", "private/ppb_find_private.h", "private/ppb_flash_font_file.h", - "private/ppb_flash_fullscreen.h", "private/ppb_host_resolver_private.h", "private/ppb_instance_private.h", "private/ppb_isolated_file_system_private.h", @@ -134,7 +133,6 @@ "private/ppb_uma_private.h", "private/ppb_x509_certificate_private.h", "private/ppp_find_private.h", - "private/ppp_flash_browser_operations.h", "private/ppp_instance_private.h", "private/ppp_pdf.h", "private/ppp_pexe_stream_handler.h",
diff --git a/ppapi/c/private/ppb_flash_fullscreen.h b/ppapi/c/private/ppb_flash_fullscreen.h deleted file mode 100644 index 85a064c..0000000 --- a/ppapi/c/private/ppb_flash_fullscreen.h +++ /dev/null
@@ -1,60 +0,0 @@ -/* Copyright (c) 2012 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* From private/ppb_flash_fullscreen.idl modified Thu Jul 26 06:15:01 2018. */ - -#ifndef PPAPI_C_PRIVATE_PPB_FLASH_FULLSCREEN_H_ -#define PPAPI_C_PRIVATE_PPB_FLASH_FULLSCREEN_H_ - -#include "ppapi/c/pp_bool.h" -#include "ppapi/c/pp_instance.h" -#include "ppapi/c/pp_macros.h" -#include "ppapi/c/pp_size.h" -#include "ppapi/c/pp_stdint.h" - -#define PPB_FLASHFULLSCREEN_INTERFACE_1_0 "PPB_FlashFullscreen;1.0" -#define PPB_FLASHFULLSCREEN_INTERFACE PPB_FLASHFULLSCREEN_INTERFACE_1_0 - -/** - * @file - * This file defines the <code>PPB_FlashFullscreen</code> interface. - */ - - -/** - * @addtogroup Interfaces - * @{ - */ -struct PPB_FlashFullscreen_1_0 { - /** - * Checks whether the plugin instance is currently in fullscreen mode. - */ - PP_Bool (*IsFullscreen)(PP_Instance instance); - /** - * Switches the plugin instance to/from fullscreen mode. Returns PP_TRUE on - * success, PP_FALSE on failure. - * - * This does not unbind the current Graphics2D or Graphics3D. Pending flushes - * and swapbuffers will execute as if the resource was off-screen. The - * transition is asynchronous. During the transition, IsFullscreen will - * return PP_FALSE, and no Graphics2D or Graphics3D can be bound. The - * transition ends at the next DidChangeView when going into fullscreen mode. - * The transition out of fullscreen mode is synchronous. - */ - PP_Bool (*SetFullscreen)(PP_Instance instance, PP_Bool fullscreen); - /** - * Gets the size of the screen in pixels. When going fullscreen, the instance - * will be resized to that size. - */ - PP_Bool (*GetScreenSize)(PP_Instance instance, struct PP_Size* size); -}; - -typedef struct PPB_FlashFullscreen_1_0 PPB_FlashFullscreen; -/** - * @} - */ - -#endif /* PPAPI_C_PRIVATE_PPB_FLASH_FULLSCREEN_H_ */ -
diff --git a/ppapi/c/private/ppp_flash_browser_operations.h b/ppapi/c/private/ppp_flash_browser_operations.h deleted file mode 100644 index 9bfc838..0000000 --- a/ppapi/c/private/ppp_flash_browser_operations.h +++ /dev/null
@@ -1,238 +0,0 @@ -/* Copyright 2012 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* From private/ppp_flash_browser_operations.idl, - * modified Wed Oct 25 09:44:49 2017. - */ - -#ifndef PPAPI_C_PRIVATE_PPP_FLASH_BROWSER_OPERATIONS_H_ -#define PPAPI_C_PRIVATE_PPP_FLASH_BROWSER_OPERATIONS_H_ - -#include "ppapi/c/pp_bool.h" -#include "ppapi/c/pp_macros.h" -#include "ppapi/c/pp_stdint.h" - -#define PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_0 \ - "PPP_Flash_BrowserOperations;1.0" -#define PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_2 \ - "PPP_Flash_BrowserOperations;1.2" -#define PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_3 \ - "PPP_Flash_BrowserOperations;1.3" -#define PPP_FLASH_BROWSEROPERATIONS_INTERFACE \ - PPP_FLASH_BROWSEROPERATIONS_INTERFACE_1_3 - -/** - * @file - * This file contains the <code>PPP_Flash_BrowserOperations</code> interface. - */ - - -/** - * @addtogroup Enums - * @{ - */ -typedef enum { - PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC = 0, - PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING = 1, - PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_LAST = - PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_PEERNETWORKING -} PP_Flash_BrowserOperations_SettingType; -PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_Flash_BrowserOperations_SettingType, 4); - -typedef enum { - /* This value is only used with <code>SetSitePermission()</code>. */ - PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT = 0, - PP_FLASH_BROWSEROPERATIONS_PERMISSION_ALLOW = 1, - PP_FLASH_BROWSEROPERATIONS_PERMISSION_BLOCK = 2, - PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK = 3, - PP_FLASH_BROWSEROPERATIONS_PERMISSION_LAST = - PP_FLASH_BROWSEROPERATIONS_PERMISSION_ASK -} PP_Flash_BrowserOperations_Permission; -PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_Flash_BrowserOperations_Permission, 4); -/** - * @} - */ - -/** - * @addtogroup Structs - * @{ - */ -struct PP_Flash_BrowserOperations_SiteSetting { - const char* site; - PP_Flash_BrowserOperations_Permission permission; -}; -/** - * @} - */ - -/** - * @addtogroup Typedefs - * @{ - */ -typedef void (*PPB_Flash_BrowserOperations_GetSettingsCallback)( - void* user_data, - PP_Bool success, - PP_Flash_BrowserOperations_Permission default_permission, - uint32_t site_count, - const struct PP_Flash_BrowserOperations_SiteSetting sites[]); -/** - * @} - */ - -/** - * @addtogroup Interfaces - * @{ - */ -/** - * This interface allows the browser to request the plugin do things. - */ -struct PPP_Flash_BrowserOperations_1_3 { - /** - * This function allows the plugin to implement the "Clear site data" feature. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin data is - * stored. On UTF16 systems (Windows), this will be encoded as UTF-8. It will - * be an absolute path and will not have a directory separator (slash) at the - * end. - * @param[in] site String specifying which site to clear the data for. This - * will be null to clear data for all sites. - * @param[in] flags Currently always 0 in Chrome to clear all data. This may - * be extended in the future to clear only specific types of data. - * @param[in] max_age The maximum age in seconds to clear data for. This - * allows the plugin to implement "clear past hour" and "clear past data", - * etc. - * - * @return PP_TRUE on success, PP_FALSE on failure. - * - * See also the NPP_ClearSiteData function in NPAPI. - * https://wiki.mozilla.org/NPAPI:ClearSiteData - */ - PP_Bool (*ClearSiteData)(const char* plugin_data_path, - const char* site, - uint64_t flags, - uint64_t max_age); - /** - * Requests the plugin to deauthorize content licenses. It prevents Flash from - * playing protected content, such as movies and music the user may have - * rented or purchased. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin settings are stored. - * - * @return <code>PP_TRUE</code> on success, <code>PP_FALSE</code> on failure. - */ - PP_Bool (*DeauthorizeContentLicenses)(const char* plugin_data_path); - /** - * Gets permission settings. <code>callback</code> will be called exactly once - * to return the settings. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin settings are stored. - * @param[in] setting_type What type of setting to retrieve. - * @param[in] callback The callback to return retrieved data. - * @param[inout] user_data An opaque pointer that will be passed to - * <code>callback</code>. - */ - void (*GetPermissionSettings)( - const char* plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - PPB_Flash_BrowserOperations_GetSettingsCallback callback, - void* user_data); - /** - * Sets default permission. It applies to all sites except those with - * site-specific settings. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin settings are stored. - * @param[in] setting_type What type of setting to set. - * @param[in] permission The default permission. - * @param[in] clear_site_specific Whether to remove all site-specific - * settings. - * - * @return <code>PP_TRUE</code> on success, <code>PP_FALSE</code> on failure. - */ - PP_Bool (*SetDefaultPermission)( - const char* plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - PP_Bool clear_site_specific); - /** - * Sets site-specific permission. If a site has already got site-specific - * permission and it is not in <code>sites</code>, it won't be affected. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin settings are stored. - * @param[in] setting_type What type of setting to set. - * @param[in] site_count How many items are there in <code>sites</code>. - * @param[in] sites The site-specific settings. If a site is specified with - * <code>PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT</code> permission, it - * will be removed from the site-specific list. - * - * @return <code>PP_TRUE</code> on success, <code>PP_FALSE</code> on failure. - */ - PP_Bool (*SetSitePermission)( - const char* plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - uint32_t site_count, - const struct PP_Flash_BrowserOperations_SiteSetting sites[]); - /** - * Returns a list of sites that have stored data, for use with the - * "Clear site data" feature. - * - * @param[in] plugin_data_path String containing the directory where the - * plugin data is stored. - * @param[out] sites A NULL-terminated array of sites that have stored data. - * Use FreeSiteList on the array when done. - * - * See also the NPP_GetSitesWithData function in NPAPI: - * https://wiki.mozilla.org/NPAPI:ClearSiteData - */ - void (*GetSitesWithData)(const char* plugin_data_path, char*** sites); - /** - * Frees the list of sites returned by GetSitesWithData. - * - * @param[in] sites A NULL-terminated array of strings. - */ - void (*FreeSiteList)(char* sites[]); -}; - -typedef struct PPP_Flash_BrowserOperations_1_3 PPP_Flash_BrowserOperations; - -struct PPP_Flash_BrowserOperations_1_0 { - PP_Bool (*ClearSiteData)(const char* plugin_data_path, - const char* site, - uint64_t flags, - uint64_t max_age); -}; - -struct PPP_Flash_BrowserOperations_1_2 { - PP_Bool (*ClearSiteData)(const char* plugin_data_path, - const char* site, - uint64_t flags, - uint64_t max_age); - PP_Bool (*DeauthorizeContentLicenses)(const char* plugin_data_path); - void (*GetPermissionSettings)( - const char* plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - PPB_Flash_BrowserOperations_GetSettingsCallback callback, - void* user_data); - PP_Bool (*SetDefaultPermission)( - const char* plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - PP_Flash_BrowserOperations_Permission permission, - PP_Bool clear_site_specific); - PP_Bool (*SetSitePermission)( - const char* plugin_data_path, - PP_Flash_BrowserOperations_SettingType setting_type, - uint32_t site_count, - const struct PP_Flash_BrowserOperations_SiteSetting sites[]); -}; -/** - * @} - */ - -#endif /* PPAPI_C_PRIVATE_PPP_FLASH_BROWSER_OPERATIONS_H_ */ -
diff --git a/ppapi/cpp/BUILD.gn b/ppapi/cpp/BUILD.gn index 8dabad0..8f0bbcab 100644 --- a/ppapi/cpp/BUILD.gn +++ b/ppapi/cpp/BUILD.gn
@@ -207,8 +207,6 @@ "private/find_private.h", "private/flash_font_file.cc", "private/flash_font_file.h", - "private/flash_fullscreen.cc", - "private/flash_fullscreen.h", "private/host_resolver_private.cc", "private/host_resolver_private.h", "private/instance_private.cc",
diff --git a/ppapi/cpp/private/flash_fullscreen.cc b/ppapi/cpp/private/flash_fullscreen.cc deleted file mode 100644 index e771c498..0000000 --- a/ppapi/cpp/private/flash_fullscreen.cc +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ppapi/cpp/private/flash_fullscreen.h" - -#include "ppapi/c/private/ppb_flash_fullscreen.h" -#include "ppapi/cpp/instance.h" -#include "ppapi/cpp/module.h" -#include "ppapi/cpp/module_impl.h" -#include "ppapi/cpp/size.h" - -namespace pp { - -namespace { - -template <> const char* interface_name<PPB_FlashFullscreen_1_0>() { - return PPB_FLASHFULLSCREEN_INTERFACE_1_0; -} - -} // namespace - -FlashFullscreen::FlashFullscreen(const InstanceHandle& instance) - : instance_(instance) { -} - -FlashFullscreen::~FlashFullscreen() { -} - -bool FlashFullscreen::IsFullscreen() { - if (has_interface<PPB_FlashFullscreen_1_0>()) { - return PP_ToBool(get_interface<PPB_FlashFullscreen_1_0>()->IsFullscreen( - instance_.pp_instance())); - } - return false; -} - -bool FlashFullscreen::SetFullscreen(bool fullscreen) { - if (has_interface<PPB_FlashFullscreen_1_0>()) { - return PP_ToBool(get_interface<PPB_FlashFullscreen_1_0>()->SetFullscreen( - instance_.pp_instance(), PP_FromBool(fullscreen))); - } - return false; -} - -bool FlashFullscreen::GetScreenSize(Size* size) { - if (has_interface<PPB_FlashFullscreen_1_0>()) { - return PP_ToBool(get_interface<PPB_FlashFullscreen_1_0>()->GetScreenSize( - instance_.pp_instance(), &size->pp_size())); - } - return false; -} - -bool FlashFullscreen::MustRecreateContexts() { - return !get_interface<PPB_FlashFullscreen_1_0>(); -} - -} // namespace pp
diff --git a/ppapi/cpp/private/flash_fullscreen.h b/ppapi/cpp/private/flash_fullscreen.h deleted file mode 100644 index 48e4ffd9..0000000 --- a/ppapi/cpp/private/flash_fullscreen.h +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PPAPI_CPP_PRIVATE_FLASH_FULLSCREEN_H_ -#define PPAPI_CPP_PRIVATE_FLASH_FULLSCREEN_H_ - -#include "ppapi/cpp/instance_handle.h" - -namespace pp { - -class Size; - -class FlashFullscreen { - public: - FlashFullscreen(const InstanceHandle& instance); - virtual ~FlashFullscreen(); - - // PPB_FlashFullscreen methods. - bool IsFullscreen(); - bool SetFullscreen(bool fullscreen); - bool GetScreenSize(Size* size); - - bool MustRecreateContexts(); - - private: - InstanceHandle instance_; -}; - -} // namespace pp - -#endif // PPAPI_CPP_PRIVATE_FLASH_FULLSCREEN_H_
diff --git a/ppapi/examples/mouse_lock/mouse_lock.cc b/ppapi/examples/mouse_lock/mouse_lock.cc index e6397e6..6b87656 100644 --- a/ppapi/examples/mouse_lock/mouse_lock.cc +++ b/ppapi/examples/mouse_lock/mouse_lock.cc
@@ -16,7 +16,7 @@ #include "ppapi/cpp/logging.h" #include "ppapi/cpp/module.h" #include "ppapi/cpp/mouse_lock.h" -#include "ppapi/cpp/private/flash_fullscreen.h" +#include "ppapi/cpp/fullscreen.h" #include "ppapi/cpp/rect.h" #include "ppapi/cpp/var.h" #include "ppapi/utility/completion_callback_factory.h" @@ -33,7 +33,7 @@ waiting_for_flush_completion_(false), callback_factory_(this), console_(NULL), - flash_fullscreen_(this) { + fullscreen_(this) { } virtual ~MyInstance() {} @@ -78,8 +78,8 @@ return true; } else if (key_event.GetKeyCode() == 70) { // Enter Flash fullscreen mode when the 'f' key is pressed. - if (!flash_fullscreen_.IsFullscreen()) - flash_fullscreen_.SetFullscreen(true); + if (!fullscreen_.IsFullscreen()) + fullscreen_.SetFullscreen(true); return true; } return false; @@ -252,7 +252,7 @@ const PPB_Console* console_; - pp::FlashFullscreen flash_fullscreen_; + pp::Fullscreen fullscreen_; pp::Graphics2D device_context_; };
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c index 430ee6e..11e7f50 100644 --- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c +++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
@@ -3067,8 +3067,6 @@ /* Not generating wrapper methods for PPB_Flash_FontFile_0_2 */ -/* Not generating wrapper methods for PPB_FlashFullscreen_1_0 */ - /* Begin wrapper methods for PPB_HostResolver_Private_0_1 */ static PP_Resource Pnacl_M19_PPB_HostResolver_Private_Create(PP_Instance instance) { @@ -3759,12 +3757,6 @@ /* Not generating wrapper methods for PPP_Find_Private_0_3 */ -/* Not generating wrapper methods for PPP_Flash_BrowserOperations_1_0 */ - -/* Not generating wrapper methods for PPP_Flash_BrowserOperations_1_2 */ - -/* Not generating wrapper methods for PPP_Flash_BrowserOperations_1_3 */ - /* Begin wrapper methods for PPP_Instance_Private_0_1 */ static struct PP_Var Pnacl_M18_PPP_Instance_Private_GetInstanceObject(PP_Instance instance) { @@ -4611,8 +4603,6 @@ /* Not generating wrapper interface for PPB_Flash_FontFile_0_2 */ -/* Not generating wrapper interface for PPB_FlashFullscreen_1_0 */ - static const struct PPB_HostResolver_Private_0_1 Pnacl_Wrappers_PPB_HostResolver_Private_0_1 = { .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M19_PPB_HostResolver_Private_Create, .IsHostResolver = (PP_Bool (*)(PP_Resource resource))&Pnacl_M19_PPB_HostResolver_Private_IsHostResolver, @@ -4790,12 +4780,6 @@ /* Not generating wrapper interface for PPP_Find_Private_0_3 */ -/* Not generating wrapper interface for PPP_Flash_BrowserOperations_1_0 */ - -/* Not generating wrapper interface for PPP_Flash_BrowserOperations_1_2 */ - -/* Not generating wrapper interface for PPP_Flash_BrowserOperations_1_3 */ - static const struct PPP_Instance_Private_0_1 Pnacl_Wrappers_PPP_Instance_Private_0_1 = { .GetInstanceObject = &Pnacl_M18_PPP_Instance_Private_GetInstanceObject };
diff --git a/ppapi/proxy/BUILD.gn b/ppapi/proxy/BUILD.gn index 63c770b..e0052bd 100644 --- a/ppapi/proxy/BUILD.gn +++ b/ppapi/proxy/BUILD.gn
@@ -138,8 +138,6 @@ "proxy_channel.cc", "proxy_channel.h", "proxy_completion_callback_factory.h", - "proxy_module.cc", - "proxy_module.h", "proxy_object_var.cc", "proxy_object_var.h", "resource_creation_proxy.cc",
diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc index 8a6c33a..8d83d34 100644 --- a/ppapi/proxy/interface_list.cc +++ b/ppapi/proxy/interface_list.cc
@@ -77,7 +77,6 @@ #include "ppapi/c/private/ppb_file_ref_private.h" #include "ppapi/c/private/ppb_find_private.h" #include "ppapi/c/private/ppb_flash_font_file.h" -#include "ppapi/c/private/ppb_flash_fullscreen.h" #include "ppapi/c/private/ppb_host_resolver_private.h" #include "ppapi/c/private/ppb_isolated_file_system_private.h" #include "ppapi/c/private/ppb_net_address_private.h"
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index 43e9955..0051604 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h
@@ -59,7 +59,6 @@ #include "ppapi/c/private/ppb_isolated_file_system_private.h" #include "ppapi/c/private/ppb_net_address_private.h" #include "ppapi/c/private/ppb_pdf.h" -#include "ppapi/c/private/ppp_flash_browser_operations.h" #include "ppapi/c/private/ppp_pdf.h" #include "ppapi/proxy/host_resolver_private_resource.h" #include "ppapi/proxy/network_list_resource.h" @@ -82,7 +81,6 @@ #include "ppapi/shared_impl/ppb_input_event_shared.h" #include "ppapi/shared_impl/ppb_tcp_socket_shared.h" #include "ppapi/shared_impl/ppb_view_shared.h" -#include "ppapi/shared_impl/ppp_flash_browser_operations_shared.h" #include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h" #include "ppapi/shared_impl/socket_option_data.h" #include "ppapi/shared_impl/url_request_info_data.h" @@ -99,10 +97,6 @@ IPC_ENUM_TRAITS_MAX_VALUE(PP_DeviceType_Dev, PP_DEVICETYPE_DEV_MAX) IPC_ENUM_TRAITS_MAX_VALUE(PP_FileSystemType, PP_FILESYSTEMTYPE_ISOLATED) IPC_ENUM_TRAITS_MAX_VALUE(PP_FileType, PP_FILETYPE_OTHER) -IPC_ENUM_TRAITS_MAX_VALUE(PP_Flash_BrowserOperations_Permission, - PP_FLASH_BROWSEROPERATIONS_PERMISSION_LAST) -IPC_ENUM_TRAITS_MAX_VALUE(PP_Flash_BrowserOperations_SettingType, - PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_LAST) IPC_ENUM_TRAITS_MAX_VALUE(PP_ImageDataFormat, PP_IMAGEDATAFORMAT_LAST) IPC_ENUM_TRAITS_MIN_MAX_VALUE(PP_InputEvent_MouseButton, PP_INPUTEVENT_MOUSEBUTTON_FIRST, @@ -442,11 +436,6 @@ IPC_STRUCT_TRAITS_MEMBER(file_system_plugin_resource) IPC_STRUCT_TRAITS_END() -IPC_STRUCT_TRAITS_BEGIN(ppapi::FlashSiteSetting) - IPC_STRUCT_TRAITS_MEMBER(site) - IPC_STRUCT_TRAITS_MEMBER(permission) -IPC_STRUCT_TRAITS_END() - IPC_STRUCT_TRAITS_BEGIN(ppapi::MediaStreamAudioTrackShared::Attributes) IPC_STRUCT_TRAITS_MEMBER(buffers) IPC_STRUCT_TRAITS_MEMBER(duration) @@ -651,66 +640,6 @@ IPC_MESSAGE_CONTROL1(PpapiMsg_SetNetworkState, bool /* online */) -// Requests a list of sites that have data stored from the plugin. The plugin -// process will respond with PpapiHostMsg_GetSitesWithDataResult. This is used -// for Flash. -IPC_MESSAGE_CONTROL2(PpapiMsg_GetSitesWithData, - uint32_t /* request_id */, - base::FilePath /* plugin_data_path */) -IPC_MESSAGE_CONTROL2(PpapiHostMsg_GetSitesWithDataResult, - uint32_t /* request_id */, - std::vector<std::string> /* sites */) - -// Instructs the plugin to clear data for the given site & time. The plugin -// process will respond with PpapiHostMsg_ClearSiteDataResult. This is used -// for Flash. -IPC_MESSAGE_CONTROL5(PpapiMsg_ClearSiteData, - uint32_t /* request_id */, - base::FilePath /* plugin_data_path */, - std::string /* site */, - uint64_t /* flags */, - uint64_t /* max_age */) -IPC_MESSAGE_CONTROL2(PpapiHostMsg_ClearSiteDataResult, - uint32_t /* request_id */, - bool /* success */) - -IPC_MESSAGE_CONTROL2(PpapiMsg_DeauthorizeContentLicenses, - uint32_t /* request_id */, - base::FilePath /* plugin_data_path */) -IPC_MESSAGE_CONTROL2(PpapiHostMsg_DeauthorizeContentLicensesResult, - uint32_t /* request_id */, - bool /* success */) - -IPC_MESSAGE_CONTROL3(PpapiMsg_GetPermissionSettings, - uint32_t /* request_id */, - base::FilePath /* plugin_data_path */, - PP_Flash_BrowserOperations_SettingType /* setting_type */) -IPC_MESSAGE_CONTROL4( - PpapiHostMsg_GetPermissionSettingsResult, - uint32_t /* request_id */, - bool /* success */, - PP_Flash_BrowserOperations_Permission /* default_permission */, - ppapi::FlashSiteSettings /* sites */) - -IPC_MESSAGE_CONTROL5(PpapiMsg_SetDefaultPermission, - uint32_t /* request_id */, - base::FilePath /* plugin_data_path */, - PP_Flash_BrowserOperations_SettingType /* setting_type */, - PP_Flash_BrowserOperations_Permission /* permission */, - bool /* clear_site_specific */) -IPC_MESSAGE_CONTROL2(PpapiHostMsg_SetDefaultPermissionResult, - uint32_t /* request_id */, - bool /* success */) - -IPC_MESSAGE_CONTROL4(PpapiMsg_SetSitePermission, - uint32_t /* request_id */, - base::FilePath /* plugin_data_path */, - PP_Flash_BrowserOperations_SettingType /* setting_type */, - ppapi::FlashSiteSettings /* sites */) -IPC_MESSAGE_CONTROL2(PpapiHostMsg_SetSitePermissionResult, - uint32_t /* request_id */, - bool /* success */) - // Broker Process. IPC_SYNC_MESSAGE_CONTROL2_1(PpapiMsg_ConnectToPlugin, PP_Instance /* instance */,
diff --git a/ppapi/proxy/ppapi_param_traits.h b/ppapi/proxy/ppapi_param_traits.h index 8e57cb6d..24b6e8e 100644 --- a/ppapi/proxy/ppapi_param_traits.h +++ b/ppapi/proxy/ppapi_param_traits.h
@@ -34,7 +34,6 @@ struct PPBURLLoader_UpdateProgress_Params; struct SerializedDirEntry; struct SerializedFontDescription; -class SerializedFlashMenu; class SerializedHandle; class SerializedVar; @@ -167,15 +166,6 @@ static void Log(const param_type& p, std::string* l); }; -template<> -struct PPAPI_PROXY_EXPORT ParamTraits<ppapi::proxy::SerializedFlashMenu> { - typedef ppapi::proxy::SerializedFlashMenu param_type; - static void Write(base::Pickle* m, const param_type& p); - static bool Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* r); - static void Log(const param_type& p, std::string* l); -}; #endif // !defined(OS_NACL) && !defined(NACL_WIN64) template<>
diff --git a/ppapi/proxy/ppp_instance_proxy_unittest.cc b/ppapi/proxy/ppp_instance_proxy_unittest.cc index c3098d7..2a4b285 100644 --- a/ppapi/proxy/ppp_instance_proxy_unittest.cc +++ b/ppapi/proxy/ppp_instance_proxy_unittest.cc
@@ -12,7 +12,6 @@ #include "ppapi/c/ppb_fullscreen.h" #include "ppapi/c/ppb_url_loader.h" #include "ppapi/c/ppp_instance.h" -#include "ppapi/c/private/ppb_flash_fullscreen.h" #include "ppapi/proxy/locking_resource_releaser.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/ppapi_proxy_test.h" @@ -99,13 +98,12 @@ &HandleDocumentLoad }; -// PPP_Instance_Proxy::DidChangeView relies on PPB_(Flash)Fullscreen being +// PPP_Instance_Proxy::DidChangeView relies on PPB_Fullscreen being // available with a valid implementation of IsFullScreen, so we mock it. PP_Bool IsFullscreen(PP_Instance instance) { return PP_FALSE; } PPB_Fullscreen ppb_fullscreen = { &IsFullscreen }; -PPB_FlashFullscreen ppb_flash_fullscreen = { &IsFullscreen }; } // namespace @@ -118,8 +116,6 @@ TEST_F(PPP_Instance_ProxyTest, PPPInstance1_0) { plugin().RegisterTestInterface(PPP_INSTANCE_INTERFACE_1_0, &ppp_instance_1_0); - host().RegisterTestInterface(PPB_FLASHFULLSCREEN_INTERFACE, - &ppb_flash_fullscreen); host().RegisterTestInterface(PPB_FULLSCREEN_INTERFACE, &ppb_fullscreen);
diff --git a/ppapi/proxy/proxy_module.cc b/ppapi/proxy/proxy_module.cc deleted file mode 100644 index db32ac9..0000000 --- a/ppapi/proxy/proxy_module.cc +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ppapi/proxy/proxy_module.h" - -#include "base/memory/singleton.h" - -namespace ppapi { -namespace proxy { - -ProxyModule::ProxyModule() { -} - -ProxyModule::~ProxyModule() { -} - -// static -ProxyModule* ProxyModule::GetInstance() { - return base::Singleton<ProxyModule>::get(); -} - -const std::string& ProxyModule::GetFlashCommandLineArgs() { - return flash_command_line_args_; -} - -void ProxyModule::SetFlashCommandLineArgs(const std::string& args) { - flash_command_line_args_ = args; -} - -} // namespace proxy -} // namespace ppapi
diff --git a/ppapi/proxy/proxy_module.h b/ppapi/proxy/proxy_module.h deleted file mode 100644 index 21f53b1..0000000 --- a/ppapi/proxy/proxy_module.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PPAPI_PROXY_PROXY_MODULE_H_ -#define PPAPI_PROXY_PROXY_MODULE_H_ - -#include <string> - -#include "base/macros.h" -#include "ppapi/proxy/ppapi_proxy_export.h" - -namespace base { -template<typename T> struct DefaultSingletonTraits; -} - -namespace ppapi { -namespace proxy { - -class PPAPI_PROXY_EXPORT ProxyModule { - public: - // The global singleton getter. - static ProxyModule* GetInstance(); - - // TODO(viettrungluu): Generalize this for use with other plugins if it proves - // necessary. (Currently, we can't do this easily, since we can't tell from - // |PpapiPluginMain()| which plugin will be loaded.) - const std::string& GetFlashCommandLineArgs(); - void SetFlashCommandLineArgs(const std::string& args); - - private: - friend struct base::DefaultSingletonTraits<ProxyModule>; - - std::string flash_command_line_args_; - - ProxyModule(); - ~ProxyModule(); - - DISALLOW_COPY_AND_ASSIGN(ProxyModule); -}; - -} // namespace proxy -} // namespace ppapi - -#endif // PPAPI_PROXY_PROXY_MODULE_H_
diff --git a/ppapi/shared_impl/BUILD.gn b/ppapi/shared_impl/BUILD.gn index 150d3112..24e5734 100644 --- a/ppapi/shared_impl/BUILD.gn +++ b/ppapi/shared_impl/BUILD.gn
@@ -87,7 +87,6 @@ "ppb_var_shared.h", "ppb_view_shared.cc", "ppb_view_shared.h", - "ppp_flash_browser_operations_shared.h", "ppp_instance_combined.cc", "ppp_instance_combined.h", "proxy_lock.cc",
diff --git a/ppapi/shared_impl/ppp_flash_browser_operations_shared.h b/ppapi/shared_impl/ppp_flash_browser_operations_shared.h deleted file mode 100644 index 7584390..0000000 --- a/ppapi/shared_impl/ppp_flash_browser_operations_shared.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PPAPI_SHARED_IMPL_PPP_FLASH_BROWSER_OPERATIONS_SHARED_H_ -#define PPAPI_SHARED_IMPL_PPP_FLASH_BROWSER_OPERATIONS_SHARED_H_ - -#include <string> -#include <vector> - -#include "ppapi/c/private/ppp_flash_browser_operations.h" - -namespace ppapi { - -struct FlashSiteSetting { - FlashSiteSetting() - : permission(PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT) {} - FlashSiteSetting(const std::string& in_site, - PP_Flash_BrowserOperations_Permission in_permission) - : site(in_site), permission(in_permission) {} - - std::string site; - PP_Flash_BrowserOperations_Permission permission; -}; - -typedef std::vector<FlashSiteSetting> FlashSiteSettings; - -} // namespace ppapi - -#endif // PPAPI_SHARED_IMPL_PPP_FLASH_BROWSER_OPERATIONS_SHARED_H_
diff --git a/ppapi/tests/all_cpp_includes.h b/ppapi/tests/all_cpp_includes.h index c4f4561..13741a7 100644 --- a/ppapi/tests/all_cpp_includes.h +++ b/ppapi/tests/all_cpp_includes.h
@@ -48,7 +48,6 @@ #include "ppapi/cpp/private/camera_device_private.h" #include "ppapi/cpp/private/find_private.h" #include "ppapi/cpp/private/flash_font_file.h" -#include "ppapi/cpp/private/flash_fullscreen.h" #include "ppapi/cpp/private/instance_private.h" #include "ppapi/cpp/private/net_address_private.h" #include "ppapi/cpp/private/tcp_socket_private.h"
diff --git a/ppapi/tests/test_flash_fullscreen.cc b/ppapi/tests/test_flash_fullscreen.cc deleted file mode 100644 index 2018702..0000000 --- a/ppapi/tests/test_flash_fullscreen.cc +++ /dev/null
@@ -1,204 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ppapi/tests/test_flash_fullscreen.h" - -#include <stdio.h> -#include <string.h> -#include <string> - -#include "ppapi/c/private/ppb_flash_fullscreen.h" -#include "ppapi/cpp/graphics_2d.h" -#include "ppapi/cpp/input_event.h" -#include "ppapi/cpp/instance.h" -#include "ppapi/cpp/module.h" -#include "ppapi/cpp/point.h" -#include "ppapi/cpp/private/flash_fullscreen.h" -#include "ppapi/cpp/rect.h" -#include "ppapi/cpp/size.h" -#include "ppapi/tests/test_utils.h" -#include "ppapi/tests/testing_instance.h" - -REGISTER_TEST_CASE(FlashFullscreen); - -namespace { - -bool IsFullscreenView(const pp::Rect& position, - const pp::Rect& clip, - const pp::Size& screen_size) { - return (position.point() == pp::Point(0, 0) && - position.size() == screen_size && - clip.point() == pp::Point(0, 0) && - clip.size() == screen_size); -} - -} // namespace - -TestFlashFullscreen::TestFlashFullscreen(TestingInstance* instance) - : TestCase(instance), - screen_mode_(instance), - fullscreen_pending_(false), - normal_pending_(false), - fullscreen_event_(instance->pp_instance()), - normal_event_(instance->pp_instance()) { - screen_mode_.GetScreenSize(&screen_size_); -} - -bool TestFlashFullscreen::Init() { - return CheckTestingInterface(); -} - -void TestFlashFullscreen::RunTests(const std::string& filter) { - RUN_TEST(GetScreenSize, filter); - RUN_TEST(NormalToFullscreenToNormal, filter); -} - -std::string TestFlashFullscreen::TestGetScreenSize() { - if (screen_size_.width() < 320 || screen_size_.width() > 2560) - return ReportError("screen_size.width()", screen_size_.width()); - if (screen_size_.height() < 200 || screen_size_.height() > 2048) - return ReportError("screen_size.height()", screen_size_.height()); - PASS(); -} - -std::string TestFlashFullscreen::TestNormalToFullscreenToNormal() { - // 0. Start in normal mode. - if (screen_mode_.IsFullscreen()) - return ReportError("IsFullscreen() at start", true); - - // This is only allowed within a contet of a user gesture (e.g. mouse click). - if (screen_mode_.SetFullscreen(true)) - return ReportError("SetFullscreen(true) outside of user gesture", true); - - // 1. Switch to fullscreen. - // The transition is asynchronous and ends at the next DidChangeView(). - // No graphics devices can be bound while in transition. - fullscreen_pending_ = true; - instance_->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); - SimulateUserGesture(); - // DidChangeView() will call the callback once in fullscreen mode. - fullscreen_event_.Wait(); - if (GotError()) - return Error(); - if (fullscreen_pending_) - return "fullscreen_pending_ has not been reset"; - if (!screen_mode_.IsFullscreen()) - return ReportError("IsFullscreen() in fullscreen", false); - pp::Graphics2D graphics2d_fullscreen(instance_, pp::Size(10, 10), false); - if (graphics2d_fullscreen.is_null()) - return "Failed to create graphics2d_fullscreen"; - if (!instance_->BindGraphics(graphics2d_fullscreen)) - return ReportError("BindGraphics() in fullscreen", false); - - // 2. Stay in fullscreen. No change. - if (!screen_mode_.SetFullscreen(true)) - return ReportError("SetFullscreen(true) in fullscreen", false); - if (!screen_mode_.IsFullscreen()) - return ReportError("IsFullscreen() in fullscreen^2", false); - - // 3. Switch to normal. - // The transition is synchronous in-process and asynchornous out-of-process - // because proxied IsFullscreen saves a roundtrip by relying on information - // communicated via a previous call to DidChangeView. - // Graphics devices can be bound right away. - normal_pending_ = true; - if (!screen_mode_.SetFullscreen(false)) - return ReportError("SetFullscreen(false) in fullscreen", false); - pp::Graphics2D graphics2d_normal(instance_, pp::Size(15, 15), false); - if (graphics2d_normal.is_null()) - return "Failed to create graphics2d_normal"; - if (!instance_->BindGraphics(graphics2d_normal)) - return ReportError("BindGraphics() in normal transition", false); - if (testing_interface_->IsOutOfProcess()) { - if (!screen_mode_.IsFullscreen()) - return ReportError("IsFullscreen() in normal transition", false); - normal_event_.Wait(); - if (normal_pending_) - return "normal_pending_ has not been reset"; - } - if (screen_mode_.IsFullscreen()) - return ReportError("IsFullscreen() in normal", true); - - // 4. Stay in normal. No change. - if (!screen_mode_.SetFullscreen(false)) - return ReportError("SetFullscreen(false) in normal", false); - if (screen_mode_.IsFullscreen()) - return ReportError("IsFullscreen() in normal^2", true); - - PASS(); -} - -// Transition to fullscreen is asynchornous ending at DidChangeView. -// Transition to normal is synchronous in-process and asynchronous -// out-of-process ending at DidChangeView. -void TestFlashFullscreen::DidChangeView(const pp::View& view) { - pp::Rect position = view.GetRect(); - pp::Rect clip = view.GetClipRect(); - if (normal_position_.IsEmpty()) - normal_position_ = view.GetRect(); - if (fullscreen_pending_ && IsFullscreenView(position, clip, screen_size_)) { - fullscreen_pending_ = false; - fullscreen_event_.Signal(); - } else if (normal_pending_ && - !IsFullscreenView(position, clip, screen_size_)) { - normal_pending_ = false; - if (testing_interface_->IsOutOfProcess()) - normal_event_.Signal(); - } -} - -void TestFlashFullscreen::SimulateUserGesture() { - pp::Point plugin_center( - normal_position_.x() + normal_position_.width() / 2, - normal_position_.y() + normal_position_.height() / 2); - pp::Point mouse_movement; - pp::MouseInputEvent input_event( - instance_, - PP_INPUTEVENT_TYPE_MOUSEDOWN, - NowInTimeTicks(), // time_stamp - 0, // modifiers - PP_INPUTEVENT_MOUSEBUTTON_LEFT, - plugin_center, - 1, // click_count - mouse_movement); - - testing_interface_->SimulateInputEvent(instance_->pp_instance(), - input_event.pp_resource()); -} - -bool TestFlashFullscreen::GotError() { - return !error_.empty(); -} - -std::string TestFlashFullscreen::Error() { - std::string last_error = error_; - error_.clear(); - return last_error; -} - -void TestFlashFullscreen::FailFullscreenTest(const std::string& error) { - error_ = error; - fullscreen_event_.Signal(); -} - -bool TestFlashFullscreen::HandleInputEvent(const pp::InputEvent& event) { - if (event.GetType() != PP_INPUTEVENT_TYPE_MOUSEDOWN && - event.GetType() != PP_INPUTEVENT_TYPE_MOUSEUP) { - return false; - } - - instance_->ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE); - if (screen_mode_.IsFullscreen()) { - FailFullscreenTest( - ReportError("IsFullscreen() before fullscreen transition", true)); - return false; - } - if (!screen_mode_.SetFullscreen(true)) { - FailFullscreenTest( - ReportError("SetFullscreen(true) in normal", false)); - return false; - } - // DidChangeView() will complete the transition to fullscreen. - return false; -}
diff --git a/ppapi/tests/test_flash_fullscreen.h b/ppapi/tests/test_flash_fullscreen.h deleted file mode 100644 index 0318727..0000000 --- a/ppapi/tests/test_flash_fullscreen.h +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PPAPI_TESTS_TEST_FLASH_FULLSCREEN_H_ -#define PPAPI_TESTS_TEST_FLASH_FULLSCREEN_H_ - -#include <string> - -#include "ppapi/cpp/private/flash_fullscreen.h" -#include "ppapi/cpp/size.h" -#include "ppapi/tests/test_case.h" -#include "ppapi/tests/test_utils.h" - -namespace pp { -class Rect; -} // namespace pp - -class TestFlashFullscreen : public TestCase { - public: - explicit TestFlashFullscreen(TestingInstance* instance); - - // TestCase implementation. - bool Init() override; - void RunTests(const std::string& filter) override; - void DidChangeView(const pp::View& view) override; - bool HandleInputEvent(const pp::InputEvent& event) override; - - private: - std::string TestGetScreenSize(); - std::string TestNormalToFullscreenToNormal(); - void SimulateUserGesture(); - bool GotError(); - std::string Error(); - void FailFullscreenTest(const std::string& error); - - std::string error_; - - pp::FlashFullscreen screen_mode_; - pp::Size screen_size_; - pp::Rect normal_position_; - - bool fullscreen_pending_; - bool normal_pending_; - NestedEvent fullscreen_event_; - NestedEvent normal_event_; -}; - -#endif // PPAPI_TESTS_TEST_FLASH_FULLSCREEN_H_
diff --git a/ppapi/tests/test_flash_fullscreen_for_browser_ui.cc b/ppapi/tests/test_flash_fullscreen_for_browser_ui.cc deleted file mode 100644 index 4bb1004f..0000000 --- a/ppapi/tests/test_flash_fullscreen_for_browser_ui.cc +++ /dev/null
@@ -1,190 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ppapi/tests/test_flash_fullscreen_for_browser_ui.h" - -#include <GLES2/gl2.h> - -#include "ppapi/c/ppb_opengles2.h" -#include "ppapi/cpp/input_event.h" -#include "ppapi/cpp/instance.h" -#include "ppapi/cpp/rect.h" -#include "ppapi/tests/testing_instance.h" - -REGISTER_TEST_CASE(FlashFullscreenForBrowserUI); - -TestFlashFullscreenForBrowserUI:: - TestFlashFullscreenForBrowserUI(TestingInstance* instance) - : TestCase(instance), - screen_mode_(instance), - view_change_event_(instance->pp_instance()), - callback_factory_(this) { - // This plugin should not be removed after this TestCase passes because - // browser UI testing requires it to remain and to be interactive. - instance_->set_remove_plugin(false); -} - -TestFlashFullscreenForBrowserUI::~TestFlashFullscreenForBrowserUI() { -} - -bool TestFlashFullscreenForBrowserUI::Init() { - opengl_es2_ = static_cast<const PPB_OpenGLES2*>( - pp::Module::Get()->GetBrowserInterface(PPB_OPENGLES2_INTERFACE)); - return opengl_es2_ && CheckTestingInterface(); -} - -void TestFlashFullscreenForBrowserUI::RunTests(const std::string& filter) { - RUN_TEST(EnterFullscreen, filter); -} - -std::string TestFlashFullscreenForBrowserUI::TestEnterFullscreen() { - if (screen_mode_.IsFullscreen()) - return ReportError("IsFullscreen() at start", true); - - // This is only allowed within a contet of a user gesture (e.g. mouse click). - if (screen_mode_.SetFullscreen(true)) - return ReportError("SetFullscreen(true) outside of user gesture", true); - - int32_t attribs[] = {PP_GRAPHICS3DATTRIB_RED_SIZE, 8, - PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, - PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, - PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, - PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, - PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, - PP_GRAPHICS3DATTRIB_WIDTH, layer_size_.width(), - PP_GRAPHICS3DATTRIB_HEIGHT, layer_size_.height(), - PP_GRAPHICS3DATTRIB_NONE}; - graphics_3d_ = pp::Graphics3D(instance_, attribs); - instance_->BindGraphics(graphics_3d_); - - // Trigger another call to SetFullscreen(true) from HandleInputEvent(). - // The transition is asynchronous and ends at the next DidChangeView(). - view_change_event_.Reset(); - request_fullscreen_ = true; - instance_->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); - SimulateUserGesture(); - // DidChangeView() will call the callback once in fullscreen mode. - view_change_event_.Wait(); - if (GotError()) - return Error(); - - if (!screen_mode_.IsFullscreen()) - return ReportError("IsFullscreen() in fullscreen", false); - - const int32_t result = - instance_->RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_MOUSE | - PP_INPUTEVENT_CLASS_KEYBOARD); - if (result != PP_OK) - return ReportError("RequestFilteringInputEvents() failed", result); - - PASS(); -} - -void TestFlashFullscreenForBrowserUI::DidChangeView(const pp::View& view) { - layer_size_ = view.GetRect().size(); - if (normal_position_.IsEmpty()) - normal_position_ = view.GetRect(); - - if (!graphics_3d_.is_null()) { - graphics_3d_.ResizeBuffers(layer_size_.width(), layer_size_.height()); - RequestPaint(); - } - - view_change_event_.Signal(); -} - -void TestFlashFullscreenForBrowserUI::SimulateUserGesture() { - pp::Point plugin_center( - normal_position_.x() + normal_position_.width() / 2, - normal_position_.y() + normal_position_.height() / 2); - pp::Point mouse_movement; - pp::MouseInputEvent input_event( - instance_, - PP_INPUTEVENT_TYPE_MOUSEDOWN, - NowInTimeTicks(), // time_stamp - 0, // modifiers - PP_INPUTEVENT_MOUSEBUTTON_LEFT, - plugin_center, - 1, // click_count - mouse_movement); - - testing_interface_->SimulateInputEvent(instance_->pp_instance(), - input_event.pp_resource()); -} - -bool TestFlashFullscreenForBrowserUI::GotError() { - return !error_.empty(); -} - -std::string TestFlashFullscreenForBrowserUI::Error() { - std::string last_error = error_; - error_.clear(); - return last_error; -} - -void TestFlashFullscreenForBrowserUI::FailFullscreenTest( - const std::string& error) { - error_ = error; - view_change_event_.Signal(); -} - -bool TestFlashFullscreenForBrowserUI::HandleInputEvent( - const pp::InputEvent& event) { - if (event.GetType() != PP_INPUTEVENT_TYPE_MOUSEDOWN && - event.GetType() != PP_INPUTEVENT_TYPE_MOUSEUP && - event.GetType() != PP_INPUTEVENT_TYPE_CHAR) { - return false; - } - - if (request_fullscreen_) { - instance_->ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE); - if (screen_mode_.IsFullscreen()) { - FailFullscreenTest( - ReportError("IsFullscreen() before fullscreen transition", true)); - return false; - } - request_fullscreen_ = false; - if (!screen_mode_.SetFullscreen(true)) { - FailFullscreenTest( - ReportError("SetFullscreen(true) in normal", false)); - return false; - } - // DidChangeView() will complete the transition to fullscreen. - return false; - } - - ++num_trigger_events_; - RequestPaint(); - - return true; -} - -void TestFlashFullscreenForBrowserUI::RequestPaint() { - if (swap_pending_) - needs_paint_ = true; - else - DoPaint(); -} - -void TestFlashFullscreenForBrowserUI::DoPaint() { - if (num_trigger_events_ == 0) - opengl_es2_->ClearColor(graphics_3d_.pp_resource(), 0.0f, 1.0f, 0.0f, 1.0f); - else if (num_trigger_events_ % 2) - opengl_es2_->ClearColor(graphics_3d_.pp_resource(), 1.0f, 0.0f, 0.0f, 1.0f); - else - opengl_es2_->ClearColor(graphics_3d_.pp_resource(), 0.0f, 0.0f, 1.0f, 1.0f); - - opengl_es2_->Clear(graphics_3d_.pp_resource(), GL_COLOR_BUFFER_BIT); - swap_pending_ = true; - graphics_3d_.SwapBuffers( - callback_factory_.NewCallback(&TestFlashFullscreenForBrowserUI::DidSwap)); -} - -void TestFlashFullscreenForBrowserUI::DidSwap(int32_t last_compositor_result) { - swap_pending_ = false; - if (needs_paint_) { - needs_paint_ = false; - DoPaint(); - } -}
diff --git a/ppapi/tests/test_flash_fullscreen_for_browser_ui.h b/ppapi/tests/test_flash_fullscreen_for_browser_ui.h deleted file mode 100644 index 64ee4cb..0000000 --- a/ppapi/tests/test_flash_fullscreen_for_browser_ui.h +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PPAPI_TESTS_TEST_FLASH_FULLSCREEN_FOR_BROWSER_UI_H_ -#define PPAPI_TESTS_TEST_FLASH_FULLSCREEN_FOR_BROWSER_UI_H_ - -#include <stdint.h> - -#include <string> - -#include "ppapi/cpp/graphics_3d.h" -#include "ppapi/cpp/private/flash_fullscreen.h" -#include "ppapi/cpp/size.h" -#include "ppapi/tests/test_case.h" -#include "ppapi/tests/test_utils.h" -#include "ppapi/utility/completion_callback_factory.h" - -struct PPB_OpenGLES2; - -// This is a special TestCase whose purpose is *not* to test the correctness of -// the Pepper APIs. Instead, this is a simulated Flash plugin, used to place -// the browser window and other UI elements into Flash Fullscreen mode for -// layout, event, focus, etc. testing. See -// chrome/browser/ui/exclusive_access/ -// flash_fullscreen_interactive_browsertest.cc. -// -// At start, this simulated Flash plugin will enter fullscreen and paint a green -// color fill. From there, it will respond to mouse clicks or key presses by -// toggling its fill color between red and blue. The browser test reads these -// color changes to detect the desired behavior. -class TestFlashFullscreenForBrowserUI : public TestCase { - public: - explicit TestFlashFullscreenForBrowserUI(TestingInstance* instance); - ~TestFlashFullscreenForBrowserUI() override; - - // TestCase implementation. - bool Init() override; - void RunTests(const std::string& filter) override; - void DidChangeView(const pp::View& view) override; - bool HandleInputEvent(const pp::InputEvent& event) override; - - private: - std::string TestEnterFullscreen(); - void RequestPaint(); - void DoPaint(); - void DidSwap(int32_t last_compositor_result); - void SimulateUserGesture(); - bool GotError(); - std::string Error(); - void FailFullscreenTest(const std::string& error); - - // OpenGL ES2 interface. - const PPB_OpenGLES2* opengl_es2_ = nullptr; - - std::string error_; - - pp::FlashFullscreen screen_mode_; - NestedEvent view_change_event_; - - pp::Graphics3D graphics_3d_; - pp::Size layer_size_; - pp::Rect normal_position_; - - int num_trigger_events_ = 0; - bool request_fullscreen_ = false; - bool swap_pending_ = false; - bool needs_paint_ = false; - - pp::CompletionCallbackFactory<TestFlashFullscreenForBrowserUI> - callback_factory_; -}; - -#endif // PPAPI_TESTS_TEST_FLASH_FULLSCREEN_FOR_BROWSER_UI_H_
diff --git a/ppapi/thunk/BUILD.gn b/ppapi/thunk/BUILD.gn index 4fcf795..1fc5932 100644 --- a/ppapi/thunk/BUILD.gn +++ b/ppapi/thunk/BUILD.gn
@@ -148,7 +148,6 @@ "ppb_buffer_thunk.cc", "ppb_char_set_thunk.cc", "ppb_flash_font_file_thunk.cc", - "ppb_flash_fullscreen_thunk.cc", "ppb_gles_chromium_texture_mapping_thunk.cc", "ppb_pdf_thunk.cc", "ppb_url_util_thunk.cc",
diff --git a/ppapi/thunk/interfaces_ppb_private.h b/ppapi/thunk/interfaces_ppb_private.h index 6f07ee1..07780c4 100644 --- a/ppapi/thunk/interfaces_ppb_private.h +++ b/ppapi/thunk/interfaces_ppb_private.h
@@ -33,7 +33,6 @@ PPB_FileChooserTrusted_0_6) PROXIED_IFACE(PPB_FILEREFPRIVATE_INTERFACE_0_1, PPB_FileRefPrivate_0_1) -PROXIED_IFACE(PPB_FLASHFULLSCREEN_INTERFACE_1_0, PPB_FlashFullscreen_1_0) #endif // !defined(OS_NACL) #include "ppapi/thunk/interfaces_postamble.h"
diff --git a/ppapi/thunk/ppb_flash_fullscreen_thunk.cc b/ppapi/thunk/ppb_flash_fullscreen_thunk.cc deleted file mode 100644 index 6cb3dfc..0000000 --- a/ppapi/thunk/ppb_flash_fullscreen_thunk.cc +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ppapi/c/ppb_fullscreen.h" -#include "ppapi/c/private/ppb_flash_fullscreen.h" -#include "ppapi/thunk/thunk.h" -#include "ppapi/thunk/enter.h" -#include "ppapi/thunk/ppb_flash_fullscreen_api.h" -#include "ppapi/thunk/ppb_instance_api.h" -#include "ppapi/thunk/resource_creation_api.h" - -namespace ppapi { -namespace thunk { - -namespace { - -PP_Bool IsFullscreen(PP_Instance instance) { - EnterInstanceAPI<PPB_Flash_Fullscreen_API> enter(instance); - if (enter.failed()) - return PP_FALSE; - return enter.functions()->IsFullscreen(instance); -} - -PP_Bool SetFullscreen(PP_Instance instance, PP_Bool fullscreen) { - EnterInstanceAPI<PPB_Flash_Fullscreen_API> enter(instance); - if (enter.failed()) - return PP_FALSE; - return enter.functions()->SetFullscreen(instance, fullscreen); -} - -// TODO(raymes): The codepaths for GetScreenSize in PPB_Fullscreen and -// PPB_Flash_Fullscreen are the same. Consider deprecating the flash version. -PP_Bool GetScreenSize(PP_Instance instance, PP_Size* size) { - EnterInstance enter(instance); - if (enter.failed()) - return PP_FALSE; - return enter.functions()->GetScreenSize(instance, size); -} - -const PPB_FlashFullscreen_1_0 g_ppb_flash_fullscreen_thunk = { - &IsFullscreen, &SetFullscreen, &GetScreenSize}; - -} // namespace - -const PPB_FlashFullscreen_1_0* GetPPB_FlashFullscreen_1_0_Thunk() { - return &g_ppb_flash_fullscreen_thunk; -} - -} // namespace thunk -} // namespace ppapi
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.cc index 7fe4475..18429ea 100644 --- a/services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.cc +++ b/services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.cc
@@ -18,6 +18,7 @@ const char kExtensionHistogramName[] = "Extension"; const char kGpuHistogramName[] = "Gpu"; const char kNetworkServiceHistogramName[] = "NetworkService"; +const char kPaintPreviewCompositorHistogramName[] = "PaintPreviewCompositor"; const char kRendererHistogramName[] = "Renderer"; const char kUtilityHistogramName[] = "Utility"; @@ -37,6 +38,8 @@ return kGpuHistogramName; case HistogramProcessType::kNetworkService: return kNetworkServiceHistogramName; + case HistogramProcessType::kPaintPreviewCompositor: + return kPaintPreviewCompositorHistogramName; case HistogramProcessType::kRenderer: return kRendererHistogramName; case HistogramProcessType::kUtility:
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.h b/services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.h index 5ed4e1ac..b1b1a46 100644 --- a/services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.h +++ b/services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.h
@@ -29,6 +29,7 @@ kExtension, kGpu, kNetworkService, + kPaintPreviewCompositor, kRenderer, kUtility, };
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc index f905fbdc..e8032e4 100644 --- a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc +++ b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
@@ -26,6 +26,7 @@ #include "base/threading/thread_id_name_manager.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" +#include "base/trace_event/task_execution_macros.h" #include "base/trace_event/thread_instruction_count.h" #include "base/trace_event/trace_event.h" #include "base/trace_event/trace_log.h" @@ -1018,20 +1019,17 @@ TEST_F(TraceEventDataSourceTest, TaskExecutionEvent) { CreateTraceEventDataSource(); - INTERNAL_TRACE_EVENT_ADD( - TRACE_EVENT_PHASE_INSTANT, "toplevel", "ThreadControllerImpl::RunTask", - TRACE_EVENT_SCOPE_THREAD | TRACE_EVENT_FLAG_TYPED_PROTO_ARGS, "src_file", - "my_file", "src_func", "my_func"); - INTERNAL_TRACE_EVENT_ADD( - TRACE_EVENT_PHASE_INSTANT, "toplevel", "ThreadControllerImpl::RunTask", - TRACE_EVENT_SCOPE_THREAD | TRACE_EVENT_FLAG_TYPED_PROTO_ARGS, "src_file", - "my_file", "src_func", "my_func"); + base::PendingTask task; + task.posted_from = + base::Location("my_func", "my_file", 0, /*program_counter=*/&task); + { TRACE_TASK_EXECUTION("ThreadControllerImpl::RunTask1", task); } + { TRACE_TASK_EXECUTION("ThreadControllerImpl::RunTask1", task); } size_t packet_index = ExpectStandardPreamble(); auto* e_packet = producer_client()->GetFinalizedPacket(packet_index++); ExpectTraceEvent(e_packet, /*category_iid=*/1u, /*name_iid=*/1u, - TRACE_EVENT_PHASE_INSTANT, TRACE_EVENT_SCOPE_THREAD); + TRACE_EVENT_PHASE_BEGIN); const auto& annotations = e_packet->track_event().debug_annotations(); EXPECT_EQ(annotations.size(), 0); @@ -1043,9 +1041,9 @@ EXPECT_EQ(locations[0].function_name(), "my_func"); // Second event should refer to the same interning entries. - auto* e_packet2 = producer_client()->GetFinalizedPacket(packet_index++); + auto* e_packet2 = producer_client()->GetFinalizedPacket(++packet_index); ExpectTraceEvent(e_packet2, /*category_iid=*/1u, /*name_iid=*/1u, - TRACE_EVENT_PHASE_INSTANT, TRACE_EVENT_SCOPE_THREAD); + TRACE_EVENT_PHASE_BEGIN); EXPECT_EQ(e_packet2->track_event().task_execution().posted_from_iid(), 1u); EXPECT_EQ(e_packet2->interned_data().source_locations().size(), 0); @@ -1054,16 +1052,16 @@ TEST_F(TraceEventDataSourceTest, TaskExecutionEventWithoutFunction) { CreateTraceEventDataSource(); - INTERNAL_TRACE_EVENT_ADD( - TRACE_EVENT_PHASE_INSTANT, "toplevel", "ThreadControllerImpl::RunTask", - TRACE_EVENT_SCOPE_THREAD | TRACE_EVENT_FLAG_TYPED_PROTO_ARGS, "src", - "my_file"); + base::PendingTask task; + task.posted_from = base::Location(/*function_name=*/nullptr, "my_file", 0, + /*program_counter=*/&task); + { TRACE_TASK_EXECUTION("ThreadControllerImpl::RunTask", task); } size_t packet_index = ExpectStandardPreamble(); auto* e_packet = producer_client()->GetFinalizedPacket(packet_index++); ExpectTraceEvent(e_packet, /*category_iid=*/1u, /*name_iid=*/1u, - TRACE_EVENT_PHASE_INSTANT, TRACE_EVENT_SCOPE_THREAD); + TRACE_EVENT_PHASE_BEGIN, TRACE_EVENT_SCOPE_THREAD); const auto& annotations = e_packet->track_event().debug_annotations(); EXPECT_EQ(annotations.size(), 0);
diff --git a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc index 38ee903..75d5d52 100644 --- a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc +++ b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
@@ -67,12 +67,6 @@ constexpr uint64_t kThreadInstructionCountTrackUuidBit = static_cast<uint64_t>(1u) << 34; -// Names of events that should be converted into a TaskExecution event. -const char* kTaskExecutionEventCategory = "toplevel"; -const char* kTaskExecutionEventNames[3] = {"ThreadControllerImpl::RunTask", - "ThreadPool_RunTask", - "SimpleAlarmTimer::OnTimerFired"}; - void AddConvertableToTraceFormat( base::trace_event::ConvertableToTraceFormat* value, perfetto::protos::pbzero::DebugAnnotation* annotation) { @@ -474,13 +468,6 @@ const size_t kMaxSize = base::trace_event::TraceArguments::kMaxSize; InterningIndexEntry interned_annotation_names[kMaxSize] = { InterningIndexEntry{}}; - InterningIndexEntry interned_source_location{}; - InterningIndexEntry interned_log_message_body{}; - - const char* src_file = nullptr; - const char* src_func = nullptr; - const char* log_message_body = nullptr; - int line_number = 0; // No need to write the event name for end events (sync or nestable async). // Trace processor will match them without, provided event nesting is correct. @@ -510,49 +497,8 @@ } } } else { - // TODO(eseckler): Remove special handling of typed events here once we - // support them in TRACE_EVENT macros. - if (flags & TRACE_EVENT_FLAG_TYPED_PROTO_ARGS) { - if (trace_event->arg_size() == 2u) { - DCHECK_EQ(strcmp(category_name, kTaskExecutionEventCategory), 0); - DCHECK(strcmp(trace_event->name(), kTaskExecutionEventNames[0]) == 0 || - strcmp(trace_event->name(), kTaskExecutionEventNames[1]) == 0 || - strcmp(trace_event->name(), kTaskExecutionEventNames[2]) == 0); - // Double argument task execution event (src_file, src_func). - DCHECK_EQ(trace_event->arg_type(0), TRACE_VALUE_TYPE_STRING); - DCHECK_EQ(trace_event->arg_type(1), TRACE_VALUE_TYPE_STRING); - src_file = trace_event->arg_value(0).as_string; - src_func = trace_event->arg_value(1).as_string; - } else { - // arg_size == 1 enforced by the maximum number of parameter == 2. - DCHECK_EQ(trace_event->arg_size(), 1u); - - if (trace_event->arg_type(0) == TRACE_VALUE_TYPE_STRING) { - // Single argument task execution event (src_file). - DCHECK_EQ(strcmp(category_name, kTaskExecutionEventCategory), 0); - DCHECK( - strcmp(trace_event->name(), kTaskExecutionEventNames[0]) == 0 || - strcmp(trace_event->name(), kTaskExecutionEventNames[1]) == 0 || - strcmp(trace_event->name(), kTaskExecutionEventNames[2]) == 0); - src_file = trace_event->arg_value(0).as_string; - } else { - DCHECK_EQ(trace_event->arg_type(0), TRACE_VALUE_TYPE_CONVERTABLE); - DCHECK(strcmp(category_name, "log") == 0); - DCHECK(strcmp(trace_event->name(), "LogMessage") == 0); - const base::trace_event::LogMessage* value = - static_cast<base::trace_event::LogMessage*>( - trace_event->arg_value(0).as_convertable); - src_file = value->file(); - line_number = value->line_number(); - log_message_body = value->message().c_str(); - - interned_log_message_body = - interned_log_message_bodies_.LookupOrAdd(value->message()); - } // else - } // else - interned_source_location = interned_source_locations_.LookupOrAdd( - std::make_tuple(src_file, src_func, line_number)); + NOTREACHED(); } else if (!privacy_filtering_enabled_) { for (size_t i = 0; i < trace_event->arg_size() && trace_event->arg_name(i); ++i) { @@ -626,14 +572,7 @@ track_event->add_category_iids(interned_category.id); } - if (interned_log_message_body.id) { - auto* log_message = track_event->set_log_message(); - log_message->set_source_location_iid(interned_source_location.id); - log_message->set_body_iid(interned_log_message_body.id); - } else if (interned_source_location.id) { - track_event->set_task_execution()->set_posted_from_iid( - interned_source_location.id); - } else if (!privacy_filtering_enabled_) { + if (!privacy_filtering_enabled_) { WriteDebugAnnotations(trace_event, track_event, interned_annotation_names); } @@ -796,19 +735,7 @@ std::make_tuple(IndexType::kName, IndexData{trace_event_name}, std::move(interned_name))); } - if (interned_log_message_body.id && !interned_log_message_body.was_emitted) { - pending_interning_updates_.push_back( - std::make_tuple(IndexType::kLogMessage, IndexData{log_message_body}, - std::move(interned_log_message_body))); - } - if (interned_source_location.id) { - if (!interned_source_location.was_emitted) { - pending_interning_updates_.push_back(std::make_tuple( - IndexType::kSourceLocation, - IndexData{std::make_tuple(src_file, src_func, line_number)}, - std::move(interned_source_location))); - } - } else if (!privacy_filtering_enabled_) { + if (!privacy_filtering_enabled_) { for (size_t i = 0; i < trace_event->arg_size() && trace_event->arg_name(i); ++i) { DCHECK(interned_annotation_names[i].id);
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 27a661a..bc867499 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -55,6 +55,2803 @@ } ] }, + "android-inverse-fieldtrials-pie-x86-fyi-rel": { + "gtest_tests": [ + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "absl_hardening_tests", + "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--gtest_filter=-ImportantSitesUtilBrowserTest.DSENotConsideredImportantInRegularMode" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "android_browsertests", + "test_id_prefix": "ninja://chrome/test:android_browsertests/" + }, + { + "args": [ + "--test-launcher-batch-limit=1", + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "android_sync_integration_tests", + "test_id_prefix": "ninja://chrome/test:android_sync_integration_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "android_webview_unittests", + "test_id_prefix": "ninja://android_webview/test:android_webview_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "base_unittests", + "test_id_prefix": "ninja://base:base_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "base_util_unittests", + "test_id_prefix": "ninja://base/util:base_util_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "blink_common_unittests", + "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "blink_heap_unittests", + "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "blink_platform_unittests", + "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "webkit_unit_tests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "blink_unittests", + "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "boringssl_crypto_tests", + "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "boringssl_ssl_tests", + "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "breakpad_unittests", + "test_id_prefix": "ninja://third_party/breakpad:breakpad_unittests/" + }, + { + "args": [ + "--gtest_filter=-*UsingRealWebcam*", + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "capture_unittests", + "test_id_prefix": "ninja://media/capture:capture_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cast_unittests", + "test_id_prefix": "ninja://media/cast:cast_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.cc_unittests.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "cc_unittests", + "test_id_prefix": "ninja://cc:cc_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "chrome_java_test_pagecontroller_tests", + "test_id_prefix": "ninja://chrome/test/android:chrome_java_test_pagecontroller_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "chrome_public_smoke_test", + "test_id_prefix": "ninja://chrome/android:chrome_public_smoke_test/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--git-revision=${got_revision}", + "--avd-config=../../tools/android/avd/proto/generic_playstore_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-8", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_playstore_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_playstore_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chrome-gold@chops-service-accounts.iam.gserviceaccount.com", + "shards": 20 + }, + "test": "chrome_public_test_apk", + "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/" + }, + { + "args": [ + "--disable-features=NetworkServiceInProcess", + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--git-revision=${got_revision}", + "--avd-config=../../tools/android/avd/proto/generic_playstore_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "network_service_out_of_process_chrome_public_test_apk", + "precommit_args": [ + "--gerrit-issue=${patch_issue}", + "--gerrit-patchset=${patch_set}", + "--buildbucket-id=${buildbucket_build_id}" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-8", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_playstore_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_playstore_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chrome-gold@chops-service-accounts.iam.gserviceaccount.com", + "shards": 20 + }, + "test": "chrome_public_test_apk", + "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "components_browsertests", + "test_id_prefix": "ninja://components:components_browsertests/" + }, + { + "args": [ + "--disable-features=NetworkServiceInProcess", + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "network_service_out_of_process_components_browsertests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "components_browsertests", + "test_id_prefix": "ninja://components:components_browsertests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "components_unittests", + "test_id_prefix": "ninja://components:components_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.content_browsertests.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 20 + }, + "test": "content_browsertests", + "test_id_prefix": "ninja://content/test:content_browsertests/" + }, + { + "args": [ + "--disable-features=NetworkServiceInProcess", + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.content_browsertests.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "network_service_out_of_process_content_browsertests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 20 + }, + "test": "content_browsertests", + "test_id_prefix": "ninja://content/test:content_browsertests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--gtest_filter=-ContentViewScrollingTest.testFling" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 3 + }, + "test": "content_shell_test_apk", + "test_id_prefix": "ninja://content/shell/android:content_shell_test_apk/" + }, + { + "args": [ + "--disable-features=NetworkServiceInProcess", + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--gtest_filter=-ContentViewScrollingTest.testFling" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "network_service_out_of_process_content_shell_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 5 + }, + "test": "content_shell_test_apk", + "test_id_prefix": "ninja://content/shell/android:content_shell_test_apk/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "content_unittests", + "test_id_prefix": "ninja://content/test:content_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "crypto_unittests", + "test_id_prefix": "ninja://crypto:crypto_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "device_unittests", + "test_id_prefix": "ninja://device:device_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "display_unittests", + "test_id_prefix": "ninja://ui/display:display_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "events_unittests", + "test_id_prefix": "ninja://ui/events:events_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gcm_unit_tests", + "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gfx_unittests", + "test_id_prefix": "ninja://ui/gfx:gfx_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gin_unittests", + "test_id_prefix": "ninja://gin:gin_unittests/" + }, + { + "args": [ + "--use-cmd-decoder=validating", + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.gl_tests.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "gl_tests_validating", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gl_tests", + "test_id_prefix": "ninja://gpu:gl_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gl_unittests", + "test_id_prefix": "ninja://ui/gl:gl_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "google_apis_unittests", + "test_id_prefix": "ninja://google_apis:google_apis_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gpu_unittests", + "test_id_prefix": "ninja://gpu:gpu_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "gwp_asan_unittests", + "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ipc_tests", + "test_id_prefix": "ninja://ipc:ipc_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "jingle_unittests", + "test_id_prefix": "ninja://jingle:jingle_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "latency_unittests", + "test_id_prefix": "ninja://ui/latency:latency_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "libjingle_xmpp_unittests", + "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "media_blink_unittests", + "test_id_prefix": "ninja://media/blink:media_blink_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.media_unittests.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "media_unittests", + "test_id_prefix": "ninja://media:media_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "midi_unittests", + "test_id_prefix": "ninja://media/midi:midi_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "mojo_test_apk", + "test_id_prefix": "ninja://mojo/public/java/system:mojo_test_apk/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "mojo_unittests", + "test_id_prefix": "ninja://mojo:mojo_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "monochrome_public_bundle_fake_modules_smoke_test", + "test_id_prefix": "ninja://chrome/android:monochrome_public_bundle_fake_modules_smoke_test/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "monochrome_public_bundle_smoke_test", + "test_id_prefix": "ninja://chrome/android:monochrome_public_bundle_smoke_test/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "monochrome_public_smoke_test", + "test_id_prefix": "ninja://chrome/android:monochrome_public_smoke_test/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.net_unittests.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "net_unittests", + "test_id_prefix": "ninja://net:net_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.sandbox_linux_unittests.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "sandbox_linux_unittests", + "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "services_unittests", + "test_id_prefix": "ninja://services:services_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "shell_dialogs_unittests", + "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "skia_unittests", + "test_id_prefix": "ninja://skia:skia_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "sql_unittests", + "test_id_prefix": "ninja://sql:sql_unittests/" + }, + { + "args": [ + "standalone_angle_unittests", + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "standalone_angle_unittests", + "test_id_prefix": "ninja://third_party/angle/src/tests:standalone_angle_unittests/", + "use_isolated_scripts_api": true + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "storage_unittests", + "test_id_prefix": "ninja://storage:storage_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "system_webview_shell_layout_test_apk", + "test_id_prefix": "ninja://android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ui_android_unittests", + "test_id_prefix": "ninja://ui/android:ui_android_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ui_base_unittests", + "test_id_prefix": "ninja://ui/base:ui_base_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "ui_touch_selection_unittests", + "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "unit_tests", + "test_id_prefix": "ninja://chrome/test:unit_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "url_unittests", + "test_id_prefix": "ninja://url:url_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.viz_unittests.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "viz_unittests", + "test_id_prefix": "ninja://components/viz:viz_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_browsertests", + "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_bundle_test", + "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_bundle_test/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_instrumentation_test_apk", + "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_apk/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_private_instrumentation_test_apk", + "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_private_instrumentation_test_apk/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "weblayer_unittests", + "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "chromium/android_webview/tools/cts_archive", + "location": "android_webview/tools/cts_archive", + "revision": "ai8Ig4HlO0vG6aP_JP2uhyruE2yPzze8PFP1g8Z4_hgC" + } + ], + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 2 + }, + "test": "webview_cts_tests", + "test_id_prefix": "ninja://android_webview/test:webview_cts_tests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.webview_instrumentation_test_apk.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 7 + }, + "test": "webview_instrumentation_test_apk", + "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/" + }, + { + "args": [ + "--enable-features=NetworkService,NetworkServiceInProcess", + "--test-launcher-filter-file=../../testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter", + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", + "--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.webview_instrumentation_test_apk.filter" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "name": "network_service_webview_instrumentation_test_apk", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", + "shards": 15 + }, + "test": "webview_instrumentation_test_apk", + "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "webview_ui_test_app_test_apk", + "test_id_prefix": "ninja://android_webview/tools/automated_ui_tests:webview_ui_test_app_test_apk/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "wtf_unittests", + "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/" + }, + { + "args": [ + "--avd-config=../../tools/android/avd/proto/generic_android28.textpb" + ], + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "device_os": null, + "device_type": null, + "machine_type": "n1-standard-4", + "os": "Ubuntu-16.04", + "pool": "chromium.tests.avd" + } + ], + "named_caches": [ + { + "name": "avd_generic_android28", + "path": ".android" + }, + { + "name": "system_images_android_28_google_apis_x86", + "path": ".emulator_sdk" + } + ], + "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" + }, + "test": "zlib_unittests", + "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/" + } + ] + }, "android-pie-arm64-wpt-rel-non-cq": { "isolated_scripts": [ {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 22b0d62..e79806fd 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -25,6 +25,11 @@ { 'android_browsertests': { 'modifications': { + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--gtest_filter=-ImportantSitesUtilBrowserTest.DSENotConsideredImportantInRegularMode', # https://crbug.com/1034001 + ], + }, 'android-pie-arm64-rel': { 'args': [ '--gtest_filter=-ImportantSitesUtilBrowserTest.DSENotConsideredImportantInRegularMode', # https://crbug.com/1034001 @@ -659,6 +664,12 @@ 'shards': 3, }, }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + # https://crbug.com/1039860 + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.cc_unittests.filter', + ], + }, 'android-marshmallow-x86-rel-non-cq': { # https://crbug.com/1039860 'args': [ @@ -744,6 +755,31 @@ 'shards': 25, }, }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--avd-config=../../tools/android/avd/proto/generic_playstore_android28.textpb', + # https://crbug.com/1046059 + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter', + ], + 'swarming': { + 'named_caches': [ + { + 'name': 'avd_generic_playstore_android28', + 'path': '.android', + }, + { + 'name': 'system_images_android_28_google_apis_playstore_x86', + 'path': '.emulator_sdk', + }, + ], + 'dimension_sets': [ + { + # Use 8-cores to shorten test runtime. + 'machine_type': 'n1-standard-8', + }, + ], + }, + }, 'android-lollipop-arm-rel-swarming': { 'swarming': { 'service_account': 'chrome-gold-dev@chops-service-accounts.iam.gserviceaccount.com' @@ -799,6 +835,7 @@ 'remove_from': [ 'Lollipop Tablet Tester', 'Marshmallow Tablet Tester', + 'android-inverse-fieldtrials-pie-x86-fyi-rel', 'android-marshmallow-x86-rel-non-cq', 'android-pie-x86-rel', 'android-pie-arm64-rel', # https://crbug.com/1010211 @@ -968,6 +1005,14 @@ 'shards': 18, }, }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.content_browsertests.filter', + ], + 'swarming': { + 'shards': 20, + }, + }, 'android-lollipop-arm-rel': { 'swarming': { 'shards': 15, @@ -1063,6 +1108,11 @@ 'android-code-coverage-native', # crbug/1018434 ], 'modifications': { + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--gtest_filter=-ContentViewScrollingTest.testFling', + ], + }, 'android-marshmallow-x86-rel-non-cq': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_m.content_shell_test_apk.filter', @@ -1353,6 +1403,11 @@ ], }, }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.gl_tests.filter', + ], + }, 'android-marshmallow-x86-rel-non-cq': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.gl_tests.filter', @@ -1624,6 +1679,11 @@ }, 'media_unittests': { 'modifications': { + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.media_unittests.filter', + ], + }, 'android-marshmallow-x86-rel-non-cq': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_m.media_unittests.filter', @@ -1818,6 +1878,12 @@ 'shards': 4, } }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + # crbug.com/1046060 + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.net_unittests.filter', + ], + }, 'android-marshmallow-x86-rel-non-cq': { # crbug.com/1046060 'args': [ @@ -1996,6 +2062,31 @@ 'Feature=RenderTest', # https://crbug.com/1068294 ], }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--avd-config=../../tools/android/avd/proto/generic_playstore_android28.textpb', + # https://crbug.com/1046059 + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter', + ], + 'swarming': { + 'named_caches': [ + { + 'name': 'avd_generic_playstore_android28', + 'path': '.android', + }, + { + 'name': 'system_images_android_28_google_apis_playstore_x86', + 'path': '.emulator_sdk', + }, + ], + 'dimension_sets': [ + { + # Use 8-cores to shorten test runtime. + 'machine_type': 'n1-standard-8', + }, + ], + }, + }, 'android-marshmallow-x86-rel-non-cq': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_m.chrome_public_test_apk.filter', @@ -2068,6 +2159,14 @@ 'shards': 8, }, }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_p.content_browsertests.filter', + ], + 'swarming': { + 'shards': 20, + }, + }, 'android-marshmallow-x86-rel-non-cq': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_m.content_browsertests.filter', @@ -2106,6 +2205,11 @@ 'android-code-coverage-native', # crbug/1018434 ], 'modifications': { + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--gtest_filter=-ContentViewScrollingTest.testFling', + ], + }, 'android-marshmallow-x86-rel-non-cq': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator_m.content_shell_test_apk.filter', @@ -2133,6 +2237,14 @@ 'android-code-coverage-native', # https://crbug.com/1018431 ], 'modifications': { + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.webview_instrumentation_test_apk.filter', + ], + 'swarming': { + 'shards': 15, + }, + }, 'android-marshmallow-x86-rel-non-cq': { 'swarming': { 'shards': 15, @@ -2210,6 +2322,7 @@ 'android-asan', 'android-code-coverage', 'android-code-coverage-native', + 'android-inverse-fieldtrials-pie-x86-fyi-rel', 'android-lollipop-arm-rel', 'android-marshmallow-arm64-rel', 'android-marshmallow-x86-rel-non-cq', @@ -2376,6 +2489,11 @@ '--shard-timeout=300', ], }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.sandbox_linux_unittests.filter', + ] + }, 'android-lollipop-arm-rel': { 'args': [ '--shard-timeout=300', @@ -2861,6 +2979,11 @@ }, 'viz_unittests': { 'modifications': { + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.viz_unittests.filter', + ], + }, 'android-marshmallow-x86-rel-non-cq': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.viz_unittests.filter', @@ -2875,6 +2998,7 @@ }, 'vr_android_unittests': { 'remove_from': [ + 'android-inverse-fieldtrials-pie-x86-fyi-rel', 'android-marshmallow-x86-rel-non-cq', 'android-pie-x86-rel', 'android-code-coverage-native', # crbug/1018434 @@ -2882,6 +3006,7 @@ }, 'vr_common_unittests': { 'remove_from': [ + 'android-inverse-fieldtrials-pie-x86-fyi-rel', 'android-marshmallow-x86-rel-non-cq', 'android-pie-x86-rel', 'android-code-coverage-native', # crbug/1018431 @@ -2889,6 +3014,7 @@ }, 'vr_pixeltests': { 'remove_from': [ + 'android-inverse-fieldtrials-pie-x86-fyi-rel', 'android-marshmallow-x86-rel-non-cq', 'android-pie-x86-rel', 'VR Linux', @@ -3089,6 +3215,11 @@ # either passing or there is more capacity. 'experiment_percentage': 0, }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'args': [ + '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.webview_instrumentation_test_apk.filter', + ], + }, 'android-pie-x86-rel': { 'args': [ '--test-launcher-filter-file=../../testing/buildbot/filters/android.emulator.webview_instrumentation_test_apk.filter',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index e725745..ecee8b1 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -1065,6 +1065,17 @@ 'use_swarming': True, 'os_type': 'android', }, + 'android-inverse-fieldtrials-pie-x86-fyi-rel': { + 'mixins': [ + 'pie-x86-emulator', + 'emulator-4-cores', + 'linux-xenial', + 'x86-64', + ], + 'test_suites': { + 'gtest_tests': 'android_pie_rel_gtests', + }, + }, 'android-pie-arm64-wpt-rel-non-cq': { 'mixins': [ 'pie_fleet',
diff --git a/testing/variations/OWNERS b/testing/variations/OWNERS index e09f1bb..a8da0e7 100644 --- a/testing/variations/OWNERS +++ b/testing/variations/OWNERS
@@ -1,5 +1,7 @@ file://base/metrics/OWNERS +per-file fieldtrial_testing_config.json=caitlinfischer@google.com + # Use the following owners only if: # - You work in the same area as them. # - They are already aware of the field trial being modified.
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 095c8b16..0c9a876 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1655,6 +1655,24 @@ ] } ], + "ClientSideDetectionModelOnAndroid": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "EnabledWithModel55", + "params": { + "ModelNum": "55" + }, + "enable_features": [ + "ClientSideDetectionModelOnAndroid" + ] + } + ] + } + ], "CodeCacheDeletionWithoutFilter": [ { "platforms": [ @@ -3713,21 +3731,6 @@ ] } ], - "InterestFeedFeedback": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "InterestFeedFeedback" - ] - } - ] - } - ], "InterestFeedV2": [ { "platforms": [ @@ -6732,6 +6735,22 @@ ] } ], + "TabSearch": [ + { + "platforms": [ + "chromeos" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "TabSearch", + "TabSearchFixedEntrypoint" + ] + } + ] + } + ], "TabToGTSAnimation": [ { "platforms": [
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl index c3648f2..bf45556 100644 --- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl +++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -4664,6 +4664,20 @@ InvalidPrefix # An unknown error was encountered when trying to store this cookie. UnknownError + # The cookie had the "SameSite=Strict" attribute but came from a response + # with the same registrable domain but a different scheme. + # This includes navigation requests intitiated by other origins. + # This is the "Schemeful Same-Site" version of the blocked reason. + SchemefulSameSiteStrict + # The cookie had the "SameSite=Lax" attribute but came from a response + # with the same registrable domain but a different scheme. + # This is the "Schemeful Same-Site" version of the blocked reason. + SchemefulSameSiteLax + # The cookie didn't specify a "SameSite" attribute and was defaulted to + # "SameSite=Lax" and broke the same rules specified in the SchemefulSameSiteLax + # value. + # This is the "Schemeful Same-Site" version of the blocked reason. + SchemefulSameSiteUnspecifiedTreatedAsLax # Types of reasons why a cookie may not be sent with a request. experimental type CookieBlockedReason extends string @@ -4692,6 +4706,20 @@ UserPreferences # An unknown error was encountered when trying to send this cookie. UnknownError + # The cookie had the "SameSite=Strict" attribute but came from a response + # with the same registrable domain but a different scheme. + # This includes navigation requests intitiated by other origins. + # This is the "Schemeful Same-Site" version of the blocked reason. + SchemefulSameSiteStrict + # The cookie had the "SameSite=Lax" attribute but came from a response + # with the same registrable domain but a different scheme. + # This is the "Schemeful Same-Site" version of the blocked reason. + SchemefulSameSiteLax + # The cookie didn't specify a "SameSite" attribute and was defaulted to + # "SameSite=Lax" and broke the same rules specified in the SchemefulSameSiteLax + # value. + # This is the "Schemeful Same-Site" version of the blocked reason. + SchemefulSameSiteUnspecifiedTreatedAsLax # A cookie which was not stored from a response with the corresponding reason. experimental type BlockedSetCookieWithReason extends object
diff --git a/third_party/blink/public/mojom/use_counter/css_property_id.mojom b/third_party/blink/public/mojom/use_counter/css_property_id.mojom index 41bef250..036069d6 100644 --- a/third_party/blink/public/mojom/use_counter/css_property_id.mojom +++ b/third_party/blink/public/mojom/use_counter/css_property_id.mojom
@@ -721,6 +721,7 @@ kLineGapOverride = 675, kMathShift = 676, kMathDepth = 677, + kAdvanceProportionalOverride = 678, // 1. Add new features above this line (don't change the assigned numbers of // the existing items). // 2. Run the src/tools/metrics/histograms/update_use_counter_css.py script
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index 6a0296ff..1bcbb49 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2872,7 +2872,7 @@ kV8WheelEvent_DeltaMode_AttributeGetter = 3541, kV8Touch_Force_AttributeGetter = 3542, kWebGLRenderingContextMakeXRCompatible = 3543, - kIdentifiabilityStudyReserved3544 = 3544, + kV8WebGLCompressedTextureASTC_GetSupportedProfiles_Method = 3544, kIdentifiabilityStudyReserved3545 = 3545, kV8BeforeInstallPromptEvent_Platforms_AttributeGetter = 3546, kIdentifiabilityStudyReserved3547 = 3547, @@ -2896,10 +2896,10 @@ kIdentifiabilityStudyReserved3565 = 3565, kV8BaseAudioContext_SampleRate_AttributeGetter = 3566, kWindowScreenId = 3567, - kIdentifiabilityStudyReserved3568 = 3568, - kIdentifiabilityStudyReserved3569 = 3569, - kIdentifiabilityStudyReserved3570 = 3570, - kIdentifiabilityStudyReserved3571 = 3571, + kWebGLRenderingContextGetParameter = 3568, + kWebGLRenderingContextGetRenderbufferParameter = 3569, + kWebGLRenderingContextGetShaderPrecisionFormat = 3570, + kWebGL2RenderingContextGetInternalFormatParameter = 3571, kIdentifiabilityStudyReserved3572 = 3572, kIdentifiabilityStudyReserved3573 = 3573, kIdentifiabilityStudyReserved3574 = 3574,
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py index 5828b08..34b5c49 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -2986,6 +2986,17 @@ } return; } +""")) + if cg_context.interface.identifier in ("HTMLEmbedElement", + "HTMLObjectElement"): + body.append( + TextNode("""\ +// HTMLEmbedElement and HTMLObjectElement's named properties implementation +// depend on the default fallback behavior. So, just fallback. +""")) + else: + body.append( + TextNode("""\ // step 2.2.2.2. Invoke the named property setter with P and Desc.[[Value]]. ${class_name}::NamedPropertySetterCallback( ${v8_property_name}, ${v8_property_desc}.value(), ${info});
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index c241d86..f2880b07 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1634,6 +1634,14 @@ sources = [ "css/parser/css.proto" ] } +fuzzer_test("blink_html_tokenizer_fuzzer") { + sources = [ "html/parser/html_tokenizer_fuzzer.cc" ] + deps = [ + ":core", + "//third_party/blink/renderer/platform:blink_fuzzer_test_support", + ] +} + # Fuzzers for blink::FeaturePolicy. fuzzer_test("feature_policy_fuzzer") { sources = [ "feature_policy/feature_policy_fuzzer.cc" ]
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5 index 2150f76..f2240fc 100644 --- a/third_party/blink/renderer/core/css/css_properties.json5 +++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -5146,6 +5146,12 @@ runtime_flag: "CSSFontFaceAdvanceOverride", }, { + name: "advance-proportional-override", + is_descriptor: true, + is_property: false, + runtime_flag: "CSSFontFaceAdvanceProportionalOverride", + }, + { name: "line-gap-override", is_descriptor: true, is_property: false,
diff --git a/third_party/blink/renderer/core/css/font_face.cc b/third_party/blink/renderer/core/css/font_face.cc index 61acf2a..8d8ccbc 100644 --- a/third_party/blink/renderer/core/css/font_face.cc +++ b/third_party/blink/renderer/core/css/font_face.cc
@@ -209,6 +209,8 @@ AtRuleDescriptorID::LineGapOverride) && font_face->SetPropertyFromStyle(properties, AtRuleDescriptorID::AdvanceOverride) && + font_face->SetPropertyFromStyle( + properties, AtRuleDescriptorID::AdvanceProportionalOverride) && font_face->GetFontSelectionCapabilities().IsValid() && !font_face->family().IsEmpty()) { font_face->InitCSSFontFace(document->GetExecutionContext(), *src); @@ -423,6 +425,9 @@ case AtRuleDescriptorID::AdvanceOverride: advance_override_ = value; break; + case AtRuleDescriptorID::AdvanceProportionalOverride: + advance_proportional_override_ = ConvertFontMetricOverrideValue(value); + break; default: NOTREACHED(); return false; @@ -868,6 +873,7 @@ visitor->Trace(descent_override_); visitor->Trace(line_gap_override_); visitor->Trace(advance_override_); + visitor->Trace(advance_proportional_override_); visitor->Trace(error_); visitor->Trace(loaded_property_); visitor->Trace(css_font_face_); @@ -913,6 +919,11 @@ result.advance_override = To<CSSPrimitiveValue>(*advance_override_).GetFloatValue(); } + if (advance_proportional_override_) { + result.advance_proportional_override = + To<CSSPrimitiveValue>(*advance_proportional_override_).GetFloatValue() / + 100; + } return result; }
diff --git a/third_party/blink/renderer/core/css/font_face.h b/third_party/blink/renderer/core/css/font_face.h index 39194852..e8d6061 100644 --- a/third_party/blink/renderer/core/css/font_face.h +++ b/third_party/blink/renderer/core/css/font_face.h
@@ -143,7 +143,7 @@ bool HasFontMetricsOverride() const { return ascent_override_ || descent_override_ || line_gap_override_ || - advance_override_; + advance_override_ || advance_proportional_override_; } FontMetricsOverride GetFontMetricsOverride() const; @@ -189,6 +189,7 @@ Member<const CSSValue> descent_override_; Member<const CSSValue> line_gap_override_; Member<const CSSValue> advance_override_; + Member<const CSSValue> advance_proportional_override_; LoadStatusType status_; Member<DOMException> error_;
diff --git a/third_party/blink/renderer/core/css/mathml.css b/third_party/blink/renderer/core/css/mathml.css index fdbf23a..7a26d29 100644 --- a/third_party/blink/renderer/core/css/mathml.css +++ b/third_party/blink/renderer/core/css/mathml.css
@@ -56,8 +56,13 @@ outline: auto 1px -webkit-focus-ring-color; } -mphantom { - visibility: hidden; +mspace { + overflow: hidden !important; +} + +/* <mrow>-like elements */ +semantics > :not(:first-child) { + display: none; } merror { @@ -65,8 +70,8 @@ background-color: lightYellow; } -mspace { - overflow: hidden !important; +mphantom { + visibility: hidden; } /* Token elements */
diff --git a/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc b/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc index b0e3faf..bb96208 100644 --- a/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc +++ b/third_party/blink/renderer/core/css/parser/at_rule_descriptor_parser.cc
@@ -205,11 +205,18 @@ CSSValue* ConsumeAdvanceOverride(CSSParserTokenRange& range, const CSSParserContext& context) { - if (!RuntimeEnabledFeatures::CSSFontMetricsOverrideEnabled()) + if (!RuntimeEnabledFeatures::CSSFontFaceAdvanceOverrideEnabled()) return nullptr; return css_parsing_utils::ConsumeNumber(range, context, kValueRangeAll); } +CSSValue* ConsumeAdvanceProportionalOverride(CSSParserTokenRange& range, + const CSSParserContext& context) { + if (!RuntimeEnabledFeatures::CSSFontFaceAdvanceProportionalOverrideEnabled()) + return nullptr; + return ConsumeFontMetricOverride(range, context); +} + } // namespace CSSValue* AtRuleDescriptorParser::ParseFontFaceDescriptor( @@ -267,6 +274,9 @@ case AtRuleDescriptorID::AdvanceOverride: parsed_value = ConsumeAdvanceOverride(range, context); break; + case AtRuleDescriptorID::AdvanceProportionalOverride: + parsed_value = ConsumeAdvanceProportionalOverride(range, context); + break; default: break; }
diff --git a/third_party/blink/renderer/core/css/parser/at_rule_names.json5 b/third_party/blink/renderer/core/css/parser/at_rule_names.json5 index d318365..489d83b6 100644 --- a/third_party/blink/renderer/core/css/parser/at_rule_names.json5 +++ b/third_party/blink/renderer/core/css/parser/at_rule_names.json5
@@ -58,6 +58,9 @@ name: "advance-override" }, { + name: "advance-proportional-override" + }, + { name: "line-gap-override", }, {
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc index ff8ebe8..02e648d 100644 --- a/third_party/blink/renderer/core/css/style_engine_test.cc +++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -3241,6 +3241,34 @@ UpdateAllLifecyclePhases(); } +// https://crbug.com/1137624 +TEST_F(StyleEngineTest, DisabledAdvanceOverrideDescriptor) { + ScopedCSSFontFaceAdvanceOverrideForTest advance_override_disabled(false); + + GetDocument().body()->setInnerHTML(R"HTML( + <style> + @font-face { + font-family: custom-font; + src: url(fake-font.woff); + advance-override: 0.1; + } + </style> + )HTML"); + + // Shouldn't crash. + UpdateAllLifecyclePhases(); + + // 'advance-override' should be ignored when disabled. + const FontFace* font_face = GetStyleEngine() + .GetFontSelector() + ->GetFontFaceCache() + ->CssConnectedFontFaces() + .front() + .Get(); + ASSERT_TRUE(font_face); + EXPECT_FALSE(font_face->HasFontMetricsOverride()); +} + class StyleEngineSimTest : public SimTest {}; TEST_F(StyleEngineSimTest, OwnerColorScheme) {
diff --git a/third_party/blink/renderer/core/exported/web_image.cc b/third_party/blink/renderer/core/exported/web_image.cc index 399aaf9..377a8a1 100644 --- a/third_party/blink/renderer/core/exported/web_image.cc +++ b/third_party/blink/renderer/core/exported/web_image.cc
@@ -48,8 +48,7 @@ const bool data_complete = true; std::unique_ptr<ImageDecoder> decoder(ImageDecoder::Create( data, data_complete, ImageDecoder::kAlphaPremultiplied, - ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore(), - ImageDecoder::OverrideAllowDecodeToYuv::kDeny)); + ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore())); if (!decoder || !decoder->IsSizeAvailable()) return {}; @@ -116,8 +115,7 @@ const bool data_complete = true; std::unique_ptr<ImageDecoder> decoder(ImageDecoder::Create( data, data_complete, ImageDecoder::kAlphaPremultiplied, - ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore(), - ImageDecoder::OverrideAllowDecodeToYuv::kDeny)); + ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore())); if (!decoder || !decoder->IsSizeAvailable()) return {}; @@ -150,8 +148,7 @@ const bool data_complete = true; std::unique_ptr<ImageDecoder> decoder(ImageDecoder::Create( data, data_complete, ImageDecoder::kAlphaPremultiplied, - ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore(), - ImageDecoder::OverrideAllowDecodeToYuv::kDeny)); + ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore())); if (!decoder || !decoder->IsSizeAvailable() || decoder->FrameCount() == 0) return {};
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc index 56b8918..f0bcfc4f 100644 --- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc +++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -36,7 +36,6 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "build/build_config.h" -#include "cc/test/fake_layer_tree_frame_sink.h" #include "cc/test/test_ukm_recorder_factory.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_settings.h" @@ -776,6 +775,11 @@ return ScreenInfo(); } +cc::FakeLayerTreeFrameSink* TestWebWidgetClient::LastCreatedFrameSink() { + DCHECK(layer_tree_host_->IsSingleThreaded()); + return last_created_frame_sink_; +} + mojo::PendingAssociatedRemote<mojom::blink::WidgetHost> TestWebWidgetClient::BindNewWidgetHost() { receiver_.reset(); @@ -792,7 +796,10 @@ std::unique_ptr<cc::LayerTreeFrameSink> TestWebWidgetClient::AllocateNewLayerTreeFrameSink() { - return cc::FakeLayerTreeFrameSink::Create3d(); + std::unique_ptr<cc::FakeLayerTreeFrameSink> sink = + cc::FakeLayerTreeFrameSink::Create3d(); + last_created_frame_sink_ = sink.get(); + return sink; } void TestWebWidgetClient::WillQueueSyntheticEvent(
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.h b/third_party/blink/renderer/core/frame/frame_test_helpers.h index d4bb2db02..4400f44 100644 --- a/third_party/blink/renderer/core/frame/frame_test_helpers.h +++ b/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -38,6 +38,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "cc/test/fake_layer_tree_frame_sink.h" #include "cc/test/test_task_graph_runner.h" #include "cc/trees/layer_tree_host.h" #include "components/viz/common/surfaces/frame_sink_id.h" @@ -222,6 +223,12 @@ layer_tree_host_ = layer_tree_host; } + // The returned pointer is valid after AllocateNewLayerTreeFrameSink() occurs, + // until another call to AllocateNewLayerTreeFrameSink() happens. This + // pointer is valid to use from the main thread for tests that use a single + // threaded compositor, such as SimCompositor tests. + cc::FakeLayerTreeFrameSink* LastCreatedFrameSink(); + virtual ScreenInfo GetInitialScreenInfo(); mojo::PendingAssociatedRemote<mojom::blink::WidgetHost> BindNewWidgetHost(); @@ -266,6 +273,7 @@ WebFrameWidget* frame_widget_ = nullptr; cc::LayerTreeHost* layer_tree_host_ = nullptr; cc::TestTaskGraphRunner test_task_graph_runner_; + cc::FakeLayerTreeFrameSink* last_created_frame_sink_ = nullptr; blink::scheduler::WebFakeThreadScheduler fake_thread_scheduler_; Vector<std::unique_ptr<blink::WebCoalescedInputEvent>> injected_scroll_events_;
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc index c58de1d..02b1b73b 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
@@ -195,10 +195,6 @@ metrics_data->paint = main_frame_percentage_records_[static_cast<unsigned>(MetricId::kPaint)] .interval_duration; - metrics_data->scrolling_coordinator = - main_frame_percentage_records_[static_cast<unsigned>( - MetricId::kScrollingCoordinator)] - .interval_duration; metrics_data->composite_commit = main_frame_percentage_records_[static_cast<unsigned>( MetricId::kCompositingCommit)] @@ -431,7 +427,6 @@ CASE_FOR_ID(Layout); CASE_FOR_ID(ForcedStyleAndLayout); CASE_FOR_ID(HitTestDocumentUpdate); - CASE_FOR_ID(ScrollingCoordinator); CASE_FOR_ID(HandleInputEvents); CASE_FOR_ID(Animate); CASE_FOR_ID(UpdateLayers); @@ -477,7 +472,6 @@ CASE_FOR_ID(Layout, i); CASE_FOR_ID(ForcedStyleAndLayout, i); CASE_FOR_ID(HitTestDocumentUpdate, i); - CASE_FOR_ID(ScrollingCoordinator, i); CASE_FOR_ID(HandleInputEvents, i); CASE_FOR_ID(Animate, i); CASE_FOR_ID(UpdateLayers, i);
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h index 6fcf258..c61642f 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
@@ -125,8 +125,8 @@ : public RefCounted<LocalFrameUkmAggregator> { public: // Changing these values requires changing the names of metrics specified - // below. For every metric name added here, add an entry in the - // metric_strings_ array below. + // below. For every metric name added here, add an entry in the array in + // metrics_data() below. enum MetricId { kCompositingAssignments, kCompositingCommit, @@ -139,7 +139,6 @@ kLayout, kForcedStyleAndLayout, kHitTestDocumentUpdate, - kScrollingCoordinator, kHandleInputEvents, kAnimate, kUpdateLayers, @@ -173,7 +172,6 @@ {"Layout", true}, {"ForcedStyleAndLayout", true}, {"HitTestDocumentUpdate", true}, - {"ScrollingCoordinator", true}, {"HandleInputEvents", true}, {"Animate", true}, {"UpdateLayers", false},
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc index 92e1c21..fcbf085 100644 --- a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator_test.cc
@@ -308,8 +308,6 @@ EXPECT_EQ(metrics_data->compositing_assignments.InMillisecondsF(), millisecond_for_step); EXPECT_EQ(metrics_data->paint.InMillisecondsF(), millisecond_for_step); - EXPECT_EQ(metrics_data->scrolling_coordinator.InMillisecondsF(), - millisecond_for_step); EXPECT_EQ(metrics_data->composite_commit.InMillisecondsF(), millisecond_for_step); // Do not check the value in metrics_data.update_layers because it
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 804247a..daae425 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -151,6 +151,7 @@ #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk_subset_recorder.h" #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h" #include "third_party/blink/renderer/platform/instrumentation/histogram.h" +#include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h" #include "third_party/blink/renderer/platform/language.h" @@ -3818,6 +3819,34 @@ } } +void LocalFrameView::SetViewportIntersection( + const ViewportIntersectionState& intersection_state) { + // The viewport intersection of the main frame is not tracked. + DCHECK(!GetFrame().IsMainFrame()); + + if (auto* document_resource_coordinator = + frame_->GetDocument()->GetResourceCoordinator()) { + gfx::RectF transform_rect = + gfx::RectF(gfx::Rect(intersection_state.viewport_intersection)); + + // The viewport intersection in the child frame's coordinate system is + // transformed into the intersection in the viewport's coordinate system. + intersection_state.main_frame_transform.TransformRect(&transform_rect); + + // Get rid of the possible floating point values for x and y of the + // resulting rectangle. + IntRect rect = EnclosingIntRect( + FloatRect(transform_rect.x(), transform_rect.y(), + transform_rect.width(), transform_rect.height())); + + // Return <0, 0, 0, 0> if there is no area. + if (rect.IsEmpty()) + rect.SetLocation(IntPoint(0, 0)); + + document_resource_coordinator->SetViewportIntersection(rect); + } +} + PhysicalOffset LocalFrameView::ViewportToFrame( const PhysicalOffset& point_in_viewport) const { PhysicalOffset point_in_root_frame = PhysicalOffset::FromFloatPointRound(
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index 822bcdca..2f693002 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -738,7 +738,7 @@ void ParentVisibleChanged() override; void NotifyFrameRectsChangedIfNeeded(); void SetViewportIntersection( - const ViewportIntersectionState& intersection_state) override {} + const ViewportIntersectionState& intersection_state) override; void VisibilityForThrottlingChanged() override; bool LifecycleUpdatesThrottled() const override { return lifecycle_updates_throttled_;
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_test.cc b/third_party/blink/renderer/core/frame/web_frame_widget_test.cc index a4e6410..b41bde52 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_test.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_test.cc
@@ -6,6 +6,8 @@ #include "base/run_loop.h" #include "base/test/metrics/histogram_tester.h" +#include "build/build_config.h" +#include "cc/layers/solid_color_layer.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h" #include "third_party/blink/renderer/core/frame/web_view_frame_widget.h" @@ -102,6 +104,19 @@ EXPECT_EQ(gfx::PointF(150.27, 150.25), point); } +#if defined(OS_ANDROID) +TEST_F(WebFrameWidgetSimTest, ForceSendMetadataOnInput) { + cc::LayerTreeHost* layer_tree_host = + WebView().MainFrameViewWidget()->LayerTreeHost(); + // We should not have any force send metadata requests at start. + EXPECT_FALSE(layer_tree_host->TakeForceSendMetadataRequest()); + // ShowVirtualKeyboard will trigger a text input state update. + WebView().MainFrameViewWidget()->ShowVirtualKeyboard(); + // We should now have a force send metadata request. + EXPECT_TRUE(layer_tree_host->TakeForceSendMetadataRequest()); +} +#endif // defined(OS_ANDROID) + const char EVENT_LISTENER_RESULT_HISTOGRAM[] = "Event.PassiveListeners"; // Keep in sync with enum defined in @@ -378,4 +393,113 @@ SendInputEvent(scroll, base::DoNothing()); } +class NotifySwapTimesWebFrameWidgetTest : public SimTest { + public: + void SetUp() override { + SimTest::SetUp(); + + WebView().StopDeferringMainFrameUpdate(); + FrameWidgetBase()->UpdateCompositorViewportRect(gfx::Rect(200, 100)); + + auto root_layer = cc::SolidColorLayer::Create(); + root_layer->SetBounds(gfx::Size(200, 100)); + root_layer->SetBackgroundColor(SK_ColorGREEN); + FrameWidgetBase()->LayerTreeHost()->SetRootLayer(root_layer); + + auto color_layer = cc::SolidColorLayer::Create(); + color_layer->SetBounds(gfx::Size(100, 100)); + root_layer->AddChild(color_layer); + color_layer->SetBackgroundColor(SK_ColorRED); + } + + WebViewFrameWidget* FrameWidgetBase() { + return static_cast<WebViewFrameWidget*>(MainFrame().FrameWidget()); + } + + // |swap_to_presentation| determines how long after swap should presentation + // happen. This can be negative, positive, or zero. If zero, an invalid (null) + // presentation time is used. + void CompositeAndWaitForPresentation(base::TimeDelta swap_to_presentation) { + base::RunLoop swap_run_loop; + base::RunLoop presentation_run_loop; + + // Register callbacks for swap time and presentation time. + base::TimeTicks swap_time; + MainFrame().FrameWidget()->NotifySwapAndPresentationTime( + base::BindOnce( + [](base::OnceClosure swap_quit_closure, base::TimeTicks* swap_time, + blink::WebSwapResult result, base::TimeTicks timestamp) { + DCHECK(!timestamp.is_null()); + *swap_time = timestamp; + std::move(swap_quit_closure).Run(); + }, + swap_run_loop.QuitClosure(), &swap_time), + base::BindOnce( + [](base::OnceClosure presentation_quit_closure, + blink::WebSwapResult result, base::TimeTicks timestamp) { + DCHECK(!timestamp.is_null()); + std::move(presentation_quit_closure).Run(); + }, + presentation_run_loop.QuitClosure())); + + // Composite and wait for the swap to complete. + Compositor().BeginFrame(/*time_delta_in_seconds=*/0.016, /*raster=*/true); + swap_run_loop.Run(); + + // Present and wait for it to complete. + viz::FrameTimingDetails timing_details; + if (!swap_to_presentation.is_zero()) { + timing_details.presentation_feedback = gfx::PresentationFeedback( + /*presentation_time=*/swap_time + swap_to_presentation, + base::TimeDelta::FromMilliseconds(16), 0); + } + auto* last_frame_sink = WebWidgetClient().LastCreatedFrameSink(); + last_frame_sink->NotifyDidPresentCompositorFrame(1, timing_details); + presentation_run_loop.Run(); + } +}; + +TEST_F(NotifySwapTimesWebFrameWidgetTest, PresentationTimestampValid) { + base::HistogramTester histograms; + + CompositeAndWaitForPresentation(base::TimeDelta::FromMilliseconds(2)); + + EXPECT_THAT(histograms.GetAllSamples( + "PageLoad.Internal.Renderer.PresentationTime.Valid"), + testing::ElementsAre(base::Bucket(true, 1))); + EXPECT_THAT( + histograms.GetAllSamples( + "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime"), + testing::ElementsAre(base::Bucket(2, 1))); +} + +TEST_F(NotifySwapTimesWebFrameWidgetTest, PresentationTimestampInvalid) { + base::HistogramTester histograms; + + CompositeAndWaitForPresentation(base::TimeDelta()); + + EXPECT_THAT(histograms.GetAllSamples( + "PageLoad.Internal.Renderer.PresentationTime.Valid"), + testing::ElementsAre(base::Bucket(false, 1))); + EXPECT_THAT( + histograms.GetAllSamples( + "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime"), + testing::IsEmpty()); +} + +TEST_F(NotifySwapTimesWebFrameWidgetTest, + PresentationTimestampEarlierThanSwaptime) { + base::HistogramTester histograms; + + CompositeAndWaitForPresentation(base::TimeDelta::FromMilliseconds(-2)); + + EXPECT_THAT(histograms.GetAllSamples( + "PageLoad.Internal.Renderer.PresentationTime.Valid"), + testing::ElementsAre(base::Bucket(false, 1))); + EXPECT_THAT( + histograms.GetAllSamples( + "PageLoad.Internal.Renderer.PresentationTime.DeltaFromSwapTime"), + testing::IsEmpty()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc index 80ca8e2..9c0491f2 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
@@ -579,4 +579,9 @@ compositor_viewport_pixel_rect); } +void WebViewFrameWidget::UpdateCompositorViewportRect( + const gfx::Rect& compositor_viewport_pixel_rect) { + widget_base_->UpdateCompositorViewportRect(compositor_viewport_pixel_rect); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.h b/third_party/blink/renderer/core/frame/web_view_frame_widget.h index 17f0144..6c701c0 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.h +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.h
@@ -149,6 +149,8 @@ void UpdateSurfaceAndCompositorRect( const viz::LocalSurfaceId& new_local_surface_id, const gfx::Rect& compositor_viewport_pixel_rect); + void UpdateCompositorViewportRect( + const gfx::Rect& compositor_viewport_pixel_rect); void SetIsNestedMainFrameWidget(bool is_nested); void DidAutoResize(const gfx::Size& size); void SetDeviceColorSpaceForTesting(const gfx::ColorSpace& color_space);
diff --git a/third_party/blink/renderer/core/html/parser/BUILD.gn b/third_party/blink/renderer/core/html/parser/BUILD.gn index 28b00f4..a9aa6d9 100644 --- a/third_party/blink/renderer/core/html/parser/BUILD.gn +++ b/third_party/blink/renderer/core/html/parser/BUILD.gn
@@ -2,7 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//testing/libfuzzer/fuzzer_test.gni") import("//third_party/blink/renderer/core/core.gni") blink_core_sources("parser") { @@ -88,11 +87,3 @@ configs += [ "//build/config/compiler:optimize_max" ] } } - -fuzzer_test("blink_html_tokenizer_fuzzer") { - sources = [ "html_tokenizer_fuzzer.cc" ] - deps = [ - "../../:core", - "../../../platform:blink_fuzzer_test_support", - ] -}
diff --git a/third_party/blink/renderer/core/html/portal/OWNERS b/third_party/blink/renderer/core/html/portal/OWNERS index 4c925a2..5ca25353 100644 --- a/third_party/blink/renderer/core/html/portal/OWNERS +++ b/third_party/blink/renderer/core/html/portal/OWNERS
@@ -3,4 +3,4 @@ lfg@chromium.org mcnee@chromium.org -# COMPONENT: Blink>HTML>Portal +# COMPONENT: Blink>Portals
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc index 7a5f455e..3648cfe 100644 --- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc +++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -620,8 +620,7 @@ : ImageDecoder::kAlphaNotPremultiplied, ImageDecoder::kDefaultBitDepth, parsed_options.has_color_space_conversion ? ColorBehavior::Tag() - : ColorBehavior::Ignore(), - ImageDecoder::OverrideAllowDecodeToYuv::kDeny)); + : ColorBehavior::Ignore())); auto skia_image = ImageBitmap::GetSkImageFromDecoder(std::move(decoder)); if (!skia_image) return;
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc index 32c3910..1df081c 100644 --- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc +++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc
@@ -307,7 +307,7 @@ SegmentReader::CreateFromSkData( SkData::MakeWithoutCopy(contents.Data(), contents.DataLength())), data_complete, alpha_option, ImageDecoder::kDefaultBitDepth, - color_behavior, ImageDecoder::OverrideAllowDecodeToYuv::kDeny); + color_behavior); sk_sp<SkImage> frame; ImageOrientationEnum orientation = kDefaultImageOrientation; if (decoder) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc index b7ca963..69274774 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -294,14 +294,23 @@ // TODO(layout-dev): Handle cases where the old items are not consecutive. const ComputedStyle& new_style = layout_text->StyleRef(); bool collapse_spaces = new_style.CollapseWhiteSpace(); + bool preserve_newlines = new_style.PreserveNewline(); if (NGInlineItem* last_item = LastItemToCollapseWith(items_)) { if (collapse_spaces) { switch (last_item->EndCollapseType()) { case NGInlineItem::kCollapsible: - // If the original string starts with a collapsible space, it may be - // collapsed. - if (original_string[old_item0.StartOffset()] == kSpaceCharacter) - return false; + switch (original_string[old_item0.StartOffset()]) { + case kSpaceCharacter: + // If the original string starts with a collapsible space, it may + // be collapsed. + return false; + case kNewlineCharacter: + // Collapsible spaces immediately before a preserved newline + // should be removed to be consistent with + // AppendForcedBreakCollapseWhitespace. + if (preserve_newlines) + return false; + } // If the last item ended with a collapsible space run with segment // breaks, we need to run the full algorithm to apply segment break // rules. This may result in removal of the space in the last item. @@ -363,7 +372,7 @@ return false; } - if (new_style.PreserveNewline()) { + if (preserve_newlines) { // We exit and then re-enter all bidi contexts around a forced break. So, We // must go through the full pipeline to ensure that we exit and enter the // correct bidi contexts the re-layout.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc index 4590e3c..7ed1b99 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -877,8 +877,10 @@ unsigned line_text_offset = item_result.StartOffset() - line_info->StartOffset(); DCHECK_EQ(kObjectReplacementCharacter, line_text[line_text_offset]); - item_result.inline_size += - spacing.ComputeSpacing(line_text_offset, 0.0, offset); + item_result.inline_size += spacing.ComputeSpacing( + line_text_offset, item_result.inline_size.ToFloat(), + 0.0 /* advance-override */, 1.0 /* advance-proportional-override */, + offset); // |offset| is non-zero only before CJK characters. DCHECK_EQ(offset, 0.f); }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc index 637c294..0c73dda 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -199,7 +199,8 @@ // No margins should pierce outside formatting-context roots. DCHECK(!fragment.IsFormattingContextRoot() || end_margin_strut.IsEmpty()); - AddChild(fragment, offset, /* inline_container */ nullptr, &end_margin_strut); + AddChild(fragment, offset, /* inline_container */ nullptr, &end_margin_strut, + child_layout_result.IsSelfCollapsing()); if (fragment.IsBox()) PropagateBreak(child_layout_result); } @@ -207,7 +208,8 @@ void NGBoxFragmentBuilder::AddChild(const NGPhysicalContainerFragment& child, const LogicalOffset& child_offset, const LayoutInline* inline_container, - const NGMarginStrut* margin_strut) { + const NGMarginStrut* margin_strut, + bool is_self_collapsing) { LogicalOffset adjusted_offset = child_offset; if (box_type_ != NGPhysicalBoxFragment::NGBoxType::kInlineBox) { @@ -254,7 +256,13 @@ if (margin_strut) { NGMarginStrut end_margin_strut = *margin_strut; end_margin_strut.Append(margins.block_end, /* is_quirky */ false); - margins.block_end = end_margin_strut.Sum(); + + // Self-collapsing blocks are special, their end margin-strut is part + // of their inflow position. To correctly determine the "end" margin, + // we need to the "final" margin-strut from their end margin-strut. + margins.block_end = is_self_collapsing + ? end_margin_strut.Sum() - margin_strut->Sum() + : end_margin_strut.Sum(); } NGFragment fragment(GetWritingDirection(), child);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h index a2cba0ed..cbdd5f5 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -209,7 +209,8 @@ void AddChild(const NGPhysicalContainerFragment&, const LogicalOffset&, const LayoutInline* inline_container = nullptr, - const NGMarginStrut* margin_strut = nullptr); + const NGMarginStrut* margin_strut = nullptr, + bool is_self_collapsing = false); // Manually add a break token to the builder. Note that we're assuming that // this break token is for content in the same flow as this parent.
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.cc index 4504b93..1ebd3e35 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.cc +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.cc
@@ -80,28 +80,16 @@ needs_transform_update_ = true; } -bool LayoutSVGTransformableContainer::IsUseElement() const { - NOT_DESTROYED(); - const SVGElement& element = *GetElement(); - if (IsA<SVGUseElement>(element)) - return true; - // Nested <use> are replaced by <g> during shadow tree expansion. - if (IsA<SVGGElement>(element) && To<SVGGElement>(element).InUseShadowTree()) - return IsA<SVGUseElement>(element.CorrespondingElement()); - return false; -} - SVGTransformChange LayoutSVGTransformableContainer::CalculateLocalTransform( bool bounds_changed) { NOT_DESTROYED(); SVGElement* element = GetElement(); DCHECK(element); - // If we're either the LayoutObject for a <use> element, or for any <g> - // element inside the shadow tree, that was created during the use/symbol/svg - // expansion in SVGUseElement. These containers need to respect the - // translations induced by their corresponding use elements x/y attributes. - if (IsUseElement()) { + // If we're the LayoutObject for a <use> element, this container needs to + // respect the translations induced by their corresponding use elements x/y + // attributes. + if (IsA<SVGUseElement>(element)) { const ComputedStyle& style = StyleRef(); const SVGComputedStyle& svg_style = style.SvgStyle(); SVGLengthContext length_context(element);
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h b/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h index 036a1f63..f24bbf4a 100644 --- a/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h +++ b/third_party/blink/renderer/core/layout/svg/layout_svg_transformable_container.h
@@ -52,7 +52,6 @@ NOT_DESTROYED(); return local_transform_; } - bool IsUseElement() const; bool needs_transform_update_ : 1; bool transform_uses_reference_box_ : 1;
diff --git a/third_party/blink/renderer/core/loader/threaded_icon_loader.cc b/third_party/blink/renderer/core/loader/threaded_icon_loader.cc index b64704d..777ce82 100644 --- a/third_party/blink/renderer/core/loader/threaded_icon_loader.cc +++ b/third_party/blink/renderer/core/loader/threaded_icon_loader.cc
@@ -104,8 +104,7 @@ std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create( std::move(data), /* data_complete= */ true, ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth, - ColorBehavior::TransformToSRGB(), - ImageDecoder::OverrideAllowDecodeToYuv::kDeny); + ColorBehavior::TransformToSRGB()); if (!decoder) { notify_complete(-1.0);
diff --git a/third_party/blink/renderer/core/mathml/mathml_operator_element.cc b/third_party/blink/renderer/core/mathml/mathml_operator_element.cc index df7273d..fca4f281 100644 --- a/third_party/blink/renderer/core/mathml/mathml_operator_element.cc +++ b/third_party/blink/renderer/core/mathml/mathml_operator_element.cc
@@ -254,6 +254,13 @@ return properties_.flags & flag; } +void MathMLOperatorElement::CheckFormAfterSiblingChange() { + if (properties_.dictionary_category != + MathMLOperatorDictionaryCategory::kUndefined && + !FastHasAttribute(mathml_names::kFormAttr)) + SetOperatorFormDirty(); +} + void MathMLOperatorElement::SetOperatorFormDirty() { properties_.dictionary_category = MathMLOperatorDictionaryCategory::kUndefined;
diff --git a/third_party/blink/renderer/core/mathml/mathml_operator_element.h b/third_party/blink/renderer/core/mathml/mathml_operator_element.h index 44f23a9..c8795d2 100644 --- a/third_party/blink/renderer/core/mathml/mathml_operator_element.h +++ b/third_party/blink/renderer/core/mathml/mathml_operator_element.h
@@ -44,6 +44,8 @@ double DefaultLeadingSpace(); double DefaultTrailingSpace(); + void CheckFormAfterSiblingChange(); + private: base::Optional<OperatorContent> operator_content_; // Operator properties calculated from dictionary and attributes.
diff --git a/third_party/blink/renderer/core/mathml/mathml_row_element.cc b/third_party/blink/renderer/core/mathml/mathml_row_element.cc index 57abe138..3a35f12f 100644 --- a/third_party/blink/renderer/core/mathml/mathml_row_element.cc +++ b/third_party/blink/renderer/core/mathml/mathml_row_element.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/core/mathml/mathml_row_element.h" #include "third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.h" +#include "third_party/blink/renderer/core/mathml/mathml_operator_element.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" namespace blink { @@ -22,4 +23,18 @@ return new LayoutNGMathMLBlock(this); } +void MathMLRowElement::ChildrenChanged(const ChildrenChange& change) { + if (change.by_parser == ChildrenChangeSource::kAPI) { + for (auto* child = firstChild(); child; child = child->nextSibling()) { + if (child->HasTagName(mathml_names::kMoTag)) { + // TODO(crbug.com/1124298): make this work for embellished operators. + static_cast<MathMLOperatorElement*>(child) + ->CheckFormAfterSiblingChange(); + } + } + } + + MathMLElement::ChildrenChanged(change); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/mathml/mathml_row_element.h b/third_party/blink/renderer/core/mathml/mathml_row_element.h index 62936bb..1641e85 100644 --- a/third_party/blink/renderer/core/mathml/mathml_row_element.h +++ b/third_party/blink/renderer/core/mathml/mathml_row_element.h
@@ -16,6 +16,8 @@ public: explicit MathMLRowElement(const QualifiedName&, Document&); + void ChildrenChanged(const ChildrenChange&) override; + private: LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout legacy) override;
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc index 965f828..c9d8315 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
@@ -3,6 +3,8 @@ // found in the LICENSE file. #include "third_party/blink/renderer/core/paint/image_paint_timing_detector.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "services/metrics/public/cpp/ukm_recorder.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/layout/layout_image_resource.h" @@ -175,6 +177,17 @@ need_update_timing_at_frame_end_ = true; } +void ImagePaintTimingDetector::StopRecordEntries() { + is_recording_ = false; + if (frame_view_->GetFrame().IsMainFrame()) { + DCHECK(frame_view_->GetFrame().GetDocument()); + ukm::builders::Blink_PaintTiming( + frame_view_->GetFrame().GetDocument()->UkmSourceID()) + .SetLCPDebugging_HasViewportImage(contains_full_viewport_image_) + .Record(ukm::UkmRecorder::Get()); + } +} + void ImagePaintTimingDetector::RegisterNotifySwapTime() { auto callback = WTF::Bind(&ImagePaintTimingDetector::ReportSwapTime, WrapCrossThreadWeakPersistent(this), @@ -307,8 +320,10 @@ // SVG, so |rect_size| can be larger than |*viewport_size| in edge cases. If // the rect occupies the whole viewport, disregard this candidate by saying // the size is 0. - if (rect_size >= *viewport_size_) + if (rect_size >= *viewport_size_) { + contains_full_viewport_image_ = true; return 0; + } rect_size = DownScaleIfIntrinsicSizeIsSmaller( rect_size, intrinsic_size.Area(),
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector.h b/third_party/blink/renderer/core/paint/image_paint_timing_detector.h index 00a5869..2a36fc9 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
@@ -266,7 +266,7 @@ // an image is recorded before stopping recording, and finish loading after // stopping recording, the detector can still observe the loading being // finished. - inline void StopRecordEntries() { is_recording_ = false; } + void StopRecordEntries(); inline bool IsRecording() const { return is_recording_; } inline bool FinishedReportingImages() const { return !is_recording_ && num_pending_swap_callbacks_ == 0; @@ -322,6 +322,8 @@ // |FindLargestPaintCandidate| occur during the paint tree walk. bool need_update_timing_at_frame_end_ = false; + bool contains_full_viewport_image_ = false; + // We cache the viewport size computation to avoid performing it on every // image. This value is reset when paint is finished and is computed if unset // when needed. 0 means that the size has not been computed.
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc b/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc index 25c5e1f3..613206bc 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
@@ -8,6 +8,8 @@ #include "base/test/test_mock_time_task_runner.h" #include "base/test/trace_event_analyzer.h" #include "build/build_config.h" +#include "components/ukm/test_ukm_recorder.h" +#include "services/metrics/public/cpp/ukm_builders.h" #include "third_party/blink/public/web/web_performance.h" #include "third_party/blink/public/web/web_widget_client.h" #include "third_party/blink/renderer/core/frame/frame_test_helpers.h" @@ -50,6 +52,8 @@ "oIRn/wsGUQIIy4Vr9TH6SYFCNzw4nALn5627K4vIttOUOwfa5YnrDYzt/9OLv9I5l8kk5hZ3XL" \ "O20b7tbR7zHLy/BX8G0IeBEM7ZN1NGIaFUaKLgAAAAAElFTkSuQmCC" +using UkmPaintTiming = ukm::builders::Blink_PaintTiming; + class ImagePaintTimingDetectorTest : public testing::Test, public PaintTestConfigurations { public: @@ -259,6 +263,10 @@ GetPaintTimingDetector().NotifyScroll(mojom::blink::ScrollType::kUser); } + void SimulateKeyDown() { + GetPaintTimingDetector().NotifyInputEvent(WebInputEvent::Type::kKeyDown); + } + void SimulateKeyUp() { GetPaintTimingDetector().NotifyInputEvent(WebInputEvent::Type::kKeyUp); } @@ -305,6 +313,7 @@ } TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_OneImage) { + ukm::TestAutoSetUkmRecorder test_ukm_recorder; SetBodyInnerHTML(R"HTML( <img id="target"></img> )HTML"); @@ -315,6 +324,13 @@ EXPECT_EQ(record->first_size, 25ul); EXPECT_TRUE(record->loaded); EXPECT_EQ(ExperimentalLargestPaintSize(), 25ul); + // Simulate some input event to force StopRecordEntries(). + SimulateKeyDown(); + auto entries = test_ukm_recorder.GetEntriesByName(UkmPaintTiming::kEntryName); + EXPECT_EQ(1ul, entries.size()); + auto* entry = entries[0]; + test_ukm_recorder.ExpectEntryMetric( + entry, UkmPaintTiming::kLCPDebugging_HasViewportImageName, false); } TEST_P(ImagePaintTimingDetectorTest, InsertionOrderIsSecondaryRankingKey) { @@ -1234,4 +1250,23 @@ EXPECT_EQ(CountVisibleImageRecords(), 0u); } +TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_FullViewportImage) { + ukm::TestAutoSetUkmRecorder test_ukm_recorder; + SetBodyInnerHTML(R"HTML( + <style>body {margin: 0px;}</style> + <img id="target"></img> + )HTML"); + SetImageAndPaint("target", 3000, 3000); + UpdateAllLifecyclePhasesAndInvokeCallbackIfAny(); + ImageRecord* record = FindLargestPaintCandidate(); + EXPECT_FALSE(record); + // Simulate some input event to force StopRecordEntries(). + SimulateKeyDown(); + auto entries = test_ukm_recorder.GetEntriesByName(UkmPaintTiming::kEntryName); + EXPECT_EQ(1ul, entries.size()); + auto* entry = entries[0]; + test_ukm_recorder.ExpectEntryMetric( + entry, UkmPaintTiming::kLCPDebugging_HasViewportImageName, true); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/third_party/blink/renderer/core/paint/paint_layer_painter.cc index 5ee89f4..e264bc6 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_painter.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -374,8 +374,7 @@ // is not scrolled and should be above scrolled content. bool should_paint_self_outline = is_self_painting_layer && !is_painting_overlay_overflow_controls && - (is_painting_composited_decoration || - (!is_painting_overflow_contents && !is_painting_mask)) && + is_painting_composited_decoration && paint_layer_.GetLayoutObject().StyleRef().HasOutline(); PhysicalOffset subpixel_accumulation =
diff --git a/third_party/blink/renderer/core/testing/sim/sim_compositor.cc b/third_party/blink/renderer/core/testing/sim/sim_compositor.cc index 7f95c512..8c2610ae 100644 --- a/third_party/blink/renderer/core/testing/sim/sim_compositor.cc +++ b/third_party/blink/renderer/core/testing/sim/sim_compositor.cc
@@ -34,7 +34,8 @@ test_web_view_client_ = &view_client; } -SimCanvas::Commands SimCompositor::BeginFrame(double time_delta_in_seconds) { +SimCanvas::Commands SimCompositor::BeginFrame(double time_delta_in_seconds, + bool raster) { DCHECK(web_view_); DCHECK(!layer_tree_host()->defer_main_frame_update()); // Verify that the need for a BeginMainFrame has been registered, and would @@ -49,8 +50,7 @@ SimCanvas::Commands commands; paint_commands_ = &commands; - layer_tree_host()->Composite(last_frame_time_, - /*raster=*/false); + layer_tree_host()->Composite(last_frame_time_, raster); paint_commands_ = nullptr; return commands;
diff --git a/third_party/blink/renderer/core/testing/sim/sim_compositor.h b/third_party/blink/renderer/core/testing/sim/sim_compositor.h index a99cbd5..ed1013e 100644 --- a/third_party/blink/renderer/core/testing/sim/sim_compositor.h +++ b/third_party/blink/renderer/core/testing/sim/sim_compositor.h
@@ -45,7 +45,9 @@ // Returns all drawing commands that were issued during painting the frame // (including cached ones). // TODO(dcheng): This should take a base::TimeDelta. - SimCanvas::Commands BeginFrame(double time_delta_in_seconds = 0.016); + // Rasterization of tiles is only performed when |raster| is true. + SimCanvas::Commands BeginFrame(double time_delta_in_seconds = 0.016, + bool raster = false); // Similar to BeginFrame() but doesn't require NeedsBeginFrame(). This is // useful for testing the painting after a frame is throttled (for which
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc index f56b035..3f732b2 100644 --- a/third_party/blink/renderer/core/timing/performance.cc +++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -675,10 +675,6 @@ const String& container_src, const String& container_id, const String& container_name) { - if (!HasObserverFor(PerformanceEntry::kLongTask)) - return; - - UseCounter::Count(GetExecutionContext(), WebFeature::kLongTaskObserver); auto* entry = MakeGarbageCollected<PerformanceLongTaskTiming>( MonotonicTimeToDOMHighResTimeStamp(start_time), MonotonicTimeToDOMHighResTimeStamp(end_time), name, container_type,
diff --git a/third_party/blink/renderer/core/timing/performance_observer.cc b/third_party/blink/renderer/core/timing/performance_observer.cc index f73c1eb6..60a2ac8 100644 --- a/third_party/blink/renderer/core/timing/performance_observer.cc +++ b/third_party/blink/renderer/core/timing/performance_observer.cc
@@ -211,6 +211,9 @@ if (filter_options_ & PerformanceEntry::kResource) { UseCounter::Count(GetExecutionContext(), WebFeature::kResourceTiming); } + if (filter_options_ & PerformanceEntry::kLongTask) { + UseCounter::Count(GetExecutionContext(), WebFeature::kLongTaskObserver); + } if (is_registered_) performance_->UpdatePerformanceObserverFilterOptions(); else
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc index 3a438c2c..e57e539 100644 --- a/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc +++ b/third_party/blink/renderer/modules/clipboard/clipboard_writer.cc
@@ -55,7 +55,7 @@ SegmentReader::CreateFromSkData(SkData::MakeWithoutCopy( png_data->Data(), png_data->ByteLengthAsSizeT())), true, ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth, - ColorBehavior::Tag(), ImageDecoder::OverrideAllowDecodeToYuv::kDeny); + ColorBehavior::Tag()); sk_sp<SkImage> image = nullptr; // |decoder| is nullptr if |png_data| doesn't begin with the PNG signature. if (decoder)
diff --git a/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc b/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc index 3ed19f7..5bff0af 100644 --- a/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc +++ b/third_party/blink/renderer/modules/video_rvfc/video_frame_callback_requester_impl.cc
@@ -48,14 +48,7 @@ MakeGarbageCollected<VideoFrameRequestCallbackCollection>( element.GetExecutionContext())) {} -VideoFrameCallbackRequesterImpl::~VideoFrameCallbackRequesterImpl() { - if (!observing_immersive_session_) - return; - - auto* frame_provider = GetXRFrameProvider(); - if (frame_provider) - frame_provider->RemoveImmersiveSessionObserver(this); -} +VideoFrameCallbackRequesterImpl::~VideoFrameCallbackRequesterImpl() = default; // static VideoFrameCallbackRequesterImpl& VideoFrameCallbackRequesterImpl::From(
diff --git a/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc b/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc index b8ae5c0..6f6e3485 100644 --- a/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc +++ b/third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc
@@ -298,8 +298,7 @@ DCHECK(canDecodeType(mime_type_)); decoder_ = ImageDecoder::CreateByMimeType( mime_type_, segment_reader_, data_complete_, premultiply_alpha, - ImageDecoder::kHighBitDepthToHalfFloat, color_behavior, - ImageDecoder::OverrideAllowDecodeToYuv::kDeny, desired_size); + ImageDecoder::kHighBitDepthToHalfFloat, color_behavior, desired_size); // CreateByImageType() can't fail if we use a supported image type. Which we // DCHECK above via canDecodeType().
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl index 1d3f5504..830f701b 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl +++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.idl
@@ -283,7 +283,7 @@ /* Framebuffer objects */ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); void framebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture? texture, GLint level, GLint layer); - [CallWith=ScriptState] any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname); + [HighEntropy, MeasureAs=WebGL2RenderingContextGetInternalFormatParameter, CallWith=ScriptState] any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname); void invalidateFramebuffer(GLenum target, sequence<GLenum> attachments); void invalidateSubFramebuffer(GLenum target, sequence<GLenum> attachments, GLint x, GLint y, GLsizei width, GLsizei height); void readBuffer(GLenum mode);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.idl b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.idl index 916dc26..1350ff7 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.idl +++ b/third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.idl
@@ -38,5 +38,5 @@ const unsigned long COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC; const unsigned long COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD; - sequence<DOMString> getSupportedProfiles(); + [HighEntropy=Direct, Measure] sequence<DOMString> getSupportedProfiles(); };
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl index 4bf2227..4886751 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.idl
@@ -551,15 +551,15 @@ [CallWith=ScriptState, HighEntropy, Measure] object? getExtension(DOMString name); [CallWith=ScriptState] any getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname); - [CallWith=ScriptState] any getParameter(GLenum pname); + [HighEntropy, MeasureAs=WebGLRenderingContextGetParameter, CallWith=ScriptState] any getParameter(GLenum pname); [CallWith=ScriptState] any getProgramParameter(WebGLProgram program, GLenum pname); DOMString? getProgramInfoLog(WebGLProgram program); - [CallWith=ScriptState] any getRenderbufferParameter(GLenum target, GLenum pname); + [HighEntropy, MeasureAs=WebGLRenderingContextGetRenderbufferParameter, CallWith=ScriptState] any getRenderbufferParameter(GLenum target, GLenum pname); [CallWith=ScriptState] any getShaderParameter(WebGLShader shader, GLenum pname); DOMString? getShaderInfoLog(WebGLShader shader); - WebGLShaderPrecisionFormat getShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype); + [HighEntropy, MeasureAs=WebGLRenderingContextGetShaderPrecisionFormat] WebGLShaderPrecisionFormat getShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype); DOMString? getShaderSource(WebGLShader shader);
diff --git a/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h b/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h index f44a2e6..f032453 100644 --- a/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h +++ b/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h
@@ -36,7 +36,7 @@ HeapVector<Member<DOMPointReadOnly>> offset_bounds_geometry_; std::unique_ptr<TransformationMatrix> mojo_from_bounded_native_; - unsigned int stage_parameters_id_ = 0; + uint32_t stage_parameters_id_ = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc index 91cdc116..bc96b93 100644 --- a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc +++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
@@ -65,11 +65,6 @@ immersive_observers_.insert(observer); } -void XRFrameProvider::RemoveImmersiveSessionObserver( - ImmersiveSessionObserver* observer) { - immersive_observers_.erase(observer); -} - void XRFrameProvider::OnSessionStarted( XRSession* session, device::mojom::blink::XRSessionPtr session_ptr) { @@ -200,8 +195,9 @@ TRACE_EVENT0("gpu", __FUNCTION__); DCHECK(session); - auto options = device::mojom::blink::XRFrameDataRequestOptions::New( - session->LightEstimationEnabled()); + auto options = device::mojom::blink::XRFrameDataRequestOptions::New(); + options->include_lighting_estimation_data = session->LightEstimationEnabled(); + options->stage_parameters_id = session->StageParametersId(); // Immersive frame logic. if (session->immersive()) { @@ -424,8 +420,10 @@ request->value = nullptr; } else { auto& data_provider = provider->value->Value(); - auto options = device::mojom::blink::XRFrameDataRequestOptions::New( - session->LightEstimationEnabled()); + auto options = device::mojom::blink::XRFrameDataRequestOptions::New(); + options->include_lighting_estimation_data = + session->LightEstimationEnabled(); + options->stage_parameters_id = session->StageParametersId(); data_provider->GetFrameData( std::move(options), @@ -503,8 +501,9 @@ frame_data->right_eye); } - if (frame_data && frame_data->stage_parameters_updated) { - immersive_session_->UpdateStageParameters(frame_data->stage_parameters); + if (frame_data) { + immersive_session_->UpdateStageParameters(frame_data->stage_parameters_id, + frame_data->stage_parameters); } // Run immersive_session_->OnFrame() in a posted task to ensure that @@ -550,6 +549,11 @@ if (session->ended()) continue; + if (inline_frame_data) { + session->UpdateStageParameters(inline_frame_data->stage_parameters_id, + inline_frame_data->stage_parameters); + } + if (inline_frame_data && inline_frame_data->mojo_space_reset) { session->OnMojoSpaceReset(); }
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.h b/third_party/blink/renderer/modules/xr/xr_frame_provider.h index d6765e8..b827363 100644 --- a/third_party/blink/renderer/modules/xr/xr_frame_provider.h +++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.h
@@ -62,8 +62,9 @@ return immersive_data_provider_.get(); } + // Adds an ImmersiveSessionObserver. Observers will be automatically removed + // by Oilpan when they are destroyed, and their WeakMember becomes null. void AddImmersiveSessionObserver(ImmersiveSessionObserver*); - void RemoveImmersiveSessionObserver(ImmersiveSessionObserver*); virtual void Trace(Visitor*) const; @@ -115,6 +116,9 @@ immersive_presentation_provider_; device::mojom::blink::VRPosePtr immersive_frame_pose_; bool is_immersive_frame_position_emulated_ = false; + + // Note: Oilpan automatically removes destroyed observers from + // |immersive_observers_| and does not need an explicit removal. HeapHashSet<WeakMember<ImmersiveSessionObserver>> immersive_observers_; // Time the first immersive frame has arrived - used to align the monotonic
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space.h b/third_party/blink/renderer/modules/xr/xr_reference_space.h index 61aeac5..9ce87ba1 100644 --- a/third_party/blink/renderer/modules/xr/xr_reference_space.h +++ b/third_party/blink/renderer/modules/xr/xr_reference_space.h
@@ -64,7 +64,7 @@ // latest display parameters of a session. void SetMojoFromFloor(); - unsigned int stage_parameters_id_ = 0; + uint32_t stage_parameters_id_ = 0; // Floor from mojo (aka local-floor_from_mojo) transform. std::unique_ptr<TransformationMatrix> mojo_from_floor_;
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc index 644a1e0..6a5a3b78 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -502,23 +502,13 @@ } void XRSession::UpdateStageParameters( + uint32_t stage_parameters_id, const device::mojom::blink::VRStageParametersPtr& stage_parameters) { - // We don't necessarily trust the backend to only send us display info changes - // when something has actually changed, and a change here can trigger several - // other interfaces to recompute data or fire events, so it's worthwhile to - // validate that an actual change has occurred. - if (stage_parameters_) { - // If the new parameters are identical to the old ones we don't need to - // update. - if (stage_parameters_->Equals(*stage_parameters)) - return; - } else if (!stage_parameters) { - // Don't bother updating from null to null either. - return; + // Only update if the ID is different, indicating a change. + if (stage_parameters_id_ != stage_parameters_id) { + stage_parameters_id_ = stage_parameters_id; + stage_parameters_ = stage_parameters.Clone(); } - - stage_parameters_id_++; - stage_parameters_ = stage_parameters.Clone(); } ScriptPromise XRSession::requestReferenceSpace( @@ -2095,7 +2085,6 @@ void XRSession::SetXRDisplayInfo( device::mojom::blink::VRDisplayInfoPtr display_info) { UpdateEyeParameters(display_info->left_eye, display_info->right_eye); - UpdateStageParameters(display_info->stage_parameters); } const HeapVector<Member<XRViewData>>& XRSession::views() {
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h index 476e365..0520149 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.h +++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -284,10 +284,11 @@ const device::mojom::blink::VREyeParametersPtr& left_eye, const device::mojom::blink::VREyeParametersPtr& right_eye); void UpdateStageParameters( + uint32_t stage_parameters_id, const device::mojom::blink::VRStageParametersPtr& stage_parameters); // Incremented every time stage_parameters_ is changed, so that other objects // that depend on it can know when they need to update. - unsigned int StageParametersId() const { return stage_parameters_id_; } + uint32_t StageParametersId() const { return stage_parameters_id_; } // Returns true if the session recognizes passed in hit_test_source as still // existing. Intended to be used by XRFrame to implement @@ -514,7 +515,7 @@ HashSet<uint64_t> hit_test_source_ids_; HashSet<uint64_t> hit_test_source_for_transient_input_ids_; - unsigned int view_parameters_id_ = 0; + uint32_t view_parameters_id_ = 0; HeapVector<Member<XRViewData>> views_; Vector<device::mojom::blink::VREyeParametersPtr> pending_view_parameters_; @@ -530,7 +531,7 @@ HeapHashSet<Member<ScriptPromiseResolver>> request_hit_test_source_promises_; HeapVector<Member<XRReferenceSpace>> reference_spaces_; - unsigned int stage_parameters_id_ = 0; + uint32_t stage_parameters_id_ = 0; device::mojom::blink::VRStageParametersPtr stage_parameters_; HeapMojoReceiver<device::mojom::blink::XRSessionClient,
diff --git a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc index f70006bc..450df25 100644 --- a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc +++ b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
@@ -244,7 +244,7 @@ {&font_lookups_by_unique_or_family_name_, IdentifiableSurface::Type::kLocalFontLookupByUniqueOrFamilyName}, {&font_lookups_by_unique_name_only_, - IdentifiableSurface::Type::kLocalFontLookupByUniqueOrFamilyName}, + IdentifiableSurface::Type::kLocalFontLookupByUniqueNameOnly}, {&font_lookups_by_fallback_character_, IdentifiableSurface::Type::kLocalFontLookupByFallbackCharacter}, {&font_lookups_as_last_resort_,
diff --git a/third_party/blink/renderer/platform/fonts/font_metrics_override.h b/third_party/blink/renderer/platform/fonts/font_metrics_override.h index 3a04219..354603e2 100644 --- a/third_party/blink/renderer/platform/fonts/font_metrics_override.h +++ b/third_party/blink/renderer/platform/fonts/font_metrics_override.h
@@ -14,6 +14,7 @@ base::Optional<float> descent_override; base::Optional<float> line_gap_override; base::Optional<float> advance_override; + base::Optional<float> advance_proportional_override; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc index f70d3b38..de46a8b 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -861,9 +861,10 @@ continue; } - space = - spacing.ComputeSpacing(run_start_index + glyph_data.character_index, - run->font_data_->GetAdvanceOverride(), offset); + space = spacing.ComputeSpacing( + run_start_index + glyph_data.character_index, glyph_data.advance, + run->font_data_->GetAdvanceOverride(), + run->font_data_->GetAdvanceProportionalOverride(), offset); glyph_data.advance += space; total_space_for_run += space;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc index 6fa0f567..b0244842 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc
@@ -123,7 +123,9 @@ template <typename TextContainerType> float ShapeResultSpacing<TextContainerType>::ComputeSpacing( unsigned index, + float original_advance, float advance_override, + float advance_proportional_override, float& offset) { DCHECK(has_spacing_); UChar32 character = text_[index]; @@ -137,9 +139,12 @@ float spacing = 0; - bool has_letter_spacing = letter_spacing_ || advance_override; - if (has_letter_spacing && !Character::TreatAsZeroWidthSpace(character)) - spacing += letter_spacing_ + advance_override; + bool has_letter_spacing = letter_spacing_ || advance_override || + (advance_proportional_override != 1.0); + if (has_letter_spacing && !Character::TreatAsZeroWidthSpace(character)) { + spacing += original_advance * (advance_proportional_override - 1.0) + + letter_spacing_ + advance_override; + } if (treat_as_space && (index || character == kNoBreakSpaceCharacter)) spacing += word_spacing_;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h index b3bef38..64830df 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h
@@ -62,7 +62,11 @@ // The |index| is for the |TextContainerType| given in the constructor. // For justification, this function must be called incrementally since it // keeps states and counts consumed justification opportunities. - float ComputeSpacing(unsigned index, float advance_override, float& offset); + float ComputeSpacing(unsigned index, + float original_advance, + float advance_override, + float advance_proportional_override, + float& offset); private: bool IsAfterExpansion() const { return is_after_expansion_; }
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/third_party/blink/renderer/platform/fonts/simple_font_data.cc index e3553e8..e23f1f7 100644 --- a/third_party/blink/renderer/platform/fonts/simple_font_data.cc +++ b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
@@ -183,6 +183,9 @@ advance_override_ = *metrics_override.advance_override * platform_data_.size(); } + + advance_proportional_override_ = + metrics_override.advance_proportional_override; } void SimpleFontData::PlatformGlyphInit() {
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.h b/third_party/blink/renderer/platform/fonts/simple_font_data.h index a79adfd8..0abbc23 100644 --- a/third_party/blink/renderer/platform/fonts/simple_font_data.h +++ b/third_party/blink/renderer/platform/fonts/simple_font_data.h
@@ -158,10 +158,14 @@ } bool HasAdvanceOverride() const override { - return advance_override_.has_value(); + return advance_override_.has_value() || + advance_proportional_override_.has_value(); } float GetAdvanceOverride() const { return advance_override_.value_or(0); } + float GetAdvanceProportionalOverride() const { + return advance_proportional_override_.value_or(1); + } protected: SimpleFontData( @@ -213,10 +217,14 @@ unsigned visual_overflow_inflation_for_ascent_; unsigned visual_overflow_inflation_for_descent_; - // The additional spacing between letters as defined by the + // The additional advance added to each letter as defined by the // advance-override value in @font-face. base::Optional<float> advance_override_; + // The multiplier to the advance of each letter as defined by the + // advance-proportional-override value in @font-face. + base::Optional<float> advance_proportional_override_; + mutable FontHeight normalized_typo_ascent_descent_; // See discussion on crbug.com/631032 and Skiaissue
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc b/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc index c951d17..3b42e35 100644 --- a/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc +++ b/third_party/blink/renderer/platform/graphics/gpu/webgl_image_conversion.cc
@@ -3754,8 +3754,7 @@ image_->Data(), data_complete, ImageDecoder::kAlphaNotPremultiplied, ImageDecoder::kDefaultBitDepth, ignore_color_space ? ColorBehavior::Ignore() - : ColorBehavior::TransformToSRGB(), - ImageDecoder::OverrideAllowDecodeToYuv::kDeny)); + : ColorBehavior::TransformToSRGB())); if (!decoder || !decoder->FrameCount()) return; ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
diff --git a/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc b/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc index 875cc8e..e1adcf2 100644 --- a/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc +++ b/third_party/blink/renderer/platform/graphics/image_decoder_wrapper.cc
@@ -292,7 +292,6 @@ // The newly created decoder just grabbed the data. No need to reset it. return ImageDecoder::Create(data_, all_data_received_, alpha_option_, decoding_option_, decoder_color_behavior_, - ImageDecoder::OverrideAllowDecodeToYuv::kDeny, scaled_size_); }
diff --git a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc index 5622233..f0952cc 100644 --- a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc +++ b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc
@@ -529,8 +529,7 @@ if (info_header_.compression == JPEG) { alternate_decoder_ = std::make_unique<JPEGImageDecoder>( parent_->GetAlphaOption(), parent_->GetColorBehavior(), - parent_->GetMaxDecodedBytes(), - ImageDecoder::OverrideAllowDecodeToYuv::kDefault, img_data_offset_); + parent_->GetMaxDecodedBytes(), img_data_offset_); } else { alternate_decoder_ = std::make_unique<PNGImageDecoder>( parent_->GetAlphaOption(), ImageDecoder::kDefaultBitDepth,
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc index 21742cc..759dfb8 100644 --- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc +++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -160,7 +160,6 @@ AlphaOption alpha_option, HighBitDepthDecodingOption high_bit_depth_decoding_option, const ColorBehavior& color_behavior, - const OverrideAllowDecodeToYuv allow_decode_to_yuv, const SkISize& desired_size, AnimationOption animation_option) { auto type = SniffMimeTypeInternal(data); @@ -169,7 +168,7 @@ return CreateByMimeType(type, std::move(data), data_complete, alpha_option, high_bit_depth_decoding_option, color_behavior, - allow_decode_to_yuv, desired_size, animation_option); + desired_size, animation_option); } std::unique_ptr<ImageDecoder> ImageDecoder::CreateByMimeType( @@ -179,7 +178,6 @@ AlphaOption alpha_option, HighBitDepthDecodingOption high_bit_depth_decoding_option, const ColorBehavior& color_behavior, - const OverrideAllowDecodeToYuv allow_decode_to_yuv, const SkISize& desired_size, AnimationOption animation_option) { const size_t max_decoded_bytes = @@ -190,8 +188,8 @@ std::unique_ptr<ImageDecoder> decoder; if (mime_type == "image/jpeg" || mime_type == "image/pjpeg" || mime_type == "image/jpg") { - decoder = std::make_unique<JPEGImageDecoder>( - alpha_option, color_behavior, max_decoded_bytes, allow_decode_to_yuv); + decoder = std::make_unique<JPEGImageDecoder>(alpha_option, color_behavior, + max_decoded_bytes); } else if (mime_type == "image/png" || mime_type == "image/x-png" || mime_type == "image/apng") { decoder = std::make_unique<PNGImageDecoder>(
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.h b/third_party/blink/renderer/platform/image-decoders/image_decoder.h index 65bf235..75c4836 100644 --- a/third_party/blink/renderer/platform/image-decoders/image_decoder.h +++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
@@ -148,13 +148,6 @@ kMaxValue = kWebPAnimationFormat, }; - // Enforces YUV decoding to be disallowed in the image decoder. The default - // value defers the YUV decoding decision to the decoder. - enum class OverrideAllowDecodeToYuv { - kDefault, - kDeny, - }; - // For images which contain both animations and still images, indicates which // is preferred. When unspecified the decoder will use hints from the data // stream to make a decision. @@ -183,8 +176,6 @@ AlphaOption, HighBitDepthDecodingOption, const ColorBehavior&, - const OverrideAllowDecodeToYuv allow_decode_to_yuv = - OverrideAllowDecodeToYuv::kDefault, const SkISize& desired_size = SkISize::MakeEmpty(), AnimationOption animation_option = AnimationOption::kUnspecified); static std::unique_ptr<ImageDecoder> Create( @@ -193,14 +184,11 @@ AlphaOption alpha_option, HighBitDepthDecodingOption high_bit_depth_decoding_option, const ColorBehavior& color_behavior, - const OverrideAllowDecodeToYuv allow_decode_to_yuv = - OverrideAllowDecodeToYuv::kDefault, const SkISize& desired_size = SkISize::MakeEmpty(), AnimationOption animation_option = AnimationOption::kUnspecified) { return Create(SegmentReader::CreateFromSharedBuffer(std::move(data)), data_complete, alpha_option, high_bit_depth_decoding_option, - color_behavior, allow_decode_to_yuv, desired_size, - animation_option); + color_behavior, desired_size, animation_option); } // Similar to above, but does not allow mime sniffing. Creates explicitly @@ -212,8 +200,6 @@ AlphaOption alpha_option, HighBitDepthDecodingOption high_bit_depth_decoding_option, const ColorBehavior& color_behavior, - const OverrideAllowDecodeToYuv allow_decode_to_yuv = - OverrideAllowDecodeToYuv::kDefault, const SkISize& desired_size = SkISize::MakeEmpty(), AnimationOption animation_option = AnimationOption::kUnspecified); @@ -442,13 +428,12 @@ ImageDecoder(AlphaOption alpha_option, HighBitDepthDecodingOption high_bit_depth_decoding_option, const ColorBehavior& color_behavior, - size_t max_decoded_bytes, - const bool allow_decode_to_yuv = false) + size_t max_decoded_bytes) : premultiply_alpha_(alpha_option == kAlphaPremultiplied), high_bit_depth_decoding_option_(high_bit_depth_decoding_option), color_behavior_(color_behavior), max_decoded_bytes_(max_decoded_bytes), - allow_decode_to_yuv_(allow_decode_to_yuv), + allow_decode_to_yuv_(false), purge_aggressively_(false) {} // Calculates the most recent frame whose image data may be needed in
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc index f408680a..57f7cd5 100644 --- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc +++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.cc
@@ -599,14 +599,12 @@ return true; } - // Decode the JPEG data. If |only_size| is specified, then only the size - // information will be decoded. - bool Decode(bool only_size) { + // Decode the JPEG data. + bool Decode(JPEGImageDecoder::DecodingMode decoding_mode) { // We need to do the setjmp here. Otherwise bad things will happen if (setjmp(err_.setjmp_buffer)) return decoder_->SetFailed(); - J_COLOR_SPACE override_color_space = JCS_UNKNOWN; switch (state_) { case JPEG_HEADER: { // Read file parameters with jpeg_read_header(). @@ -615,9 +613,6 @@ switch (info_.jpeg_color_space) { case JCS_YCbCr: - if (decoder_->CanDecodeToYUV() && - YuvSubsampling(info_) == cc::YUVSubsampling::k420) - override_color_space = JCS_YCbCr; FALLTHROUGH; // libjpeg can convert YCbCr image pixels to RGB. case JCS_GRAYSCALE: FALLTHROUGH; // libjpeg can convert GRAYSCALE image pixels to RGB. @@ -678,13 +673,6 @@ } info_.scale_num = max_numerator; - // Scaling caused by running low on memory isn't supported by YUV - // decoding since YUV decoding is performed on full sized images. At - // this point, buffers and various image info structs have already been - // set up for the scaled size after reading the image header using this - // decoder, so using the full size is no longer possible. - if (info_.scale_num != info_.scale_denom) - override_color_space = JCS_UNKNOWN; jpeg_calc_output_dimensions(&info_); decoder_->SetDecodedSize(info_.output_width, info_.output_height); @@ -726,16 +714,6 @@ } free(profile_buf); } - if (Decoder()->ColorTransform()) { - override_color_space = JCS_UNKNOWN; - } - } - if (override_color_space == JCS_YCbCr) { - info_.out_color_space = JCS_YCbCr; - info_.raw_data_out = TRUE; - uv_size_ = ComputeYUVSize( - &info_, - 1); // U size and V size have to be the same if we got here } // Don't allocate a giant and superfluous memory buffer when the @@ -746,7 +724,7 @@ err_.num_corrupt_warnings = 0; } - if (only_size) { + if (decoding_mode == JPEGImageDecoder::DecodingMode::kDecodeHeader) { // This exits the function while there is still potentially // data in the buffer. Before this function is called again, // the SharedBuffer may be collapsed (by a call to @@ -763,8 +741,15 @@ } FALLTHROUGH; case JPEG_START_DECOMPRESS: - if (info_.out_color_space == JCS_YCbCr) + if (decoding_mode == JPEGImageDecoder::DecodingMode::kDecodeToYuv) { + DCHECK(decoder_->CanDecodeToYUV()); DCHECK(decoder_->HasImagePlanes()); + info_.out_color_space = JCS_YCbCr; + info_.raw_data_out = TRUE; + uv_size_ = ComputeYUVSize(&info_, 1); + // U size and V size have to be the same if we got here + DCHECK_EQ(uv_size_, ComputeYUVSize(&info_, 2)); + } // Set parameters for decompression. // FIXME -- Should reset dct_method and dither mode for final pass @@ -990,19 +975,14 @@ ->Complete(); } -JPEGImageDecoder::JPEGImageDecoder( - AlphaOption alpha_option, - const ColorBehavior& color_behavior, - size_t max_decoded_bytes, - const OverrideAllowDecodeToYuv allow_decode_to_yuv, - size_t offset) - : ImageDecoder( - alpha_option, - ImageDecoder::kDefaultBitDepth, - color_behavior, - max_decoded_bytes, - allow_decode_to_yuv == OverrideAllowDecodeToYuv::kDefault && - RuntimeEnabledFeatures::DecodeJpeg420ImagesToYUVEnabled()), +JPEGImageDecoder::JPEGImageDecoder(AlphaOption alpha_option, + const ColorBehavior& color_behavior, + size_t max_decoded_bytes, + size_t offset) + : ImageDecoder(alpha_option, + ImageDecoder::kDefaultBitDepth, + color_behavior, + max_decoded_bytes), offset_(offset) {} JPEGImageDecoder::~JPEGImageDecoder() = default; @@ -1021,17 +1001,22 @@ void JPEGImageDecoder::OnSetData(SegmentReader* data) { if (reader_) reader_->SetData(data); - // TODO(crbug.com/943519): Incremental YUV decoding is not currently - // supported. - if (IsAllDataReceived()) { - // TODO(crbug.com/919627): Right now |allow_decode_to_yuv_| is false by - // default and is set by the blink feature DecodeJpeg420ImagesToYUV. - // - // Calling IsSizeAvailable() ensures the reader is created and the output - // color space is set. - allow_decode_to_yuv_ &= - IsSizeAvailable() && reader_->Info()->out_color_space == JCS_YCbCr; - } + + allow_decode_to_yuv_ = + // Incremental YUV decoding is not currently supported (crbug.com/943519). + IsAllDataReceived() && + // TODO(sashamcintosh): Cleanup. Finch experiment is enabled by default. + RuntimeEnabledFeatures::DecodeJpeg420ImagesToYUVEnabled() && + // Ensures that the reader is created, the scale numbers are known, + // the color profile is known, and the subsampling is known. + IsSizeAvailable() && + // YUV decoding to a smaller size is not supported. + reader_->Info()->scale_num == reader_->Info()->scale_denom && + // TODO(crbug.com/911246): Support color space transformations on planar + // data. + !ColorTransform() && + // TODO(crbug.com/919627): Support 4:4:4 and 4:2:2 sub samplings. + GetYUVSubsampling() == cc::YUVSubsampling::k420; } void JPEGImageDecoder::SetDecodedSize(unsigned width, unsigned height) { @@ -1049,7 +1034,7 @@ DCHECK(reader_); const jpeg_decompress_struct* info = reader_->Info(); - DCHECK_EQ(info->out_color_space, JCS_YCbCr); + DCHECK_EQ(info->jpeg_color_space, JCS_YCbCr); return ComputeYUVSize(info, static_cast<int>(index)); } @@ -1057,7 +1042,7 @@ DCHECK(reader_); const jpeg_decompress_struct* info = reader_->Info(); - DCHECK_EQ(info->out_color_space, JCS_YCbCr); + DCHECK_EQ(info->jpeg_color_space, JCS_YCbCr); return ComputeYUVWidthBytes(info, static_cast<int>(index)); } @@ -1090,7 +1075,7 @@ { TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Decode Image", "imageType", "JPEG"); - Decode(false); + Decode(DecodingMode::kDecodeToYuv); } } @@ -1344,14 +1329,17 @@ frame_buffer_cache_[0].SetStatus(ImageFrame::kFrameComplete); } -inline bool IsComplete(const JPEGImageDecoder* decoder, bool only_size) { - if (decoder->HasImagePlanes() && !only_size) +inline bool IsComplete(const JPEGImageDecoder* decoder, + JPEGImageDecoder::DecodingMode decoding_mode) { + if (decoding_mode == JPEGImageDecoder::DecodingMode::kDecodeToYuv) { + DCHECK(decoder->HasImagePlanes()); return true; + } return decoder->FrameIsDecodedAtIndex(0); } -void JPEGImageDecoder::Decode(bool only_size) { +void JPEGImageDecoder::Decode(DecodingMode decoding_mode) { if (Failed()) return; @@ -1362,11 +1350,11 @@ // If we couldn't decode the image but have received all the data, decoding // has failed. - if (!reader_->Decode(only_size) && IsAllDataReceived()) + if (!reader_->Decode(decoding_mode) && IsAllDataReceived()) SetFailed(); // If decoding is done or failed, we don't need the JPEGImageReader anymore. - if (IsComplete(this, only_size) || Failed()) + if (IsComplete(this, decoding_mode) || Failed()) reader_.reset(); }
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h index 97a8b171..3360431f 100644 --- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h +++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder.h
@@ -39,7 +39,6 @@ JPEGImageDecoder(AlphaOption, const ColorBehavior&, size_t max_decoded_bytes, - const OverrideAllowDecodeToYuv allow_decode_to_yuv, size_t offset = 0); ~JPEGImageDecoder() override; @@ -73,27 +72,33 @@ void SetSupportedDecodeSizes(Vector<SkISize> sizes); - // TODO(crbug.com/919627): |allow_decode_to_yuv_| is false by - // default and is only set true for unit tests. Remove it once - // JPEG YUV decoding is finished and YUV decoding is enabled by default. - void SetDecodeToYuvForTesting(bool decode_to_yuv) { - allow_decode_to_yuv_ = decode_to_yuv; - } + enum class DecodingMode { + // Stop decoding after calculating the image size and parsing the header. + kDecodeHeader, + // Assumes that YUV decoding is possible. Eg. image planes are set and + // CanDecodeToYUV is true. + kDecodeToYuv, + // For images that can be decoded as YUV, the caller may request + // non-YUV decoding anyway. Eg. when bitmap backing is needed. + kDecodeToBitmap, + }; private: // ImageDecoder: - void DecodeSize() override { Decode(true); } - void Decode(size_t) override { Decode(false); } + void DecodeSize() override { Decode(DecodingMode::kDecodeHeader); } + void Decode(size_t) override { + // Use DecodeToYUV for YUV decoding. + Decode(DecodingMode::kDecodeToBitmap); + } cc::ImageHeaderMetadata MakeMetadataForDecodeAcceleration() const override; // Attempts to calculate the coded size of the JPEG image. Returns a zero // initialized gfx::Size upon failure. gfx::Size GetImageCodedSize() const; - // Decodes the image. If |only_size| is true, stops decoding after - // calculating the image size. If decoding fails but there is no more + // Decodes the image. If decoding fails but there is no more // data coming, sets the "decode failure" flag. - void Decode(bool only_size); + void Decode(DecodingMode decoding_mode); std::unique_ptr<JPEGImageReader> reader_; const size_t offset_;
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc index 03e9114..24c3c03 100644 --- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc +++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
@@ -49,13 +49,10 @@ namespace { -std::unique_ptr<JPEGImageDecoder> CreateJPEGDecoder( - size_t max_decoded_bytes, - ImageDecoder::OverrideAllowDecodeToYuv allow_decode_to_yuv = - ImageDecoder::OverrideAllowDecodeToYuv::kDeny) { +std::unique_ptr<JPEGImageDecoder> CreateJPEGDecoder(size_t max_decoded_bytes) { return std::make_unique<JPEGImageDecoder>( ImageDecoder::kAlphaNotPremultiplied, ColorBehavior::TransformToSRGB(), - max_decoded_bytes, allow_decode_to_yuv); + max_decoded_bytes); } std::unique_ptr<ImageDecoder> CreateJPEGDecoder() { @@ -85,9 +82,8 @@ scoped_refptr<SharedBuffer> data = ReadFile(image_file_path); ASSERT_TRUE(data); - std::unique_ptr<JPEGImageDecoder> decoder = CreateJPEGDecoder( - max_decoded_bytes, ImageDecoder::OverrideAllowDecodeToYuv::kDefault); - decoder->SetDecodeToYuvForTesting(true); + std::unique_ptr<JPEGImageDecoder> decoder = + CreateJPEGDecoder(max_decoded_bytes); decoder->SetData(data.get(), true); ASSERT_TRUE(decoder->IsSizeAvailable()); @@ -217,9 +213,7 @@ scoped_refptr<SharedBuffer> data = ReadFile(jpeg_file); ASSERT_TRUE(data); - std::unique_ptr<JPEGImageDecoder> decoder = CreateJPEGDecoder( - 230 * 230 * 4, ImageDecoder::OverrideAllowDecodeToYuv::kDefault); - decoder->SetDecodeToYuvForTesting(true); + std::unique_ptr<JPEGImageDecoder> decoder = CreateJPEGDecoder(230 * 230 * 4); decoder->SetData(data.get(), true); ASSERT_TRUE(decoder->IsSizeAvailable());
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc index cdc6ad92..2e002e3 100644 --- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc +++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.cc
@@ -50,6 +50,11 @@ service_->SetHasNonEmptyBeforeUnload(has_nonempty_beforeunload); } +void DocumentResourceCoordinator::SetViewportIntersection( + const gfx::Rect& viewport_intersection) { + service_->SetViewportIntersection(viewport_intersection); +} + void DocumentResourceCoordinator::SetOriginTrialFreezePolicy( InterventionPolicy policy) { service_->SetOriginTrialFreezePolicy(policy);
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h index a3b67ff..06309a5 100644 --- a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h +++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h
@@ -29,6 +29,7 @@ void SetNetworkAlmostIdle(); void SetLifecycleState(performance_manager::mojom::LifecycleState); void SetHasNonEmptyBeforeUnload(bool has_nonempty_beforeunload); + void SetViewportIntersection(const gfx::Rect& viewport_intersection); void SetOriginTrialFreezePolicy( performance_manager::mojom::InterventionPolicy policy); // A one way switch that marks a frame as being an adframe.
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 7312a356..3c7baf8 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -453,11 +453,20 @@ status: "experimental", }, { + // Experimental @font-face descriptor advance-override. + // Not standardized yet, and subject to changes. name: "CSSFontFaceAdvanceOverride", status: "test", depends_on: ["CSSFontMetricsOverride"], }, { + // Experimental @font-face descriptor advance-proportional-override. + // Not standardized yet, and subject to changes. + name: "CSSFontFaceAdvanceProportionalOverride", + status: "test", + depends_on: ["CSSFontMetricsOverride"], + }, + { // @font-face descriptors ascent-override, descent-override and // line-gap-override. // https://drafts.csswg.org/css-fonts-4/#font-metrics-override-desc
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng index 0113c94..fdbdc81 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng +++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -202,6 +202,7 @@ crbug.com/591099 external/wpt/css/css-text/white-space/control-chars-00C.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-001.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-002.html [ Failure ] +crbug.com/591099 external/wpt/css/css-text/white-space/pre-line-with-space-and-newline.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-012.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-013.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/white-space/white-space-pre-wrap-trailing-spaces-014.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 46502eb..d9f3bf6f 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -1224,11 +1224,9 @@ crbug.com/6606 external/wpt/mathml/presentation-markup/fractions/frac-parameters-gap-006.html [ Failure ] crbug.com/6606 external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html [ Failure ] crbug.com/6606 external/wpt/mathml/presentation-markup/mrow/legacy-mrow-like-elements-001.html [ Failure ] -crbug.com/6606 external/wpt/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002.html [ Failure ] crbug.com/6606 external/wpt/mathml/presentation-markup/operators/embellished-operator-001.html [ Failure ] crbug.com/6606 external/wpt/mathml/presentation-markup/operators/embellished-operator-002.html [ Failure ] crbug.com/6606 external/wpt/mathml/presentation-markup/operators/mo-axis-height-1.html [ Failure ] -crbug.com/6606 external/wpt/mathml/presentation-markup/operators/mo-form-dynamic.html [ Failure ] crbug.com/6606 external/wpt/mathml/presentation-markup/scripts/cramped-001.html [ Failure ] crbug.com/6606 external/wpt/mathml/presentation-markup/spaces/space-like-001.html [ Failure ] crbug.com/6606 external/wpt/mathml/presentation-markup/spaces/space-like-002.html [ Failure ] @@ -2659,7 +2657,6 @@ crbug.com/626703 [ Mac11.0 ] external/wpt/html/semantics/embedded-content/media-elements/preserves-pitch.html [ Timeout ] crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-during-and-after-dispatch.tentative.html [ Timeout ] crbug.com/626703 [ Mac11.0 ] external/wpt/scroll-to-text-fragment/redirects.html [ Timeout ] -crbug.com/626703 [ Linux ] external/wpt/mathml/presentation-markup/operators/operator-dictionary-symmetric-005.html [ Failure Crash ] crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html?Backspace [ Timeout ] crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html?TypingA [ Timeout ] crbug.com/626703 external/wpt/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html?Delete [ Timeout ] @@ -5728,9 +5725,6 @@ crbug.com/907125 external/wpt/lifecycle/child-display-none.tentative.html [ Timeout Failure ] crbug.com/907125 external/wpt/lifecycle/worker-dispay-none.tentative.html [ Timeout Failure ] -# Tests that json modules load correctly within the context of service workers -crbug.com/967018 external/wpt/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative.html [ Failure ] - # Sheriff 2019-11-04 # Updated by Sheriff on 2020-05-29: flaky on all platforms. crbug.com/1084441 media/controls/video-overlay-cast-dark-rendering.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index f23590a7..bb479bb 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -687,11 +687,6 @@ "args": [ "--js-flags=--harmony-weak-refs" ] }, { - "prefix": "media-devtools", - "bases": [ "inspector-protocol/media" ], - "args": ["--enable-features=MediaInspectorLogging"] - }, - { "prefix": "link-disabled-old-behavior", "bases": [ "external/wpt/css/cssom" ], "args": ["--disable-features=LinkDisabledNewSpecBehavior"]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index c025c65..99b249a 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -86728,6 +86728,32 @@ {} ] ], + "webkit-line-clamp-036.html": [ + "cc5fb5b13ede54c59a0c69d2a1290a765e575826", + [ + null, + [ + [ + "/css/css-overflow/reference/webkit-line-clamp-036-ref.html", + "==" + ] + ], + {} + ] + ], + "webkit-line-clamp-037.html": [ + "86015228f88e4c622c4bd1c20cb35a20619075c7", + [ + null, + [ + [ + "/css/css-overflow/reference/webkit-line-clamp-037-ref.html", + "==" + ] + ], + {} + ] + ], "webkit-line-clamp-with-line-height.tentative.html": [ "a82635f986b60ff4853785dc40b7bbe985af4eb1", [ @@ -159588,7 +159614,7 @@ ] ], "mo-form.html": [ - "b67b389ec1c4aca155e1f29908325ade67f37e76", + "d037989d1e427c8686cc9c813bbc9a4c6a66e00b", [ null, [ @@ -193325,6 +193351,14 @@ "f7488ba2ec6ebeae2d281b29586aaedb9effab97", [] ], + "webkit-line-clamp-036-ref.html": [ + "2219e3106d3107bb081b8896d7db898b4dda3c35", + [] + ], + "webkit-line-clamp-037-ref.html": [ + "2927716d76dbc8ebc8b98169c533301214a517aa", + [] + ], "webkit-line-clamp-with-line-height-ref.html": [ "c2c8914161af668cd57ce7ebac15b2100d93be8b", [] @@ -231550,7 +231584,7 @@ [] ], "mo-form-ref.html": [ - "608ad4bbadedf0cd1f7a848493add9636efac275", + "b249fe43b591b70bed7e9f75962497db56ba119a", [] ], "mo-lspace-rspace-dynamic-ref.html": [ @@ -285860,7 +285894,7 @@ ] }, "font-face-range-order.html": [ - "ed0508a18ff7c4d2e447f6227146f294950fe1e1", + "b198a9fb572d38a87e25cc71e932821d8e96b16c", [ null, {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/font-face-range-order.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/font-face-range-order.html index ed0508a..b198a9f 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-fonts/font-face-range-order.html +++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/font-face-range-order.html
@@ -20,15 +20,12 @@ } </style> <script> - async_test(function(t) { - document.fonts.load("12px reversed-range-test").then((fonts) => { - t.step( () => { - assert_equals(fonts[0].stretch, "200% 50%", "Stretch value must be returned as specified."); - assert_equals(fonts[0].style, "oblique 90deg -90deg", "Style value must be returned as specified."); - assert_equals(fonts[0].weight, "900 100", "Weight value must be returned as specified."); - }); - t.done() - })}); + promise_test(async (t) => { + const fonts = await document.fonts.load("12px reversed-range-test"); + assert_equals(fonts[0].stretch, "200% 50%", "Stretch value must be returned as specified."); + assert_equals(fonts[0].style, "oblique 90deg -90deg", "Style value must be returned as specified."); + assert_equals(fonts[0].weight, "900 100", "Weight value must be returned as specified."); + }); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollable-overflow-self-collapsing.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollable-overflow-self-collapsing.html new file mode 100644 index 0000000..cf47f240 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/scrollable-overflow-self-collapsing.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta name="assert" content="This ensures that an end self-collapsing block contributes to the scrollable overflow correctly."> +<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#scrollable" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.target')"> + <div class="target" style="width: 100px; height: 100px; overflow: scroll;" data-expected-scroll-height="110"> + <div style="width: 50px; height: 100px; margin-bottom: 10px; background: lime;"></div> + <div></div> <!-- self-collapsing --> + </div> + <div class="target" style="width: 100px; height: 100px; overflow: scroll;" data-expected-scroll-height="150"> + <div style="width: 50px; height: 100px; margin-bottom: 10px; background: lime;"></div> + <div style="margin-bottom: 50px;"></div> <!-- self-collapsing --> + </div> + <div class="target" style="width: 100px; height: 100px; overflow: scroll;" data-expected-scroll-height="180"> + <div style="width: 50px; height: 100px; margin-bottom: 30px; background: lime;"></div> + <div style="margin-bottom: 100px;"> <!-- self-collapsing --> + <div style="margin-top: -20px;"></div> + </div> + </div> + <div id=log></div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-line-with-space-and-newline.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-line-with-space-and-newline.html new file mode 100644 index 0000000..5d75597d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/pre-line-with-space-and-newline.html
@@ -0,0 +1,44 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Test: 'white-space: pre-line' with space and newline</title> +<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-text/#white-space-phase-1"> +<link rel="help" href="https://crbug.com/1136688"> +<link rel="match" href="../../reference/ref-filled-green-200px-square.html"> +<meta name="assert" content=" + Checks that collapsible spaces immediately preceding a sequent break are removed. + That still applies if they are separated into different inline elements. + Also, if some text is inserted dynamically, the browser should not crash."> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<style> +span { + font: 25px/1 Ahem; + background: red; + color: green; +} +i { + white-space: pre-line; +} +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div class="static together"> + <span>XXXXXXXX<i> </i>XXXXXXXX</span> +</div> +<div class="static separated"> + <span>XXXXXXXX<i> </i><i> </i>XXXXXXXX</span> +</div> +<div class="dynamic together"> + <span>XXXXXXXX<i> </i></span> +</div> +<div class="dynamic separated"> + <span>XXXXXXXX<i> </i><i> </i></span> +</div> +<script> +// Force layout +document.body.offsetLeft; + +// Insert text, should not crash +for (let span of document.querySelectorAll(".dynamic > span")) { + span.append("XXXXXXXX"); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/translucent-outline-ref.html b/third_party/blink/web_tests/external/wpt/css/css-ui/translucent-outline-ref.html new file mode 100644 index 0000000..383e256 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/translucent-outline-ref.html
@@ -0,0 +1,3 @@ +<!DOCTYPE html> +There should be a square in uniform pale green color. +<div style="width: 100px; height: 100px; background: rgba(0, 128, 0, 0.5)"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/translucent-outline.html b/third_party/blink/web_tests/external/wpt/css/css-ui/translucent-outline.html new file mode 100644 index 0000000..38109a5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/translucent-outline.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>Outline with translucent color, will-change:transform and negative-z index child</title> +<link rel="help" title="7.1. 'outline' property" href="http://www.w3.org/TR/css3-ui/#outline"> +<link rel="match" href="translucent-outline-ref.html"> +<style>div { will-change: transform; }</style> +There should be a square in uniform pale green color. +<div style="position: relative; top: 25px; left: 25px; + width: 50px; height: 50px; + outline: 25px solid rgba(0, 128, 0, 0.5); + background: rgba(0, 128, 0, 0.5)"> + <div style="position: absolute; width: 10px; height: 10px; z-index: -1"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative-expected.txt new file mode 100644 index 0000000..8b394c75 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL Javascript importing JSON Module should load within the context of a service worker promise_test: Unhandled rejection with value: object "AbortError: Failed to register a ServiceWorker for scope ('https://web-platform.test:8444/html/semantics/scripting-1/the-script-element/json-module/') with script ('https://web-platform.test:8444/html/semantics/scripting-1/the-script-element/json-module/serviceworker.js'): ServiceWorker cannot be started" +FAIL JSON Modules should load within the context of a service worker promise_test: Unhandled rejection with value: object "SecurityError: Failed to register a ServiceWorker for scope ('https://web-platform.test:8444/html/semantics/scripting-1/the-script-element/json-module/') with script ('https://web-platform.test:8444/html/semantics/scripting-1/the-script-element/json-module/module.json'): The script has an unsupported MIME type ('application/json')." +PASS JSON Module dynamic import should not load within the context of a service worker +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/longtask-timing/longtask-before-observer.window.js b/third_party/blink/web_tests/external/wpt/longtask-timing/longtask-before-observer.window.js new file mode 100644 index 0000000..b7d4eb9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/longtask-timing/longtask-before-observer.window.js
@@ -0,0 +1,16 @@ +async_test(t => { + assert_implements(window.PerformanceLongTaskTiming, 'Longtasks are not supported.'); + // Create a long task before any observer. + const begin = window.performance.now(); + while (window.performance.now() < begin + 60); + // After a timeout, add an observer with buffered flag. + t.step_timeout(() => { + new PerformanceObserver(t.step_func_done(list => { + list.getEntries().forEach(entry => { + assert_equals(entry.entryType, 'longtask'); + assert_equals(entry.name, 'self'); + assert_greater_than(entry.duration, 50); + }); + })).observe({type: 'longtask', buffered: true}); + }, 0); +}, 'PerformanceObserver with buffered flag can see previous longtask entries.');
diff --git a/third_party/blink/web_tests/external/wpt/portals/OWNERS b/third_party/blink/web_tests/external/wpt/portals/OWNERS index 13d38116..542026e 100644 --- a/third_party/blink/web_tests/external/wpt/portals/OWNERS +++ b/third_party/blink/web_tests/external/wpt/portals/OWNERS
@@ -1,3 +1,3 @@ -# COMPONENT: Blink>HTML>Portal +# COMPONENT: Blink>Portals # WPT-NOTIFY: true file://third_party/blink/renderer/core/html/portal/OWNERS
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js b/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js index c661971..41e1e7f 100644 --- a/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js +++ b/third_party/blink/web_tests/external/wpt/resources/chromium/webxr-test.js
@@ -350,7 +350,7 @@ this.bounds_ = null; this.send_mojo_space_reset_ = false; this.stageParameters_ = null; - this.stageParametersUpdated_ = false; + this.stageParametersId_ = 1; this.service_ = service; @@ -552,11 +552,7 @@ onStageParametersUpdated() { // Indicate for the frame loop that the stage parameters have been updated. - this.stageParametersUpdated_ = true; - this.displayInfo_.stageParameters = this.stageParameters_; - if (this.sessionClient_.ptr.isBound()) { - this.sessionClient_.onChanged(this.displayInfo_); - } + this.stageParametersId_++; } simulateResetPose() { @@ -723,8 +719,6 @@ const mojo_space_reset = this.send_mojo_space_reset_; this.send_mojo_space_reset_ = false; - const stage_parameters_updated = this.stageParametersUpdated_; - this.stageParametersUpdated_ = false; if (this.pose_) { this.pose_.poseIndex++; } @@ -753,7 +747,7 @@ bufferHolder: null, bufferSize: {}, stageParameters: this.stageParameters_, - stageParametersUpdated: stage_parameters_updated, + stageParametersId: this.stageParametersId_, }; this.next_frame_id_++;
diff --git a/third_party/blink/web_tests/fast/files/resources/hello_world.xls b/third_party/blink/web_tests/fast/files/resources/hello_world.xls new file mode 100644 index 0000000..20431270 --- /dev/null +++ b/third_party/blink/web_tests/fast/files/resources/hello_world.xls Binary files differ
diff --git a/third_party/blink/web_tests/fast/files/resources/hello_world.xlsx b/third_party/blink/web_tests/fast/files/resources/hello_world.xlsx new file mode 100644 index 0000000..42a81d4c --- /dev/null +++ b/third_party/blink/web_tests/fast/files/resources/hello_world.xlsx Binary files differ
diff --git a/third_party/blink/web_tests/fast/files/xls-mime-type.html b/third_party/blink/web_tests/fast/files/xls-mime-type.html new file mode 100644 index 0000000..9d29da75 --- /dev/null +++ b/third_party/blink/web_tests/fast/files/xls-mime-type.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<head> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> +</head> +<body> + <iframe id="formiframe" name="formiframe"></iframe> + <form target="formiframe" id="myform" action="/forms/resources/return-content-type.php" enctype="multipart/form-data" method="post"> + <input type="text" name="textinput" value="hello world"> + <input type="file" name="fileinput" id="fileinput"> + <input type="submit"> + </form> + <script> + window.test(() => { + if (!window.eventSender) + return; + const fileinput = document.getElementById('fileinput'); + window.eventSender.beginDragWithFiles(['resources/hello_world.xls']); + const centerx = fileinput.offsetLeft + fileinput.offsetWidth / 2; + const centery = fileinput.offsetTop + fileinput.offsetHeight / 2; + window.eventSender.mouseMoveTo(centerx, centery); + window.eventSender.mouseUp(); + assert_equals(fileinput.files[0].type, 'application/vnd.ms-excel'); + }); + </script> +</body>
diff --git a/third_party/blink/web_tests/fast/files/xlsx-mime-type.html b/third_party/blink/web_tests/fast/files/xlsx-mime-type.html new file mode 100644 index 0000000..81a020e --- /dev/null +++ b/third_party/blink/web_tests/fast/files/xlsx-mime-type.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<head> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> +</head> +<body> + <iframe id="formiframe" name="formiframe"></iframe> + <form target="formiframe" id="myform" action="/forms/resources/return-content-type.php" enctype="multipart/form-data" method="post"> + <input type="text" name="textinput" value="hello world"> + <input type="file" name="fileinput" id="fileinput"> + <input type="submit"> + </form> + <script> + window.test(() => { + if (!window.eventSender) + return; + const fileinput = document.getElementById('fileinput'); + window.eventSender.beginDragWithFiles(['resources/hello_world.xlsx']); + const centerx = fileinput.offsetLeft + fileinput.offsetWidth / 2; + const centery = fileinput.offsetTop + fileinput.offsetHeight / 2; + window.eventSender.mouseMoveTo(centerx, centery); + window.eventSender.mouseUp(); + assert_equals(fileinput.files[0].type, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + }); + </script> +</body>
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/console-truncate-long-messages.js b/third_party/blink/web_tests/http/tests/devtools/console/console-truncate-long-messages.js index 4d1ea747..ad45a09 100644 --- a/third_party/blink/web_tests/http/tests/devtools/console/console-truncate-long-messages.js +++ b/third_party/blink/web_tests/http/tests/devtools/console/console-truncate-long-messages.js
@@ -7,13 +7,13 @@ await TestRunner.loadModule('console_test_runner'); await TestRunner.showPanel('console'); - var consoleView = Console.ConsoleView.instance(); - - var maxLength = 40; - Console.ConsoleViewMessage._MaxTokenizableStringLength = maxLength; + const consoleView = Console.ConsoleView.instance(); + const maxLength = 40; + Console.ConsoleViewMessage.setMaxTokenizableStringLength(maxLength); ObjectUI.ObjectPropertiesSection._maxRenderableStringLength = maxLength; - var visibleLength = Console.ConsoleViewMessage._LongStringVisibleLength = 20; - var overMaxLength = maxLength * 2; + const visibleLength = 20; + Console.ConsoleViewMessage.setLongStringVisibleLength(visibleLength); + const overMaxLength = maxLength * 2; TestRunner.addResult(`Setting max length to: ${maxLength}`); TestRunner.addResult(`Setting long string visible length to: ${visibleLength}`); @@ -44,17 +44,17 @@ function dumpMessageLengths() { consoleView._visibleViewMessages.forEach((message, index) => { - var text = consoleMessageText(index); + const text = consoleMessageText(index); TestRunner.addResult(`Message: ${index}, length: ${text.length}, ${text}`); }); function consoleMessageText(index) { - var messageElement = consoleView._visibleViewMessages[index].element(); - var anchor = messageElement.querySelector('.console-message-anchor'); + const messageElement = consoleView._visibleViewMessages[index].element(); + const anchor = messageElement.querySelector('.console-message-anchor'); if (anchor) anchor.remove(); - var links = messageElement.querySelectorAll('.devtools-link'); - for (var link of links) + const links = messageElement.querySelectorAll('.devtools-link'); + for (const link of links) TestRunner.addResult(`Link: ${link.textContent}`); return messageElement.deepTextContent(); }
diff --git a/third_party/blink/web_tests/http/tests/portals/OWNERS b/third_party/blink/web_tests/http/tests/portals/OWNERS index 95933363..739ad28 100644 --- a/third_party/blink/web_tests/http/tests/portals/OWNERS +++ b/third_party/blink/web_tests/http/tests/portals/OWNERS
@@ -1 +1 @@ -# COMPONENT: Blink>HTML>Portal +# COMPONENT: Blink>Portals
diff --git a/third_party/blink/web_tests/virtual/json-modules/external/wpt/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative-expected.txt b/third_party/blink/web_tests/virtual/json-modules/external/wpt/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative-expected.txt new file mode 100644 index 0000000..9bce732 --- /dev/null +++ b/third_party/blink/web_tests/virtual/json-modules/external/wpt/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +PASS Javascript importing JSON Module should load within the context of a service worker +PASS JSON Modules should load within the context of a service worker +PASS JSON Module dynamic import should not load within the context of a service worker +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/media-devtools/inspector-protocol/media/README.txt b/third_party/blink/web_tests/virtual/media-devtools/inspector-protocol/media/README.txt deleted file mode 100644 index 1e76653..0000000 --- a/third_party/blink/web_tests/virtual/media-devtools/inspector-protocol/media/README.txt +++ /dev/null
@@ -1,2 +0,0 @@ -# This suite runs the tests in inspector-protocol/media -# with --enable-features=MediaInspectorLogging
diff --git a/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt b/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt index d778606..b45c332 100644 --- a/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt +++ b/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt
@@ -2,6 +2,7 @@ advanceOverride +advanceProportionalOverride alignContent alignItems alignSelf
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-fonts/advance-proportional-override-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-fonts/advance-proportional-override-ref.html new file mode 100644 index 0000000..dca5281 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/css/css-fonts/advance-proportional-override-ref.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/5533"> +<link rel="assert" title="Tests that advance-proportional-override sets advance to characters rendered with the font face only"> +<title>Tests the advance-proportional-override descriptor of @font-face</title> +<style> +@font-face { + font-family: custom-font; + src: local(Ahem), url(/fonts/Ahem.ttf); + unicode-range: U+0-7F; /* ASCII only */ +} + +.target { + font: 20px custom-font, sans-serif; +} + +.letter-spacing { + letter-spacing: 1em; +} + +</style> + +<p>advance-proportional-override should affect Ahem characters only.</p> + +<div class="target"> + <span class="letter-spacing">XXX</span>一二三<span class="letter-spacing">XXX</span> +</div> + +<p>advance-proportional-override: 100% should be the same as no override.</p> + +<div class="target"> + XXX一二三XXX +</div>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-fonts/advance-proportional-override.html b/third_party/blink/web_tests/wpt_internal/css/css-fonts/advance-proportional-override.html new file mode 100644 index 0000000..5939aef --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/css/css-fonts/advance-proportional-override.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" href="mailto:xiaochengh@chromium.org"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/5533"> +<link rel="match" href="advance-proportional-override-ref.html"> +<link rel="assert" title="Tests that advance-porportional-override sets advance to characters rendered with the font face only"> +<title>Tests the advance-proportional-override descriptor of @font-face</title> +<style> +@font-face { + font-family: custom-font; + src: local(Ahem), url(/fonts/Ahem.ttf); + advance-proportional-override: 200%; + unicode-range: U+0-7F; /* ASCII only */ +} + +.target { + font: 20px custom-font, sans-serif; +} + +@font-face { + font-family: reference-font; + src: local(Ahem), url(/fonts/Ahem.ttf); + advance-proportional-override: 100%; + unicode-range: U+0-7F; /* ASCII only */ +} + +.reference { + font: 20px reference-font, sans-serif; +} + +</style> + +<p>advance-proportional-override should affect Ahem characters only.</p> + +<div class="target"> + XXX一二三XXX +</div> + +<p>advance-proportional-override: 100% should be the same as no override.</p> + +<div class="reference"> + XXX一二三XXX +</div>
diff --git a/third_party/d3/README.chromium b/third_party/d3/README.chromium index a5f9893..031d7bee 100644 --- a/third_party/d3/README.chromium +++ b/third_party/d3/README.chromium
@@ -1,13 +1,13 @@ Name: d3 Short Name: d3 URL: https://github.com/d3/d3 -Version: 5.7.0 -CPEPrefix: cpe:/a:d3.js_project:d3.js:5.7.0::~~~node.js~~ -Date: Fri Aug 24 5:46 PM 2018 EDT -Revision: e35d1f74f9337a2eee4aa704f38025621c8ae9d0 +Version: 5.16.0 +CPEPrefix: cpe:/a:d3.js_project:d3.js:5.16.0::~~~node.js~~ +Date: Mon Apr 20 1:58 PM 2020 EDT +Revision: 7244e45e68af39c519f76667a03039d5b24dd453 License: BSD 3-Clause License File: src/LICENSE -Security Critical: No +Security Critical: Yes License Android Compatible: Yes Description:
diff --git a/third_party/d3/src/API.md b/third_party/d3/src/API.md deleted file mode 100644 index f6ba4a7..0000000 --- a/third_party/d3/src/API.md +++ /dev/null
@@ -1,1321 +0,0 @@ -# D3 API Reference - -D3 is a [collection of modules](https://github.com/d3) that are designed to work together; you can use the modules independently, or you can use them together as part of the default build. The source and documentation for each module is available in its repository. Follow the links below to learn more. For changes between major versions, see [CHANGES](https://github.com/d3/d3/blob/master/CHANGES.md); see also the [release notes](https://github.com/d3/d3/releases) and the [3.x reference](https://github.com/d3/d3-3.x-api-reference/blob/master/API-Reference.md). - -* [Arrays](#arrays-d3-array) ([Statistics](#statistics), [Search](#search), [Transformations](#transformations), [Histograms](#histograms)) -* [Axes](#axes-d3-axis) -* [Brushes](#brushes-d3-brush) -* [Chords](#chords-d3-chord) -* [Collections](#collections-d3-collection) ([Objects](#objects), [Maps](#maps), [Sets](#sets), [Nests](#nests)) -* [Colors](#colors-d3-color) -* [Color Schemes](#color-schemes-d3-scale-chromatic) -* [Contours](#contours-d3-contour) -* [Dispatches](#dispatches-d3-dispatch) -* [Dragging](#dragging-d3-drag) -* [Delimiter-Separated Values](#delimiter-separated-values-d3-dsv) -* [Easings](#easings-d3-ease) -* [Fetches](#fetches-d3-fetch) -* [Forces](#forces-d3-force) -* [Number Formats](#number-formats-d3-format) -* [Geographies](#geographies-d3-geo) ([Paths](#paths), [Projections](#projections), [Spherical Math](#spherical-math), [Spherical Shapes](#spherical-shapes), [Streams](#streams), [Transforms](#transforms)) -* [Hierarchies](#hierarchies-d3-hierarchy) -* [Interpolators](#interpolators-d3-interpolate) -* [Paths](#paths-d3-path) -* [Polygons](#polygons-d3-polygon) -* [Quadtrees](#quadtrees-d3-quadtree) -* [Random Numbers](#random-numbers-d3-random) -* [Scales](#scales-d3-scale) ([Continuous](#continuous-scales), [Sequential](#sequential-scales), [Diverging](#diverging-scales), [Quantize](#quantize-scales), [Ordinal](#ordinal-scales)) -* [Selections](#selections-d3-selection) ([Selecting](#selecting-elements), [Modifying](#modifying-elements), [Data](#joining-data), [Events](#handling-events), [Control](#control-flow), [Local Variables](#local-variables), [Namespaces](#namespaces)) -* [Shapes](#shapes-d3-shape) ([Arcs](#arcs), [Pies](#pies), [Lines](#lines), [Areas](#areas), [Curves](#curves), [Links](#links), [Symbols](#symbols), [Stacks](#stacks)) -* [Time Formats](#time-formats-d3-time-format) -* [Time Intervals](#time-intervals-d3-time) -* [Timers](#timers-d3-timer) -* [Transitions](#transitions-d3-transition) -* [Voronoi Diagrams](#voronoi-diagrams-d3-voronoi) -* [Zooming](#zooming-d3-zoom) - -D3 uses [semantic versioning](http://semver.org/). The current version is exposed as d3.version. - -## [Arrays (d3-array)](https://github.com/d3/d3-array) - -Array manipulation, ordering, searching, summarizing, etc. - -### [Statistics](https://github.com/d3/d3-array/blob/master/README.md#statistics) - -Methods for computing basic summary statistics. - -* [d3.min](https://github.com/d3/d3-array/blob/master/README.md#min) - compute the minimum value in an array. -* [d3.max](https://github.com/d3/d3-array/blob/master/README.md#max) - compute the maximum value in an array. -* [d3.extent](https://github.com/d3/d3-array/blob/master/README.md#extent) - compute the minimum and maximum value in an array. -* [d3.sum](https://github.com/d3/d3-array/blob/master/README.md#sum) - compute the sum of an array of numbers. -* [d3.mean](https://github.com/d3/d3-array/blob/master/README.md#mean) - compute the arithmetic mean of an array of numbers. -* [d3.median](https://github.com/d3/d3-array/blob/master/README.md#median) - compute the median of an array of numbers (the 0.5-quantile). -* [d3.quantile](https://github.com/d3/d3-array/blob/master/README.md#quantile) - compute a quantile for a sorted array of numbers. -* [d3.variance](https://github.com/d3/d3-array/blob/master/README.md#variance) - compute the variance of an array of numbers. -* [d3.deviation](https://github.com/d3/d3-array/blob/master/README.md#deviation) - compute the standard deviation of an array of numbers. - -### [Search](https://github.com/d3/d3-array/blob/master/README.md#search) - -Methods for searching arrays for a specific element. - -* [d3.scan](https://github.com/d3/d3-array/blob/master/README.md#scan) - linear search for an element using a comparator. -* [d3.bisect](https://github.com/d3/d3-array/blob/master/README.md#bisect) - binary search for a value in a sorted array. -* [d3.bisectRight](https://github.com/d3/d3-array/blob/master/README.md#bisectRight) - binary search for a value in a sorted array. -* [d3.bisectLeft](https://github.com/d3/d3-array/blob/master/README.md#bisectLeft) - binary search for a value in a sorted array. -* [d3.bisector](https://github.com/d3/d3-array/blob/master/README.md#bisector) - bisect using an accessor or comparator. -* [*bisector*.left](https://github.com/d3/d3-array/blob/master/README.md#bisector_left) - bisectLeft, with the given comparator. -* [*bisector*.right](https://github.com/d3/d3-array/blob/master/README.md#bisector_right) - bisectRight, with the given comparator. -* [d3.ascending](https://github.com/d3/d3-array/blob/master/README.md#ascending) - compute the natural order of two values. -* [d3.descending](https://github.com/d3/d3-array/blob/master/README.md#descending) - compute the natural order of two values. - -### [Transformations](https://github.com/d3/d3-array/blob/master/README.md#transformations) - -Methods for transforming arrays and for generating new arrays. - -* [d3.cross](https://github.com/d3/d3-array/blob/master/README.md#cross) - compute the Cartesian product of two arrays. -* [d3.merge](https://github.com/d3/d3-array/blob/master/README.md#merge) - merge multiple arrays into one array. -* [d3.pairs](https://github.com/d3/d3-array/blob/master/README.md#pairs) - create an array of adjacent pairs of elements. -* [d3.permute](https://github.com/d3/d3-array/blob/master/README.md#permute) - reorder an array of elements according to an array of indexes. -* [d3.shuffle](https://github.com/d3/d3-array/blob/master/README.md#shuffle) - randomize the order of an array. -* [d3.ticks](https://github.com/d3/d3-array/blob/master/README.md#ticks) - generate representative values from a numeric interval. -* [d3.tickIncrement](https://github.com/d3/d3-array/blob/master/README.md#tickIncrement) - generate representative values from a numeric interval. -* [d3.tickStep](https://github.com/d3/d3-array/blob/master/README.md#tickStep) - generate representative values from a numeric interval. -* [d3.range](https://github.com/d3/d3-array/blob/master/README.md#range) - generate a range of numeric values. -* [d3.transpose](https://github.com/d3/d3-array/blob/master/README.md#transpose) - transpose an array of arrays. -* [d3.zip](https://github.com/d3/d3-array/blob/master/README.md#zip) - transpose a variable number of arrays. - -### [Histograms](https://github.com/d3/d3-array/blob/master/README.md#histograms) - -Bin discrete samples into continuous, non-overlapping intervals. - -* [d3.histogram](https://github.com/d3/d3-array/blob/master/README.md#histogram) - create a new histogram generator. -* [*histogram*](https://github.com/d3/d3-array/blob/master/README.md#_histogram) - compute the histogram for the given array of samples. -* [*histogram*.value](https://github.com/d3/d3-array/blob/master/README.md#histogram_value) - specify a value accessor for each sample. -* [*histogram*.domain](https://github.com/d3/d3-array/blob/master/README.md#histogram_domain) - specify the interval of observable values. -* [*histogram*.thresholds](https://github.com/d3/d3-array/blob/master/README.md#histogram_thresholds) - specify how values are divided into bins. -* [d3.thresholdFreedmanDiaconis](https://github.com/d3/d3-array/blob/master/README.md#thresholdFreedmanDiaconis) - the Freedman–Diaconis binning rule. -* [d3.thresholdScott](https://github.com/d3/d3-array/blob/master/README.md#thresholdScott) - Scott’s normal reference binning rule. -* [d3.thresholdSturges](https://github.com/d3/d3-array/blob/master/README.md#thresholdSturges) - Sturges’ binning formula. - -## [Axes (d3-axis)](https://github.com/d3/d3-axis) - -Human-readable reference marks for scales. - -* [d3.axisTop](https://github.com/d3/d3-axis/blob/master/README.md#axisTop) - create a new top-oriented axis generator. -* [d3.axisRight](https://github.com/d3/d3-axis/blob/master/README.md#axisRight) - create a new right-oriented axis generator. -* [d3.axisBottom](https://github.com/d3/d3-axis/blob/master/README.md#axisBottom) - create a new bottom-oriented axis generator. -* [d3.axisLeft](https://github.com/d3/d3-axis/blob/master/README.md#axisLeft) - create a new left-oriented axis generator. -* [*axis*](https://github.com/d3/d3-axis/blob/master/README.md#_axis) - generate an axis for the given selection. -* [*axis*.scale](https://github.com/d3/d3-axis/blob/master/README.md#axis_scale) - set the scale. -* [*axis*.ticks](https://github.com/d3/d3-axis/blob/master/README.md#axis_ticks) - customize how ticks are generated and formatted. -* [*axis*.tickArguments](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickArguments) - customize how ticks are generated and formatted. -* [*axis*.tickValues](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickValues) - set the tick values explicitly. -* [*axis*.tickFormat](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickFormat) - set the tick format explicitly. -* [*axis*.tickSize](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickSize) - set the size of the ticks. -* [*axis*.tickSizeInner](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickSizeInner) - set the size of inner ticks. -* [*axis*.tickSizeOuter](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickSizeOuter) - set the size of outer (extent) ticks. -* [*axis*.tickPadding](https://github.com/d3/d3-axis/blob/master/README.md#axis_tickPadding) - set the padding between ticks and labels. - -## [Brushes (d3-brush)](https://github.com/d3/d3-brush) - -Select a one- or two-dimensional region using the mouse or touch. - -* [d3.brush](https://github.com/d3/d3-brush/blob/master/README.md#brush) - create a new two-dimensional brush. -* [d3.brushX](https://github.com/d3/d3-brush/blob/master/README.md#brushX) - create a brush along the *x*-dimension. -* [d3.brushY](https://github.com/d3/d3-brush/blob/master/README.md#brushY) - create a brush along the *y*-dimension. -* [*brush*](https://github.com/d3/d3-brush/blob/master/README.md#_brush) - apply the brush to a selection. -* [*brush*.move](https://github.com/d3/d3-brush/blob/master/README.md#brush_move) - move the brush selection. -* [*brush*.extent](https://github.com/d3/d3-brush/blob/master/README.md#brush_extent) - define the brushable region. -* [*brush*.filter](https://github.com/d3/d3-brush/blob/master/README.md#brush_filter) - control which input events initiate brushing. -* [*brush*.handleSize](https://github.com/d3/d3-brush/blob/master/README.md#brush_handleSize) - set the size of the brush handles. -* [*brush*.on](https://github.com/d3/d3-brush/blob/master/README.md#brush_on) - listen for brush events. -* [d3.brushSelection](https://github.com/d3/d3-brush/blob/master/README.md#brushSelection) - get the brush selection for a given node. - -## [Chords (d3-chord)](https://github.com/d3/d3-chord) - -* [d3.chord](https://github.com/d3/d3-chord/blob/master/README.md#chord) - create a new chord layout. -* [*chord*](https://github.com/d3/d3-chord/blob/master/README.md#_chord) - compute the layout for the given matrix. -* [*chord*.padAngle](https://github.com/d3/d3-chord/blob/master/README.md#chord_padAngle) - set the padding between adjacent groups. -* [*chord*.sortGroups](https://github.com/d3/d3-chord/blob/master/README.md#chord_sortGroups) - define the group order. -* [*chord*.sortSubgroups](https://github.com/d3/d3-chord/blob/master/README.md#chord_sortSubgroups) - define the source and target order within groups. -* [*chord*.sortChords](https://github.com/d3/d3-chord/blob/master/README.md#chord_sortChords) - define the chord order across groups. -* [d3.ribbon](https://github.com/d3/d3-chord/blob/master/README.md#ribbon) - create a ribbon shape generator. -* [*ribbon*](https://github.com/d3/d3-chord/blob/master/README.md#_ribbon) - generate a ribbon shape. -* [*ribbon*.source](https://github.com/d3/d3-chord/blob/master/README.md#ribbon_source) - set the source accessor. -* [*ribbon*.target](https://github.com/d3/d3-chord/blob/master/README.md#ribbon_target) - set the target accessor. -* [*ribbon*.radius](https://github.com/d3/d3-chord/blob/master/README.md#ribbon_radius) - set the ribbon source or target radius. -* [*ribbon*.startAngle](https://github.com/d3/d3-chord/blob/master/README.md#ribbon_startAngle) - set the ribbon source or target start angle. -* [*ribbon*.endAngle](https://github.com/d3/d3-chord/blob/master/README.md#ribbon_endAngle) - set the ribbon source or target end angle. -* [*ribbon*.context](https://github.com/d3/d3-chord/blob/master/README.md#ribbon_context) - set the render context. - -## [Collections (d3-collection)](https://github.com/d3/d3-collection) - -Handy data structures for elements keyed by string. - -### [Objects](https://github.com/d3/d3-collection/blob/master/README.md#objects) - -Methods for converting associative arrays (objects) to arrays. - -* [d3.keys](https://github.com/d3/d3-collection/blob/master/README.md#keys) - list the keys of an associative array. -* [d3.values](https://github.com/d3/d3-collection/blob/master/README.md#values) - list the values of an associated array. -* [d3.entries](https://github.com/d3/d3-collection/blob/master/README.md#entries) - list the key-value entries of an associative array. - -### [Maps](https://github.com/d3/d3-collection/blob/master/README.md#maps) - -Like ES6 Map, but with string keys and a few other differences. - -* [d3.map](https://github.com/d3/d3-collection/blob/master/README.md#map) - create a new, empty map. -* [*map*.has](https://github.com/d3/d3-collection/blob/master/README.md#map_has) - returns true if the map contains the given key. -* [*map*.get](https://github.com/d3/d3-collection/blob/master/README.md#map_get) - get the value for the given key. -* [*map*.set](https://github.com/d3/d3-collection/blob/master/README.md#map_set) - set the value for the given key. -* [*map*.remove](https://github.com/d3/d3-collection/blob/master/README.md#map_remove) - remove the entry for given key. -* [*map*.clear](https://github.com/d3/d3-collection/blob/master/README.md#map_clear) - remove all entries. -* [*map*.keys](https://github.com/d3/d3-collection/blob/master/README.md#map_keys) - get the array of keys. -* [*map*.values](https://github.com/d3/d3-collection/blob/master/README.md#map_values) - get the array of values. -* [*map*.entries](https://github.com/d3/d3-collection/blob/master/README.md#map_entries) - get the array of entries (key-values objects). -* [*map*.each](https://github.com/d3/d3-collection/blob/master/README.md#map_each) - call a function for each entry. -* [*map*.empty](https://github.com/d3/d3-collection/blob/master/README.md#map_empty) - returns false if the map has at least one entry. -* [*map*.size](https://github.com/d3/d3-collection/blob/master/README.md#map_size) - compute the number of entries. - -### [Sets](https://github.com/d3/d3-collection/blob/master/README.md#sets) - -Like ES6 Set, but with string keys and a few other differences. - -* [d3.set](https://github.com/d3/d3-collection/blob/master/README.md#set) - create a new, empty set. -* [*set*.has](https://github.com/d3/d3-collection/blob/master/README.md#set_has) - returns true if the set contains the given value. -* [*set*.add](https://github.com/d3/d3-collection/blob/master/README.md#set_add) - add the given value. -* [*set*.remove](https://github.com/d3/d3-collection/blob/master/README.md#set_remove) - remove the given value. -* [*set*.clear](https://github.com/d3/d3-collection/blob/master/README.md#set_clear) - remove all values. -* [*set*.values](https://github.com/d3/d3-collection/blob/master/README.md#set_values) - get the array of values. -* [*set*.each](https://github.com/d3/d3-collection/blob/master/README.md#set_each) - call a function for each value. -* [*set*.empty](https://github.com/d3/d3-collection/blob/master/README.md#set_empty) - returns true if the set has at least one value. -* [*set*.size](https://github.com/d3/d3-collection/blob/master/README.md#set_size) - compute the number of values. - -### [Nests](https://github.com/d3/d3-collection/blob/master/README.md#nests) - -Group data into arbitrary hierarchies. - -* [d3.nest](https://github.com/d3/d3-collection/blob/master/README.md#nest) - create a new nest generator. -* [*nest*.key](https://github.com/d3/d3-collection/blob/master/README.md#nest_key) - add a level to the nest hierarchy. -* [*nest*.sortKeys](https://github.com/d3/d3-collection/blob/master/README.md#nest_sortKeys) - sort the current nest level by key. -* [*nest*.sortValues](https://github.com/d3/d3-collection/blob/master/README.md#nest_sortValues) - sort the leaf nest level by value. -* [*nest*.rollup](https://github.com/d3/d3-collection/blob/master/README.md#nest_rollup) - specify a rollup function for leaf values. -* [*nest*.map](https://github.com/d3/d3-collection/blob/master/README.md#nest_map) - generate the nest, returning a map. -* [*nest*.object](https://github.com/d3/d3-collection/blob/master/README.md#nest_object) - generate the nest, returning an associative array. -* [*nest*.entries](https://github.com/d3/d3-collection/blob/master/README.md#nest_entries) - generate the nest, returning an array of key-values tuples. - -## [Colors (d3-color)](https://github.com/d3/d3-color) - -Color manipulation and color space conversion. - -* [d3.color](https://github.com/d3/d3-color/blob/master/README.md#color) - parse the given CSS color specifier. -* [*color*.rgb](https://github.com/d3/d3-color/blob/master/README.md#color_rgb) - compute the RGB equivalent of this color. -* [*color*.brighter](https://github.com/d3/d3-color/blob/master/README.md#color_brighter) - create a brighter copy of this color. -* [*color*.darker](https://github.com/d3/d3-color/blob/master/README.md#color_darker) - create a darker copy of this color. -* [*color*.displayable](https://github.com/d3/d3-color/blob/master/README.md#color_displayable) - returns true if the color is displayable on standard hardware. -* [*color*.hex](https://github.com/d3/d3-color/blob/master/README.md#color_hex) - returns the hexadecimal RGB string representation of this color. -* [*color*.toString](https://github.com/d3/d3-color/blob/master/README.md#color_toString) - returns the RGB string representation of this color. -* [d3.rgb](https://github.com/d3/d3-color/blob/master/README.md#rgb) - create a new RGB color. -* [d3.hsl](https://github.com/d3/d3-color/blob/master/README.md#hsl) - create a new HSL color. -* [d3.lab](https://github.com/d3/d3-color/blob/master/README.md#lab) - create a new Lab color. -* [d3.hcl](https://github.com/d3/d3-color/blob/master/README.md#hcl) - create a new HCL color. -* [d3.lch](https://github.com/d3/d3-color/blob/master/README.md#lch) - create a new HCL color. -* [d3.gray](https://github.com/d3/d3-color/blob/master/README.md#gray) - create a new Lab gray. -* [d3.cubehelix](https://github.com/d3/d3-color/blob/master/README.md#cubehelix) - create a new Cubehelix color. - -## [Color Schemes (d3-scale-chromatic)](https://github.com/d3/d3-scale-chromatic) - -Color ramps and palettes for quantitative, ordinal and categorical scales. - -### Categorical - -* [d3.schemeCategory10](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeCategory10) - -* [d3.schemeAccent](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeAccent) - -* [d3.schemeDark2](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeDark2) - -* [d3.schemePaired](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePaired) - -* [d3.schemePastel1](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePastel1) - -* [d3.schemePastel2](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePastel2) - -* [d3.schemeSet1](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeSet1) - -* [d3.schemeSet2](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeSet2) - -* [d3.schemeSet3](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeSet3) - - -### Diverging - -* [d3.interpolateBrBG](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolatePiYG](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolatePRGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolatePuOr](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateRdBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateRdGy](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateRdYlBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateRdYlGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateSpectral](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.schemeBrBG](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeBrBG) - -* [d3.schemePiYG](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePiYG) - -* [d3.schemePRGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePRGn) - -* [d3.schemePuOr](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePuOr) - -* [d3.schemeRdBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeRdBu) - -* [d3.schemeRdGy](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeRdGy) - -* [d3.schemeRdYlBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeRdYlBu) - -* [d3.schemeRdYlGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeRdYlGn) - -* [d3.schemeSpectral](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeSpectral) - - -### Sequential (Single Hue) - -* [d3.interpolateBlues](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateGreens](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateGreys](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateOranges](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolatePurples](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateReds](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.schemeBlues](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeBlues) - -* [d3.schemeGreens](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeGreens) - -* [d3.schemeGreys](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeGreys) - -* [d3.schemeOranges](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeOranges) - -* [d3.schemePurples](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePurples) - -* [d3.schemeReds](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeReds) - - -### Sequential (Multi-Hue) - -* [d3.interpolateBuGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateBuPu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateCool](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateCubehelixDefault](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateGnBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateInferno](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateMagma](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateOrRd](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolatePlasma](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolatePuBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolatePuBuGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolatePuRd](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateRdPu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateViridis](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateWarm](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateYlGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateYlGnBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateYlOrBr](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.interpolateYlOrRd](https://github.com/d3/d3-scale-chromatic/blob/master/README.md) - -* [d3.schemeBuGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeBuGn) - -* [d3.schemeBuPu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeBuPu) - -* [d3.schemeGnBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeGnBu) - -* [d3.schemeOrRd](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeOrRd) - -* [d3.schemePuBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePuBu) - -* [d3.schemePuBuGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePuBuGn) - -* [d3.schemePuRd](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemePuRd) - -* [d3.schemeRdPu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeRdPu) - -* [d3.schemeYlGn](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeYlGn) - -* [d3.schemeYlGnBu](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeYlGnBu) - -* [d3.schemeYlOrBr](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeYlOrBr) - -* [d3.schemeYlOrRd](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeYlOrRd) - - -### Cyclical - -* [d3.interpolateRainbow](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#interpolateRainbow) - the “less-angry” rainbow -* [d3.interpolateSinebow](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#interpolateSinebow) - the “sinebow” smooth rainbow - -## [Contours (d3-contour)](https://github.com/d3/d3-contour) - -Compute contour polygons using marching squares. - -* [d3.contours](https://github.com/d3/d3-contour/blob/master/README.md#contours) - create a new contour generator. -* [contours](https://github.com/d3/d3-contour/blob/master/README.md#_contours) - compute the contours for a given grid of values. -* [contours.contour](https://github.com/d3/d3-contour/blob/master/README.md#contours_contour) - -* [contours.size](https://github.com/d3/d3-contour/blob/master/README.md#contours_size) - -* [contours.smooth](https://github.com/d3/d3-contour/blob/master/README.md#contours_smooth) - -* [contours.thresholds](https://github.com/d3/d3-contour/blob/master/README.md#contours_thresholds) - -* [d3.contourDensity](https://github.com/d3/d3-contour/blob/master/README.md#contourDensity) - create a new density estimator. -* [density](https://github.com/d3/d3-contour/blob/master/README.md#_density) - estimate the density of a given array of samples. -* [density.x](https://github.com/d3/d3-contour/blob/master/README.md#density_x) - -* [density.y](https://github.com/d3/d3-contour/blob/master/README.md#density_y) - -* [density.cellSize](https://github.com/d3/d3-contour/blob/master/README.md#density_cellSize) - -* [density.thresholds](https://github.com/d3/d3-contour/blob/master/README.md#density_thresholds) - -* [density.bandwidth](https://github.com/d3/d3-contour/blob/master/README.md#density_bandwidth) - -* [density.weight](https://github.com/d3/d3-contour/blob/master/README.md#density_weight) - - -## [Dispatches (d3-dispatch)](https://github.com/d3/d3-dispatch) - -Separate concerns using named callbacks. - -* [d3.dispatch](https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch) - create a custom event dispatcher. -* [*dispatch*.on](https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch_on) - register or unregister an event listener. -* [*dispatch*.copy](https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch_copy) - create a copy of a dispatcher. -* [*dispatch*.*call*](https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch_call) - dispatch an event to registered listeners. -* [*dispatch*.*apply*](https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch_apply) - dispatch an event to registered listeners. - -## [Dragging (d3-drag)](https://github.com/d3/d3-drag) - -Drag and drop SVG, HTML or Canvas using mouse or touch input. - -* [d3.drag](https://github.com/d3/d3-drag/blob/master/README.md#drag) - create a drag behavior. -* [*drag*](https://github.com/d3/d3-drag/blob/master/README.md#_drag) - apply the drag behavior to a selection. -* [*drag*.container](https://github.com/d3/d3-drag/blob/master/README.md#drag_container) - set the coordinate system. -* [*drag*.filter](https://github.com/d3/d3-drag/blob/master/README.md#drag_filter) - ignore some initiating input events. -* [*drag*.touchable](https://github.com/d3/d3-drag/blob/master/README.md#drag_touchable) - set the touch support detector. -* [*drag*.subject](https://github.com/d3/d3-drag/blob/master/README.md#drag_subject) - set the thing being dragged. -* [*drag*.clickDistance](https://github.com/d3/d3-drag/blob/master/README.md#drag_clickDistance) - set the click distance threshold. -* [*drag*.on](https://github.com/d3/d3-drag/blob/master/README.md#drag_on) - listen for drag events. -* [*event*.on](https://github.com/d3/d3-drag/blob/master/README.md#event_on) - listen for drag events on the current gesture. -* [d3.dragDisable](https://github.com/d3/d3-drag/blob/master/README.md#dragDisable) - prevent native drag-and-drop and text selection. -* [d3.dragEnable](https://github.com/d3/d3-drag/blob/master/README.md#dragEnable) - enable native drag-and-drop and text selection. - -## [Delimiter-Separated Values (d3-dsv)](https://github.com/d3/d3-dsv) - -Parse and format delimiter-separated values, most commonly CSV and TSV. - -* [d3.dsvFormat](https://github.com/d3/d3-dsv/blob/master/README.md#dsvFormat) - create a new parser and formatter for the given delimiter. -* [*dsv*.parse](https://github.com/d3/d3-dsv/blob/master/README.md#dsv_parse) - parse the given string, returning an array of objects. -* [*dsv*.parseRows](https://github.com/d3/d3-dsv/blob/master/README.md#dsv_parseRows) - parse the given string, returning an array of rows. -* [*dsv*.format](https://github.com/d3/d3-dsv/blob/master/README.md#dsv_format) - format the given array of objects. -* [*dsv*.formatRows](https://github.com/d3/d3-dsv/blob/master/README.md#dsv_formatRows) - format the given array of rows. -* [d3.csvParse](https://github.com/d3/d3-dsv/blob/master/README.md#csvParse) - parse the given CSV string, returning an array of objects. -* [d3.csvParseRows](https://github.com/d3/d3-dsv/blob/master/README.md#csvParseRows) - parse the given CSV string, returning an array of rows. -* [d3.csvFormat](https://github.com/d3/d3-dsv/blob/master/README.md#csvFormat) - format the given array of objects as CSV. -* [d3.csvFormatRows](https://github.com/d3/d3-dsv/blob/master/README.md#csvFormatRows) - format the given array of rows as CSV. -* [d3.tsvParse](https://github.com/d3/d3-dsv/blob/master/README.md#tsvParse) - parse the given TSV string, returning an array of objects. -* [d3.tsvParseRows](https://github.com/d3/d3-dsv/blob/master/README.md#tsvParseRows) - parse the given TSV string, returning an array of rows. -* [d3.tsvFormat](https://github.com/d3/d3-dsv/blob/master/README.md#tsvFormat) - format the given array of objects as TSV. -* [d3.tsvFormatRows](https://github.com/d3/d3-dsv/blob/master/README.md#tsvFormatRows) - format the given array of rows as TSV. - -## [Easings (d3-ease)](https://github.com/d3/d3-ease) - -Easing functions for smooth animation. - -* [*ease*](https://github.com/d3/d3-ease/blob/master/README.md#_ease) - ease the given normalized time. -* [d3.easeLinear](https://github.com/d3/d3-ease/blob/master/README.md#easeLinear) - linear easing; the identity function. -* [d3.easePolyIn](https://github.com/d3/d3-ease/blob/master/README.md#easePolyIn) - polynomial easing; raises time to the given power. -* [d3.easePolyOut](https://github.com/d3/d3-ease/blob/master/README.md#easePolyOut) - reverse polynomial easing. -* [d3.easePolyInOut](https://github.com/d3/d3-ease/blob/master/README.md#easePolyInOut) - symmetric polynomial easing. -* [*poly*.exponent](https://github.com/d3/d3-ease/blob/master/README.md#poly_exponent) - specify the polynomial exponent. -* [d3.easeQuad](https://github.com/d3/d3-ease/blob/master/README.md#easeQuad) - an alias for easeQuadInOut. -* [d3.easeQuadIn](https://github.com/d3/d3-ease/blob/master/README.md#easeQuadIn) - quadratic easing; squares time. -* [d3.easeQuadOut](https://github.com/d3/d3-ease/blob/master/README.md#easeQuadOut) - reverse quadratic easing. -* [d3.easeQuadInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeQuadInOut) - symmetric quadratic easing. -* [d3.easeCubic](https://github.com/d3/d3-ease/blob/master/README.md#easeCubic) - an alias for easeCubicInOut. -* [d3.easeCubicIn](https://github.com/d3/d3-ease/blob/master/README.md#easeCubicIn) - cubic easing; cubes time. -* [d3.easeCubicOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCubicOut) - reverse cubic easing. -* [d3.easeCubicInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCubicInOut) - symmetric cubic easing. -* [d3.easeSin](https://github.com/d3/d3-ease/blob/master/README.md#easeSin) - an alias for easeSinInOut. -* [d3.easeSinIn](https://github.com/d3/d3-ease/blob/master/README.md#easeSinIn) - sinusoidal easing. -* [d3.easeSinOut](https://github.com/d3/d3-ease/blob/master/README.md#easeSinOut) - reverse sinusoidal easing. -* [d3.easeSinInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeSinInOut) - symmetric sinusoidal easing. -* [d3.easeExp](https://github.com/d3/d3-ease/blob/master/README.md#easeExp) - an alias for easeExpInOut. -* [d3.easeExpIn](https://github.com/d3/d3-ease/blob/master/README.md#easeExpIn) - exponential easing. -* [d3.easeExpOut](https://github.com/d3/d3-ease/blob/master/README.md#easeExpOut) - reverse exponential easing. -* [d3.easeExpInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeExpInOut) - symmetric exponential easing. -* [d3.easeCircle](https://github.com/d3/d3-ease/blob/master/README.md#easeCircle) - an alias for easeCircleInOut. -* [d3.easeCircleIn](https://github.com/d3/d3-ease/blob/master/README.md#easeCircleIn) - circular easing. -* [d3.easeCircleOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCircleOut) - reverse circular easing. -* [d3.easeCircleInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeCircleInOut) - symmetric circular easing. -* [d3.easeElastic](https://github.com/d3/d3-ease/blob/master/README.md#easeElastic) - an alias for easeElasticOut. -* [d3.easeElasticIn](https://github.com/d3/d3-ease/blob/master/README.md#easeElasticIn) - elastic easing, like a rubber band. -* [d3.easeElasticOut](https://github.com/d3/d3-ease/blob/master/README.md#easeElasticOut) - reverse elastic easing. -* [d3.easeElasticInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeElasticInOut) - symmetric elastic easing. -* [*elastic*.amplitude](https://github.com/d3/d3-ease/blob/master/README.md#elastic_amplitude) - specify the elastic amplitude. -* [*elastic*.period](https://github.com/d3/d3-ease/blob/master/README.md#elastic_period) - specify the elastic period. -* [d3.easeBack](https://github.com/d3/d3-ease/blob/master/README.md#easeBack) - an alias for easeBackInOut. -* [d3.easeBackIn](https://github.com/d3/d3-ease/blob/master/README.md#easeBackIn) - anticipatory easing, like a dancer bending his knees before jumping. -* [d3.easeBackOut](https://github.com/d3/d3-ease/blob/master/README.md#easeBackOut) - reverse anticipatory easing. -* [d3.easeBackInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeBackInOut) - symmetric anticipatory easing. -* [*back*.overshoot](https://github.com/d3/d3-ease/blob/master/README.md#back_overshoot) - specify the amount of overshoot. -* [d3.easeBounce](https://github.com/d3/d3-ease/blob/master/README.md#easeBounce) - an alias for easeBounceOut. -* [d3.easeBounceIn](https://github.com/d3/d3-ease/blob/master/README.md#easeBounceIn) - bounce easing, like a rubber ball. -* [d3.easeBounceOut](https://github.com/d3/d3-ease/blob/master/README.md#easeBounceOut) - reverse bounce easing. -* [d3.easeBounceInOut](https://github.com/d3/d3-ease/blob/master/README.md#easeBounceInOut) - symmetric bounce easing. - -## [Fetches (d3-fetch)](https://github.com/d3/d3-fetch) - -Convenience methods on top of the Fetch API. - -* [d3.blob](https://github.com/d3/d3-fetch/blob/master/README.md#blob) - get a file as a blob. -* [d3.buffer](https://github.com/d3/d3-fetch/blob/master/README.md#buffer) - get a file as an array buffer. -* [d3.csv](https://github.com/d3/d3-fetch/blob/master/README.md#csv) - get a comma-separated values (CSV) file. -* [d3.dsv](https://github.com/d3/d3-fetch/blob/master/README.md#dsv) - get a delimiter-separated values (CSV) file. -* [d3.image](https://github.com/d3/d3-fetch/blob/master/README.md#image) - get an image. -* [d3.json](https://github.com/d3/d3-fetch/blob/master/README.md#json) - get a JSON file. -* [d3.text](https://github.com/d3/d3-fetch/blob/master/README.md#text) - get a plain text file. -* [d3.tsv](https://github.com/d3/d3-fetch/blob/master/README.md#tsv) - get a tab-separated values (TSV) file. - -## [Forces (d3-force)](https://github.com/d3/d3-force) - -Force-directed graph layout using velocity Verlet integration. - -* [d3.forceSimulation](https://github.com/d3/d3-force/blob/master/README.md#forceSimulation) - create a new force simulation. -* [*simulation*.restart](https://github.com/d3/d3-force/blob/master/README.md#simulation_restart) - reheat and restart the simulation’s timer. -* [*simulation*.stop](https://github.com/d3/d3-force/blob/master/README.md#simulation_stop) - stop the simulation’s timer. -* [*simulation*.tick](https://github.com/d3/d3-force/blob/master/README.md#simulation_tick) - advance the simulation one step. -* [*simulation*.nodes](https://github.com/d3/d3-force/blob/master/README.md#simulation_nodes) - set the simulation’s nodes. -* [*simulation*.alpha](https://github.com/d3/d3-force/blob/master/README.md#simulation_alpha) - set the current alpha. -* [*simulation*.alphaMin](https://github.com/d3/d3-force/blob/master/README.md#simulation_alphaMin) - set the minimum alpha threshold. -* [*simulation*.alphaDecay](https://github.com/d3/d3-force/blob/master/README.md#simulation_alphaDecay) - set the alpha exponential decay rate. -* [*simulation*.alphaTarget](https://github.com/d3/d3-force/blob/master/README.md#simulation_alphaTarget) - set the target alpha. -* [*simulation*.velocityDecay](https://github.com/d3/d3-force/blob/master/README.md#simulation_velocityDecay) - set the velocity decay rate. -* [*simulation*.force](https://github.com/d3/d3-force/blob/master/README.md#simulation_force) - add or remove a force. -* [*simulation*.find](https://github.com/d3/d3-force/blob/master/README.md#simulation_find) - find the closest node to the given position. -* [*simulation*.on](https://github.com/d3/d3-force/blob/master/README.md#simulation_on) - add or remove an event listener. -* [*force*](https://github.com/d3/d3-force/blob/master/README.md#_force) - apply the force. -* [*force*.initialize](https://github.com/d3/d3-force/blob/master/README.md#force_initialize) - initialize the force with the given nodes. -* [d3.forceCenter](https://github.com/d3/d3-force/blob/master/README.md#forceCenter) - create a centering force. -* [*center*.x](https://github.com/d3/d3-force/blob/master/README.md#center_x) - set the center *x*-coordinate. -* [*center*.y](https://github.com/d3/d3-force/blob/master/README.md#center_y) - set the center *y*-coordinate. -* [d3.forceCollide](https://github.com/d3/d3-force/blob/master/README.md#forceCollide) - create a circle collision force. -* [*collide*.radius](https://github.com/d3/d3-force/blob/master/README.md#collide_radius) - set the circle radius. -* [*collide*.strength](https://github.com/d3/d3-force/blob/master/README.md#collide_strength) - set the collision resolution strength. -* [*collide*.iterations](https://github.com/d3/d3-force/blob/master/README.md#collide_iterations) - set the number of iterations. -* [d3.forceLink](https://github.com/d3/d3-force/blob/master/README.md#forceLink) - create a link force. -* [*link*.links](https://github.com/d3/d3-force/blob/master/README.md#link_links) - set the array of links. -* [*link*.id](https://github.com/d3/d3-force/blob/master/README.md#link_id) - link nodes by numeric index or string identifier. -* [*link*.distance](https://github.com/d3/d3-force/blob/master/README.md#link_distance) - set the link distance. -* [*link*.strength](https://github.com/d3/d3-force/blob/master/README.md#link_strength) - set the link strength. -* [*link*.iterations](https://github.com/d3/d3-force/blob/master/README.md#link_iterations) - set the number of iterations. -* [d3.forceManyBody](https://github.com/d3/d3-force/blob/master/README.md#forceManyBody) - create a many-body force. -* [*manyBody*.strength](https://github.com/d3/d3-force/blob/master/README.md#manyBody_strength) - set the force strength. -* [*manyBody*.theta](https://github.com/d3/d3-force/blob/master/README.md#manyBody_theta) - set the Barnes–Hut approximation accuracy. -* [*manyBody*.distanceMin](https://github.com/d3/d3-force/blob/master/README.md#manyBody_distanceMin) - limit the force when nodes are close. -* [*manyBody*.distanceMax](https://github.com/d3/d3-force/blob/master/README.md#manyBody_distanceMax) - limit the force when nodes are far. -* [d3.forceX](https://github.com/d3/d3-force/blob/master/README.md#forceX) - create an *x*-positioning force. -* [*x*.strength](https://github.com/d3/d3-force/blob/master/README.md#x_strength) - set the force strength. -* [*x*.x](https://github.com/d3/d3-force/blob/master/README.md#x_x) - set the target *x*-coordinate. -* [d3.forceY](https://github.com/d3/d3-force/blob/master/README.md#forceY) - create an *y*-positioning force. -* [*y*.strength](https://github.com/d3/d3-force/blob/master/README.md#y_strength) - set the force strength. -* [*y*.y](https://github.com/d3/d3-force/blob/master/README.md#y_y) - set the target *y*-coordinate. -* [d3.forceRadial](https://github.com/d3/d3-force/blob/master/README.md#forceRadial) - create a radial positioning force. -* [*radial*.strength](https://github.com/d3/d3-force/blob/master/README.md#radial_strength) - set the force strength. -* [*radial*.radius](https://github.com/d3/d3-force/blob/master/README.md#radial_radius) - set the target radius. -* [*radial*.x](https://github.com/d3/d3-force/blob/master/README.md#radial_x) - set the target center *x*-coordinate. -* [*radial*.y](https://github.com/d3/d3-force/blob/master/README.md#radial_y) - set the target center *y*-coordinate. - -## [Number Formats (d3-format)](https://github.com/d3/d3-format) - -Format numbers for human consumption. - -* [d3.format](https://github.com/d3/d3-format/blob/master/README.md#format) - alias for *locale*.format on the default locale. -* [d3.formatPrefix](https://github.com/d3/d3-format/blob/master/README.md#formatPrefix) - alias for *locale*.formatPrefix on the default locale. -* [d3.formatSpecifier](https://github.com/d3/d3-format/blob/master/README.md#formatSpecifier) - parse a number format specifier. -* [d3.formatLocale](https://github.com/d3/d3-format/blob/master/README.md#formatLocale) - define a custom locale. -* [d3.formatDefaultLocale](https://github.com/d3/d3-format/blob/master/README.md#formatDefaultLocale) - define the default locale. -* [*locale*.format](https://github.com/d3/d3-format/blob/master/README.md#locale_format) - create a number format. -* [*locale*.formatPrefix](https://github.com/d3/d3-format/blob/master/README.md#locale_formatPrefix) - create a SI-prefix number format. -* [d3.precisionFixed](https://github.com/d3/d3-format/blob/master/README.md#precisionFixed) - compute decimal precision for fixed-point notation. -* [d3.precisionPrefix](https://github.com/d3/d3-format/blob/master/README.md#precisionPrefix) - compute decimal precision for SI-prefix notation. -* [d3.precisionRound](https://github.com/d3/d3-format/blob/master/README.md#precisionRound) - compute significant digits for rounded notation. - -## [Geographies (d3-geo)](https://github.com/d3/d3-geo) - -Geographic projections, shapes and math. - -### [Paths](https://github.com/d3/d3-geo/blob/master/README.md#paths) - -* [d3.geoPath](https://github.com/d3/d3-geo/blob/master/README.md#geoPath) - create a new geographic path generator. -* [*path*](https://github.com/d3/d3-geo/blob/master/README.md#_path) - project and render the specified feature. -* [*path*.area](https://github.com/d3/d3-geo/blob/master/README.md#path_area) - compute the projected planar area of a given feature. -* [*path*.bounds](https://github.com/d3/d3-geo/blob/master/README.md#path_bounds) - compute the projected planar bounding box of a given feature. -* [*path*.centroid](https://github.com/d3/d3-geo/blob/master/README.md#path_centroid) - compute the projected planar centroid of a given feature. -* [*path*.measure](https://github.com/d3/d3-geo/blob/master/README.md#path_measure) - compute the projected planar length of a given feature. -* [*path*.projection](https://github.com/d3/d3-geo/blob/master/README.md#path_projection) - set the geographic projection. -* [*path*.context](https://github.com/d3/d3-geo/blob/master/README.md#path_context) - set the render context. -* [*path*.pointRadius](https://github.com/d3/d3-geo/blob/master/README.md#path_pointRadius) - set the radius to display point features. - -### [Projections](https://github.com/d3/d3-geo/blob/master/README.md#projections) - -* [*projection*](https://github.com/d3/d3-geo/blob/master/README.md#_projection) - project the specified point from the sphere to the plane. -* [*projection*.invert](https://github.com/d3/d3-geo/blob/master/README.md#projection_invert) - unproject the specified point from the plane to the sphere. -* [*projection*.stream](https://github.com/d3/d3-geo/blob/master/README.md#projection_stream) - wrap the specified stream to project geometry. -* [*projection*.clipAngle](https://github.com/d3/d3-geo/blob/master/README.md#projection_clipAngle) - set the radius of the clip circle. -* [*projection*.clipExtent](https://github.com/d3/d3-geo/blob/master/README.md#projection_clipExtent) - set the viewport clip extent, in pixels. -* [*projection*.angle](https://github.com/d3/d3-geo/blob/master/README.md#projection_angle) - set the post-projection rotation. -* [*projection*.scale](https://github.com/d3/d3-geo/blob/master/README.md#projection_scale) - set the scale factor. -* [*projection*.translate](https://github.com/d3/d3-geo/blob/master/README.md#projection_translate) - set the translation offset. -* [*projection*.fitExtent](https://github.com/d3/d3-geo/blob/master/README.md#projection_fitExtent) - set the scale and translate to fit a GeoJSON object. -* [*projection*.fitSize](https://github.com/d3/d3-geo/blob/master/README.md#projection_fitSize) - set the scale and translate to fit a GeoJSON object. -* [*projection*.fitWidth](https://github.com/d3/d3-geo/blob/master/README.md#projection_fitWidth) - set the scale and translate to fit a GeoJSON object. -* [*projection*.fitHeight](https://github.com/d3/d3-geo/blob/master/README.md#projection_fitHeight) - set the scale and translate to fit a GeoJSON object. -* [*projection*.center](https://github.com/d3/d3-geo/blob/master/README.md#projection_center) - set the center point. -* [*projection*.rotate](https://github.com/d3/d3-geo/blob/master/README.md#projection_rotate) - set the three-axis spherical rotation angles. -* [*projection*.precision](https://github.com/d3/d3-geo/blob/master/README.md#projection_precision) - set the precision threshold for adaptive sampling. -* [*projection*.preclip](https://github.com/d3/d3-geo/blob/master/README.md#projection.preclip) - set the spherical clipping stream transform. -* [*projection*.postclip](https://github.com/d3/d3-geo/blob/master/README.md#projection.postclip) - set the planar clipping stream transform. -* [d3.geoClipAntimeridian](https://github.com/d3/d3-geo/blob/master/README.md#geoClipAntimeridian) - cuts spherical geometries that cross the antimeridian. -* [d3.geoClipCircle](https://github.com/d3/d3-geo/blob/master/README.md#geoClipCircle) - clips spherical geometries to a small circle. -* [d3.geoClipRectangle](https://github.com/d3/d3-geo/blob/master/README.md#geoClipRectangle) - clips planar geometries to a rectangular viewport. -* [d3.geoAlbers](https://github.com/d3/d3-geo/blob/master/README.md#geoAlbers) - the Albers equal-area conic projection. -* [d3.geoAlbersUsa](https://github.com/d3/d3-geo/blob/master/README.md#geoAlbersUsa) - a composite Albers projection for the United States. -* [d3.geoAzimuthalEqualArea](https://github.com/d3/d3-geo/blob/master/README.md#geoAzimuthalEqualArea) - the azimuthal equal-area projection. -* [d3.geoAzimuthalEquidistant](https://github.com/d3/d3-geo/blob/master/README.md#geoAzimuthalEquidistant) - the azimuthal equidistant projection. -* [d3.geoConicConformal](https://github.com/d3/d3-geo/blob/master/README.md#geoConicConformal) - the conic conformal projection. -* [d3.geoConicEqualArea](https://github.com/d3/d3-geo/blob/master/README.md#geoConicEqualArea) - the conic equal-area (Albers) projection. -* [d3.geoConicEquidistant](https://github.com/d3/d3-geo/blob/master/README.md#geoConicEquidistant) - the conic equidistant projection. -* [*conic*.parallels](https://github.com/d3/d3-geo/blob/master/README.md#conic_parallels) - set the two standard parallels. -* [d3.geoEquirectangular](https://github.com/d3/d3-geo/blob/master/README.md#geoEquirectangular) - the equirectangular (plate carreé) projection. -* [d3.geoGnomonic](https://github.com/d3/d3-geo/blob/master/README.md#geoGnomonic) - the gnomonic projection. -* [d3.geoMercator](https://github.com/d3/d3-geo/blob/master/README.md#geoMercator) - the spherical Mercator projection. -* [d3.geoOrthographic](https://github.com/d3/d3-geo/blob/master/README.md#geoOrthographic) - the azimuthal orthographic projection. -* [d3.geoStereographic](https://github.com/d3/d3-geo/blob/master/README.md#geoStereographic) - the azimuthal stereographic projection. -* [d3.geoTransverseMercator](https://github.com/d3/d3-geo/blob/master/README.md#geoTransverseMercator) - the transverse spherical Mercator projection. -* [*project*](https://github.com/d3/d3-geo/blob/master/README.md#_project) - project the specified point from the sphere to the plane. -* [*project*.invert](https://github.com/d3/d3-geo/blob/master/README.md#project_invert) - unproject the specified point from the plane to the sphere. -* [d3.geoProjection](https://github.com/d3/d3-geo/blob/master/README.md#geoProjection) - create a custom projection. -* [d3.geoProjectionMutator](https://github.com/d3/d3-geo/blob/master/README.md#geoProjectionMutator) - create a custom configurable projection. -* [d3.geoAzimuthalEqualAreaRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoAzimuthalEqualAreaRaw) - the raw azimuthal equal-area projection. -* [d3.geoAzimuthalEquidistantRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoAzimuthalEquidistantRaw) - the raw azimuthal equidistant projection. -* [d3.geoConicConformalRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoConicConformalRaw) - the raw conic conformal projection. -* [d3.geoConicEqualAreaRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoConicEqualAreaRaw) - the raw conic equal-area (Albers) projection. -* [d3.geoConicEquidistantRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoConicEquidistantRaw) - the raw conic equidistant projection. -* [d3.geoEquirectangularRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoEquirectangularRaw) - the raw equirectangular (plate carreé) projection. -* [d3.geoGnomonicRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoGnomonicRaw) - the raw gnomonic projection. -* [d3.geoMercatorRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoMercatorRaw) - the raw Mercator projection. -* [d3.geoOrthographicRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoOrthographicRaw) - the raw azimuthal orthographic projection. -* [d3.geoStereographicRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoStereographicRaw) - the raw azimuthal stereographic projection. -* [d3.geoTransverseMercatorRaw](https://github.com/d3/d3-geo/blob/master/README.md#geoTransverseMercatorRaw) - the raw transverse spherical Mercator projection. - -### [Spherical Math](https://github.com/d3/d3-geo/blob/master/README.md#spherical-math) - -* [d3.geoArea](https://github.com/d3/d3-geo/blob/master/README.md#geoArea) - compute the spherical area of a given feature. -* [d3.geoBounds](https://github.com/d3/d3-geo/blob/master/README.md#geoBounds) - compute the latitude-longitude bounding box for a given feature. -* [d3.geoCentroid](https://github.com/d3/d3-geo/blob/master/README.md#geoCentroid) - compute the spherical centroid of a given feature. -* [d3.geoContains](https://github.com/d3/d3-geo/blob/master/README.md#geoContains) - test whether a point is inside a given feature. -* [d3.geoDistance](https://github.com/d3/d3-geo/blob/master/README.md#geoDistance) - compute the great-arc distance between two points. -* [d3.geoLength](https://github.com/d3/d3-geo/blob/master/README.md#geoLength) - compute the length of a line string or the perimeter of a polygon. -* [d3.geoInterpolate](https://github.com/d3/d3-geo/blob/master/README.md#geoInterpolate) - interpolate between two points along a great arc. -* [d3.geoRotation](https://github.com/d3/d3-geo/blob/master/README.md#geoRotation) - create a rotation function for the specified angles. -* [*rotation*](https://github.com/d3/d3-geo/blob/master/README.md#_rotation) - rotate the given point around the sphere. -* [*rotation*.invert](https://github.com/d3/d3-geo/blob/master/README.md#rotation_invert) - unrotate the given point around the sphere. - -### [Spherical Shapes](https://github.com/d3/d3-geo/blob/master/README.md#spherical-shapes) - -* [d3.geoCircle](https://github.com/d3/d3-geo/blob/master/README.md#geoCircle) - create a circle generator. -* [*circle*](https://github.com/d3/d3-geo/blob/master/README.md#_circle) - generate a piecewise circle as a Polygon. -* [*circle*.center](https://github.com/d3/d3-geo/blob/master/README.md#circle_center) - specify the circle center in latitude and longitude. -* [*circle*.radius](https://github.com/d3/d3-geo/blob/master/README.md#circle_radius) - specify the angular radius in degrees. -* [*circle*.precision](https://github.com/d3/d3-geo/blob/master/README.md#circle_precision) - specify the precision of the piecewise circle. -* [d3.geoGraticule](https://github.com/d3/d3-geo/blob/master/README.md#geoGraticule) - create a graticule generator. -* [*graticule*](https://github.com/d3/d3-geo/blob/master/README.md#_graticule) - generate a MultiLineString of meridians and parallels. -* [*graticule*.lines](https://github.com/d3/d3-geo/blob/master/README.md#graticule_lines) - generate an array of LineStrings of meridians and parallels. -* [*graticule*.outline](https://github.com/d3/d3-geo/blob/master/README.md#graticule_outline) - generate a Polygon of the graticule’s extent. -* [*graticule*.extent](https://github.com/d3/d3-geo/blob/master/README.md#graticule_extent) - get or set the major & minor extents. -* [*graticule*.extentMajor](https://github.com/d3/d3-geo/blob/master/README.md#graticule_extentMajor) - get or set the major extent. -* [*graticule*.extentMinor](https://github.com/d3/d3-geo/blob/master/README.md#graticule_extentMinor) - get or set the minor extent. -* [*graticule*.step](https://github.com/d3/d3-geo/blob/master/README.md#graticule_step) - get or set the major & minor step intervals. -* [*graticule*.stepMajor](https://github.com/d3/d3-geo/blob/master/README.md#graticule_stepMajor) - get or set the major step intervals. -* [*graticule*.stepMinor](https://github.com/d3/d3-geo/blob/master/README.md#graticule_stepMinor) - get or set the minor step intervals. -* [*graticule*.precision](https://github.com/d3/d3-geo/blob/master/README.md#graticule_precision) - get or set the latitudinal precision. -* [d3.geoGraticule10](https://github.com/d3/d3-geo/blob/master/README.md#geoGraticule10) - generate the default 10° global graticule. - -#### [Streams](https://github.com/d3/d3-geo/blob/master/README.md#streams) - -* [d3.geoStream](https://github.com/d3/d3-geo/blob/master/README.md#geoStream) - convert a GeoJSON object to a geometry stream. -* [*stream*.point](https://github.com/d3/d3-geo/blob/master/README.md#stream_point) - indicates a point with the specified coordinates. -* [*stream*.lineStart](https://github.com/d3/d3-geo/blob/master/README.md#stream_lineStart) - indicates the start of a line or ring. -* [*stream*.lineEnd](https://github.com/d3/d3-geo/blob/master/README.md#stream_lineEnd) - indicates the end of a line or ring. -* [*stream*.polygonStart](https://github.com/d3/d3-geo/blob/master/README.md#stream_polygonStart) - indicates the start of a polygon. -* [*stream*.polygonEnd](https://github.com/d3/d3-geo/blob/master/README.md#stream_polygonEnd) - indicates the end of a polygon. -* [*stream*.sphere](https://github.com/d3/d3-geo/blob/master/README.md#stream_sphere) - indicates the sphere. - -### [Transforms](https://github.com/d3/d3-geo/blob/master/README.md#transforms) - -* [d3.geoIdentity](https://github.com/d3/d3-geo/blob/master/README.md#geoIdentity) - scale, translate or clip planar geometry. -* [*identity*.reflectX](https://github.com/d3/d3-geo/blob/master/README.md#identity_reflectX) - reflect the *x*-dimension. -* [*identity*.reflectY](https://github.com/d3/d3-geo/blob/master/README.md#identity_reflectY) - reflect the *y*-dimension. -* [d3.geoTransform](https://github.com/d3/d3-geo/blob/master/README.md#geoTransform) - define a custom geometry transform. - -## [Hierarchies (d3-hierarchy)](https://github.com/d3/d3-hierarchy) - -Layout algorithms for visualizing hierarchical data. - -* [d3.hierarchy](https://github.com/d3/d3-hierarchy/blob/master/README.md#hierarchy) - constructs a root node from hierarchical data. -* [*node*.ancestors](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_ancestors) - generate an array of ancestors. -* [*node*.descendants](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_descendants) - generate an array of descendants. -* [*node*.leaves](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_leaves) - generate an array of leaves. -* [*node*.path](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_path) - generate the shortest path to another node. -* [*node*.links](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_links) - generate an array of links. -* [*node*.sum](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_sum) - evaluate and aggregate quantitative values. -* [*node*.sort](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_sort) - sort all descendant siblings. -* [*node*.count](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_count) - count the number of leaves. -* [*node*.each](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_each) - breadth-first traversal. -* [*node*.eachAfter](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_eachAfter) - post-order traversal. -* [*node*.eachBefore](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_eachBefore) - pre-order traversal. -* [*node*.copy](https://github.com/d3/d3-hierarchy/blob/master/README.md#node_copy) - copy a hierarchy. -* [d3.stratify](https://github.com/d3/d3-hierarchy/blob/master/README.md#stratify) - create a new stratify operator. -* [*stratify*](https://github.com/d3/d3-hierarchy/blob/master/README.md#_stratify) - construct a root node from tabular data. -* [*stratify*.id](https://github.com/d3/d3-hierarchy/blob/master/README.md#stratify_id) - set the node id accessor. -* [*stratify*.parentId](https://github.com/d3/d3-hierarchy/blob/master/README.md#stratify_parentId) - set the parent node id accessor. -* [d3.cluster](https://github.com/d3/d3-hierarchy/blob/master/README.md#cluster) - create a new cluster (dendrogram) layout. -* [*cluster*](https://github.com/d3/d3-hierarchy/blob/master/README.md#_cluster) - layout the specified hierarchy in a dendrogram. -* [*cluster*.size](https://github.com/d3/d3-hierarchy/blob/master/README.md#cluster_size) - set the layout size. -* [*cluster*.nodeSize](https://github.com/d3/d3-hierarchy/blob/master/README.md#cluster_nodeSize) - set the node size. -* [*cluster*.separation](https://github.com/d3/d3-hierarchy/blob/master/README.md#cluster_separation) - set the separation between leaves. -* [d3.tree](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree) - create a new tidy tree layout. -* [*tree*](https://github.com/d3/d3-hierarchy/blob/master/README.md#_tree) - layout the specified hierarchy in a tidy tree. -* [*tree*.size](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree_size) - set the layout size. -* [*tree*.nodeSize](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree_nodeSize) - set the node size. -* [*tree*.separation](https://github.com/d3/d3-hierarchy/blob/master/README.md#tree_separation) - set the separation between nodes. -* [d3.treemap](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap) - create a new treemap layout. -* [*treemap*](https://github.com/d3/d3-hierarchy/blob/master/README.md#_treemap) - layout the specified hierarchy as a treemap. -* [*treemap*.tile](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_tile) - set the tiling method. -* [*treemap*.size](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_size) - set the layout size. -* [*treemap*.round](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_round) - set whether the output coordinates are rounded. -* [*treemap*.padding](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_padding) - set the padding. -* [*treemap*.paddingInner](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingInner) - set the padding between siblings. -* [*treemap*.paddingOuter](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingOuter) - set the padding between parent and children. -* [*treemap*.paddingTop](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingTop) - set the padding between the parent’s top edge and children. -* [*treemap*.paddingRight](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingRight) - set the padding between the parent’s right edge and children. -* [*treemap*.paddingBottom](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingBottom) - set the padding between the parent’s bottom edge and children. -* [*treemap*.paddingLeft](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap_paddingLeft) - set the padding between the parent’s left edge and children. -* [d3.treemapBinary](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemapBinary) - tile using a balanced binary tree. -* [d3.treemapDice](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemapDice) - tile into a horizontal row. -* [d3.treemapSlice](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemapSlice) - tile into a vertical column. -* [d3.treemapSliceDice](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemapSliceDice) - alternate between slicing and dicing. -* [d3.treemapSquarify](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemapSquarify) - tile using squarified rows per Bruls *et. al.* -* [d3.treemapResquarify](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemapResquarify) - like d3.treemapSquarify, but performs stable updates. -* [*squarify*.ratio](https://github.com/d3/d3-hierarchy/blob/master/README.md#squarify_ratio) - set the desired rectangle aspect ratio. -* [d3.partition](https://github.com/d3/d3-hierarchy/blob/master/README.md#partition) - create a new partition (icicle or sunburst) layout. -* [*partition*](https://github.com/d3/d3-hierarchy/blob/master/README.md#_partition) - layout the specified hierarchy as a partition diagram. -* [*partition*.size](https://github.com/d3/d3-hierarchy/blob/master/README.md#partition_size) - set the layout size. -* [*partition*.round](https://github.com/d3/d3-hierarchy/blob/master/README.md#partition_round) - set whether the output coordinates are rounded. -* [*partition*.padding](https://github.com/d3/d3-hierarchy/blob/master/README.md#partition_padding) - set the padding. -* [d3.pack](https://github.com/d3/d3-hierarchy/blob/master/README.md#pack) - create a new circle-packing layout. -* [*pack*](https://github.com/d3/d3-hierarchy/blob/master/README.md#_pack) - layout the specified hierarchy using circle-packing. -* [*pack*.radius](https://github.com/d3/d3-hierarchy/blob/master/README.md#pack_radius) - set the radius accessor. -* [*pack*.size](https://github.com/d3/d3-hierarchy/blob/master/README.md#pack_size) - set the layout size. -* [*pack*.padding](https://github.com/d3/d3-hierarchy/blob/master/README.md#pack_padding) - set the padding. -* [d3.packSiblings](https://github.com/d3/d3-hierarchy/blob/master/README.md#packSiblings) - pack the specified array of circles. -* [d3.packEnclose](https://github.com/d3/d3-hierarchy/blob/master/README.md#packEnclose) - enclose the specified array of circles. - -## [Interpolators (d3-interpolate)](https://github.com/d3/d3-interpolate) - -Interpolate numbers, colors, strings, arrays, objects, whatever! - -* [d3.interpolate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate) - interpolate arbitrary values. -* [d3.interpolateArray](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateArray) - interpolate arrays of arbitrary values. -* [d3.interpolateDate](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateDate) - interpolate dates. -* [d3.interpolateNumber](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateNumber) - interpolate numbers. -* [d3.interpolateObject](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateObject) - interpolate arbitrary objects. -* [d3.interpolateRound](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRound) - interpolate integers. -* [d3.interpolateString](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateString) - interpolate strings with embedded numbers. -* [d3.interpolateTransformCss](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateTransformCss) - interpolate 2D CSS transforms. -* [d3.interpolateTransformSvg](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateTransformSvg) - interpolate 2D SVG transforms. -* [d3.interpolateZoom](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateZoom) - zoom and pan between two views. -* [d3.interpolateRgb](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRgb) - interpolate RGB colors. -* [d3.interpolateRgbBasis](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRgbBasis) - generate a B-spline through a set of colors. -* [d3.interpolateRgbBasisClosed](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateRgbBasisClosed) - generate a closed B-spline through a set of colors. -* [d3.interpolateHsl](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateHsl) - interpolate HSL colors. -* [d3.interpolateHslLong](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateHslLong) - interpolate HSL colors, the long way. -* [d3.interpolateLab](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateLab) - interpolate Lab colors. -* [d3.interpolateHcl](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateHcl) - interpolate HCL colors. -* [d3.interpolateHclLong](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateHclLong) - interpolate HCL colors, the long way. -* [d3.interpolateCubehelix](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateCubehelix) - interpolate Cubehelix colors. -* [d3.interpolateCubehelixLong](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateCubehelixLong) - interpolate Cubehelix colors, the long way. -* [*interpolate*.gamma](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolate_gamma) - apply gamma correction during interpolation. -* [d3.interpolateBasis](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateBasis) - generate a B-spline through a set of values. -* [d3.interpolateBasisClosed](https://github.com/d3/d3-interpolate/blob/master/README.md#interpolateBasisClosed) - generate a closed B-spline through a set of values. -* [d3.piecewise](https://github.com/d3/d3-interpolate/blob/master/README.md#piecewise) - generate a piecewise linear interpolator from a set of values. -* [d3.quantize](https://github.com/d3/d3-interpolate/blob/master/README.md#quantize) - generate uniformly-spaced samples from an interpolator. - -## [Paths (d3-path)](https://github.com/d3/d3-path) - -Serialize Canvas path commands to SVG. - -* [d3.path](https://github.com/d3/d3-path/blob/master/README.md#path) - create a new path serializer. -* [*path*.moveTo](https://github.com/d3/d3-path/blob/master/README.md#path_moveTo) - move to the given point. -* [*path*.closePath](https://github.com/d3/d3-path/blob/master/README.md#path_closePath) - close the current subpath. -* [*path*.lineTo](https://github.com/d3/d3-path/blob/master/README.md#path_lineTo) - draw a straight line segment. -* [*path*.quadraticCurveTo](https://github.com/d3/d3-path/blob/master/README.md#path_quadraticCurveTo) - draw a quadratic Bézier segment. -* [*path*.bezierCurveTo](https://github.com/d3/d3-path/blob/master/README.md#path_bezierCurveTo) - draw a cubic Bézier segment. -* [*path*.arcTo](https://github.com/d3/d3-path/blob/master/README.md#path_arcTo) - draw a circular arc segment. -* [*path*.arc](https://github.com/d3/d3-path/blob/master/README.md#path_arc) - draw a circular arc segment. -* [*path*.rect](https://github.com/d3/d3-path/blob/master/README.md#path_rect) - draw a rectangle. -* [*path*.toString](https://github.com/d3/d3-path/blob/master/README.md#path_toString) - serialize to an SVG path data string. - -## [Polygons (d3-polygon)](https://github.com/d3/d3-polygon) - -Geometric operations for two-dimensional polygons. - -* [d3.polygonArea](https://github.com/d3/d3-polygon/blob/master/README.md#polygonArea) - compute the area of the given polygon. -* [d3.polygonCentroid](https://github.com/d3/d3-polygon/blob/master/README.md#polygonCentroid) - compute the centroid of the given polygon. -* [d3.polygonHull](https://github.com/d3/d3-polygon/blob/master/README.md#polygonHull) - compute the convex hull of the given points. -* [d3.polygonContains](https://github.com/d3/d3-polygon/blob/master/README.md#polygonContains) - test whether a point is inside a polygon. -* [d3.polygonLength](https://github.com/d3/d3-polygon/blob/master/README.md#polygonLength) - compute the length of the given polygon’s perimeter. - -## [Quadtrees (d3-quadtree)](https://github.com/d3/d3-quadtree) - -Two-dimensional recursive spatial subdivision. - -* [d3.quadtree](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree) - create a new, empty quadtree. -* [*quadtree*.x](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_x) - set the *x* accessor. -* [*quadtree*.y](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_y) - set the *y* accessor. -* [*quadtree*.add](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_add) - add a datum to a quadtree. -* [*quadtree*.addAll](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_addAll) - add an array of data to a quadtree. -* [*quadtree*.remove](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_remove) - remove a datum from a quadtree. -* [*quadtree*.removeAll](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_removeAll) - remove an array of data from a quadtree. -* [*quadtree*.copy](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_copy) - create a copy of a quadtree. -* [*quadtree*.root](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_root) - get the quadtree’s root node. -* [*quadtree*.data](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_data) - retrieve all data from the quadtree. -* [*quadtree*.size](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_size) - count the number of data in the quadtree. -* [*quadtree*.find](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_find) - quickly find the closest datum in a quadtree. -* [*quadtree*.visit](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_visit) - selectively visit nodes in a quadtree. -* [*quadtree*.visitAfter](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_visitAfter) - visit all nodes in a quadtree. -* [*quadtree*.cover](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_cover) - extend the quadtree to cover a point. -* [*quadtree*.extent](https://github.com/d3/d3-quadtree/blob/master/README.md#quadtree_extent) - extend the quadtree to cover an extent. - -## [Random Numbers (d3-random)](https://github.com/d3/d3-random) - -Generate random numbers from various distributions. - -* [d3.randomUniform](https://github.com/d3/d3-random/blob/master/README.md#randomUniform) - from a uniform distribution. -* [d3.randomNormal](https://github.com/d3/d3-random/blob/master/README.md#randomNormal) - from a normal distribution. -* [d3.randomLogNormal](https://github.com/d3/d3-random/blob/master/README.md#randomLogNormal) - from a log-normal distribution. -* [d3.randomBates](https://github.com/d3/d3-random/blob/master/README.md#randomBates) - from a Bates distribution. -* [d3.randomIrwinHall](https://github.com/d3/d3-random/blob/master/README.md#randomIrwinHall) - from an Irwin–Hall distribution. -* [d3.randomExponential](https://github.com/d3/d3-random/blob/master/README.md#randomExponential) - from an exponential distribution. -* [*random*.source](https://github.com/d3/d3-random/blob/master/README.md#random_source) - set the source of randomness. - -## [Scales (d3-scale)](https://github.com/d3/d3-scale) - -Encodings that map abstract data to visual representation. - -### [Continuous Scales](https://github.com/d3/d3-scale/blob/master/README.md#continuous-scales) - -Map a continuous, quantitative domain to a continuous range. - -* [*continuous*](https://github.com/d3/d3-scale/blob/master/README.md#_continuous) - compute the range value corresponding to a given domain value. -* [*continuous*.invert](https://github.com/d3/d3-scale/blob/master/README.md#continuous_invert) - compute the domain value corresponding to a given range value. -* [*continuous*.domain](https://github.com/d3/d3-scale/blob/master/README.md#continuous_domain) - set the input domain. -* [*continuous*.range](https://github.com/d3/d3-scale/blob/master/README.md#continuous_range) - set the output range. -* [*continuous*.rangeRound](https://github.com/d3/d3-scale/blob/master/README.md#continuous_rangeRound) - set the output range and enable rounding. -* [*continuous*.clamp](https://github.com/d3/d3-scale/blob/master/README.md#continuous_clamp) - enable clamping to the domain or range. -* [*continuous*.interpolate](https://github.com/d3/d3-scale/blob/master/README.md#continuous_interpolate) - set the output interpolator. -* [*continuous*.ticks](https://github.com/d3/d3-scale/blob/master/README.md#continuous_ticks) - compute representative values from the domain. -* [*continuous*.tickFormat](https://github.com/d3/d3-scale/blob/master/README.md#continuous_tickFormat) - format ticks for human consumption. -* [*continuous*.nice](https://github.com/d3/d3-scale/blob/master/README.md#continuous_nice) - extend the domain to nice round numbers. -* [*continuous*.copy](https://github.com/d3/d3-scale/blob/master/README.md#continuous_copy) - create a copy of this scale. -* [d3.scaleLinear](https://github.com/d3/d3-scale/blob/master/README.md#scaleLinear) - create a quantitative linear scale. -* [d3.scalePow](https://github.com/d3/d3-scale/blob/master/README.md#scalePow) - create a quantitative power scale. -* [*pow*](https://github.com/d3/d3-scale/blob/master/README.md#_pow) - compute the range value corresponding to a given domain value. -* [*pow*.invert](https://github.com/d3/d3-scale/blob/master/README.md#pow_invert) - compute the domain value corresponding to a given range value. -* [*pow*.exponent](https://github.com/d3/d3-scale/blob/master/README.md#pow_exponent) - set the power exponent. -* [*pow*.domain](https://github.com/d3/d3-scale/blob/master/README.md#pow_domain) - set the input domain. -* [*pow*.range](https://github.com/d3/d3-scale/blob/master/README.md#pow_range) - set the output range. -* [*pow*.rangeRound](https://github.com/d3/d3-scale/blob/master/README.md#pow_rangeRound) - set the output range and enable rounding. -* [*pow*.clamp](https://github.com/d3/d3-scale/blob/master/README.md#pow_clamp) - enable clamping to the domain or range. -* [*pow*.interpolate](https://github.com/d3/d3-scale/blob/master/README.md#pow_interpolate) - set the output interpolator. -* [*pow*.ticks](https://github.com/d3/d3-scale/blob/master/README.md#pow_ticks) - compute representative values from the domain. -* [*pow*.tickFormat](https://github.com/d3/d3-scale/blob/master/README.md#pow_tickFormat) - format ticks for human consumption. -* [*pow*.nice](https://github.com/d3/d3-scale/blob/master/README.md#pow_nice) - extend the domain to nice round numbers. -* [*pow*.copy](https://github.com/d3/d3-scale/blob/master/README.md#pow_copy) - create a copy of this scale. -* [d3.scaleSqrt](https://github.com/d3/d3-scale/blob/master/README.md#scaleSqrt) - create a quantitative power scale with exponent 0.5. -* [d3.scaleLog](https://github.com/d3/d3-scale/blob/master/README.md#scaleLog) - create a quantitative logarithmic scale. -* [*log*](https://github.com/d3/d3-scale/blob/master/README.md#_log) - compute the range value corresponding to a given domain value. -* [*log*.invert](https://github.com/d3/d3-scale/blob/master/README.md#log_invert) - compute the domain value corresponding to a given range value. -* [*log*.base](https://github.com/d3/d3-scale/blob/master/README.md#log_base) - set the logarithm base. -* [*log*.domain](https://github.com/d3/d3-scale/blob/master/README.md#log_domain) - set the input domain. -* [*log*.range](https://github.com/d3/d3-scale/blob/master/README.md#log_range) - set the output range. -* [*log*.rangeRound](https://github.com/d3/d3-scale/blob/master/README.md#log_rangeRound) - set the output range and enable rounding. -* [*log*.clamp](https://github.com/d3/d3-scale/blob/master/README.md#log_clamp) - enable clamping to the domain or range. -* [*log*.interpolate](https://github.com/d3/d3-scale/blob/master/README.md#log_interpolate) - set the output interpolator. -* [*log*.ticks](https://github.com/d3/d3-scale/blob/master/README.md#log_ticks) - compute representative values from the domain. -* [*log*.tickFormat](https://github.com/d3/d3-scale/blob/master/README.md#log_tickFormat) - format ticks for human consumption. -* [*log*.nice](https://github.com/d3/d3-scale/blob/master/README.md#log_nice) - extend the domain to nice round numbers. -* [*log*.copy](https://github.com/d3/d3-scale/blob/master/README.md#log_copy) - create a copy of this scale. -* [d3.scaleIdentity](https://github.com/d3/d3-scale/blob/master/README.md#identity) - create a quantitative identity scale. -* [d3.scaleTime](https://github.com/d3/d3-scale/blob/master/README.md#scaleTime) - create a linear scale for time. -* [*time*](https://github.com/d3/d3-scale/blob/master/README.md#_time) - compute the range value corresponding to a given domain value. -* [*time*.invert](https://github.com/d3/d3-scale/blob/master/README.md#time_invert) - compute the domain value corresponding to a given range value. -* [*time*.domain](https://github.com/d3/d3-scale/blob/master/README.md#time_domain) - set the input domain. -* [*time*.range](https://github.com/d3/d3-scale/blob/master/README.md#time_range) - set the output range. -* [*time*.rangeRound](https://github.com/d3/d3-scale/blob/master/README.md#time_rangeRound) - set the output range and enable rounding. -* [*time*.clamp](https://github.com/d3/d3-scale/blob/master/README.md#time_clamp) - enable clamping to the domain or range. -* [*time*.interpolate](https://github.com/d3/d3-scale/blob/master/README.md#time_interpolate) - set the output interpolator. -* [*time*.ticks](https://github.com/d3/d3-scale/blob/master/README.md#time_ticks) - compute representative values from the domain. -* [*time*.tickFormat](https://github.com/d3/d3-scale/blob/master/README.md#time_tickFormat) - format ticks for human consumption. -* [*time*.nice](https://github.com/d3/d3-scale/blob/master/README.md#time_nice) - extend the domain to nice round times. -* [*time*.copy](https://github.com/d3/d3-scale/blob/master/README.md#time_copy) - create a copy of this scale. -* [d3.scaleUtc](https://github.com/d3/d3-scale/blob/master/README.md#scaleUtc) - create a linear scale for UTC. - -### [Sequential Scales](https://github.com/d3/d3-scale/blob/master/README.md#sequential-scales) - -Map a continuous, quantitative domain to a continuous, fixed interpolator. - -* [d3.scaleSequential](https://github.com/d3/d3-scale/blob/master/README.md#scaleSequential) - create a sequential scale. -* [*sequential*.interpolator](https://github.com/d3/d3-scale/blob/master/README.md#sequential_interpolator) - set the scale’s output interpolator. - -### [Diverging Scales](https://github.com/d3/d3-scale/blob/master/README.md#diverging-scales) - -Map a continuous, quantitative domain to a continuous, fixed interpolator. - -* [d3.scaleDiverging](https://github.com/d3/d3-scale/blob/master/README.md#scaleDiverging) - create a diverging scale. -* [*diverging*.interpolator](https://github.com/d3/d3-scale/blob/master/README.md#diverging_interpolator) - set the scale’s output interpolator. - -### [Quantize Scales](https://github.com/d3/d3-scale/blob/master/README.md#quantize-scales) - -Map a continuous, quantitative domain to a discrete range. - -* [d3.scaleQuantize](https://github.com/d3/d3-scale/blob/master/README.md#scaleQuantize) - create a uniform quantizing linear scale. -* [*quantize*](https://github.com/d3/d3-scale/blob/master/README.md#_quantize) - compute the range value corresponding to a given domain value. -* [*quantize*.invertExtent](https://github.com/d3/d3-scale/blob/master/README.md#quantize_invertExtent) - compute the domain values corresponding to a given range value. -* [*quantize*.domain](https://github.com/d3/d3-scale/blob/master/README.md#quantize_domain) - set the input domain. -* [*quantize*.range](https://github.com/d3/d3-scale/blob/master/README.md#quantize_range) - set the output range. -* [*quantize*.nice](https://github.com/d3/d3-scale/blob/master/README.md#quantize_nice) - extend the domain to nice round numbers. -* [*quantize*.ticks](https://github.com/d3/d3-scale/blob/master/README.md#quantize_ticks) - compute representative values from the domain. -* [*quantize*.tickFormat](https://github.com/d3/d3-scale/blob/master/README.md#quantize_tickFormat) - format ticks for human consumption. -* [*quantize*.copy](https://github.com/d3/d3-scale/blob/master/README.md#quantize_copy) - create a copy of this scale. -* [d3.scaleQuantile](https://github.com/d3/d3-scale/blob/master/README.md#scaleQuantile) - create a quantile quantizing linear scale. -* [*quantile*](https://github.com/d3/d3-scale/blob/master/README.md#_quantile) - compute the range value corresponding to a given domain value. -* [*quantile*.invertExtent](https://github.com/d3/d3-scale/blob/master/README.md#quantile_invertExtent) - compute the domain values corresponding to a given range value. -* [*quantile*.domain](https://github.com/d3/d3-scale/blob/master/README.md#quantile_domain) - set the input domain. -* [*quantile*.range](https://github.com/d3/d3-scale/blob/master/README.md#quantile_range) - set the output range. -* [*quantile*.quantiles](https://github.com/d3/d3-scale/blob/master/README.md#quantile_quantiles) - get the quantile thresholds. -* [*quantile*.copy](https://github.com/d3/d3-scale/blob/master/README.md#quantile_copy) - create a copy of this scale. -* [d3.scaleThreshold](https://github.com/d3/d3-scale/blob/master/README.md#scaleThreshold) - create an arbitrary quantizing linear scale. -* [*threshold*](https://github.com/d3/d3-scale/blob/master/README.md#_threshold) - compute the range value corresponding to a given domain value. -* [*threshold*.invertExtent](https://github.com/d3/d3-scale/blob/master/README.md#threshold_invertExtent) - compute the domain values corresponding to a given range value. -* [*threshold*.domain](https://github.com/d3/d3-scale/blob/master/README.md#threshold_domain) - set the input domain. -* [*threshold*.range](https://github.com/d3/d3-scale/blob/master/README.md#threshold_range) - set the output range. -* [*threshold*.copy](https://github.com/d3/d3-scale/blob/master/README.md#threshold_copy) - create a copy of this scale. - -### [Ordinal Scales](https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales) - -Map a discrete domain to a discrete range. - -* [d3.scaleOrdinal](https://github.com/d3/d3-scale/blob/master/README.md#scaleOrdinal) - create an ordinal scale. -* [*ordinal*](https://github.com/d3/d3-scale/blob/master/README.md#_ordinal) - compute the range value corresponding to a given domain value. -* [*ordinal*.domain](https://github.com/d3/d3-scale/blob/master/README.md#ordinal_domain) - set the input domain. -* [*ordinal*.range](https://github.com/d3/d3-scale/blob/master/README.md#ordinal_range) - set the output range. -* [*ordinal*.unknown](https://github.com/d3/d3-scale/blob/master/README.md#ordinal_unknown) - set the output value for unknown inputs. -* [*ordinal*.copy](https://github.com/d3/d3-scale/blob/master/README.md#ordinal_copy) - create a copy of this scale. -* [d3.scaleImplicit](https://github.com/d3/d3-scale/blob/master/README.md#scaleImplicit) - a special unknown value for implicit domains. -* [d3.scaleBand](https://github.com/d3/d3-scale/blob/master/README.md#scaleBand) - create an ordinal band scale. -* [*band*](https://github.com/d3/d3-scale/blob/master/README.md#_band) - compute the band start corresponding to a given domain value. -* [*band*.domain](https://github.com/d3/d3-scale/blob/master/README.md#band_domain) - set the input domain. -* [*band*.range](https://github.com/d3/d3-scale/blob/master/README.md#band_range) - set the output range. -* [*band*.rangeRound](https://github.com/d3/d3-scale/blob/master/README.md#band_rangeRound) - set the output range and enable rounding. -* [*band*.round](https://github.com/d3/d3-scale/blob/master/README.md#band_round) - enable rounding. -* [*band*.paddingInner](https://github.com/d3/d3-scale/blob/master/README.md#band_paddingInner) - set padding between bands. -* [*band*.paddingOuter](https://github.com/d3/d3-scale/blob/master/README.md#band_paddingOuter) - set padding outside the first and last bands. -* [*band*.padding](https://github.com/d3/d3-scale/blob/master/README.md#band_padding) - set padding outside and between bands. -* [*band*.align](https://github.com/d3/d3-scale/blob/master/README.md#band_align) - set band alignment, if there is extra space. -* [*band*.bandwidth](https://github.com/d3/d3-scale/blob/master/README.md#band_bandwidth) - get the width of each band. -* [*band*.step](https://github.com/d3/d3-scale/blob/master/README.md#band_step) - get the distance between the starts of adjacent bands. -* [*band*.copy](https://github.com/d3/d3-scale/blob/master/README.md#band_copy) - create a copy of this scale. -* [d3.scalePoint](https://github.com/d3/d3-scale/blob/master/README.md#scalePoint) - create an ordinal point scale. -* [*point*](https://github.com/d3/d3-scale/blob/master/README.md#_point) - compute the point corresponding to a given domain value. -* [*point*.domain](https://github.com/d3/d3-scale/blob/master/README.md#point_domain) - set the input domain. -* [*point*.range](https://github.com/d3/d3-scale/blob/master/README.md#point_range) - set the output range. -* [*point*.rangeRound](https://github.com/d3/d3-scale/blob/master/README.md#point_rangeRound) - set the output range and enable rounding. -* [*point*.round](https://github.com/d3/d3-scale/blob/master/README.md#point_round) - enable rounding. -* [*point*.padding](https://github.com/d3/d3-scale/blob/master/README.md#point_padding) - set padding outside the first and last point. -* [*point*.align](https://github.com/d3/d3-scale/blob/master/README.md#point_align) - set point alignment, if there is extra space. -* [*point*.bandwidth](https://github.com/d3/d3-scale/blob/master/README.md#point_bandwidth) - returns zero. -* [*point*.step](https://github.com/d3/d3-scale/blob/master/README.md#point_step) - get the distance between the starts of adjacent points. -* [*point*.copy](https://github.com/d3/d3-scale/blob/master/README.md#point_copy) - create a copy of this scale. - -## [Selections (d3-selection)](https://github.com/d3/d3-selection) - -Transform the DOM by selecting elements and joining to data. - -### [Selecting Elements](https://github.com/d3/d3-selection/blob/master/README.md#selecting-elements) - -* [d3.selection](https://github.com/d3/d3-selection/blob/master/README.md#selection) - select the root document element. -* [d3.select](https://github.com/d3/d3-selection/blob/master/README.md#select) - select an element from the document. -* [d3.selectAll](https://github.com/d3/d3-selection/blob/master/README.md#selectAll) - select multiple elements from the document. -* [*selection*.select](https://github.com/d3/d3-selection/blob/master/README.md#selection_select) - select a descendant element for each selected element. -* [*selection*.selectAll](https://github.com/d3/d3-selection/blob/master/README.md#selection_selectAll) - select multiple descendants for each selected element. -* [*selection*.filter](https://github.com/d3/d3-selection/blob/master/README.md#selection_filter) - filter elements based on data. -* [*selection*.merge](https://github.com/d3/d3-selection/blob/master/README.md#selection_merge) - merge this selection with another. -* [d3.matcher](https://github.com/d3/d3-selection/blob/master/README.md#matcher) - test whether an element matches a selector. -* [d3.selector](https://github.com/d3/d3-selection/blob/master/README.md#selector) - select an element. -* [d3.selectorAll](https://github.com/d3/d3-selection/blob/master/README.md#selectorAll) - select elements. -* [d3.window](https://github.com/d3/d3-selection/blob/master/README.md#window) - get a node’s owner window. -* [d3.style](https://github.com/d3/d3-selection/blob/master/README.md#style) - get a node’s current style value. - -### [Modifying Elements](https://github.com/d3/d3-selection/blob/master/README.md#modifying-elements) - -* [*selection*.attr](https://github.com/d3/d3-selection/blob/master/README.md#selection_attr) - get or set an attribute. -* [*selection*.classed](https://github.com/d3/d3-selection/blob/master/README.md#selection_classed) - get, add or remove CSS classes. -* [*selection*.style](https://github.com/d3/d3-selection/blob/master/README.md#selection_style) - get or set a style property. -* [*selection*.property](https://github.com/d3/d3-selection/blob/master/README.md#selection_property) - get or set a (raw) property. -* [*selection*.text](https://github.com/d3/d3-selection/blob/master/README.md#selection_text) - get or set the text content. -* [*selection*.html](https://github.com/d3/d3-selection/blob/master/README.md#selection_html) - get or set the inner HTML. -* [*selection*.append](https://github.com/d3/d3-selection/blob/master/README.md#selection_append) - create, append and select new elements. -* [*selection*.insert](https://github.com/d3/d3-selection/blob/master/README.md#selection_insert) - create, insert and select new elements. -* [*selection*.remove](https://github.com/d3/d3-selection/blob/master/README.md#selection_remove) - remove elements from the document. -* [*selection*.clone](https://github.com/d3/d3-selection/blob/master/README.md#selection_clone) - insert clones of selected elements. -* [*selection*.sort](https://github.com/d3/d3-selection/blob/master/README.md#selection_sort) - sort elements in the document based on data. -* [*selection*.order](https://github.com/d3/d3-selection/blob/master/README.md#selection_order) - reorders elements in the document to match the selection. -* [*selection*.raise](https://github.com/d3/d3-selection/blob/master/README.md#selection_raise) - reorders each element as the last child of its parent. -* [*selection*.lower](https://github.com/d3/d3-selection/blob/master/README.md#selection_lower) - reorders each element as the first child of its parent. -* [d3.create](https://github.com/d3/d3-selection/blob/master/README.md#create) - create and select a detached element. -* [d3.creator](https://github.com/d3/d3-selection/blob/master/README.md#creator) - create an element by name. - -### [Joining Data](https://github.com/d3/d3-selection/blob/master/README.md#joining-data) - -* [*selection*.data](https://github.com/d3/d3-selection/blob/master/README.md#selection_data) - join elements to data. -* [*selection*.enter](https://github.com/d3/d3-selection/blob/master/README.md#selection_enter) - get the enter selection (data missing elements). -* [*selection*.exit](https://github.com/d3/d3-selection/blob/master/README.md#selection_exit) - get the exit selection (elements missing data). -* [*selection*.datum](https://github.com/d3/d3-selection/blob/master/README.md#selection_datum) - get or set element data (without joining). - -### [Handling Events](https://github.com/d3/d3-selection/blob/master/README.md#handling-events) - -* [*selection*.on](https://github.com/d3/d3-selection/blob/master/README.md#selection_on) - add or remove event listeners. -* [*selection*.dispatch](https://github.com/d3/d3-selection/blob/master/README.md#selection_dispatch) - dispatch a custom event. -* [d3.event](https://github.com/d3/d3-selection/blob/master/README.md#event) - the current user event, during interaction. -* [d3.customEvent](https://github.com/d3/d3-selection/blob/master/README.md#customEvent) - temporarily define a custom event. -* [d3.mouse](https://github.com/d3/d3-selection/blob/master/README.md#mouse) - get the mouse position relative to a given container. -* [d3.touch](https://github.com/d3/d3-selection/blob/master/README.md#touch) - get a touch position relative to a given container. -* [d3.touches](https://github.com/d3/d3-selection/blob/master/README.md#touches) - get the touch positions relative to a given container. -* [d3.clientPoint](https://github.com/d3/d3-selection/blob/master/README.md#clientPoint) - get a position relative to a given container. - -### [Control Flow](https://github.com/d3/d3-selection/blob/master/README.md#control-flow) - -* [*selection*.each](https://github.com/d3/d3-selection/blob/master/README.md#selection_each) - call a function for each element. -* [*selection*.call](https://github.com/d3/d3-selection/blob/master/README.md#selection_call) - call a function with this selection. -* [*selection*.empty](https://github.com/d3/d3-selection/blob/master/README.md#selection_empty) - returns true if this selection is empty. -* [*selection*.nodes](https://github.com/d3/d3-selection/blob/master/README.md#selection_nodes) - returns an array of all selected elements. -* [*selection*.node](https://github.com/d3/d3-selection/blob/master/README.md#selection_node) - returns the first (non-null) element. -* [*selection*.size](https://github.com/d3/d3-selection/blob/master/README.md#selection_size) - returns the count of elements. - -### [Local Variables](https://github.com/d3/d3-selection/blob/master/README.md#local-variables) - -* [d3.local](https://github.com/d3/d3-selection/blob/master/README.md#local) - declares a new local variable. -* [*local*.set](https://github.com/d3/d3-selection/blob/master/README.md#local_set) - set a local variable’s value. -* [*local*.get](https://github.com/d3/d3-selection/blob/master/README.md#local_get) - get a local variable’s value. -* [*local*.remove](https://github.com/d3/d3-selection/blob/master/README.md#local_remove) - delete a local variable. -* [*local*.toString](https://github.com/d3/d3-selection/blob/master/README.md#local_toString) - get the property identifier of a local variable. - -### [Namespaces](https://github.com/d3/d3-selection/blob/master/README.md#namespaces) - -* [d3.namespace](https://github.com/d3/d3-selection/blob/master/README.md#namespace) - qualify a prefixed XML name, such as “xlink:href”. -* [d3.namespaces](https://github.com/d3/d3-selection/blob/master/README.md#namespaces) - the built-in XML namespaces. - -## [Shapes (d3-shape)](https://github.com/d3/d3-shape) - -Graphical primitives for visualization. - -### [Arcs](https://github.com/d3/d3-shape/blob/master/README.md#arcs) - -Circular or annular sectors, as in a pie or donut chart. - -* [d3.arc](https://github.com/d3/d3-shape/blob/master/README.md#arc) - create a new arc generator. -* [*arc*](https://github.com/d3/d3-shape/blob/master/README.md#_arc) - generate an arc for the given datum. -* [*arc*.centroid](https://github.com/d3/d3-shape/blob/master/README.md#arc_centroid) - compute an arc’s midpoint. -* [*arc*.innerRadius](https://github.com/d3/d3-shape/blob/master/README.md#arc_innerRadius) - set the inner radius. -* [*arc*.outerRadius](https://github.com/d3/d3-shape/blob/master/README.md#arc_outerRadius) - set the outer radius. -* [*arc*.cornerRadius](https://github.com/d3/d3-shape/blob/master/README.md#arc_cornerRadius) - set the corner radius, for rounded corners. -* [*arc*.startAngle](https://github.com/d3/d3-shape/blob/master/README.md#arc_startAngle) - set the start angle. -* [*arc*.endAngle](https://github.com/d3/d3-shape/blob/master/README.md#arc_endAngle) - set the end angle. -* [*arc*.padAngle](https://github.com/d3/d3-shape/blob/master/README.md#arc_padAngle) - set the angle between adjacent arcs, for padded arcs. -* [*arc*.padRadius](https://github.com/d3/d3-shape/blob/master/README.md#arc_padRadius) - set the radius at which to linearize padding. -* [*arc*.context](https://github.com/d3/d3-shape/blob/master/README.md#arc_context) - set the rendering context. - -### [Pies](https://github.com/d3/d3-shape/blob/master/README.md#pies) - -Compute the necessary angles to represent a tabular dataset as a pie or donut chart. - -* [d3.pie](https://github.com/d3/d3-shape/blob/master/README.md#pie) - create a new pie generator. -* [*pie*](https://github.com/d3/d3-shape/blob/master/README.md#_pie) - compute the arc angles for the given dataset. -* [*pie*.value](https://github.com/d3/d3-shape/blob/master/README.md#pie_value) - set the value accessor. -* [*pie*.sort](https://github.com/d3/d3-shape/blob/master/README.md#pie_sort) - set the sort order comparator. -* [*pie*.sortValues](https://github.com/d3/d3-shape/blob/master/README.md#pie_sortValues) - set the sort order comparator. -* [*pie*.startAngle](https://github.com/d3/d3-shape/blob/master/README.md#pie_startAngle) - set the overall start angle. -* [*pie*.endAngle](https://github.com/d3/d3-shape/blob/master/README.md#pie_endAngle) - set the overall end angle. -* [*pie*.padAngle](https://github.com/d3/d3-shape/blob/master/README.md#pie_padAngle) - set the pad angle between adjacent arcs. - -### [Lines](https://github.com/d3/d3-shape/blob/master/README.md#lines) - -A spline or polyline, as in a line chart. - -* [d3.line](https://github.com/d3/d3-shape/blob/master/README.md#line) - create a new line generator. -* [*line*](https://github.com/d3/d3-shape/blob/master/README.md#_line) - generate a line for the given dataset. -* [*line*.x](https://github.com/d3/d3-shape/blob/master/README.md#line_x) - set the *x* accessor. -* [*line*.y](https://github.com/d3/d3-shape/blob/master/README.md#line_y) - set the *y* accessor. -* [*line*.defined](https://github.com/d3/d3-shape/blob/master/README.md#line_defined) - set the defined accessor. -* [*line*.curve](https://github.com/d3/d3-shape/blob/master/README.md#line_curve) - set the curve interpolator. -* [*line*.context](https://github.com/d3/d3-shape/blob/master/README.md#line_context) - set the rendering context. -* [d3.radialLine](https://github.com/d3/d3-shape/blob/master/README.md#radialLine) - create a new radial line generator. -* [*radialLine*](https://github.com/d3/d3-shape/blob/master/README.md#_radialLine) - generate a line for the given dataset. -* [*radialLine*.angle](https://github.com/d3/d3-shape/blob/master/README.md#radialLine_angle) - set the angle accessor. -* [*radialLine*.radius](https://github.com/d3/d3-shape/blob/master/README.md#radialLine_radius) - set the radius accessor. -* [*radialLine*.defined](https://github.com/d3/d3-shape/blob/master/README.md#radialLine_defined) - set the defined accessor. -* [*radialLine*.curve](https://github.com/d3/d3-shape/blob/master/README.md#radialLine_curve) - set the curve interpolator. -* [*radialLine*.context](https://github.com/d3/d3-shape/blob/master/README.md#radialLine_context) - set the rendering context. - -### [Areas](https://github.com/d3/d3-shape/blob/master/README.md#areas) - -An area, defined by a bounding topline and baseline, as in an area chart. - -* [d3.area](https://github.com/d3/d3-shape/blob/master/README.md#area) - create a new area generator. -* [*area*](https://github.com/d3/d3-shape/blob/master/README.md#_area) - generate an area for the given dataset. -* [*area*.x](https://github.com/d3/d3-shape/blob/master/README.md#area_x) - set the *x0* and *x1* accessors. -* [*area*.x0](https://github.com/d3/d3-shape/blob/master/README.md#area_x0) - set the baseline *x* accessor. -* [*area*.x1](https://github.com/d3/d3-shape/blob/master/README.md#area_x1) - set the topline *x* accessor. -* [*area*.y](https://github.com/d3/d3-shape/blob/master/README.md#area_y) - set the *y0* and *y1* accessors. -* [*area*.y0](https://github.com/d3/d3-shape/blob/master/README.md#area_y0) - set the baseline *y* accessor. -* [*area*.y1](https://github.com/d3/d3-shape/blob/master/README.md#area_y1) - set the topline *y* accessor. -* [*area*.defined](https://github.com/d3/d3-shape/blob/master/README.md#area_defined) - set the defined accessor. -* [*area*.curve](https://github.com/d3/d3-shape/blob/master/README.md#area_curve) - set the curve interpolator. -* [*area*.context](https://github.com/d3/d3-shape/blob/master/README.md#area_context) - set the rendering context. -* [*area*.lineX0](https://github.com/d3/d3-shape/blob/master/README.md#area_lineX0) - derive a line for the left edge of an area. -* [*area*.lineX1](https://github.com/d3/d3-shape/blob/master/README.md#area_lineX1) - derive a line for the right edge of an area. -* [*area*.lineY0](https://github.com/d3/d3-shape/blob/master/README.md#area_lineY0) - derive a line for the top edge of an area. -* [*area*.lineY1](https://github.com/d3/d3-shape/blob/master/README.md#area_lineY1) - derive a line for the bottom edge of an area. -* [d3.radialArea](https://github.com/d3/d3-shape/blob/master/README.md#radialArea) - create a new radial area generator. -* [*radialArea*](https://github.com/d3/d3-shape/blob/master/README.md#_radialArea) - generate an area for the given dataset. -* [*radialArea*.angle](https://github.com/d3/d3-shape/blob/master/README.md#radialArea_angle) - set the start and end angle accessors. -* [*radialArea*.startAngle](https://github.com/d3/d3-shape/blob/master/README.md#radialArea_startAngle) - set the start angle accessor. -* [*radialArea*.endAngle](https://github.com/d3/d3-shape/blob/master/README.md#radialArea_endAngle) - set the end angle accessor. -* [*radialArea*.radius](https://github.com/d3/d3-shape/blob/master/README.md#radialArea_radius) - set the inner and outer radius accessors. -* [*radialArea*.innerRadius](https://github.com/d3/d3-shape/blob/master/README.md#radialArea_innerRadius) - set the inner radius accessor. -* [*radialArea*.outerRadius](https://github.com/d3/d3-shape/blob/master/README.md#radialArea_outerRadius) - set the outer radius accessor. -* [*radialArea*.defined](https://github.com/d3/d3-shape/blob/master/README.md#radialArea_defined) - set the defined accessor. -* [*radialArea*.curve](https://github.com/d3/d3-shape/blob/master/README.md#radialArea_curve) - set the curve interpolator. -* [*radialArea*.context](https://github.com/d3/d3-shape/blob/master/README.md#radialArea_context) - set the rendering context. -* [*radialArea*.lineStartAngle](https://github.com/d3/d3-shape/blob/master/README.md#area_lineStartAngle) - derive a line for the start edge of an area. -* [*radialArea*.lineEndAngle](https://github.com/d3/d3-shape/blob/master/README.md#area_lineEndAngle) - derive a line for the end edge of an area. -* [*radialArea*.lineInnerRadius](https://github.com/d3/d3-shape/blob/master/README.md#area_lineInnerRadius) - derive a line for the inner edge of an area. -* [*radialArea*.lineOuterRadius](https://github.com/d3/d3-shape/blob/master/README.md#area_lineOuterRadius) - derive a line for the outer edge of an area. - -### [Curves](https://github.com/d3/d3-shape/blob/master/README.md#curves) - -Interpolate between points to produce a continuous shape. - -* [d3.curveBasis](https://github.com/d3/d3-shape/blob/master/README.md#curveBasis) - a cubic basis spline, repeating the end points. -* [d3.curveBasisClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveBasisClosed) - a closed cubic basis spline. -* [d3.curveBasisOpen](https://github.com/d3/d3-shape/blob/master/README.md#curveBasisOpen) - a cubic basis spline. -* [d3.curveBundle](https://github.com/d3/d3-shape/blob/master/README.md#curveBundle) - a straightened cubic basis spline. -* [*bundle*.beta](https://github.com/d3/d3-shape/blob/master/README.md#bundle_beta) - set the bundle tension *beta*. -* [d3.curveCardinal](https://github.com/d3/d3-shape/blob/master/README.md#curveCardinal) - a cubic cardinal spline, with one-sided difference at each end. -* [d3.curveCardinalClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveCardinalClosed) - a closed cubic cardinal spline. -* [d3.curveCardinalOpen](https://github.com/d3/d3-shape/blob/master/README.md#curveCardinalOpen) - a cubic cardinal spline. -* [*cardinal*.tension](https://github.com/d3/d3-shape/blob/master/README.md#cardinal_tension) - set the cardinal spline tension. -* [d3.curveCatmullRom](https://github.com/d3/d3-shape/blob/master/README.md#curveCatmullRom) - a cubic Catmull–Rom spline, with one-sided difference at each end. -* [d3.curveCatmullRomClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveCatmullRomClosed) - a closed cubic Catmull–Rom spline. -* [d3.curveCatmullRomOpen](https://github.com/d3/d3-shape/blob/master/README.md#curveCatmullRomOpen) - a cubic Catmull–Rom spline. -* [*catmullRom*.alpha](https://github.com/d3/d3-shape/blob/master/README.md#catmullRom_alpha) - set the Catmull–Rom parameter *alpha*. -* [d3.curveLinear](https://github.com/d3/d3-shape/blob/master/README.md#curveLinear) - a polyline. -* [d3.curveLinearClosed](https://github.com/d3/d3-shape/blob/master/README.md#curveLinearClosed) - a closed polyline. -* [d3.curveMonotoneX](https://github.com/d3/d3-shape/blob/master/README.md#curveMonotoneX) - a cubic spline that, given monotonicity in *x*, preserves it in *y*. -* [d3.curveMonotoneY](https://github.com/d3/d3-shape/blob/master/README.md#curveMonotoneY) - a cubic spline that, given monotonicity in *y*, preserves it in *x*. -* [d3.curveNatural](https://github.com/d3/d3-shape/blob/master/README.md#curveNatural) - a natural cubic spline. -* [d3.curveStep](https://github.com/d3/d3-shape/blob/master/README.md#curveStep) - a piecewise constant function. -* [d3.curveStepAfter](https://github.com/d3/d3-shape/blob/master/README.md#curveStepAfter) - a piecewise constant function. -* [d3.curveStepBefore](https://github.com/d3/d3-shape/blob/master/README.md#curveStepBefore) - a piecewise constant function. -* [*curve*.areaStart](https://github.com/d3/d3-shape/blob/master/README.md#curve_areaStart) - start a new area segment. -* [*curve*.areaEnd](https://github.com/d3/d3-shape/blob/master/README.md#curve_areaEnd) - end the current area segment. -* [*curve*.lineStart](https://github.com/d3/d3-shape/blob/master/README.md#curve_lineStart) - start a new line segment. -* [*curve*.lineEnd](https://github.com/d3/d3-shape/blob/master/README.md#curve_lineEnd) - end the current line segment. -* [*curve*.point](https://github.com/d3/d3-shape/blob/master/README.md#curve_point) - add a point to the current line segment. - -### [Links](https://github.com/d3/d3-shape/blob/master/README.md#links) - -A smooth cubic Bézier curve from a source to a target. - -* [d3.linkVertical](https://github.com/d3/d3-shape/blob/master/README.md#linkVertical) - create a new vertical link generator. -* [d3.linkHorizontal](https://github.com/d3/d3-shape/blob/master/README.md#linkHorizontal) - create a new horizontal link generator. -* [*link*](https://github.com/d3/d3-shape/blob/master/README.md#_link) - generate a link. -* [*link*.source](https://github.com/d3/d3-shape/blob/master/README.md#link_source) - set the source accessor. -* [*link*.target](https://github.com/d3/d3-shape/blob/master/README.md#link_target) - set the target accessor. -* [*link*.x](https://github.com/d3/d3-shape/blob/master/README.md#link_x) - set the point *x*-accessor. -* [*link*.y](https://github.com/d3/d3-shape/blob/master/README.md#link_y) - set the point *y*-accessor. -* [d3.linkRadial](https://github.com/d3/d3-shape/blob/master/README.md#linkRadial) - create a new radial link generator. -* [*radialLink*.angle](https://github.com/d3/d3-shape/blob/master/README.md#radialLink_angle) - set the point *angle* accessor. -* [*radialLink*.radius](https://github.com/d3/d3-shape/blob/master/README.md#radialLink_radius) - set the point *radius* accessor. - -### [Symbols](https://github.com/d3/d3-shape/blob/master/README.md#symbols) - -A categorical shape encoding, as in a scatterplot. - -* [d3.symbol](https://github.com/d3/d3-shape/blob/master/README.md#symbol) - create a new symbol generator. -* [*symbol*](https://github.com/d3/d3-shape/blob/master/README.md#_symbol) - generate a symbol for the given datum. -* [*symbol*.type](https://github.com/d3/d3-shape/blob/master/README.md#symbol_type) - set the symbol type. -* [*symbol*.size](https://github.com/d3/d3-shape/blob/master/README.md#symbol_size) - set the size of the symbol in square pixels. -* [*symbol*.context](https://github.com/d3/d3-shape/blob/master/README.md#symbol_context) - set the rendering context. -* [d3.symbols](https://github.com/d3/d3-shape/blob/master/README.md#symbols) - the array of built-in symbol types. -* [d3.symbolCircle](https://github.com/d3/d3-shape/blob/master/README.md#symbolCircle) - a circle. -* [d3.symbolCross](https://github.com/d3/d3-shape/blob/master/README.md#symbolCross) - a Greek cross with arms of equal length. -* [d3.symbolDiamond](https://github.com/d3/d3-shape/blob/master/README.md#symbolDiamond) - a rhombus. -* [d3.symbolSquare](https://github.com/d3/d3-shape/blob/master/README.md#symbolSquare) - a square. -* [d3.symbolStar](https://github.com/d3/d3-shape/blob/master/README.md#symbolStar) - a pentagonal star (pentagram). -* [d3.symbolTriangle](https://github.com/d3/d3-shape/blob/master/README.md#symbolTriangle) - an up-pointing triangle. -* [d3.symbolWye](https://github.com/d3/d3-shape/blob/master/README.md#symbolWye) - a Y shape. -* [*symbolType*.draw](https://github.com/d3/d3-shape/blob/master/README.md#symbolType_draw) - draw this symbol to the given context. - -### [Stacks](https://github.com/d3/d3-shape/blob/master/README.md#stacks) - -Stack shapes, placing one adjacent to another, as in a stacked bar chart. - -* [d3.stack](https://github.com/d3/d3-shape/blob/master/README.md#stack) - create a new stack generator. -* [*stack*](https://github.com/d3/d3-shape/blob/master/README.md#_stack) - generate a stack for the given dataset. -* [*stack*.keys](https://github.com/d3/d3-shape/blob/master/README.md#stack_keys) - set the keys accessor. -* [*stack*.value](https://github.com/d3/d3-shape/blob/master/README.md#stack_value) - set the value accessor. -* [*stack*.order](https://github.com/d3/d3-shape/blob/master/README.md#stack_order) - set the order accessor. -* [*stack*.offset](https://github.com/d3/d3-shape/blob/master/README.md#stack_offset) - set the offset accessor. -* [d3.stackOrderAscending](https://github.com/d3/d3-shape/blob/master/README.md#stackOrderAscending) - put the smallest series on bottom. -* [d3.stackOrderDescending](https://github.com/d3/d3-shape/blob/master/README.md#stackOrderDescending) - put the largest series on bottom. -* [d3.stackOrderInsideOut](https://github.com/d3/d3-shape/blob/master/README.md#stackOrderInsideOut) - put larger series in the middle. -* [d3.stackOrderNone](https://github.com/d3/d3-shape/blob/master/README.md#stackOrderNone) - use the given series order. -* [d3.stackOrderReverse](https://github.com/d3/d3-shape/blob/master/README.md#stackOrderReverse) - use the reverse of the given series order. -* [d3.stackOffsetExpand](https://github.com/d3/d3-shape/blob/master/README.md#stackOffsetExpand) - normalize the baseline to zero and topline to one. -* [d3.stackOffsetDiverging](https://github.com/d3/d3-shape/blob/master/README.md#stackOffsetDiverging) - positive above zero; negative below zero. -* [d3.stackOffsetNone](https://github.com/d3/d3-shape/blob/master/README.md#stackOffsetNone) - apply a zero baseline. -* [d3.stackOffsetSilhouette](https://github.com/d3/d3-shape/blob/master/README.md#stackOffsetSilhouette) - center the streamgraph around zero. -* [d3.stackOffsetWiggle](https://github.com/d3/d3-shape/blob/master/README.md#stackOffsetWiggle) - minimize streamgraph wiggling. - -## [Time Formats (d3-time-format)](https://github.com/d3/d3-time-format) - -Parse and format times, inspired by strptime and strftime. - -* [d3.timeFormat](https://github.com/d3/d3-time-format/blob/master/README.md#timeFormat) - alias for *locale*.format on the default locale. -* [d3.timeParse](https://github.com/d3/d3-time-format/blob/master/README.md#timeParse) - alias for *locale*.parse on the default locale. -* [d3.utcFormat](https://github.com/d3/d3-time-format/blob/master/README.md#utcFormat) - alias for *locale*.utcFormat on the default locale. -* [d3.utcParse](https://github.com/d3/d3-time-format/blob/master/README.md#utcParse) - alias for *locale*.utcParse on the default locale. -* [d3.isoFormat](https://github.com/d3/d3-time-format/blob/master/README.md#isoFormat) - an ISO 8601 UTC formatter. -* [d3.isoParse](https://github.com/d3/d3-time-format/blob/master/README.md#isoParse) - an ISO 8601 UTC parser. -* [d3.timeFormatLocale](https://github.com/d3/d3-time-format/blob/master/README.md#timeFormatLocale) - define a custom locale. -* [d3.timeFormatDefaultLocale](https://github.com/d3/d3-time-format/blob/master/README.md#timeFormatDefaultLocale) - define the default locale. -* [*locale*.format](https://github.com/d3/d3-time-format/blob/master/README.md#locale_format) - create a time formatter. -* [*locale*.parse](https://github.com/d3/d3-time-format/blob/master/README.md#locale_parse) - create a time parser. -* [*locale*.utcFormat](https://github.com/d3/d3-time-format/blob/master/README.md#locale_utcFormat) - create a UTC formatter. -* [*locale*.utcParse](https://github.com/d3/d3-time-format/blob/master/README.md#locale_utcParse) - create a UTC parser. - -## [Time Intervals (d3-time)](https://github.com/d3/d3-time) - -A calculator for humanity’s peculiar conventions of time. - -* [d3.timeInterval](https://github.com/d3/d3-time/blob/master/README.md#timeInterval) - implement a new custom time interval. -* [*interval*](https://github.com/d3/d3-time/blob/master/README.md#_interval) - alias for *interval*.floor. -* [*interval*.floor](https://github.com/d3/d3-time/blob/master/README.md#interval_floor) - round down to the nearest boundary. -* [*interval*.round](https://github.com/d3/d3-time/blob/master/README.md#interval_round) - round to the nearest boundary. -* [*interval*.ceil](https://github.com/d3/d3-time/blob/master/README.md#interval_ceil) - round up to the nearest boundary. -* [*interval*.offset](https://github.com/d3/d3-time/blob/master/README.md#interval_offset) - offset a date by some number of intervals. -* [*interval*.range](https://github.com/d3/d3-time/blob/master/README.md#interval_range) - generate a range of dates at interval boundaries. -* [*interval*.filter](https://github.com/d3/d3-time/blob/master/README.md#interval_filter) - create a filtered subset of this interval. -* [*interval*.every](https://github.com/d3/d3-time/blob/master/README.md#interval_every) - create a filtered subset of this interval. -* [*interval*.count](https://github.com/d3/d3-time/blob/master/README.md#interval_count) - count interval boundaries between two dates. -* [d3.timeMillisecond](https://github.com/d3/d3-time/blob/master/README.md#timeMillisecond), [d3.utcMillisecond](https://github.com/d3/d3-time/blob/master/README.md#timeMillisecond) - the millisecond interval. -* [d3.timeMilliseconds](https://github.com/d3/d3-time/blob/master/README.md#timeMillisecond), [d3.utcMilliseconds](https://github.com/d3/d3-time/blob/master/README.md#timeMillisecond) - aliases for millisecond.range. -* [d3.timeSecond](https://github.com/d3/d3-time/blob/master/README.md#timeSecond), [d3.utcSecond](https://github.com/d3/d3-time/blob/master/README.md#timeSecond) - the second interval. -* [d3.timeSeconds](https://github.com/d3/d3-time/blob/master/README.md#timeSecond), [d3.utcSeconds](https://github.com/d3/d3-time/blob/master/README.md#timeSecond) - aliases for second.range. -* [d3.timeMinute](https://github.com/d3/d3-time/blob/master/README.md#timeMinute), [d3.utcMinute](https://github.com/d3/d3-time/blob/master/README.md#timeMinute) - the minute interval. -* [d3.timeMinutes](https://github.com/d3/d3-time/blob/master/README.md#timeMinute), [d3.utcMinutes](https://github.com/d3/d3-time/blob/master/README.md#timeMinute) - aliases for minute.range. -* [d3.timeHour](https://github.com/d3/d3-time/blob/master/README.md#timeHour), [d3.utcHour](https://github.com/d3/d3-time/blob/master/README.md#timeHour) - the hour interval. -* [d3.timeHours](https://github.com/d3/d3-time/blob/master/README.md#timeHour), [d3.utcHours](https://github.com/d3/d3-time/blob/master/README.md#timeHour) - aliases for hour.range. -* [d3.timeDay](https://github.com/d3/d3-time/blob/master/README.md#timeDay), [d3.utcDay](https://github.com/d3/d3-time/blob/master/README.md#timeDay) - the day interval. -* [d3.timeDays](https://github.com/d3/d3-time/blob/master/README.md#timeDay), [d3.utcDays](https://github.com/d3/d3-time/blob/master/README.md#timeDay) - aliases for day.range. -* [d3.timeWeek](https://github.com/d3/d3-time/blob/master/README.md#timeWeek), [d3.utcWeek](https://github.com/d3/d3-time/blob/master/README.md#timeWeek) - aliases for sunday. -* [d3.timeWeeks](https://github.com/d3/d3-time/blob/master/README.md#timeWeek), [d3.utcWeeks](https://github.com/d3/d3-time/blob/master/README.md#timeWeek) - aliases for week.range. -* [d3.timeSunday](https://github.com/d3/d3-time/blob/master/README.md#timeSunday), [d3.utcSunday](https://github.com/d3/d3-time/blob/master/README.md#timeSunday) - the week interval, starting on Sunday. -* [d3.timeSundays](https://github.com/d3/d3-time/blob/master/README.md#timeSunday), [d3.utcSundays](https://github.com/d3/d3-time/blob/master/README.md#timeSunday) - aliases for sunday.range. -* [d3.timeMonday](https://github.com/d3/d3-time/blob/master/README.md#timeMonday), [d3.utcMonday](https://github.com/d3/d3-time/blob/master/README.md#timeMonday) - the week interval, starting on Monday. -* [d3.timeMondays](https://github.com/d3/d3-time/blob/master/README.md#timeMonday), [d3.utcMondays](https://github.com/d3/d3-time/blob/master/README.md#timeMonday) - aliases for monday.range. -* [d3.timeTuesday](https://github.com/d3/d3-time/blob/master/README.md#timeTuesday), [d3.utcTuesday](https://github.com/d3/d3-time/blob/master/README.md#timeTuesday) - the week interval, starting on Tuesday. -* [d3.timeTuesdays](https://github.com/d3/d3-time/blob/master/README.md#timeTuesday), [d3.utcTuesdays](https://github.com/d3/d3-time/blob/master/README.md#timeTuesday) - aliases for tuesday.range. -* [d3.timeWednesday](https://github.com/d3/d3-time/blob/master/README.md#timeWednesday), [d3.utcWednesday](https://github.com/d3/d3-time/blob/master/README.md#timeWednesday) - the week interval, starting on Wednesday. -* [d3.timeWednesdays](https://github.com/d3/d3-time/blob/master/README.md#timeWednesday), [d3.utcWednesdays](https://github.com/d3/d3-time/blob/master/README.md#timeWednesday) - aliases for wednesday.range. -* [d3.timeThursday](https://github.com/d3/d3-time/blob/master/README.md#timeThursday), [d3.utcThursday](https://github.com/d3/d3-time/blob/master/README.md#timeThursday) - the week interval, starting on Thursday. -* [d3.timeThursdays](https://github.com/d3/d3-time/blob/master/README.md#timeThursday), [d3.utcThursdays](https://github.com/d3/d3-time/blob/master/README.md#timeThursday) - aliases for thursday.range. -* [d3.timeFriday](https://github.com/d3/d3-time/blob/master/README.md#timeFriday), [d3.utcFriday](https://github.com/d3/d3-time/blob/master/README.md#timeFriday) - the week interval, starting on Friday. -* [d3.timeFridays](https://github.com/d3/d3-time/blob/master/README.md#timeFriday), [d3.utcFridays](https://github.com/d3/d3-time/blob/master/README.md#timeFriday) - aliases for friday.range. -* [d3.timeSaturday](https://github.com/d3/d3-time/blob/master/README.md#timeSaturday), [d3.utcSaturday](https://github.com/d3/d3-time/blob/master/README.md#timeSaturday) - the week interval, starting on Saturday. -* [d3.timeSaturdays](https://github.com/d3/d3-time/blob/master/README.md#timeSaturday), [d3.utcSaturdays](https://github.com/d3/d3-time/blob/master/README.md#timeSaturday) - aliases for saturday.range. -* [d3.timeMonth](https://github.com/d3/d3-time/blob/master/README.md#timeMonth), [d3.utcMonth](https://github.com/d3/d3-time/blob/master/README.md#timeMonth) - the month interval. -* [d3.timeMonths](https://github.com/d3/d3-time/blob/master/README.md#timeMonth), [d3.utcMonths](https://github.com/d3/d3-time/blob/master/README.md#timeMonth) - aliases for month.range. -* [d3.timeYear](https://github.com/d3/d3-time/blob/master/README.md#timeYear), [d3.utcYear](https://github.com/d3/d3-time/blob/master/README.md#timeYear) - the year interval. -* [d3.timeYears](https://github.com/d3/d3-time/blob/master/README.md#timeYear), [d3.utcYears](https://github.com/d3/d3-time/blob/master/README.md#timeYear) - aliases for year.range. - -## [Timers (d3-timer)](https://github.com/d3/d3-timer) - -An efficient queue for managing thousands of concurrent animations. - -* [d3.now](https://github.com/d3/d3-timer/blob/master/README.md#now) - get the current high-resolution time. -* [d3.timer](https://github.com/d3/d3-timer/blob/master/README.md#timer) - schedule a new timer. -* [*timer*.restart](https://github.com/d3/d3-timer/blob/master/README.md#timer_restart) - reset the timer’s start time and callback. -* [*timer*.stop](https://github.com/d3/d3-timer/blob/master/README.md#timer_stop) - stop the timer. -* [d3.timerFlush](https://github.com/d3/d3-timer/blob/master/README.md#timerFlush) - immediately execute any eligible timers. -* [d3.timeout](https://github.com/d3/d3-timer/blob/master/README.md#timeout) - schedule a timer that stops on its first callback. -* [d3.interval](https://github.com/d3/d3-timer/blob/master/README.md#interval) - schedule a timer that is called with a configurable period. - -## [Transitions (d3-transition)](https://github.com/d3/d3-transition) - -Animated transitions for [selections](#selections). - -* [*selection*.transition](https://github.com/d3/d3-transition/blob/master/README.md#selection_transition) - schedule a transition for the selected elements. -* [*selection*.interrupt](https://github.com/d3/d3-transition/blob/master/README.md#selection_interrupt) - interrupt and cancel transitions on the selected elements. -* [d3.transition](https://github.com/d3/d3-transition/blob/master/README.md#transition) - schedule a transition on the root document element. -* [*transition*.select](https://github.com/d3/d3-transition/blob/master/README.md#transition_select) - schedule a transition on the selected elements. -* [*transition*.selectAll](https://github.com/d3/d3-transition/blob/master/README.md#transition_selectAll) - schedule a transition on the selected elements. -* [*transition*.filter](https://github.com/d3/d3-transition/blob/master/README.md#transition_filter) - filter elements based on data. -* [*transition*.merge](https://github.com/d3/d3-transition/blob/master/README.md#transition_merge) - merge this transition with another. -* [*transition*.selection](https://github.com/d3/d3-transition/blob/master/README.md#transition_selection) - returns a selection for this transition. -* [*transition*.transition](https://github.com/d3/d3-transition/blob/master/README.md#transition_transition) - schedule a new transition following this one. -* [*transition*.call](https://github.com/d3/d3-transition/blob/master/README.md#transition_call) - call a function with this transition. -* [*transition*.nodes](https://github.com/d3/d3-transition/blob/master/README.md#transition_nodes) - returns an array of all selected elements. -* [*transition*.node](https://github.com/d3/d3-transition/blob/master/README.md#transition_node) - returns the first (non-null) element. -* [*transition*.size](https://github.com/d3/d3-transition/blob/master/README.md#transition_size) - returns the count of elements. -* [*transition*.empty](https://github.com/d3/d3-transition/blob/master/README.md#transition_empty) - returns true if this transition is empty. -* [*transition*.each](https://github.com/d3/d3-transition/blob/master/README.md#transition_each) - call a function for each element. -* [*transition*.on](https://github.com/d3/d3-transition/blob/master/README.md#transition_on) - add or remove transition event listeners. -* [*transition*.attr](https://github.com/d3/d3-transition/blob/master/README.md#transition_attr) - tween the given attribute using the default interpolator. -* [*transition*.attrTween](https://github.com/d3/d3-transition/blob/master/README.md#transition_attrTween) - tween the given attribute using a custom interpolator. -* [*transition*.style](https://github.com/d3/d3-transition/blob/master/README.md#transition_style) - tween the given style property using the default interpolator. -* [*transition*.styleTween](https://github.com/d3/d3-transition/blob/master/README.md#transition_styleTween) - tween the given style property using a custom interpolator. -* [*transition*.text](https://github.com/d3/d3-transition/blob/master/README.md#transition_text) - set the text content when the transition starts. -* [*transition*.remove](https://github.com/d3/d3-transition/blob/master/README.md#transition_remove) - remove the selected elements when the transition ends. -* [*transition*.tween](https://github.com/d3/d3-transition/blob/master/README.md#transition_tween) - run custom code during the transition. -* [*transition*.delay](https://github.com/d3/d3-transition/blob/master/README.md#transition_delay) - specify per-element delay in milliseconds. -* [*transition*.duration](https://github.com/d3/d3-transition/blob/master/README.md#transition_duration) - specify per-element duration in milliseconds. -* [*transition*.ease](https://github.com/d3/d3-transition/blob/master/README.md#transition_ease) - specify the easing function. -* [d3.active](https://github.com/d3/d3-transition/blob/master/README.md#active) - select the active transition for a given node. -* [d3.interrupt](https://github.com/d3/d3-transition/blob/master/README.md#interrupt) - interrupt the active transition for a given node. - -## [Voronoi Diagrams (d3-voronoi)](https://github.com/d3/d3-voronoi) - -Compute the Voronoi diagram of a given set of points. - -* [d3.voronoi](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi) - create a new Voronoi generator. -* [*voronoi*](https://github.com/d3/d3-voronoi/blob/master/README.md#_voronoi) - generate a new Voronoi diagram for the given points. -* [*voronoi*.polygons](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_polygons) - compute the Voronoi polygons for the given points. -* [*voronoi*.triangles](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_triangles) - compute the Delaunay triangles for the given points. -* [*voronoi*.links](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_links) - compute the Delaunay links for the given points. -* [*voronoi*.x](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_x) - set the *x* accessor. -* [*voronoi*.y](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_y) - set the *y* accessor. -* [*voronoi*.extent](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_extent) - set the observed extent of points. -* [*voronoi*.size](https://github.com/d3/d3-voronoi/blob/master/README.md#voronoi_size) - set the observed extent of points. -* [*diagram*.polygons](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_polygons) - compute the polygons for this Voronoi diagram. -* [*diagram*.triangles](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_triangles) - compute the triangles for this Voronoi diagram. -* [*diagram*.links](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_links) - compute the links for this Voronoi diagram. -* [*diagram*.find](https://github.com/d3/d3-voronoi/blob/master/README.md#diagram_find) - find the closest point in this Voronoi diagram. - -## [Zooming (d3-zoom)](https://github.com/d3/d3-zoom) - -Pan and zoom SVG, HTML or Canvas using mouse or touch input. - -* [d3.zoom](https://github.com/d3/d3-zoom/blob/master/README.md#zoom) - create a zoom behavior. -* [*zoom*](https://github.com/d3/d3-zoom/blob/master/README.md#_zoom) - apply the zoom behavior to the selected elements. -* [*zoom*.transform](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_transform) - change the transform for the selected elements. -* [*zoom*.translateTo](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_translateTo) - translate the transform for the selected elements. -* [*zoom*.translateBy](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_translateBy) - translate the transform for the selected elements. -* [*zoom*.scaleBy](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_scaleBy) - scale the transform for the selected elements. -* [*zoom*.scaleTo](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_scaleTo) - scale the transform for the selected elements. -* [*zoom*.filter](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_filter) - control which input events initiate zooming. -* [*zoom*.touchable](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_touchable) - set the touch support detector. -* [*zoom*.wheelDelta](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_wheelDelta) - override scaling for wheel events. -* [*zoom*.clickDistance](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_clickDistance) - set the click distance threshold. -* [*zoom*.extent](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_extent) - set the extent of the viewport. -* [*zoom*.scaleExtent](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_scaleExtent) - set the allowed scale range. -* [*zoom*.translateExtent](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_translateExtent) - set the extent of the zoomable world. -* [*zoom*.constrain](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_constrain) - override the transform constraint logic. -* [*zoom*.duration](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_duration) - set the duration of zoom transitions. -* [*zoom*.interpolate](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_interpolate) - control the interpolation of zoom transitions. -* [*zoom*.on](https://github.com/d3/d3-zoom/blob/master/README.md#zoom_on) - listen for zoom events. -* [d3.zoomTransform](https://github.com/d3/d3-zoom/blob/master/README.md#zoomTransform) - get the zoom transform for a given element. -* [*transform*.scale](https://github.com/d3/d3-zoom/blob/master/README.md#transform_scale) - scale a transform by the specified amount. -* [*transform*.translate](https://github.com/d3/d3-zoom/blob/master/README.md#transform_translate) - translate a transform by the specified amount. -* [*transform*.apply](https://github.com/d3/d3-zoom/blob/master/README.md#transform_apply) - apply the transform to the given point. -* [*transform*.applyX](https://github.com/d3/d3-zoom/blob/master/README.md#transform_applyX) - apply the transform to the given *x*-coordinate. -* [*transform*.applyY](https://github.com/d3/d3-zoom/blob/master/README.md#transform_applyY) - apply the transform to the given *y*-coordinate. -* [*transform*.invert](https://github.com/d3/d3-zoom/blob/master/README.md#transform_invert) - unapply the transform to the given point. -* [*transform*.invertX](https://github.com/d3/d3-zoom/blob/master/README.md#transform_invertX) - unapply the transform to the given *x*-coordinate. -* [*transform*.invertY](https://github.com/d3/d3-zoom/blob/master/README.md#transform_invertY) - unapply the transform to the given *y*-coordinate. -* [*transform*.rescaleX](https://github.com/d3/d3-zoom/blob/master/README.md#transform_rescaleX) - apply the transform to an *x*-scale’s domain. -* [*transform*.rescaleY](https://github.com/d3/d3-zoom/blob/master/README.md#transform_rescaleY) - apply the transform to a *y*-scale’s domain. -* [*transform*.toString](https://github.com/d3/d3-zoom/blob/master/README.md#transform_toString) - format the transform as an SVG transform string. -* [d3.zoomIdentity](https://github.com/d3/d3-zoom/blob/master/README.md#zoomIdentity) - the identity transform.
diff --git a/third_party/d3/src/CHANGES.md b/third_party/d3/src/CHANGES.md index c65b4817..64c7595 100644 --- a/third_party/d3/src/CHANGES.md +++ b/third_party/d3/src/CHANGES.md
@@ -2,9 +2,11 @@ [Released March 22, 2018.](https://github.com/d3/d3/releases/tag/v5.0.0) +*This document covers only major changes. For minor and patch changes, please see the [release notes](https://github.com/d3/d3/releases).* + D3 5.0 introduces only a few non-backwards-compatible changes. -D3 now uses [Promises](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Using_promises) instead of asynchronous callbacks to load data. Promises simplify the structure of asynchronous code, especially in modern browsers that support [async and await](https://javascript.info/async-await). (See this [introduction to promises](https://beta.observablehq.com/@mbostock/introduction-to-promises) on [Observable](https://beta.observablehq.com).) For example, to load a CSV file in v4, you might say: +D3 now uses [Promises](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Using_promises) instead of asynchronous callbacks to load data. Promises simplify the structure of asynchronous code, especially in modern browsers that support [async and await](https://javascript.info/async-await). (See this [introduction to promises](https://observablehq.com/@observablehq/introduction-to-promises) on [Observable](https://observablehq.com).) For example, to load a CSV file in v4, you might say: ```js d3.csv("file.csv", function(error, data) { @@ -28,11 +30,11 @@ console.log(data); ``` -With the adoption of promises, D3 now uses the [Fetch API](https://fetch.spec.whatwg.org/) instead of [XMLHttpRequest](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest): the [d3-request](https://github.com/d3/d3-request) module has been replaced by [d3-fetch](https://github.com/d3/d3-fetch). Fetch supports many powerful new features, such as [streaming responses](https://beta.observablehq.com/@mbostock/streaming-shapefiles). D3 5.0 also deprecates and removes the [d3-queue](https://github.com/d3/d3-queue) module. Use [Promise.all](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) to run a batch of asynchronous tasks in parallel, or a helper library such as [p-queue](https://github.com/sindresorhus/p-queue) to [control concurrency](https://beta.observablehq.com/@mbostock/hello-p-queue). +With the adoption of promises, D3 now uses the [Fetch API](https://fetch.spec.whatwg.org/) instead of [XMLHttpRequest](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest): the [d3-request](https://github.com/d3/d3-request) module has been replaced by [d3-fetch](https://github.com/d3/d3-fetch). Fetch supports many powerful new features, such as [streaming responses](https://observablehq.com/@mbostock/streaming-shapefiles). D3 5.0 also deprecates and removes the [d3-queue](https://github.com/d3/d3-queue) module. Use [Promise.all](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) to run a batch of asynchronous tasks in parallel, or a helper library such as [p-queue](https://github.com/sindresorhus/p-queue) to [control concurrency](https://observablehq.com/@mbostock/hello-p-queue). D3 no longer provides the d3.schemeCategory20* categorical color schemes. These twenty-color schemes were flawed because their grouped design could falsely imply relationships in the data: a shared hue can imply that the encoded data are part of a group (a super-category), while relative lightness can imply order. Instead, D3 now includes [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic), which implements excellent schemes from ColorBrewer, including [categorical](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#categorical), [diverging](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#diverging), [sequential single-hue](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#sequential-single-hue) and [sequential multi-hue](https://github.com/d3/d3-scale-chromatic/blob/master/README.md#sequential-multi-hue) schemes. These schemes are available in both discrete and continuous variants. -D3 now provides implementations of [marching squares](https://beta.observablehq.com/@mbostock/d3-contour-plot) and [density estimation](https://beta.observablehq.com/@mbostock/d3-density-contours) via [d3-contour](https://github.com/d3/d3-contour)! There are two new [d3-selection](https://github.com/d3/d3-selection) methods: [*selection*.clone](https://github.com/d3/d3-selection/blob/master/README.md#selection_clone) for inserting clones of the selected nodes, and [d3.create](https://github.com/d3/d3-selection/blob/master/README.md#create) for creating detached elements. [Geographic projections](https://github.com/d3/d3-geo) now support [*projection*.angle](https://github.com/d3/d3-geo/blob/master/README.md#projection_angle), which has enabled several fantastic new [polyhedral projections](https://github.com/d3/d3-geo-polygon) by Philippe Rivière. +D3 now provides implementations of [marching squares](https://observablehq.com/@d3/contours) and [density estimation](https://observablehq.com/@d3/density-contours) via [d3-contour](https://github.com/d3/d3-contour)! There are two new [d3-selection](https://github.com/d3/d3-selection) methods: [*selection*.clone](https://github.com/d3/d3-selection/blob/master/README.md#selection_clone) for inserting clones of the selected nodes, and [d3.create](https://github.com/d3/d3-selection/blob/master/README.md#create) for creating detached elements. [Geographic projections](https://github.com/d3/d3-geo) now support [*projection*.angle](https://github.com/d3/d3-geo/blob/master/README.md#projection_angle), which has enabled several fantastic new [polyhedral projections](https://github.com/d3/d3-geo-polygon) by Philippe Rivière. Lastly, D3’s [package.json](https://github.com/d3/d3/blob/master/package.json) no longer pins exact versions of the dependent D3 modules. This fixes an issue with [duplicate installs](https://github.com/d3/d3/issues/3256) of D3 modules. @@ -131,7 +133,7 @@ The method signature for optional accessors has been changed to be more consistent with array methods such as [*array*.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach): the accessor is passed the current element (*d*), the index (*i*), and the array (*data*), with *this* as undefined. This affects [d3.min](https://github.com/d3/d3-array/blob/master/README.md#min), [d3.max](https://github.com/d3/d3-array/blob/master/README.md#max), [d3.extent](https://github.com/d3/d3-array/blob/master/README.md#extent), [d3.sum](https://github.com/d3/d3-array/blob/master/README.md#sum), [d3.mean](https://github.com/d3/d3-array/blob/master/README.md#mean), [d3.median](https://github.com/d3/d3-array/blob/master/README.md#median), [d3.quantile](https://github.com/d3/d3-array/blob/master/README.md#quantile), [d3.variance](https://github.com/d3/d3-array/blob/master/README.md#variance) and [d3.deviation](https://github.com/d3/d3-array/blob/master/README.md#deviation). The [d3.quantile](https://github.com/d3/d3-array/blob/master/README.md#quantile) method previously did not take an accessor. Some methods with optional arguments now treat those arguments as missing if they are null or undefined, rather than strictly checking arguments.length. -The new [d3.histogram](https://github.com/d3/d3-array/blob/master/README.md#histograms) API replaces d3.layout.histogram. Rather than exposing *bin*.x and *bin*.dx on each returned bin, the histogram exposes *bin*.x0 and *bin*.x1, guaranteeing that *bin*.x0 is exactly equal to *bin*.x1 on the preceeding bin. The “frequency” and “probability” modes are no longer supported; each bin is simply an array of elements from the input data, so *bin*.length is equal to D3 3.x’s *bin*.y in frequency mode. To compute a probability distribution, divide the number of elements in each bin by the total number of elements. +The new [d3.histogram](https://github.com/d3/d3-array/blob/master/README.md#histograms) API replaces d3.layout.histogram. Rather than exposing *bin*.x and *bin*.dx on each returned bin, the histogram exposes *bin*.x0 and *bin*.x1, guaranteeing that *bin*.x0 is exactly equal to *bin*.x1 on the preceding bin. The “frequency” and “probability” modes are no longer supported; each bin is simply an array of elements from the input data, so *bin*.length is equal to D3 3.x’s *bin*.y in frequency mode. To compute a probability distribution, divide the number of elements in each bin by the total number of elements. The *histogram*.range method has been renamed [*histogram*.domain](https://github.com/d3/d3-array/blob/master/README.md#histogram_domain) for consistency with scales. The *histogram*.bins method has been renamed [*histogram*.thresholds](https://github.com/d3/d3-array/blob/master/README.md#histogram_thresholds), and no longer accepts an upper value: *n* thresholds will produce *n* + 1 bins. If you specify a desired number of bins rather than thresholds, d3.histogram now uses [d3.ticks](https://github.com/d3/d3-array/blob/master/README.md#ticks) to compute nice bin thresholds. In addition to the default Sturges’ formula, D3 now implements the [Freedman-Diaconis rule](https://github.com/d3/d3-array/blob/master/README.md#thresholdFreedmanDiaconis) and [Scott’s normal reference rule](https://github.com/d3/d3-array/blob/master/README.md#thresholdScott). @@ -857,17 +859,17 @@ [Sequential scales](https://github.com/d3/d3-scale/blob/master/README.md#scaleSequential), are a new class of scales with a fixed output [interpolator](https://github.com/d3/d3-scale/blob/master/README.md#sequential_interpolator) instead of a [range](https://github.com/d3/d3-scale/blob/master/README.md#continuous_range). Typically these scales are used to implement continuous sequential or diverging color schemes. Inspired by Matplotlib’s new [perceptually-motived colormaps](https://bids.github.io/colormap/), 4.0 now features [viridis](https://github.com/d3/d3-scale/blob/master/README.md#interpolateViridis), [inferno](https://github.com/d3/d3-scale/blob/master/README.md#interpolateInferno), [magma](https://github.com/d3/d3-scale/blob/master/README.md#interpolateMagma), [plasma](https://github.com/d3/d3-scale/blob/master/README.md#interpolatePlasma) interpolators for use with sequential scales. Using [d3.quantize](https://github.com/d3/d3-interpolate/blob/master/README.md#quantize), these interpolators can also be applied to [quantile](https://github.com/d3/d3-scale/blob/master/README.md#quantile-scales), [quantize](https://github.com/d3/d3-scale/blob/master/README.md#quantize-scales) and [threshold](https://github.com/d3/d3-scale/blob/master/README.md#threshold-scales) scales. -[<img src="https://raw.githubusercontent.com/d3/d3-scale/master/img/viridis.png" width="100%" height="40" alt="viridis">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateViridis) -[<img src="https://raw.githubusercontent.com/d3/d3-scale/master/img/inferno.png" width="100%" height="40" alt="inferno">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateInferno) -[<img src="https://raw.githubusercontent.com/d3/d3-scale/master/img/magma.png" width="100%" height="40" alt="magma">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateMagma) -[<img src="https://raw.githubusercontent.com/d3/d3-scale/master/img/plasma.png" width="100%" height="40" alt="plasma">](https://github.com/d3/d3-scale/blob/master/README.md#interpolatePlasma) +[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/viridis.png" width="100%" height="40" alt="viridis">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateViridis) +[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/inferno.png" width="100%" height="40" alt="inferno">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateInferno) +[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/magma.png" width="100%" height="40" alt="magma">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateMagma) +[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/plasma.png" width="100%" height="40" alt="plasma">](https://github.com/d3/d3-scale/blob/master/README.md#interpolatePlasma) 4.0 also ships new Cubehelix schemes, including [Dave Green’s default](https://github.com/d3/d3-scale/blob/master/README.md#interpolateCubehelixDefault) and a [cyclical rainbow](https://github.com/d3/d3-scale/blob/master/README.md#interpolateRainbow) inspired by [Matteo Niccoli](https://mycarta.wordpress.com/2013/02/21/perceptual-rainbow-palette-the-method/): -[<img src="https://raw.githubusercontent.com/d3/d3-scale/master/img/cubehelix.png" width="100%" height="40" alt="cubehelix">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateCubehelixDefault) -[<img src="https://raw.githubusercontent.com/d3/d3-scale/master/img/rainbow.png" width="100%" height="40" alt="rainbow">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateRainbow) -[<img src="https://raw.githubusercontent.com/d3/d3-scale/master/img/warm.png" width="100%" height="40" alt="warm">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateWarm) -[<img src="https://raw.githubusercontent.com/d3/d3-scale/master/img/cool.png" width="100%" height="40" alt="cool">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateCool) +[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/cubehelix.png" width="100%" height="40" alt="cubehelix">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateCubehelixDefault) +[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/rainbow.png" width="100%" height="40" alt="rainbow">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateRainbow) +[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/warm.png" width="100%" height="40" alt="warm">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateWarm) +[<img src="https://raw.githubusercontent.com/d3/d3-scale/v1.0.0/img/cool.png" width="100%" height="40" alt="cool">](https://github.com/d3/d3-scale/blob/master/README.md#interpolateCool) For even more sequential and categorical color schemes, see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic).
diff --git a/third_party/d3/src/README.md b/third_party/d3/src/README.md index 696df69..4fa9c4a 100644 --- a/third_party/d3/src/README.md +++ b/third_party/d3/src/README.md
@@ -6,10 +6,10 @@ ## Resources +* [Introduction](https://observablehq.com/@d3/learn-d3) * [API Reference](https://github.com/d3/d3/blob/master/API.md) -* [Release Notes](https://github.com/d3/d3/releases) -* [Gallery](https://github.com/d3/d3/wiki/Gallery) -* [Examples](https://bl.ocks.org/mbostock) +* [Releases](https://github.com/d3/d3/releases) +* [Examples](https://observablehq.com/@d3/gallery) * [Wiki](https://github.com/d3/d3/wiki) ## Installing
diff --git a/third_party/d3/src/d3.js b/third_party/d3/src/d3.js index 9af5650c..632b3fa4 100644 --- a/third_party/d3/src/d3.js +++ b/third_party/d3/src/d3.js
@@ -1,11 +1,11 @@ -// https://d3js.org v5.7.0 Copyright 2018 Mike Bostock +// https://d3js.org v5.16.0 Copyright 2020 Mike Bostock (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : -(factory((global.d3 = global.d3 || {}))); -}(this, (function (exports) { 'use strict'; +(global = global || self, factory(global.d3 = global.d3 || {})); +}(this, function (exports) { 'use strict'; -var version = "5.7.0"; +var version = "5.16.0"; function ascending(a, b) { return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; @@ -737,7 +737,7 @@ function dispatch() { for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) { - if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t); + if (!(t = arguments[i] + "") || (t in _) || /[\s.]/.test(t)) throw new Error("illegal type: " + t); _[t] = []; } return new Dispatch(_); @@ -903,31 +903,14 @@ return new Selection(subgroups, parents); } -var matcher = function(selector) { +function matcher(selector) { return function() { return this.matches(selector); }; -}; - -if (typeof document !== "undefined") { - var element = document.documentElement; - if (!element.matches) { - var vendorMatches = element.webkitMatchesSelector - || element.msMatchesSelector - || element.mozMatchesSelector - || element.oMatchesSelector; - matcher = function(selector) { - return function() { - return vendorMatches.call(this, selector); - }; - }; - } } -var matcher$1 = matcher; - function selection_filter(match) { - if (typeof match !== "function") match = matcher$1(match); + if (typeof match !== "function") match = matcher(match); for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) { @@ -1089,9 +1072,17 @@ return new Selection(this._exit || this._groups.map(sparse), this._parents); } -function selection_merge(selection$$1) { +function selection_join(onenter, onupdate, onexit) { + var enter = this.enter(), update = this, exit = this.exit(); + enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + ""); + if (onupdate != null) update = onupdate(update); + if (onexit == null) exit.remove(); else onexit(exit); + return enter && update ? enter.merge(update).order() : update; +} - for (var groups0 = this._groups, groups1 = selection$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { +function selection_merge(selection) { + + for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) { if (node = group0[i] || group1[i]) { merge[i] = node; @@ -1111,7 +1102,7 @@ for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) { for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) { if (node = group[i]) { - if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); + if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next); next = node; } } @@ -1487,11 +1478,13 @@ } function selection_cloneShallow() { - return this.parentNode.insertBefore(this.cloneNode(false), this.nextSibling); + var clone = this.cloneNode(false), parent = this.parentNode; + return parent ? parent.insertBefore(clone, this.nextSibling) : clone; } function selection_cloneDeep() { - return this.parentNode.insertBefore(this.cloneNode(true), this.nextSibling); + var clone = this.cloneNode(true), parent = this.parentNode; + return parent ? parent.insertBefore(clone, this.nextSibling) : clone; } function selection_clone(deep) { @@ -1509,8 +1502,8 @@ exports.event = null; if (typeof document !== "undefined") { - var element$1 = document.documentElement; - if (!("onmouseenter" in element$1)) { + var element = document.documentElement; + if (!("onmouseenter" in element)) { filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"}; } } @@ -1664,6 +1657,7 @@ data: selection_data, enter: selection_enter, exit: selection_exit, + join: selection_join, merge: selection_merge, order: selection_order, sort: selection_sort, @@ -1793,9 +1787,9 @@ function dragDisable(view) { var root = view.document.documentElement, - selection$$1 = select(view).on("dragstart.drag", noevent, true); + selection = select(view).on("dragstart.drag", noevent, true); if ("onselectstart" in root) { - selection$$1.on("selectstart.drag", noevent, true); + selection.on("selectstart.drag", noevent, true); } else { root.__noselect = root.style.MozUserSelect; root.style.MozUserSelect = "none"; @@ -1804,13 +1798,13 @@ function yesdrag(view, noclick) { var root = view.document.documentElement, - selection$$1 = select(view).on("dragstart.drag", null); + selection = select(view).on("dragstart.drag", null); if (noclick) { - selection$$1.on("click.drag", noevent, true); - setTimeout(function() { selection$$1.on("click.drag", null); }, 0); + selection.on("click.drag", noevent, true); + setTimeout(function() { selection.on("click.drag", null); }, 0); } if ("onselectstart" in root) { - selection$$1.on("selectstart.drag", null); + selection.on("selectstart.drag", null); } else { root.style.MozUserSelect = root.__noselect; delete root.__noselect; @@ -1843,7 +1837,7 @@ // Ignore right-click, since that should open the context menu. function defaultFilter() { - return !exports.event.button; + return !exports.event.ctrlKey && !exports.event.button; } function defaultContainer() { @@ -1855,7 +1849,7 @@ } function defaultTouchable() { - return "ontouchstart" in this; + return navigator.maxTouchPoints || ("ontouchstart" in this); } function drag() { @@ -1872,8 +1866,8 @@ touchending, clickDistance2 = 0; - function drag(selection$$1) { - selection$$1 + function drag(selection) { + selection .on("mousedown.drag", mousedowned) .filter(touchable) .on("touchstart.drag", touchstarted) @@ -1914,12 +1908,12 @@ function touchstarted() { if (!filter.apply(this, arguments)) return; - var touches$$1 = exports.event.changedTouches, + var touches = exports.event.changedTouches, c = container.apply(this, arguments), - n = touches$$1.length, i, gesture; + n = touches.length, i, gesture; for (i = 0; i < n; ++i) { - if (gesture = beforestart(touches$$1[i].identifier, c, touch, this, arguments)) { + if (gesture = beforestart(touches[i].identifier, c, touch, this, arguments)) { nopropagation(); gesture("start"); } @@ -1927,11 +1921,11 @@ } function touchmoved() { - var touches$$1 = exports.event.changedTouches, - n = touches$$1.length, i, gesture; + var touches = exports.event.changedTouches, + n = touches.length, i, gesture; for (i = 0; i < n; ++i) { - if (gesture = gestures[touches$$1[i].identifier]) { + if (gesture = gestures[touches[i].identifier]) { noevent(); gesture("drag"); } @@ -1939,21 +1933,21 @@ } function touchended() { - var touches$$1 = exports.event.changedTouches, - n = touches$$1.length, i, gesture; + var touches = exports.event.changedTouches, + n = touches.length, i, gesture; if (touchending) clearTimeout(touchending); touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed! for (i = 0; i < n; ++i) { - if (gesture = gestures[touches$$1[i].identifier]) { + if (gesture = gestures[touches[i].identifier]) { nopropagation(); gesture("end"); } } } - function beforestart(id, container, point$$1, that, args) { - var p = point$$1(container, id), s, dx, dy, + function beforestart(id, container, point, that, args) { + var p = point(container, id), s, dx, dy, sublisteners = listeners.copy(); if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() { @@ -1968,7 +1962,7 @@ switch (type) { case "start": gestures[id] = gesture, n = active++; break; case "end": delete gestures[id], --active; // nobreak - case "drag": p = point$$1(container, id), n = active; break; + case "drag": p = point(container, id), n = active; break; } customEvent(new DragEvent(drag, type, s, id, n, p[0] + dx, p[1] + dy, p[0] - p0[0], p[1] - p0[1], sublisteners), sublisteners.apply, sublisteners, [type, that, args]); }; @@ -2021,8 +2015,7 @@ var reI = "\\s*([+-]?\\d+)\\s*", reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*", reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*", - reHex3 = /^#([0-9a-f]{3})$/, - reHex6 = /^#([0-9a-f]{6})$/, + reHex = /^#([0-9a-f]{3,8})$/, reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"), reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"), reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"), @@ -2182,29 +2175,46 @@ }; define(Color, color, { + copy: function(channels) { + return Object.assign(new this.constructor, this, channels); + }, displayable: function() { return this.rgb().displayable(); }, - hex: function() { - return this.rgb().hex(); - }, - toString: function() { - return this.rgb() + ""; - } + hex: color_formatHex, // Deprecated! Use color.formatHex. + formatHex: color_formatHex, + formatHsl: color_formatHsl, + formatRgb: color_formatRgb, + toString: color_formatRgb }); +function color_formatHex() { + return this.rgb().formatHex(); +} + +function color_formatHsl() { + return hslConvert(this).formatHsl(); +} + +function color_formatRgb() { + return this.rgb().formatRgb(); +} + function color(format) { - var m; + var m, l; format = (format + "").trim().toLowerCase(); - return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00 - : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000 + return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000 + : l === 3 ? new Rgb((m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1) // #f00 + : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000 + : l === 4 ? rgba((m >> 12 & 0xf) | (m >> 8 & 0xf0), (m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), (((m & 0xf) << 4) | (m & 0xf)) / 0xff) // #f000 + : null) // invalid hex : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0) : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%) : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1) : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1) : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%) : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1) - : named.hasOwnProperty(format) ? rgbn(named[format]) + : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null; } @@ -2249,24 +2259,30 @@ return this; }, displayable: function() { - return (0 <= this.r && this.r <= 255) - && (0 <= this.g && this.g <= 255) - && (0 <= this.b && this.b <= 255) + return (-0.5 <= this.r && this.r < 255.5) + && (-0.5 <= this.g && this.g < 255.5) + && (-0.5 <= this.b && this.b < 255.5) && (0 <= this.opacity && this.opacity <= 1); }, - hex: function() { - return "#" + hex(this.r) + hex(this.g) + hex(this.b); - }, - toString: function() { - var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a)); - return (a === 1 ? "rgb(" : "rgba(") - + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", " - + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", " - + Math.max(0, Math.min(255, Math.round(this.b) || 0)) - + (a === 1 ? ")" : ", " + a + ")"); - } + hex: rgb_formatHex, // Deprecated! Use color.formatHex. + formatHex: rgb_formatHex, + formatRgb: rgb_formatRgb, + toString: rgb_formatRgb })); +function rgb_formatHex() { + return "#" + hex(this.r) + hex(this.g) + hex(this.b); +} + +function rgb_formatRgb() { + var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a)); + return (a === 1 ? "rgb(" : "rgba(") + + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", " + + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", " + + Math.max(0, Math.min(255, Math.round(this.b) || 0)) + + (a === 1 ? ")" : ", " + a + ")"); +} + function hex(value) { value = Math.max(0, Math.min(255, Math.round(value) || 0)); return (value < 16 ? "0" : "") + value.toString(16); @@ -2342,6 +2358,14 @@ return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && (0 <= this.l && this.l <= 1) && (0 <= this.opacity && this.opacity <= 1); + }, + formatHsl: function() { + var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a)); + return (a === 1 ? "hsl(" : "hsla(") + + (this.h || 0) + ", " + + (this.s || 0) * 100 + "%, " + + (this.l || 0) * 100 + "%" + + (a === 1 ? ")" : ", " + a + ")"); } })); @@ -2356,7 +2380,7 @@ var deg2rad = Math.PI / 180; var rad2deg = 180 / Math.PI; -// https://beta.observablehq.com/@mbostock/lab-and-rgb +// https://observablehq.com/@mbostock/lab-and-rgb var K = 18, Xn = 0.96422, Yn = 1, @@ -2368,11 +2392,7 @@ function labConvert(o) { if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity); - if (o instanceof Hcl) { - if (isNaN(o.h)) return new Lab(o.l, 0, 0, o.opacity); - var h = o.h * deg2rad; - return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity); - } + if (o instanceof Hcl) return hcl2lab(o); if (!(o instanceof Rgb)) o = rgbConvert(o); var r = rgb2lrgb(o.r), g = rgb2lrgb(o.g), @@ -2442,7 +2462,7 @@ function hclConvert(o) { if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity); if (!(o instanceof Lab)) o = labConvert(o); - if (o.a === 0 && o.b === 0) return new Hcl(NaN, 0, o.l, o.opacity); + if (o.a === 0 && o.b === 0) return new Hcl(NaN, 0 < o.l && o.l < 100 ? 0 : NaN, o.l, o.opacity); var h = Math.atan2(o.b, o.a) * rad2deg; return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity); } @@ -2462,6 +2482,12 @@ this.opacity = +opacity; } +function hcl2lab(o) { + if (isNaN(o.h)) return new Lab(o.l, 0, 0, o.opacity); + var h = o.h * deg2rad; + return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity); +} + define(Hcl, hcl, extend(Color, { brighter: function(k) { return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity); @@ -2470,7 +2496,7 @@ return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity); }, rgb: function() { - return labConvert(this).rgb(); + return hcl2lab(this).rgb(); } })); @@ -2599,12 +2625,12 @@ } var interpolateRgb = (function rgbGamma(y) { - var color$$1 = gamma(y); + var color = gamma(y); - function rgb$$1(start, end) { - var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r), - g = color$$1(start.g, end.g), - b = color$$1(start.b, end.b), + function rgb$1(start, end) { + var r = color((start = rgb(start)).r, (end = rgb(end)).r), + g = color(start.g, end.g), + b = color(start.b, end.b), opacity = nogamma(start.opacity, end.opacity); return function(t) { start.r = r(t); @@ -2615,9 +2641,9 @@ }; } - rgb$$1.gamma = rgbGamma; + rgb$1.gamma = rgbGamma; - return rgb$$1; + return rgb$1; })(1); function rgbSpline(spline) { @@ -2626,22 +2652,22 @@ r = new Array(n), g = new Array(n), b = new Array(n), - i, color$$1; + i, color; for (i = 0; i < n; ++i) { - color$$1 = rgb(colors[i]); - r[i] = color$$1.r || 0; - g[i] = color$$1.g || 0; - b[i] = color$$1.b || 0; + color = rgb(colors[i]); + r[i] = color.r || 0; + g[i] = color.g || 0; + b[i] = color.b || 0; } r = spline(r); g = spline(g); b = spline(b); - color$$1.opacity = 1; + color.opacity = 1; return function(t) { - color$$1.r = r(t); - color$$1.g = g(t); - color$$1.b = b(t); - return color$$1 + ""; + color.r = r(t); + color.g = g(t); + color.b = b(t); + return color + ""; }; }; } @@ -2649,7 +2675,26 @@ var rgbBasis = rgbSpline(basis$1); var rgbBasisClosed = rgbSpline(basisClosed); +function numberArray(a, b) { + if (!b) b = []; + var n = a ? Math.min(b.length, a.length) : 0, + c = b.slice(), + i; + return function(t) { + for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t; + return c; + }; +} + +function isNumberArray(x) { + return ArrayBuffer.isView(x) && !(x instanceof DataView); +} + function array$1(a, b) { + return (isNumberArray(b) ? numberArray : genericArray)(a, b); +} + +function genericArray(a, b) { var nb = b ? b.length : 0, na = a ? Math.min(nb, a.length) : 0, x = new Array(na), @@ -2667,14 +2712,14 @@ function date(a, b) { var d = new Date; - return a = +a, b -= a, function(t) { - return d.setTime(a + b * t), d; + return a = +a, b = +b, function(t) { + return d.setTime(a * (1 - t) + b * t), d; }; } function interpolateNumber(a, b) { - return a = +a, b -= a, function(t) { - return a + b * t; + return a = +a, b = +b, function(t) { + return a * (1 - t) + b * t; }; } @@ -2770,7 +2815,8 @@ : t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString) : b instanceof color ? interpolateRgb : b instanceof Date ? date - : Array.isArray(b) ? array$1 + : isNumberArray(b) ? numberArray + : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object : interpolateNumber)(a, b); } @@ -2791,8 +2837,8 @@ } function interpolateRound(a, b) { - return a = +a, b -= a, function(t) { - return Math.round(a + b * t); + return a = +a, b = +b, function(t) { + return Math.round(a * (1 - t) + b * t); }; } @@ -2973,9 +3019,9 @@ return i; } -function hsl$1(hue$$1) { +function hsl$1(hue) { return function(start, end) { - var h = hue$$1((start = hsl(start)).h, (end = hsl(end)).h), + var h = hue((start = hsl(start)).h, (end = hsl(end)).h), s = nogamma(start.s, end.s), l = nogamma(start.l, end.l), opacity = nogamma(start.opacity, end.opacity); @@ -3006,9 +3052,9 @@ }; } -function hcl$1(hue$$1) { +function hcl$1(hue) { return function(start, end) { - var h = hue$$1((start = hcl(start)).h, (end = hcl(end)).h), + var h = hue((start = hcl(start)).h, (end = hcl(end)).h), c = nogamma(start.c, end.c), l = nogamma(start.l, end.l), opacity = nogamma(start.opacity, end.opacity); @@ -3025,12 +3071,12 @@ var hcl$2 = hcl$1(hue); var hclLong = hcl$1(nogamma); -function cubehelix$1(hue$$1) { +function cubehelix$1(hue) { return (function cubehelixGamma(y) { y = +y; - function cubehelix$$1(start, end) { - var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h), + function cubehelix$1(start, end) { + var h = hue((start = cubehelix(start)).h, (end = cubehelix(end)).h), s = nogamma(start.s, end.s), l = nogamma(start.l, end.l), opacity = nogamma(start.opacity, end.opacity); @@ -3043,9 +3089,9 @@ }; } - cubehelix$$1.gamma = cubehelixGamma; + cubehelix$1.gamma = cubehelixGamma; - return cubehelix$$1; + return cubehelix$1; })(1); } @@ -3200,7 +3246,7 @@ return t; } -var emptyOn = dispatch("start", "end", "interrupt"); +var emptyOn = dispatch("start", "end", "cancel", "interrupt"); var emptyTween = []; var CREATED = 0; @@ -3238,7 +3284,7 @@ function set$1(node, id) { var schedule = get$1(node, id); - if (schedule.state > STARTING) throw new Error("too late; already started"); + if (schedule.state > STARTED) throw new Error("too late; already running"); return schedule; } @@ -3281,7 +3327,6 @@ if (o.state === STARTED) return timeout$1(start); // Interrupt the active transition, if any. - // Dispatch the interrupt event. if (o.state === RUNNING) { o.state = ENDED; o.timer.stop(); @@ -3289,12 +3334,11 @@ delete schedules[i]; } - // Cancel any pre-empted transitions. No interrupt event is dispatched - // because the cancelled transitions never started. Note that this also - // removes this transition from the pending list! + // Cancel any pre-empted transitions. else if (+i < id) { o.state = ENDED; o.timer.stop(); + o.on.call("cancel", node, node.__data__, o.index, o.group); delete schedules[i]; } } @@ -3334,7 +3378,7 @@ n = tween.length; while (++i < n) { - tween[i].call(null, t); + tween[i].call(node, t); } // Dispatch the end event. @@ -3355,7 +3399,7 @@ function interrupt(node, name) { var schedules = node.__transition, - schedule$$1, + schedule, active, empty = true, i; @@ -3365,11 +3409,11 @@ name = name == null ? null : name + ""; for (i in schedules) { - if ((schedule$$1 = schedules[i]).name !== name) { empty = false; continue; } - active = schedule$$1.state > STARTING && schedule$$1.state < ENDING; - schedule$$1.state = ENDED; - schedule$$1.timer.stop(); - if (active) schedule$$1.on.call("interrupt", node, node.__data__, schedule$$1.index, schedule$$1.group); + if ((schedule = schedules[i]).name !== name) { empty = false; continue; } + active = schedule.state > STARTING && schedule.state < ENDING; + schedule.state = ENDED; + schedule.timer.stop(); + schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group); delete schedules[i]; } @@ -3385,8 +3429,8 @@ function tweenRemove(id, name) { var tween0, tween1; return function() { - var schedule$$1 = set$1(this, id), - tween = schedule$$1.tween; + var schedule = set$1(this, id), + tween = schedule.tween; // If this node shared tween with the previous node, // just assign the updated shared tween and we’re done! @@ -3402,7 +3446,7 @@ } } - schedule$$1.tween = tween1; + schedule.tween = tween1; }; } @@ -3410,8 +3454,8 @@ var tween0, tween1; if (typeof value !== "function") throw new Error; return function() { - var schedule$$1 = set$1(this, id), - tween = schedule$$1.tween; + var schedule = set$1(this, id), + tween = schedule.tween; // If this node shared tween with the previous node, // just assign the updated shared tween and we’re done! @@ -3427,7 +3471,7 @@ if (i === n) tween1.push(t); } - schedule$$1.tween = tween1; + schedule.tween = tween1; }; } @@ -3453,8 +3497,8 @@ var id = transition._id; transition.each(function() { - var schedule$$1 = set$1(this, id); - (schedule$$1.value || (schedule$$1.value = {}))[name] = value.apply(this, arguments); + var schedule = set$1(this, id); + (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments); }); return function(node) { @@ -3482,53 +3526,57 @@ }; } -function attrConstant$1(name, interpolate$$1, value1) { - var value00, +function attrConstant$1(name, interpolate, value1) { + var string00, + string1 = value1 + "", interpolate0; return function() { - var value0 = this.getAttribute(name); - return value0 === value1 ? null - : value0 === value00 ? interpolate0 - : interpolate0 = interpolate$$1(value00 = value0, value1); + var string0 = this.getAttribute(name); + return string0 === string1 ? null + : string0 === string00 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, value1); }; } -function attrConstantNS$1(fullname, interpolate$$1, value1) { - var value00, +function attrConstantNS$1(fullname, interpolate, value1) { + var string00, + string1 = value1 + "", interpolate0; return function() { - var value0 = this.getAttributeNS(fullname.space, fullname.local); - return value0 === value1 ? null - : value0 === value00 ? interpolate0 - : interpolate0 = interpolate$$1(value00 = value0, value1); + var string0 = this.getAttributeNS(fullname.space, fullname.local); + return string0 === string1 ? null + : string0 === string00 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, value1); }; } -function attrFunction$1(name, interpolate$$1, value) { - var value00, - value10, +function attrFunction$1(name, interpolate, value) { + var string00, + string10, interpolate0; return function() { - var value0, value1 = value(this); + var string0, value1 = value(this), string1; if (value1 == null) return void this.removeAttribute(name); - value0 = this.getAttribute(name); - return value0 === value1 ? null - : value0 === value00 && value1 === value10 ? interpolate0 - : interpolate0 = interpolate$$1(value00 = value0, value10 = value1); + string0 = this.getAttribute(name); + string1 = value1 + ""; + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1)); }; } -function attrFunctionNS$1(fullname, interpolate$$1, value) { - var value00, - value10, +function attrFunctionNS$1(fullname, interpolate, value) { + var string00, + string10, interpolate0; return function() { - var value0, value1 = value(this); + var string0, value1 = value(this), string1; if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local); - value0 = this.getAttributeNS(fullname.space, fullname.local); - return value0 === value1 ? null - : value0 === value00 && value1 === value10 ? interpolate0 - : interpolate0 = interpolate$$1(value00 = value0, value10 = value1); + string0 = this.getAttributeNS(fullname.space, fullname.local); + string1 = value1 + ""; + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1)); }; } @@ -3537,26 +3585,38 @@ return this.attrTween(name, typeof value === "function" ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value)) : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname) - : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value + "")); + : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value)); +} + +function attrInterpolate(name, i) { + return function(t) { + this.setAttribute(name, i.call(this, t)); + }; +} + +function attrInterpolateNS(fullname, i) { + return function(t) { + this.setAttributeNS(fullname.space, fullname.local, i.call(this, t)); + }; } function attrTweenNS(fullname, value) { + var t0, i0; function tween() { - var node = this, i = value.apply(node, arguments); - return i && function(t) { - node.setAttributeNS(fullname.space, fullname.local, i(t)); - }; + var i = value.apply(this, arguments); + if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i); + return t0; } tween._value = value; return tween; } function attrTween(name, value) { + var t0, i0; function tween() { - var node = this, i = value.apply(node, arguments); - return i && function(t) { - node.setAttribute(name, i(t)); - }; + var i = value.apply(this, arguments); + if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i); + return t0; } tween._value = value; return tween; @@ -3631,7 +3691,7 @@ } function transition_filter(match) { - if (typeof match !== "function") match = matcher$1(match); + if (typeof match !== "function") match = matcher(match); for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) { @@ -3644,10 +3704,10 @@ return new Transition(subgroups, this._parents, this._name, this._id); } -function transition_merge(transition$$1) { - if (transition$$1._id !== this._id) throw new Error; +function transition_merge(transition) { + if (transition._id !== this._id) throw new Error; - for (var groups0 = this._groups, groups1 = transition$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { + for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) { if (node = group0[i] || group1[i]) { merge[i] = node; @@ -3673,15 +3733,15 @@ function onFunction(id, name, listener) { var on0, on1, sit = start(name) ? init : set$1; return function() { - var schedule$$1 = sit(this, id), - on = schedule$$1.on; + var schedule = sit(this, id), + on = schedule.on; // If this node shared a dispatch with the previous node, // just assign the updated shared dispatch and we’re done! // Otherwise, copy-on-write. if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener); - schedule$$1.on = on1; + schedule.on = on1; }; } @@ -3705,15 +3765,15 @@ return this.on("end.remove", removeFunction(this._id)); } -function transition_select(select$$1) { +function transition_select(select) { var name = this._name, id = this._id; - if (typeof select$$1 !== "function") select$$1 = selector(select$$1); + if (typeof select !== "function") select = selector(select); for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) { - if ((node = group[i]) && (subnode = select$$1.call(node, node.__data__, i, group))) { + if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) { if ("__data__" in node) subnode.__data__ = node.__data__; subgroup[i] = subnode; schedule(subgroup[i], name, id, i, subgroup, get$1(node, id)); @@ -3724,16 +3784,16 @@ return new Transition(subgroups, this._parents, name, id); } -function transition_selectAll(select$$1) { +function transition_selectAll(select) { var name = this._name, id = this._id; - if (typeof select$$1 !== "function") select$$1 = selectorAll(select$$1); + if (typeof select !== "function") select = selectorAll(select); for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) { for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { if (node = group[i]) { - for (var children = select$$1.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) { + for (var children = select.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) { if (child = children[k]) { schedule(child, name, id, k, children, inherit); } @@ -3753,66 +3813,93 @@ return new Selection$1(this._groups, this._parents); } -function styleRemove$1(name, interpolate$$1) { - var value00, - value10, +function styleNull(name, interpolate) { + var string00, + string10, interpolate0; return function() { - var value0 = styleValue(this, name), - value1 = (this.style.removeProperty(name), styleValue(this, name)); - return value0 === value1 ? null - : value0 === value00 && value1 === value10 ? interpolate0 - : interpolate0 = interpolate$$1(value00 = value0, value10 = value1); + var string0 = styleValue(this, name), + string1 = (this.style.removeProperty(name), styleValue(this, name)); + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, string10 = string1); }; } -function styleRemoveEnd(name) { +function styleRemove$1(name) { return function() { this.style.removeProperty(name); }; } -function styleConstant$1(name, interpolate$$1, value1) { - var value00, +function styleConstant$1(name, interpolate, value1) { + var string00, + string1 = value1 + "", interpolate0; return function() { - var value0 = styleValue(this, name); - return value0 === value1 ? null - : value0 === value00 ? interpolate0 - : interpolate0 = interpolate$$1(value00 = value0, value1); + var string0 = styleValue(this, name); + return string0 === string1 ? null + : string0 === string00 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, value1); }; } -function styleFunction$1(name, interpolate$$1, value) { - var value00, - value10, +function styleFunction$1(name, interpolate, value) { + var string00, + string10, interpolate0; return function() { - var value0 = styleValue(this, name), - value1 = value(this); - if (value1 == null) value1 = (this.style.removeProperty(name), styleValue(this, name)); - return value0 === value1 ? null - : value0 === value00 && value1 === value10 ? interpolate0 - : interpolate0 = interpolate$$1(value00 = value0, value10 = value1); + var string0 = styleValue(this, name), + value1 = value(this), + string1 = value1 + ""; + if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name)); + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1)); + }; +} + +function styleMaybeRemove(id, name) { + var on0, on1, listener0, key = "style." + name, event = "end." + key, remove; + return function() { + var schedule = set$1(this, id), + on = schedule.on, + listener = schedule.value[key] == null ? remove || (remove = styleRemove$1(name)) : undefined; + + // If this node shared a dispatch with the previous node, + // just assign the updated shared dispatch and we’re done! + // Otherwise, copy-on-write. + if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener); + + schedule.on = on1; }; } function transition_style(name, value, priority) { var i = (name += "") === "transform" ? interpolateTransformCss : interpolate; return value == null ? this - .styleTween(name, styleRemove$1(name, i)) - .on("end.style." + name, styleRemoveEnd(name)) - : this.styleTween(name, typeof value === "function" - ? styleFunction$1(name, i, tweenValue(this, "style." + name, value)) - : styleConstant$1(name, i, value + ""), priority); + .styleTween(name, styleNull(name, i)) + .on("end.style." + name, styleRemove$1(name)) + : typeof value === "function" ? this + .styleTween(name, styleFunction$1(name, i, tweenValue(this, "style." + name, value))) + .each(styleMaybeRemove(this._id, name)) + : this + .styleTween(name, styleConstant$1(name, i, value), priority) + .on("end.style." + name, null); +} + +function styleInterpolate(name, i, priority) { + return function(t) { + this.style.setProperty(name, i.call(this, t), priority); + }; } function styleTween(name, value, priority) { + var t, i0; function tween() { - var node = this, i = value.apply(node, arguments); - return i && function(t) { - node.style.setProperty(name, i(t), priority); - }; + var i = value.apply(this, arguments); + if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority); + return t; } tween._value = value; return tween; @@ -3845,6 +3932,31 @@ : textConstant$1(value == null ? "" : value + "")); } +function textInterpolate(i) { + return function(t) { + this.textContent = i.call(this, t); + }; +} + +function textTween(value) { + var t0, i0; + function tween() { + var i = value.apply(this, arguments); + if (i !== i0) t0 = (i0 = i) && textInterpolate(i); + return t0; + } + tween._value = value; + return tween; +} + +function transition_textTween(value) { + var key = "text"; + if (arguments.length < 1) return (key = this.tween(key)) && key._value; + if (value == null) return this.tween(key, null); + if (typeof value !== "function") throw new Error; + return this.tween(key, textTween(value)); +} + function transition_transition() { var name = this._name, id0 = this._id, @@ -3867,6 +3979,31 @@ return new Transition(groups, this._parents, name, id1); } +function transition_end() { + var on0, on1, that = this, id = that._id, size = that.size(); + return new Promise(function(resolve, reject) { + var cancel = {value: reject}, + end = {value: function() { if (--size === 0) resolve(); }}; + + that.each(function() { + var schedule = set$1(this, id), + on = schedule.on; + + // If this node shared a dispatch with the previous node, + // just assign the updated shared dispatch and we’re done! + // Otherwise, copy-on-write. + if (on !== on0) { + on1 = (on0 = on).copy(); + on1._.cancel.push(cancel); + on1._.interrupt.push(cancel); + on1._.end.push(end); + } + + schedule.on = on1; + }); + }); +} + var id = 0; function Transition(groups, parents, name, id) { @@ -3906,11 +4043,13 @@ style: transition_style, styleTween: transition_styleTween, text: transition_text, + textTween: transition_textTween, remove: transition_remove, tween: transition_tween, delay: transition_delay, duration: transition_duration, - ease: transition_ease + ease: transition_ease, + end: transition_end }; function linear$1(t) { @@ -4169,13 +4308,13 @@ function active(node, name) { var schedules = node.__transition, - schedule$$1, + schedule, i; if (schedules) { name = name == null ? null : name + ""; for (i in schedules) { - if ((schedule$$1 = schedules[i]).state > SCHEDULED && schedule$$1.name === name) { + if ((schedule = schedules[i]).state > SCHEDULED && schedule.name === name) { return new Transition([[node]], root$1, name, +i); } } @@ -4210,24 +4349,38 @@ MODE_HANDLE = {name: "handle"}, MODE_CENTER = {name: "center"}; +function number1(e) { + return [+e[0], +e[1]]; +} + +function number2(e) { + return [number1(e[0]), number1(e[1])]; +} + +function toucher(identifier) { + return function(target) { + return touch(target, exports.event.touches, identifier); + }; +} + var X = { name: "x", - handles: ["e", "w"].map(type), - input: function(x, e) { return x && [[x[0], e[0][1]], [x[1], e[1][1]]]; }, + handles: ["w", "e"].map(type), + input: function(x, e) { return x == null ? null : [[+x[0], e[0][1]], [+x[1], e[1][1]]]; }, output: function(xy) { return xy && [xy[0][0], xy[1][0]]; } }; var Y = { name: "y", handles: ["n", "s"].map(type), - input: function(y, e) { return y && [[e[0][0], y[0]], [e[1][0], y[1]]]; }, + input: function(y, e) { return y == null ? null : [[e[0][0], +y[0]], [e[1][0], +y[1]]]; }, output: function(xy) { return xy && [xy[0][1], xy[1][1]]; } }; var XY = { name: "xy", - handles: ["n", "e", "s", "w", "nw", "ne", "se", "sw"].map(type), - input: function(xy) { return xy; }, + handles: ["n", "w", "e", "s", "nw", "ne", "sw", "se"].map(type), + input: function(xy) { return xy == null ? null : number2(xy); }, output: function(xy) { return xy; } }; @@ -4294,14 +4447,22 @@ // Ignore right-click, since that should open the context menu. function defaultFilter$1() { - return !exports.event.button; + return !exports.event.ctrlKey && !exports.event.button; } function defaultExtent() { var svg = this.ownerSVGElement || this; + if (svg.hasAttribute("viewBox")) { + svg = svg.viewBox.baseVal; + return [[svg.x, svg.y], [svg.x + svg.width, svg.y + svg.height]]; + } return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]]; } +function defaultTouchable$1() { + return navigator.maxTouchPoints || ("ontouchstart" in this); +} + // Like d3.local, but with the name “__brush” rather than auto-generated. function local$1(node) { while (!node.__brush) if (!(node = node.parentNode)) return; @@ -4333,7 +4494,9 @@ function brush$1(dim) { var extent = defaultExtent, filter = defaultFilter$1, - listeners = dispatch(brush, "start", "brush", "end"), + touchable = defaultTouchable$1, + keys = true, + listeners = dispatch("start", "brush", "end"), handleSize = 6, touchending; @@ -4380,11 +4543,16 @@ .each(redraw) .attr("fill", "none") .attr("pointer-events", "all") - .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)") - .on("mousedown.brush touchstart.brush", started); + .on("mousedown.brush", started) + .filter(touchable) + .on("touchstart.brush", started) + .on("touchmove.brush", touchmoved) + .on("touchend.brush touchcancel.brush", touchended) + .style("touch-action", "none") + .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)"); } - brush.move = function(group, selection$$1) { + brush.move = function(group, selection) { if (group.selection) { group .on("start.brush", function() { emitter(this, arguments).beforestart().start(); }) @@ -4394,16 +4562,16 @@ state = that.__brush, emit = emitter(that, arguments), selection0 = state.selection, - selection1 = dim.input(typeof selection$$1 === "function" ? selection$$1.apply(this, arguments) : selection$$1, state.extent), + selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent), i = interpolateValue(selection0, selection1); function tween(t) { - state.selection = t === 1 && empty$1(selection1) ? null : i(t); + state.selection = t === 1 && selection1 === null ? null : i(t); redraw.call(that); emit.brush(); } - return selection0 && selection1 ? tween : tween(1); + return selection0 !== null && selection1 !== null ? tween : tween(1); }); } else { group @@ -4411,35 +4579,39 @@ var that = this, args = arguments, state = that.__brush, - selection1 = dim.input(typeof selection$$1 === "function" ? selection$$1.apply(that, args) : selection$$1, state.extent), + selection1 = dim.input(typeof selection === "function" ? selection.apply(that, args) : selection, state.extent), emit = emitter(that, args).beforestart(); interrupt(that); - state.selection = selection1 == null || empty$1(selection1) ? null : selection1; + state.selection = selection1 === null ? null : selection1; redraw.call(that); emit.start().brush().end(); }); } }; + brush.clear = function(group) { + brush.move(group, null); + }; + function redraw() { var group = select(this), - selection$$1 = local$1(this).selection; + selection = local$1(this).selection; - if (selection$$1) { + if (selection) { group.selectAll(".selection") .style("display", null) - .attr("x", selection$$1[0][0]) - .attr("y", selection$$1[0][1]) - .attr("width", selection$$1[1][0] - selection$$1[0][0]) - .attr("height", selection$$1[1][1] - selection$$1[0][1]); + .attr("x", selection[0][0]) + .attr("y", selection[0][1]) + .attr("width", selection[1][0] - selection[0][0]) + .attr("height", selection[1][1] - selection[0][1]); group.selectAll(".handle") .style("display", null) - .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection$$1[1][0] - handleSize / 2 : selection$$1[0][0] - handleSize / 2; }) - .attr("y", function(d) { return d.type[0] === "s" ? selection$$1[1][1] - handleSize / 2 : selection$$1[0][1] - handleSize / 2; }) - .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection$$1[1][0] - selection$$1[0][0] + handleSize : handleSize; }) - .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection$$1[1][1] - selection$$1[0][1] + handleSize : handleSize; }); + .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection[1][0] - handleSize / 2 : selection[0][0] - handleSize / 2; }) + .attr("y", function(d) { return d.type[0] === "s" ? selection[1][1] - handleSize / 2 : selection[0][1] - handleSize / 2; }) + .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection[1][0] - selection[0][0] + handleSize : handleSize; }) + .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection[1][1] - selection[0][1] + handleSize : handleSize; }); } else { @@ -4452,8 +4624,8 @@ } } - function emitter(that, args) { - return that.__brush.emitter || new Emitter(that, args); + function emitter(that, args, clean) { + return (!clean && that.__brush.emitter) || new Emitter(that, args); } function Emitter(that, args) { @@ -4470,6 +4642,7 @@ }, start: function() { if (this.starting) this.starting = false, this.emit("start"); + else this.emit("brush"); return this; }, brush: function() { @@ -4486,42 +4659,43 @@ }; function started() { - if (exports.event.touches) { if (exports.event.changedTouches.length < exports.event.touches.length) return noevent$1(); } - else if (touchending) return; + if (touchending && !exports.event.touches) return; if (!filter.apply(this, arguments)) return; var that = this, type = exports.event.target.__data__.type, - mode = (exports.event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (exports.event.altKey ? MODE_CENTER : MODE_HANDLE), + mode = (keys && exports.event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (keys && exports.event.altKey ? MODE_CENTER : MODE_HANDLE), signX = dim === Y ? null : signsX[type], signY = dim === X ? null : signsY[type], state = local$1(that), extent = state.extent, - selection$$1 = state.selection, + selection = state.selection, W = extent[0][0], w0, w1, N = extent[0][1], n0, n1, E = extent[1][0], e0, e1, S = extent[1][1], s0, s1, - dx, - dy, + dx = 0, + dy = 0, moving, - shifting = signX && signY && exports.event.shiftKey, + shifting = signX && signY && keys && exports.event.shiftKey, lockX, lockY, - point0 = mouse(that), - point$$1 = point0, - emit = emitter(that, arguments).beforestart(); + pointer = exports.event.touches ? toucher(exports.event.changedTouches[0].identifier) : mouse, + point0 = pointer(that), + point = point0, + emit = emitter(that, arguments, true).beforestart(); if (type === "overlay") { - state.selection = selection$$1 = [ + if (selection) moving = true; + state.selection = selection = [ [w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]], [e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0] ]; } else { - w0 = selection$$1[0][0]; - n0 = selection$$1[0][1]; - e0 = selection$$1[1][0]; - s0 = selection$$1[1][1]; + w0 = selection[0][0]; + n0 = selection[0][1]; + e0 = selection[1][0]; + s0 = selection[1][1]; } w1 = w0; @@ -4536,15 +4710,15 @@ .attr("cursor", cursors[type]); if (exports.event.touches) { - group - .on("touchmove.brush", moved, true) - .on("touchend.brush touchcancel.brush", ended, true); + emit.moved = moved; + emit.ended = ended; } else { var view = select(exports.event.view) - .on("keydown.brush", keydowned, true) - .on("keyup.brush", keyupped, true) .on("mousemove.brush", moved, true) .on("mouseup.brush", ended, true); + if (keys) view + .on("keydown.brush", keydowned, true) + .on("keyup.brush", keyupped, true); dragDisable(exports.event.view); } @@ -4555,12 +4729,12 @@ emit.start(); function moved() { - var point1 = mouse(that); + var point1 = pointer(that); if (shifting && !lockX && !lockY) { - if (Math.abs(point1[0] - point$$1[0]) > Math.abs(point1[1] - point$$1[1])) lockY = true; + if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true; else lockX = true; } - point$$1 = point1; + point = point1; moving = true; noevent$1(); move(); @@ -4569,8 +4743,8 @@ function move() { var t; - dx = point$$1[0] - point0[0]; - dy = point$$1[1] - point0[1]; + dx = point[0] - point0[0]; + dy = point[1] - point0[1]; switch (mode) { case MODE_SPACE: @@ -4607,14 +4781,14 @@ if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]); } - if (state.selection) selection$$1 = state.selection; // May be set by brush.move! - if (lockX) w1 = selection$$1[0][0], e1 = selection$$1[1][0]; - if (lockY) n1 = selection$$1[0][1], s1 = selection$$1[1][1]; + if (state.selection) selection = state.selection; // May be set by brush.move! + if (lockX) w1 = selection[0][0], e1 = selection[1][0]; + if (lockY) n1 = selection[0][1], s1 = selection[1][1]; - if (selection$$1[0][0] !== w1 - || selection$$1[0][1] !== n1 - || selection$$1[1][0] !== e1 - || selection$$1[1][1] !== s1) { + if (selection[0][0] !== w1 + || selection[0][1] !== n1 + || selection[1][0] !== e1 + || selection[1][1] !== s1) { state.selection = [[w1, n1], [e1, s1]]; redraw.call(that); emit.brush(); @@ -4627,15 +4801,14 @@ if (exports.event.touches.length) return; if (touchending) clearTimeout(touchending); touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed! - group.on("touchmove.brush touchend.brush touchcancel.brush", null); } else { yesdrag(exports.event.view, moving); view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null); } group.attr("pointer-events", "all"); overlay.attr("cursor", cursors.overlay); - if (state.selection) selection$$1 = state.selection; // May be set by brush.move (on start)! - if (empty$1(selection$$1)) state.selection = null, redraw.call(that); + if (state.selection) selection = state.selection; // May be set by brush.move (on start)! + if (empty$1(selection)) state.selection = null, redraw.call(that); emit.end(); } @@ -4709,25 +4882,41 @@ } } + function touchmoved() { + emitter(this, arguments).moved(); + } + + function touchended() { + emitter(this, arguments).ended(); + } + function initialize() { var state = this.__brush || {selection: null}; - state.extent = extent.apply(this, arguments); + state.extent = number2(extent.apply(this, arguments)); state.dim = dim; return state; } brush.extent = function(_) { - return arguments.length ? (extent = typeof _ === "function" ? _ : constant$4([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), brush) : extent; + return arguments.length ? (extent = typeof _ === "function" ? _ : constant$4(number2(_)), brush) : extent; }; brush.filter = function(_) { return arguments.length ? (filter = typeof _ === "function" ? _ : constant$4(!!_), brush) : filter; }; + brush.touchable = function(_) { + return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$4(!!_), brush) : touchable; + }; + brush.handleSize = function(_) { return arguments.length ? (handleSize = +_, brush) : handleSize; }; + brush.keyModifiers = function(_) { + return arguments.length ? (keys = !!_, brush) : keys; + }; + brush.on = function() { var value = listeners.on.apply(listeners, arguments); return value === listeners ? brush : value; @@ -4954,7 +5143,7 @@ } }, arc: function(x, y, r, a0, a1, ccw) { - x = +x, y = +y, r = +r; + x = +x, y = +y, r = +r, ccw = !!ccw; var dx = r * Math.cos(a0), dy = r * Math.sin(a0), x0 = x + dx, @@ -5354,11 +5543,11 @@ function contours() { var dx = 1, dy = 1, - threshold$$1 = thresholdSturges, + threshold = thresholdSturges, smooth = smoothLinear; function contours(values) { - var tz = threshold$$1(values); + var tz = threshold(values); // Convert number of thresholds into uniform thresholds. if (!Array.isArray(tz)) { @@ -5518,7 +5707,7 @@ }; contours.thresholds = function(_) { - return arguments.length ? (threshold$$1 = typeof _ === "function" ? _ : Array.isArray(_) ? constant$6(slice$3.call(_)) : constant$6(_), contours) : threshold$$1; + return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant$6(slice$3.call(_)) : constant$6(_), contours) : threshold; }; contours.smooth = function(_) { @@ -5595,7 +5784,7 @@ o = r * 3, // grid offset, to pad for blur n = (dx + o * 2) >> k, // grid width m = (dy + o * 2) >> k, // grid height - threshold$$1 = constant$6(20); + threshold = constant$6(20); function density(data) { var values0 = new Float32Array(n * m), @@ -5618,7 +5807,7 @@ blurX({width: n, height: m, data: values0}, {width: n, height: m, data: values1}, r >> k); blurY({width: n, height: m, data: values1}, {width: n, height: m, data: values0}, r >> k); - var tz = threshold$$1(values0); + var tz = threshold(values0); // Convert number of thresholds into uniform thresholds. if (!Array.isArray(tz)) { @@ -5688,7 +5877,7 @@ }; density.thresholds = function(_) { - return arguments.length ? (threshold$$1 = typeof _ === "function" ? _ : Array.isArray(_) ? constant$6(slice$3.call(_)) : constant$6(_), density) : threshold$$1; + return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant$6(slice$3.call(_)) : constant$6(_), density) : threshold; }; density.bandwidth = function(_) { @@ -5708,7 +5897,7 @@ function objectConverter(columns) { return new Function("d", "return {" + columns.map(function(name, i) { - return JSON.stringify(name) + ": d[" + i + "]"; + return JSON.stringify(name) + ": d[" + i + "] || \"\""; }).join(",") + "}"); } @@ -5735,6 +5924,30 @@ return columns; } +function pad(value, width) { + var s = value + "", length = s.length; + return length < width ? new Array(width - length + 1).join(0) + s : s; +} + +function formatYear(year) { + return year < 0 ? "-" + pad(-year, 6) + : year > 9999 ? "+" + pad(year, 6) + : pad(year, 4); +} + +function formatDate(date) { + var hours = date.getUTCHours(), + minutes = date.getUTCMinutes(), + seconds = date.getUTCSeconds(), + milliseconds = date.getUTCMilliseconds(); + return isNaN(date) ? "Invalid Date" + : formatYear(date.getUTCFullYear()) + "-" + pad(date.getUTCMonth() + 1, 2) + "-" + pad(date.getUTCDate(), 2) + + (milliseconds ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + "." + pad(milliseconds, 3) + "Z" + : seconds ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2) + "Z" + : minutes || hours ? "T" + pad(hours, 2) + ":" + pad(minutes, 2) + "Z" + : ""); +} + function dsvFormat(delimiter) { var reFormat = new RegExp("[\"" + delimiter + "\n\r]"), DELIMITER = delimiter.charCodeAt(0); @@ -5797,13 +6010,22 @@ return rows; } - function format(rows, columns) { - if (columns == null) columns = inferColumns(rows); - return [columns.map(formatValue).join(delimiter)].concat(rows.map(function(row) { + function preformatBody(rows, columns) { + return rows.map(function(row) { return columns.map(function(column) { return formatValue(row[column]); }).join(delimiter); - })).join("\n"); + }); + } + + function format(rows, columns) { + if (columns == null) columns = inferColumns(rows); + return [columns.map(formatValue).join(delimiter)].concat(preformatBody(rows, columns)).join("\n"); + } + + function formatBody(rows, columns) { + if (columns == null) columns = inferColumns(rows); + return preformatBody(rows, columns).join("\n"); } function formatRows(rows) { @@ -5814,17 +6036,21 @@ return row.map(formatValue).join(delimiter); } - function formatValue(text) { - return text == null ? "" - : reFormat.test(text += "") ? "\"" + text.replace(/"/g, "\"\"") + "\"" - : text; + function formatValue(value) { + return value == null ? "" + : value instanceof Date ? formatDate(value) + : reFormat.test(value += "") ? "\"" + value.replace(/"/g, "\"\"") + "\"" + : value; } return { parse: parse, parseRows: parseRows, format: format, - formatRows: formatRows + formatBody: formatBody, + formatRows: formatRows, + formatRow: formatRow, + formatValue: formatValue }; } @@ -5833,14 +6059,41 @@ var csvParse = csv.parse; var csvParseRows = csv.parseRows; var csvFormat = csv.format; +var csvFormatBody = csv.formatBody; var csvFormatRows = csv.formatRows; +var csvFormatRow = csv.formatRow; +var csvFormatValue = csv.formatValue; var tsv = dsvFormat("\t"); var tsvParse = tsv.parse; var tsvParseRows = tsv.parseRows; var tsvFormat = tsv.format; +var tsvFormatBody = tsv.formatBody; var tsvFormatRows = tsv.formatRows; +var tsvFormatRow = tsv.formatRow; +var tsvFormatValue = tsv.formatValue; + +function autoType(object) { + for (var key in object) { + var value = object[key].trim(), number, m; + if (!value) value = null; + else if (value === "true") value = true; + else if (value === "false") value = false; + else if (value === "NaN") value = NaN; + else if (!isNaN(number = +value)) value = number; + else if (m = value.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)) { + if (fixtz && !!m[4] && !m[7]) value = value.replace(/-/g, "/").replace(/T/, " "); + value = new Date(value); + } + else continue; + object[key] = value; + } + return object; +} + +// https://github.com/d3/d3-dsv/issues/45 +var fixtz = new Date("2019-01-01T00:00").getHours() || new Date("2019-07-01T00:00").getHours(); function responseBlob(response) { if (!response.ok) throw new Error(response.status + " " + response.statusText); @@ -5910,8 +6163,8 @@ function parser(type) { return function(input, init) { - return text(input, init).then(function(text$$1) { - return (new DOMParser).parseFromString(text$$1, type); + return text(input, init).then(function(text) { + return (new DOMParser).parseFromString(text, type); }); }; } @@ -6040,9 +6293,8 @@ if (y > y1) y1 = y; } - // If there were no (valid) points, inherit the existing extent. - if (x1 < x0) x0 = this._x0, x1 = this._x1; - if (y1 < y0) y0 = this._y0, y1 = this._y1; + // If there were no (valid) points, abort. + if (x0 > x1 || y0 > y1) return this; // Expand the tree to cover the new points. this.cover(x0, y0).cover(x1, y1); @@ -6072,41 +6324,26 @@ } // Otherwise, double repeatedly to cover. - else if (x0 > x || x > x1 || y0 > y || y > y1) { + else { var z = x1 - x0, node = this._root, parent, i; - switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) { - case 0: { - do parent = new Array(4), parent[i] = node, node = parent; - while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1); - break; - } - case 1: { - do parent = new Array(4), parent[i] = node, node = parent; - while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1); - break; - } - case 2: { - do parent = new Array(4), parent[i] = node, node = parent; - while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y); - break; - } - case 3: { - do parent = new Array(4), parent[i] = node, node = parent; - while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y); - break; + while (x0 > x || x >= x1 || y0 > y || y >= y1) { + i = (y < y0) << 1 | (x < x0); + parent = new Array(4), parent[i] = node, node = parent, z *= 2; + switch (i) { + case 0: x1 = x0 + z, y1 = y0 + z; break; + case 1: x0 = x1 - z, y1 = y0 + z; break; + case 2: x1 = x0 + z, y0 = y1 - z; break; + case 3: x0 = x1 - z, y0 = y1 - z; break; } } if (this._root && this._root.length) this._root = node; } - // If the quadtree covers the point already, just return. - else return this; - this._x0 = x0; this._y0 = y0; this._x1 = x1; @@ -6633,27 +6870,35 @@ } } - function tick() { + function tick(iterations) { var i, n = nodes.length, node; - alpha += (alphaTarget - alpha) * alphaDecay; + if (iterations === undefined) iterations = 1; - forces.each(function(force) { - force(alpha); - }); + for (var k = 0; k < iterations; ++k) { + alpha += (alphaTarget - alpha) * alphaDecay; - for (i = 0; i < n; ++i) { - node = nodes[i]; - if (node.fx == null) node.x += node.vx *= velocityDecay; - else node.x = node.fx, node.vx = 0; - if (node.fy == null) node.y += node.vy *= velocityDecay; - else node.y = node.fy, node.vy = 0; + forces.each(function (force) { + force(alpha); + }); + + for (i = 0; i < n; ++i) { + node = nodes[i]; + if (node.fx == null) node.x += node.vx *= velocityDecay; + else node.x = node.fx, node.vx = 0; + if (node.fy == null) node.y += node.vy *= velocityDecay; + else node.y = node.fy, node.vy = 0; + } } + + return simulation; } function initializeNodes() { for (var i = 0, n = nodes.length, node; i < n; ++i) { node = nodes[i], node.index = i; + if (node.fx != null) node.x = node.fx; + if (node.fy != null) node.y = node.fy; if (isNaN(node.x) || isNaN(node.y)) { var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle; node.x = radius * Math.cos(angle); @@ -7036,24 +7281,35 @@ var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i; function formatSpecifier(specifier) { - return new FormatSpecifier(specifier); + if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier); + var match; + return new FormatSpecifier({ + fill: match[1], + align: match[2], + sign: match[3], + symbol: match[4], + zero: match[5], + width: match[6], + comma: match[7], + precision: match[8] && match[8].slice(1), + trim: match[9], + type: match[10] + }); } formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof function FormatSpecifier(specifier) { - if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier); - var match; - this.fill = match[1] || " "; - this.align = match[2] || ">"; - this.sign = match[3] || "-"; - this.symbol = match[4] || ""; - this.zero = !!match[5]; - this.width = match[6] && +match[6]; - this.comma = !!match[7]; - this.precision = match[8] && +match[8].slice(1); - this.trim = !!match[9]; - this.type = match[10] || ""; + this.fill = specifier.fill === undefined ? " " : specifier.fill + ""; + this.align = specifier.align === undefined ? ">" : specifier.align + ""; + this.sign = specifier.sign === undefined ? "-" : specifier.sign + ""; + this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + ""; + this.zero = !!specifier.zero; + this.width = specifier.width === undefined ? undefined : +specifier.width; + this.comma = !!specifier.comma; + this.precision = specifier.precision === undefined ? undefined : +specifier.precision; + this.trim = !!specifier.trim; + this.type = specifier.type === undefined ? "" : specifier.type + ""; } FormatSpecifier.prototype.toString = function() { @@ -7062,9 +7318,9 @@ + this.sign + this.symbol + (this.zero ? "0" : "") - + (this.width == null ? "" : Math.max(1, this.width | 0)) + + (this.width === undefined ? "" : Math.max(1, this.width | 0)) + (this.comma ? "," : "") - + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0)) + + (this.precision === undefined ? "" : "." + Math.max(0, this.precision | 0)) + (this.trim ? "~" : "") + this.type; }; @@ -7075,7 +7331,7 @@ switch (s[i]) { case ".": i0 = i1 = i; break; case "0": if (i0 === 0) i0 = i; i1 = i; break; - default: if (i0 > 0) { if (!+s[i]) break out; i0 = 0; } break; + default: if (!+s[i]) break out; if (i0 > 0) i0 = 0; break; } } return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s; @@ -7126,14 +7382,18 @@ return x; } -var prefixes = ["y","z","a","f","p","n","\xB5","m","","k","M","G","T","P","E","Z","Y"]; +var map$2 = Array.prototype.map, + prefixes = ["y","z","a","f","p","n","\xB5","m","","k","M","G","T","P","E","Z","Y"]; function formatLocale(locale) { - var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3, - currency = locale.currency, - decimal = locale.decimal, - numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$3, - percent = locale.percent || "%"; + var group = locale.grouping === undefined || locale.thousands === undefined ? identity$3 : formatGroup(map$2.call(locale.grouping, Number), locale.thousands + ""), + currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "", + currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "", + decimal = locale.decimal === undefined ? "." : locale.decimal + "", + numerals = locale.numerals === undefined ? identity$3 : formatNumerals(map$2.call(locale.numerals, String)), + percent = locale.percent === undefined ? "%" : locale.percent + "", + minus = locale.minus === undefined ? "-" : locale.minus + "", + nan = locale.nan === undefined ? "NaN" : locale.nan + ""; function newFormat(specifier) { specifier = formatSpecifier(specifier); @@ -7153,15 +7413,15 @@ if (type === "n") comma = true, type = "g"; // The "" type, and any invalid type, is an alias for ".12~g". - else if (!formatTypes[type]) precision == null && (precision = 12), trim = true, type = "g"; + else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g"; // If zero fill is specified, padding goes after sign and before digits. if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "="; // Compute the prefix and suffix. // For SI-prefix, the suffix is lazily computed. - var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "", - suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : ""; + var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "", + suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : ""; // What format function should we use? // Is this an integer type? @@ -7173,7 +7433,7 @@ // or clamp the specified precision to the supported range. // For significant precision, it must be in [1, 21]. // For fixed precision, it must be in [0, 20]. - precision = precision == null ? 6 + precision = precision === undefined ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision)); @@ -7188,18 +7448,20 @@ } else { value = +value; + // Determine the sign. -0 is not less than 0, but 1 / -0 is! + var valueNegative = value < 0 || 1 / value < 0; + // Perform the initial formatting. - var valueNegative = value < 0; - value = formatType(Math.abs(value), precision); + value = isNaN(value) ? nan : formatType(Math.abs(value), precision); // Trim insignificant zeros. if (trim) value = formatTrim(value); - // If a negative value rounds to zero during formatting, treat as positive. - if (valueNegative && +value === 0) valueNegative = false; + // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign. + if (valueNegative && +value === 0 && sign !== "+") valueNegative = false; // Compute the prefix and suffix. - valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix; + valuePrefix = (valueNegative ? (sign === "(" ? sign : minus) : sign === "-" || sign === "(" ? "" : sign) + valuePrefix; valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : ""); // Break the formatted value into the integer “value” part that can be @@ -7266,7 +7528,8 @@ decimal: ".", thousands: ",", grouping: [3], - currency: ["$", ""] + currency: ["$", ""], + minus: "-" }); function defaultLocale(definition) { @@ -7567,6 +7830,9 @@ else if (deltaSum > epsilon$2) phi1 = 90; else if (deltaSum < -epsilon$2) phi0 = -90; range[0] = lambda0$1, range[1] = lambda1; + }, + sphere: function() { + lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90); } }; @@ -7585,14 +7851,14 @@ cartesianNormalizeInPlace(inflection); inflection = spherical(inflection); var delta = lambda - lambda2, - sign$$1 = delta > 0 ? 1 : -1, - lambdai = inflection[0] * degrees$1 * sign$$1, + sign = delta > 0 ? 1 : -1, + lambdai = inflection[0] * degrees$1 * sign, phii, antimeridian = abs(delta) > 180; - if (antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) { + if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) { phii = inflection[1] * degrees$1; if (phii > phi1) phi1 = phii; - } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) { + } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) { phii = -inflection[1] * degrees$1; if (phii < phi0) phi0 = phii; } else { @@ -7867,7 +8133,7 @@ } function rotationIdentity(lambda, phi) { - return [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi]; + return [abs(lambda) > pi$3 ? lambda + Math.round(-lambda / tau$3) * tau$3 : lambda, phi]; } rotationIdentity.invert = rotationIdentity; @@ -8137,8 +8403,15 @@ var sum$1 = adder(); +function longitude(point) { + if (abs(point[0]) <= pi$3) + return point[0]; + else + return sign(point[0]) * ((abs(point[0]) + pi$3) % tau$3 - pi$3); +} + function polygonContains(polygon, point) { - var lambda = point[0], + var lambda = longitude(point), phi = point[1], sinPhi = sin$1(phi), normal = [sin$1(lambda), -cos$1(lambda), 0], @@ -8155,25 +8428,25 @@ var ring, m, point0 = ring[m - 1], - lambda0 = point0[0], + lambda0 = longitude(point0), phi0 = point0[1] / 2 + quarterPi, sinPhi0 = sin$1(phi0), cosPhi0 = cos$1(phi0); for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) { var point1 = ring[j], - lambda1 = point1[0], + lambda1 = longitude(point1), phi1 = point1[1] / 2 + quarterPi, sinPhi1 = sin$1(phi1), cosPhi1 = cos$1(phi1), delta = lambda1 - lambda0, - sign$$1 = delta >= 0 ? 1 : -1, - absDelta = sign$$1 * delta, + sign = delta >= 0 ? 1 : -1, + absDelta = sign * delta, antimeridian = absDelta > pi$3, k = sinPhi0 * sinPhi1; - sum$1.add(atan2(k * sign$$1 * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta))); - angle += antimeridian ? delta + sign$$1 * tau$3 : delta; + sum$1.add(atan2(k * sign * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta))); + angle += antimeridian ? delta + sign * tau$3 : delta; // Are the longitudes either side of the point’s meridian (lambda), // and are the latitudes smaller than the parallel (phi)? @@ -8954,10 +9227,23 @@ } function containsLine(coordinates, point) { - var ab = distance(coordinates[0], coordinates[1]), - ao = distance(coordinates[0], point), - ob = distance(point, coordinates[1]); - return ao + ob <= ab + epsilon$2; + var ao, bo, ab; + for (var i = 0, n = coordinates.length; i < n; i++) { + bo = distance(coordinates[i], point); + if (bo === 0) return true; + if (i > 0) { + ab = distance(coordinates[i], coordinates[i - 1]); + if ( + ab > 0 && + ao <= ab && + bo <= ab && + (ao + bo - ab) * (1 - Math.pow((ao - bo) / ab, 2)) < epsilon2$1 * ab + ) + return true; + } + ao = bo; + } + return false; } function containsPolygon(coordinates, point) { @@ -9669,17 +9955,18 @@ }); } -function scaleTranslate(k, dx, dy) { - function transform$$1(x, y) { +function scaleTranslate(k, dx, dy, sx, sy) { + function transform(x, y) { + x *= sx; y *= sy; return [dx + k * x, dy - k * y]; } - transform$$1.invert = function(x, y) { - return [(x - dx) / k, (dy - y) / k]; + transform.invert = function(x, y) { + return [(x - dx) / k * sx, (dy - y) / k * sy]; }; - return transform$$1; + return transform; } -function scaleTranslateRotate(k, dx, dy, alpha) { +function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) { var cosAlpha = cos$1(alpha), sinAlpha = sin$1(alpha), a = cosAlpha * k, @@ -9688,13 +9975,14 @@ bi = sinAlpha / k, ci = (sinAlpha * dy - cosAlpha * dx) / k, fi = (sinAlpha * dx + cosAlpha * dy) / k; - function transform$$1(x, y) { + function transform(x, y) { + x *= sx; y *= sy; return [a * x - b * y + dx, dy - b * x - a * y]; } - transform$$1.invert = function(x, y) { - return [ai * x - bi * y + ci, fi - bi * x - ai * y]; + transform.invert = function(x, y) { + return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)]; }; - return transform$$1; + return transform; } function projection(project) { @@ -9707,7 +9995,9 @@ x = 480, y = 250, // translate lambda = 0, phi = 0, // center deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, // pre-rotate - alpha = 0, // post-rotate + alpha = 0, // post-rotate angle + sx = 1, // reflectX + sy = 1, // reflectX theta = null, preclip = clipAntimeridian, // pre-clip angle x0 = null, y0, x1, y1, postclip = identity$4, // post-clip extent delta2 = 0.5, // precision @@ -9766,6 +10056,14 @@ return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees$1; }; + projection.reflectX = function(_) { + return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0; + }; + + projection.reflectY = function(_) { + return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0; + }; + projection.precision = function(_) { return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2); }; @@ -9787,10 +10085,10 @@ }; function recenter() { - var center = scaleTranslateRotate(k, 0, 0, alpha).apply(null, project(lambda, phi)), - transform$$1 = (alpha ? scaleTranslateRotate : scaleTranslate)(k, x - center[0], y - center[1], alpha); + var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)), + transform = (alpha ? scaleTranslateRotate : scaleTranslate)(k, x - center[0], y - center[1], sx, sy, alpha); rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma); - projectTransform = compose(project, transform$$1); + projectTransform = compose(project, transform); projectRotateTransform = compose(rotate, projectTransform); projectResample = resample(projectTransform, delta2); return reset(); @@ -9849,8 +10147,11 @@ } project.invert = function(x, y) { - var r0y = r0 - y; - return [atan2(x, abs(r0y)) / n * sign(r0y), asin((c - (x * x + r0y * r0y) * n * n) / (2 * n))]; + var r0y = r0 - y, + l = atan2(x, abs(r0y)) * sign(r0y); + if (r0y * n < 0) + l -= pi$3 * sign(x) * sign(r0y); + return [l / n, asin((c - (x * x + r0y * r0y) * n * n) / (2 * n))]; }; return project; @@ -10099,8 +10400,11 @@ } project.invert = function(x, y) { - var fy = f - y, r = sign(n) * sqrt(x * x + fy * fy); - return [atan2(x, abs(fy)) / n * sign(fy), 2 * atan(pow(f / r, 1 / n)) - halfPi$2]; + var fy = f - y, r = sign(n) * sqrt(x * x + fy * fy), + l = atan2(x, abs(fy)) * sign(fy); + if (fy * n < 0) + l -= pi$3 * sign(x) * sign(fy); + return [l / n, 2 * atan(pow(f / r, 1 / n)) - halfPi$2]; }; return project; @@ -10136,8 +10440,11 @@ } project.invert = function(x, y) { - var gy = g - y; - return [atan2(x, abs(gy)) / n * sign(gy), g - sign(n) * sqrt(x * x + gy * gy)]; + var gy = g - y, + l = atan2(x, abs(gy)) * sign(gy); + if (gy * n < 0) + l -= pi$3 * sign(x) * sign(gy); + return [l / n, g - sign(n) * sqrt(x * x + gy * gy)]; }; return project; @@ -10196,62 +10503,84 @@ .clipAngle(60); } -function scaleTranslate$1(kx, ky, tx, ty) { - return kx === 1 && ky === 1 && tx === 0 && ty === 0 ? identity$4 : transformer({ - point: function(x, y) { - this.stream.point(x * kx + tx, y * ky + ty); - } - }); -} - function identity$5() { - var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, transform$$1 = identity$4, // scale, translate and reflect + var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, // scale, translate and reflect + alpha = 0, ca, sa, // angle x0 = null, y0, x1, y1, // clip extent + kx = 1, ky = 1, + transform = transformer({ + point: function(x, y) { + var p = projection([x, y]); + this.stream.point(p[0], p[1]); + } + }), postclip = identity$4, cache, - cacheStream, - projection; + cacheStream; function reset() { + kx = k * sx; + ky = k * sy; cache = cacheStream = null; return projection; } - return projection = { - stream: function(stream) { - return cache && cacheStream === stream ? cache : cache = transform$$1(postclip(cacheStream = stream)); - }, - postclip: function(_) { - return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip; - }, - clipExtent: function(_) { - return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]]; - }, - scale: function(_) { - return arguments.length ? (transform$$1 = scaleTranslate$1((k = +_) * sx, k * sy, tx, ty), reset()) : k; - }, - translate: function(_) { - return arguments.length ? (transform$$1 = scaleTranslate$1(k * sx, k * sy, tx = +_[0], ty = +_[1]), reset()) : [tx, ty]; - }, - reflectX: function(_) { - return arguments.length ? (transform$$1 = scaleTranslate$1(k * (sx = _ ? -1 : 1), k * sy, tx, ty), reset()) : sx < 0; - }, - reflectY: function(_) { - return arguments.length ? (transform$$1 = scaleTranslate$1(k * sx, k * (sy = _ ? -1 : 1), tx, ty), reset()) : sy < 0; - }, - fitExtent: function(extent, object) { - return fitExtent(projection, extent, object); - }, - fitSize: function(size, object) { - return fitSize(projection, size, object); - }, - fitWidth: function(width, object) { - return fitWidth(projection, width, object); - }, - fitHeight: function(height, object) { - return fitHeight(projection, height, object); + function projection (p) { + var x = p[0] * kx, y = p[1] * ky; + if (alpha) { + var t = y * ca - x * sa; + x = x * ca + y * sa; + y = t; + } + return [x + tx, y + ty]; + } + projection.invert = function(p) { + var x = p[0] - tx, y = p[1] - ty; + if (alpha) { + var t = y * ca + x * sa; + x = x * ca - y * sa; + y = t; } + return [x / kx, y / ky]; }; + projection.stream = function(stream) { + return cache && cacheStream === stream ? cache : cache = transform(postclip(cacheStream = stream)); + }; + projection.postclip = function(_) { + return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip; + }; + projection.clipExtent = function(_) { + return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]]; + }; + projection.scale = function(_) { + return arguments.length ? (k = +_, reset()) : k; + }; + projection.translate = function(_) { + return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty]; + }; + projection.angle = function(_) { + return arguments.length ? (alpha = _ % 360 * radians, sa = sin$1(alpha), ca = cos$1(alpha), reset()) : alpha * degrees$1; + }; + projection.reflectX = function(_) { + return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0; + }; + projection.reflectY = function(_) { + return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0; + }; + projection.fitExtent = function(extent, object) { + return fitExtent(projection, extent, object); + }; + projection.fitSize = function(size, object) { + return fitSize(projection, size, object); + }; + projection.fitWidth = function(width, object) { + return fitWidth(projection, width, object); + }; + projection.fitHeight = function(height, object) { + return fitHeight(projection, height, object); + }; + + return projection; } function naturalEarth1Raw(lambda, phi) { @@ -11828,20 +12157,37 @@ return randomExponential; })(defaultSource$1); +function initRange(domain, range) { + switch (arguments.length) { + case 0: break; + case 1: this.range(domain); break; + default: this.range(range).domain(domain); break; + } + return this; +} + +function initInterpolator(domain, interpolator) { + switch (arguments.length) { + case 0: break; + case 1: this.interpolator(domain); break; + default: this.interpolator(interpolator).domain(domain); break; + } + return this; +} + var array$3 = Array.prototype; -var map$2 = array$3.map; +var map$3 = array$3.map; var slice$5 = array$3.slice; var implicit = {name: "implicit"}; -function ordinal(range) { +function ordinal() { var index = map$1(), domain = [], + range = [], unknown = implicit; - range = range == null ? [] : slice$5.call(range); - function scale(d) { var key = d + "", i = index.get(key); if (!i) { @@ -11868,12 +12214,11 @@ }; scale.copy = function() { - return ordinal() - .domain(domain) - .range(range) - .unknown(unknown); + return ordinal(domain, range).unknown(unknown); }; + initRange.apply(scale, arguments); + return scale; } @@ -11881,7 +12226,7 @@ var scale = ordinal().unknown(undefined), domain = scale.domain, ordinalRange = scale.range, - range$$1 = [0, 1], + range = [0, 1], step, bandwidth, round = false, @@ -11893,9 +12238,9 @@ function rescale() { var n = domain().length, - reverse = range$$1[1] < range$$1[0], - start = range$$1[reverse - 0], - stop = range$$1[1 - reverse]; + reverse = range[1] < range[0], + start = range[reverse - 0], + stop = range[1 - reverse]; step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2); if (round) step = Math.floor(step); start += (stop - start - step * (n - paddingInner)) * align; @@ -11910,11 +12255,11 @@ }; scale.range = function(_) { - return arguments.length ? (range$$1 = [+_[0], +_[1]], rescale()) : range$$1.slice(); + return arguments.length ? (range = [+_[0], +_[1]], rescale()) : range.slice(); }; scale.rangeRound = function(_) { - return range$$1 = [+_[0], +_[1]], round = true, rescale(); + return range = [+_[0], +_[1]], round = true, rescale(); }; scale.bandwidth = function() { @@ -11930,15 +12275,15 @@ }; scale.padding = function(_) { - return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner; + return arguments.length ? (paddingInner = Math.min(1, paddingOuter = +_), rescale()) : paddingInner; }; scale.paddingInner = function(_) { - return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner; + return arguments.length ? (paddingInner = Math.min(1, _), rescale()) : paddingInner; }; scale.paddingOuter = function(_) { - return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter; + return arguments.length ? (paddingOuter = +_, rescale()) : paddingOuter; }; scale.align = function(_) { @@ -11946,16 +12291,14 @@ }; scale.copy = function() { - return band() - .domain(domain()) - .range(range$$1) + return band(domain(), range) .round(round) .paddingInner(paddingInner) .paddingOuter(paddingOuter) .align(align); }; - return rescale(); + return initRange.apply(rescale(), arguments); } function pointish(scale) { @@ -11973,7 +12316,7 @@ } function point$1() { - return pointish(band().paddingInner(1)); + return pointish(band.apply(null, arguments).paddingInner(1)); } function constant$a(x) { @@ -11988,34 +12331,32 @@ var unit = [0, 1]; -function deinterpolateLinear(a, b) { +function identity$6(x) { + return x; +} + +function normalize(a, b) { return (b -= (a = +a)) ? function(x) { return (x - a) / b; } - : constant$a(b); + : constant$a(isNaN(b) ? NaN : 0.5); } -function deinterpolateClamp(deinterpolate) { - return function(a, b) { - var d = deinterpolate(a = +a, b = +b); - return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); }; - }; +function clamper(domain) { + var a = domain[0], b = domain[domain.length - 1], t; + if (a > b) t = a, a = b, b = t; + return function(x) { return Math.max(a, Math.min(b, x)); }; } -function reinterpolateClamp(reinterpolate) { - return function(a, b) { - var r = reinterpolate(a = +a, b = +b); - return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); }; - }; -} - -function bimap(domain, range, deinterpolate, reinterpolate) { +// normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1]. +// interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b]. +function bimap(domain, range, interpolate) { var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1]; - if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0); - else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1); + if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0); + else d0 = normalize(d0, d1), r0 = interpolate(r0, r1); return function(x) { return r0(d0(x)); }; } -function polymap(domain, range, deinterpolate, reinterpolate) { +function polymap(domain, range, interpolate) { var j = Math.min(domain.length, range.length) - 1, d = new Array(j), r = new Array(j), @@ -12028,8 +12369,8 @@ } while (++i < j) { - d[i] = deinterpolate(domain[i], domain[i + 1]); - r[i] = reinterpolate(range[i], range[i + 1]); + d[i] = normalize(domain[i], domain[i + 1]); + r[i] = interpolate(range[i], range[i + 1]); } return function(x) { @@ -12043,36 +12384,38 @@ .domain(source.domain()) .range(source.range()) .interpolate(source.interpolate()) - .clamp(source.clamp()); + .clamp(source.clamp()) + .unknown(source.unknown()); } -// deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1]. -// reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b]. -function continuous(deinterpolate, reinterpolate) { +function transformer$1() { var domain = unit, range = unit, - interpolate$$1 = interpolateValue, - clamp = false, - piecewise$$1, + interpolate = interpolateValue, + transform, + untransform, + unknown, + clamp = identity$6, + piecewise, output, input; function rescale() { - piecewise$$1 = Math.min(domain.length, range.length) > 2 ? polymap : bimap; + piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap; output = input = null; return scale; } function scale(x) { - return (output || (output = piecewise$$1(domain, range, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate$$1)))(+x); + return isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x))); } scale.invert = function(y) { - return (input || (input = piecewise$$1(range, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y); + return clamp(untransform((input || (input = piecewise(range, domain.map(transform), interpolateNumber)))(y))); }; scale.domain = function(_) { - return arguments.length ? (domain = map$2.call(_, number$2), rescale()) : domain.slice(); + return arguments.length ? (domain = map$3.call(_, number$2), clamp === identity$6 || (clamp = clamper(domain)), rescale()) : domain.slice(); }; scale.range = function(_) { @@ -12080,24 +12423,33 @@ }; scale.rangeRound = function(_) { - return range = slice$5.call(_), interpolate$$1 = interpolateRound, rescale(); + return range = slice$5.call(_), interpolate = interpolateRound, rescale(); }; scale.clamp = function(_) { - return arguments.length ? (clamp = !!_, rescale()) : clamp; + return arguments.length ? (clamp = _ ? clamper(domain) : identity$6, scale) : clamp !== identity$6; }; scale.interpolate = function(_) { - return arguments.length ? (interpolate$$1 = _, rescale()) : interpolate$$1; + return arguments.length ? (interpolate = _, rescale()) : interpolate; }; - return rescale(); + scale.unknown = function(_) { + return arguments.length ? (unknown = _, scale) : unknown; + }; + + return function(t, u) { + transform = t, untransform = u; + return rescale(); + }; } -function tickFormat(domain, count, specifier) { - var start = domain[0], - stop = domain[domain.length - 1], - step = tickStep(start, stop, count == null ? 10 : count), +function continuous(transform, untransform) { + return transformer$1()(transform, untransform); +} + +function tickFormat(start, stop, count, specifier) { + var step = tickStep(start, stop, count), precision; specifier = formatSpecifier(specifier == null ? ",f" : specifier); switch (specifier.type) { @@ -12132,7 +12484,8 @@ }; scale.tickFormat = function(count, specifier) { - return tickFormat(domain(), count, specifier); + var d = domain(); + return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier); }; scale.nice = function(count) { @@ -12179,32 +12532,40 @@ } function linear$2() { - var scale = continuous(deinterpolateLinear, interpolateNumber); + var scale = continuous(identity$6, identity$6); scale.copy = function() { return copy(scale, linear$2()); }; + initRange.apply(scale, arguments); + return linearish(scale); } -function identity$6() { - var domain = [0, 1]; +function identity$7(domain) { + var unknown; function scale(x) { - return +x; + return isNaN(x = +x) ? unknown : x; } scale.invert = scale; scale.domain = scale.range = function(_) { - return arguments.length ? (domain = map$2.call(_, number$2), scale) : domain.slice(); + return arguments.length ? (domain = map$3.call(_, number$2), scale) : domain.slice(); + }; + + scale.unknown = function(_) { + return arguments.length ? (unknown = _, scale) : unknown; }; scale.copy = function() { - return identity$6().domain(domain); + return identity$7(domain).unknown(unknown); }; + domain = arguments.length ? map$3.call(domain, number$2) : [0, 1]; + return linearish(scale); } @@ -12227,16 +12588,20 @@ return domain; } -function deinterpolate(a, b) { - return (b = Math.log(b / a)) - ? function(x) { return Math.log(x / a) / b; } - : constant$a(b); +function transformLog(x) { + return Math.log(x); } -function reinterpolate(a, b) { - return a < 0 - ? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); } - : function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); }; +function transformExp(x) { + return Math.exp(x); +} + +function transformLogn(x) { + return -Math.log(-x); +} + +function transformExpn(x) { + return -Math.exp(-x); } function pow10(x) { @@ -12262,16 +12627,21 @@ }; } -function log$1() { - var scale = continuous(deinterpolate, reinterpolate).domain([1, 10]), +function loggish(transform) { + var scale = transform(transformLog, transformExp), domain = scale.domain, base = 10, - logs = logp(10), - pows = powp(10); + logs, + pows; function rescale() { logs = logp(base), pows = powp(base); - if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows); + if (domain()[0] < 0) { + logs = reflect(logs), pows = reflect(pows); + transform(transformLogn, transformExpn); + } else { + transform(transformLog, transformExp); + } return scale; } @@ -12343,52 +12713,105 @@ })); }; + return scale; +} + +function log$1() { + var scale = loggish(transformer$1()).domain([1, 10]); + scale.copy = function() { - return copy(scale, log$1().base(base)); + return copy(scale, log$1()).base(scale.base()); }; + initRange.apply(scale, arguments); + return scale; } -function raise$1(x, exponent) { - return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent); +function transformSymlog(c) { + return function(x) { + return Math.sign(x) * Math.log1p(Math.abs(x / c)); + }; } -function pow$1() { - var exponent = 1, - scale = continuous(deinterpolate, reinterpolate), - domain = scale.domain; - - function deinterpolate(a, b) { - return (b = raise$1(b, exponent) - (a = raise$1(a, exponent))) - ? function(x) { return (raise$1(x, exponent) - a) / b; } - : constant$a(b); - } - - function reinterpolate(a, b) { - b = raise$1(b, exponent) - (a = raise$1(a, exponent)); - return function(t) { return raise$1(a + b * t, 1 / exponent); }; - } - - scale.exponent = function(_) { - return arguments.length ? (exponent = +_, domain(domain())) : exponent; +function transformSymexp(c) { + return function(x) { + return Math.sign(x) * Math.expm1(Math.abs(x)) * c; }; +} - scale.copy = function() { - return copy(scale, pow$1().exponent(exponent)); +function symlogish(transform) { + var c = 1, scale = transform(transformSymlog(c), transformSymexp(c)); + + scale.constant = function(_) { + return arguments.length ? transform(transformSymlog(c = +_), transformSymexp(c)) : c; }; return linearish(scale); } -function sqrt$1() { - return pow$1().exponent(0.5); +function symlog() { + var scale = symlogish(transformer$1()); + + scale.copy = function() { + return copy(scale, symlog()).constant(scale.constant()); + }; + + return initRange.apply(scale, arguments); } -function quantile$$1() { +function transformPow(exponent) { + return function(x) { + return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent); + }; +} + +function transformSqrt(x) { + return x < 0 ? -Math.sqrt(-x) : Math.sqrt(x); +} + +function transformSquare(x) { + return x < 0 ? -x * x : x * x; +} + +function powish(transform) { + var scale = transform(identity$6, identity$6), + exponent = 1; + + function rescale() { + return exponent === 1 ? transform(identity$6, identity$6) + : exponent === 0.5 ? transform(transformSqrt, transformSquare) + : transform(transformPow(exponent), transformPow(1 / exponent)); + } + + scale.exponent = function(_) { + return arguments.length ? (exponent = +_, rescale()) : exponent; + }; + + return linearish(scale); +} + +function pow$1() { + var scale = powish(transformer$1()); + + scale.copy = function() { + return copy(scale, pow$1()).exponent(scale.exponent()); + }; + + initRange.apply(scale, arguments); + + return scale; +} + +function sqrt$1() { + return pow$1.apply(null, arguments).exponent(0.5); +} + +function quantile() { var domain = [], range = [], - thresholds = []; + thresholds = [], + unknown; function rescale() { var i = 0, n = Math.max(1, range.length); @@ -12398,7 +12821,7 @@ } function scale(x) { - if (!isNaN(x = +x)) return range[bisectRight(thresholds, x)]; + return isNaN(x = +x) ? unknown : range[bisectRight(thresholds, x)]; } scale.invertExtent = function(y) { @@ -12421,17 +12844,22 @@ return arguments.length ? (range = slice$5.call(_), rescale()) : range.slice(); }; + scale.unknown = function(_) { + return arguments.length ? (unknown = _, scale) : unknown; + }; + scale.quantiles = function() { return thresholds.slice(); }; scale.copy = function() { - return quantile$$1() + return quantile() .domain(domain) - .range(range); + .range(range) + .unknown(unknown); }; - return scale; + return initRange.apply(scale, arguments); } function quantize$1() { @@ -12439,10 +12867,11 @@ x1 = 1, n = 1, domain = [0.5], - range = [0, 1]; + range = [0, 1], + unknown; function scale(x) { - if (x <= x) return range[bisectRight(domain, x, 0, n)]; + return x <= x ? range[bisectRight(domain, x, 0, n)] : unknown; } function rescale() { @@ -12468,22 +12897,32 @@ : [domain[i - 1], domain[i]]; }; + scale.unknown = function(_) { + return arguments.length ? (unknown = _, scale) : scale; + }; + + scale.thresholds = function() { + return domain.slice(); + }; + scale.copy = function() { return quantize$1() .domain([x0, x1]) - .range(range); + .range(range) + .unknown(unknown); }; - return linearish(scale); + return initRange.apply(linearish(scale), arguments); } function threshold$1() { var domain = [0.5], range = [0, 1], + unknown, n = 1; function scale(x) { - if (x <= x) return range[bisectRight(domain, x, 0, n)]; + return x <= x ? range[bisectRight(domain, x, 0, n)] : unknown; } scale.domain = function(_) { @@ -12499,13 +12938,18 @@ return [domain[i - 1], domain[i]]; }; + scale.unknown = function(_) { + return arguments.length ? (unknown = _, scale) : unknown; + }; + scale.copy = function() { return threshold$1() .domain(domain) - .range(range); + .range(range) + .unknown(unknown); }; - return scale; + return initRange.apply(scale, arguments); } var t0$1 = new Date, @@ -12514,10 +12958,12 @@ function newInterval(floori, offseti, count, field) { function interval(date) { - return floori(date = new Date(+date)), date; + return floori(date = arguments.length === 0 ? new Date : new Date(+date)), date; } - interval.floor = interval; + interval.floor = function(date) { + return floori(date = new Date(+date)), date; + }; interval.ceil = function(date) { return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date; @@ -12607,7 +13053,7 @@ var durationWeek = 6048e5; var second = newInterval(function(date) { - date.setTime(Math.floor(date / durationSecond) * durationSecond); + date.setTime(date - date.getMilliseconds()); }, function(date, step) { date.setTime(+date + step * durationSecond); }, function(start, end) { @@ -12618,7 +13064,7 @@ var seconds = second.range; var minute = newInterval(function(date) { - date.setTime(Math.floor(date / durationMinute) * durationMinute); + date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond); }, function(date, step) { date.setTime(+date + step * durationMinute); }, function(start, end) { @@ -12629,9 +13075,7 @@ var minutes = minute.range; var hour = newInterval(function(date) { - var offset = date.getTimezoneOffset() * durationMinute % durationHour; - if (offset < 0) offset += durationHour; - date.setTime(Math.floor((+date - offset) / durationHour) * durationHour + offset); + date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute); }, function(date, step) { date.setTime(+date + step * durationHour); }, function(start, end) { @@ -12827,8 +13271,8 @@ return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L)); } -function newYear(y) { - return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0}; +function newDate(y, m, d) { + return {y: y, m: m, d: d, H: 0, M: 0, S: 0, L: 0}; } function formatLocale$1(locale) { @@ -12868,6 +13312,7 @@ "m": formatMonthNumber, "M": formatMinutes, "p": formatPeriod, + "q": formatQuarter, "Q": formatUnixTimestamp, "s": formatUnixTimestampSeconds, "S": formatSeconds, @@ -12878,7 +13323,7 @@ "W": formatWeekNumberMonday, "x": null, "X": null, - "y": formatYear, + "y": formatYear$1, "Y": formatFullYear, "Z": formatZone, "%": formatLiteralPercent @@ -12900,6 +13345,7 @@ "m": formatUTCMonthNumber, "M": formatUTCMinutes, "p": formatUTCPeriod, + "q": formatUTCQuarter, "Q": formatUnixTimestamp, "s": formatUnixTimestampSeconds, "S": formatUTCSeconds, @@ -12932,6 +13378,7 @@ "m": parseMonthNumber, "M": parseMinutes, "p": parsePeriod, + "q": parseQuarter, "Q": parseUnixTimestamp, "s": parseUnixTimestampSeconds, "S": parseSeconds, @@ -12984,33 +13431,40 @@ }; } - function newParse(specifier, newDate) { + function newParse(specifier, Z) { return function(string) { - var d = newYear(1900), + var d = newDate(1900, undefined, 1), i = parseSpecifier(d, specifier, string += "", 0), - week, day$$1; + week, day$1; if (i != string.length) return null; // If a UNIX timestamp is specified, return it. if ("Q" in d) return new Date(d.Q); + if ("s" in d) return new Date(d.s * 1000 + ("L" in d ? d.L : 0)); + + // If this is utcParse, never use the local timezone. + if (Z && !("Z" in d)) d.Z = 0; // The am-pm flag is 0 for AM, and 1 for PM. if ("p" in d) d.H = d.H % 12 + d.p * 12; + // If the month was not specified, inherit from the quarter. + if (d.m === undefined) d.m = "q" in d ? d.q : 0; + // Convert day-of-week and week-of-year to day-of-year. if ("V" in d) { if (d.V < 1 || d.V > 53) return null; if (!("w" in d)) d.w = 1; if ("Z" in d) { - week = utcDate(newYear(d.y)), day$$1 = week.getUTCDay(); - week = day$$1 > 4 || day$$1 === 0 ? utcMonday.ceil(week) : utcMonday(week); + week = utcDate(newDate(d.y, 0, 1)), day$1 = week.getUTCDay(); + week = day$1 > 4 || day$1 === 0 ? utcMonday.ceil(week) : utcMonday(week); week = utcDay.offset(week, (d.V - 1) * 7); d.y = week.getUTCFullYear(); d.m = week.getUTCMonth(); d.d = week.getUTCDate() + (d.w + 6) % 7; } else { - week = newDate(newYear(d.y)), day$$1 = week.getDay(); - week = day$$1 > 4 || day$$1 === 0 ? monday.ceil(week) : monday(week); + week = localDate(newDate(d.y, 0, 1)), day$1 = week.getDay(); + week = day$1 > 4 || day$1 === 0 ? monday.ceil(week) : monday(week); week = day.offset(week, (d.V - 1) * 7); d.y = week.getFullYear(); d.m = week.getMonth(); @@ -13018,9 +13472,9 @@ } } else if ("W" in d || "U" in d) { if (!("w" in d)) d.w = "u" in d ? d.u % 7 : "W" in d ? 1 : 0; - day$$1 = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay(); + day$1 = "Z" in d ? utcDate(newDate(d.y, 0, 1)).getUTCDay() : localDate(newDate(d.y, 0, 1)).getDay(); d.m = 0; - d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day$$1 + 5) % 7 : d.w + d.U * 7 - (day$$1 + 6) % 7; + d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day$1 + 5) % 7 : d.w + d.U * 7 - (day$1 + 6) % 7; } // If a time zone is specified, all fields are interpreted as UTC and then @@ -13032,7 +13486,7 @@ } // Otherwise, all fields are in local time. - return newDate(d); + return localDate(d); }; } @@ -13115,6 +13569,10 @@ return locale_periods[+(d.getHours() >= 12)]; } + function formatQuarter(d) { + return 1 + ~~(d.getMonth() / 3); + } + function formatUTCShortWeekday(d) { return locale_shortWeekdays[d.getUTCDay()]; } @@ -13135,6 +13593,10 @@ return locale_periods[+(d.getUTCHours() >= 12)]; } + function formatUTCQuarter(d) { + return 1 + ~~(d.getUTCMonth() / 3); + } + return { format: function(specifier) { var f = newFormat(specifier += "", formats); @@ -13142,7 +13604,7 @@ return f; }, parse: function(specifier) { - var p = newParse(specifier += "", localDate); + var p = newParse(specifier += "", false); p.toString = function() { return specifier; }; return p; }, @@ -13152,7 +13614,7 @@ return f; }, utcParse: function(specifier) { - var p = newParse(specifier, utcDate); + var p = newParse(specifier += "", true); p.toString = function() { return specifier; }; return p; } @@ -13164,7 +13626,7 @@ percentRe = /^%/, requoteRe = /[\\^$*+?|[\]().{}]/g; -function pad(value, fill, width) { +function pad$1(value, fill, width) { var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; @@ -13225,6 +13687,11 @@ return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1; } +function parseQuarter(d, string, i) { + var n = numberRe.exec(string.slice(i, i + 1)); + return n ? (d.q = n[0] * 3 - 3, i + n[0].length) : -1; +} + function parseMonthNumber(d, string, i) { var n = numberRe.exec(string.slice(i, i + 2)); return n ? (d.m = n[0] - 1, i + n[0].length) : -1; @@ -13277,27 +13744,27 @@ function parseUnixTimestampSeconds(d, string, i) { var n = numberRe.exec(string.slice(i)); - return n ? (d.Q = (+n[0]) * 1000, i + n[0].length) : -1; + return n ? (d.s = +n[0], i + n[0].length) : -1; } function formatDayOfMonth(d, p) { - return pad(d.getDate(), p, 2); + return pad$1(d.getDate(), p, 2); } function formatHour24(d, p) { - return pad(d.getHours(), p, 2); + return pad$1(d.getHours(), p, 2); } function formatHour12(d, p) { - return pad(d.getHours() % 12 || 12, p, 2); + return pad$1(d.getHours() % 12 || 12, p, 2); } function formatDayOfYear(d, p) { - return pad(1 + day.count(year(d), d), p, 3); + return pad$1(1 + day.count(year(d), d), p, 3); } function formatMilliseconds(d, p) { - return pad(d.getMilliseconds(), p, 3); + return pad$1(d.getMilliseconds(), p, 3); } function formatMicroseconds(d, p) { @@ -13305,30 +13772,30 @@ } function formatMonthNumber(d, p) { - return pad(d.getMonth() + 1, p, 2); + return pad$1(d.getMonth() + 1, p, 2); } function formatMinutes(d, p) { - return pad(d.getMinutes(), p, 2); + return pad$1(d.getMinutes(), p, 2); } function formatSeconds(d, p) { - return pad(d.getSeconds(), p, 2); + return pad$1(d.getSeconds(), p, 2); } function formatWeekdayNumberMonday(d) { - var day$$1 = d.getDay(); - return day$$1 === 0 ? 7 : day$$1; + var day = d.getDay(); + return day === 0 ? 7 : day; } function formatWeekNumberSunday(d, p) { - return pad(sunday.count(year(d), d), p, 2); + return pad$1(sunday.count(year(d) - 1, d), p, 2); } function formatWeekNumberISO(d, p) { - var day$$1 = d.getDay(); - d = (day$$1 >= 4 || day$$1 === 0) ? thursday(d) : thursday.ceil(d); - return pad(thursday.count(year(d), d) + (year(d).getDay() === 4), p, 2); + var day = d.getDay(); + d = (day >= 4 || day === 0) ? thursday(d) : thursday.ceil(d); + return pad$1(thursday.count(year(d), d) + (year(d).getDay() === 4), p, 2); } function formatWeekdayNumberSunday(d) { @@ -13336,42 +13803,42 @@ } function formatWeekNumberMonday(d, p) { - return pad(monday.count(year(d), d), p, 2); + return pad$1(monday.count(year(d) - 1, d), p, 2); } -function formatYear(d, p) { - return pad(d.getFullYear() % 100, p, 2); +function formatYear$1(d, p) { + return pad$1(d.getFullYear() % 100, p, 2); } function formatFullYear(d, p) { - return pad(d.getFullYear() % 10000, p, 4); + return pad$1(d.getFullYear() % 10000, p, 4); } function formatZone(d) { var z = d.getTimezoneOffset(); return (z > 0 ? "-" : (z *= -1, "+")) - + pad(z / 60 | 0, "0", 2) - + pad(z % 60, "0", 2); + + pad$1(z / 60 | 0, "0", 2) + + pad$1(z % 60, "0", 2); } function formatUTCDayOfMonth(d, p) { - return pad(d.getUTCDate(), p, 2); + return pad$1(d.getUTCDate(), p, 2); } function formatUTCHour24(d, p) { - return pad(d.getUTCHours(), p, 2); + return pad$1(d.getUTCHours(), p, 2); } function formatUTCHour12(d, p) { - return pad(d.getUTCHours() % 12 || 12, p, 2); + return pad$1(d.getUTCHours() % 12 || 12, p, 2); } function formatUTCDayOfYear(d, p) { - return pad(1 + utcDay.count(utcYear(d), d), p, 3); + return pad$1(1 + utcDay.count(utcYear(d), d), p, 3); } function formatUTCMilliseconds(d, p) { - return pad(d.getUTCMilliseconds(), p, 3); + return pad$1(d.getUTCMilliseconds(), p, 3); } function formatUTCMicroseconds(d, p) { @@ -13379,15 +13846,15 @@ } function formatUTCMonthNumber(d, p) { - return pad(d.getUTCMonth() + 1, p, 2); + return pad$1(d.getUTCMonth() + 1, p, 2); } function formatUTCMinutes(d, p) { - return pad(d.getUTCMinutes(), p, 2); + return pad$1(d.getUTCMinutes(), p, 2); } function formatUTCSeconds(d, p) { - return pad(d.getUTCSeconds(), p, 2); + return pad$1(d.getUTCSeconds(), p, 2); } function formatUTCWeekdayNumberMonday(d) { @@ -13396,13 +13863,13 @@ } function formatUTCWeekNumberSunday(d, p) { - return pad(utcSunday.count(utcYear(d), d), p, 2); + return pad$1(utcSunday.count(utcYear(d) - 1, d), p, 2); } function formatUTCWeekNumberISO(d, p) { - var day$$1 = d.getUTCDay(); - d = (day$$1 >= 4 || day$$1 === 0) ? utcThursday(d) : utcThursday.ceil(d); - return pad(utcThursday.count(utcYear(d), d) + (utcYear(d).getUTCDay() === 4), p, 2); + var day = d.getUTCDay(); + d = (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d); + return pad$1(utcThursday.count(utcYear(d), d) + (utcYear(d).getUTCDay() === 4), p, 2); } function formatUTCWeekdayNumberSunday(d) { @@ -13410,15 +13877,15 @@ } function formatUTCWeekNumberMonday(d, p) { - return pad(utcMonday.count(utcYear(d), d), p, 2); + return pad$1(utcMonday.count(utcYear(d) - 1, d), p, 2); } function formatUTCYear(d, p) { - return pad(d.getUTCFullYear() % 100, p, 2); + return pad$1(d.getUTCFullYear() % 100, p, 2); } function formatUTCFullYear(d, p) { - return pad(d.getUTCFullYear() % 10000, p, 4); + return pad$1(d.getUTCFullYear() % 10000, p, 4); } function formatUTCZone() { @@ -13494,8 +13961,8 @@ return t instanceof Date ? +t : +new Date(+t); } -function calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format) { - var scale = continuous(deinterpolateLinear, interpolateNumber), +function calendar(year, month, week, day, hour, minute, second, millisecond, format) { + var scale = continuous(identity$6, identity$6), invert = scale.invert, domain = scale.domain; @@ -13509,34 +13976,34 @@ formatYear = format("%Y"); var tickIntervals = [ - [second$$1, 1, durationSecond$1], - [second$$1, 5, 5 * durationSecond$1], - [second$$1, 15, 15 * durationSecond$1], - [second$$1, 30, 30 * durationSecond$1], - [minute$$1, 1, durationMinute$1], - [minute$$1, 5, 5 * durationMinute$1], - [minute$$1, 15, 15 * durationMinute$1], - [minute$$1, 30, 30 * durationMinute$1], - [ hour$$1, 1, durationHour$1 ], - [ hour$$1, 3, 3 * durationHour$1 ], - [ hour$$1, 6, 6 * durationHour$1 ], - [ hour$$1, 12, 12 * durationHour$1 ], - [ day$$1, 1, durationDay$1 ], - [ day$$1, 2, 2 * durationDay$1 ], + [second, 1, durationSecond$1], + [second, 5, 5 * durationSecond$1], + [second, 15, 15 * durationSecond$1], + [second, 30, 30 * durationSecond$1], + [minute, 1, durationMinute$1], + [minute, 5, 5 * durationMinute$1], + [minute, 15, 15 * durationMinute$1], + [minute, 30, 30 * durationMinute$1], + [ hour, 1, durationHour$1 ], + [ hour, 3, 3 * durationHour$1 ], + [ hour, 6, 6 * durationHour$1 ], + [ hour, 12, 12 * durationHour$1 ], + [ day, 1, durationDay$1 ], + [ day, 2, 2 * durationDay$1 ], [ week, 1, durationWeek$1 ], - [ month$$1, 1, durationMonth ], - [ month$$1, 3, 3 * durationMonth ], - [ year$$1, 1, durationYear ] + [ month, 1, durationMonth ], + [ month, 3, 3 * durationMonth ], + [ year, 1, durationYear ] ]; - function tickFormat(date$$1) { - return (second$$1(date$$1) < date$$1 ? formatMillisecond - : minute$$1(date$$1) < date$$1 ? formatSecond - : hour$$1(date$$1) < date$$1 ? formatMinute - : day$$1(date$$1) < date$$1 ? formatHour - : month$$1(date$$1) < date$$1 ? (week(date$$1) < date$$1 ? formatDay : formatWeek) - : year$$1(date$$1) < date$$1 ? formatMonth - : formatYear)(date$$1); + function tickFormat(date) { + return (second(date) < date ? formatMillisecond + : minute(date) < date ? formatSecond + : hour(date) < date ? formatMinute + : day(date) < date ? formatHour + : month(date) < date ? (week(date) < date ? formatDay : formatWeek) + : year(date) < date ? formatMonth + : formatYear)(date); } function tickInterval(interval, start, stop, step) { @@ -13550,14 +14017,14 @@ i = bisector(function(i) { return i[2]; }).right(tickIntervals, target); if (i === tickIntervals.length) { step = tickStep(start / durationYear, stop / durationYear, interval); - interval = year$$1; + interval = year; } else if (i) { i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i]; step = i[1]; interval = i[0]; } else { step = Math.max(tickStep(start, stop, interval), 1); - interval = millisecond$$1; + interval = millisecond; } } @@ -13569,7 +14036,7 @@ }; scale.domain = function(_) { - return arguments.length ? domain(map$2.call(_, number$3)) : domain().map(date$1); + return arguments.length ? domain(map$3.call(_, number$3)) : domain().map(date$1); }; scale.ticks = function(interval, step) { @@ -13596,33 +14063,37 @@ }; scale.copy = function() { - return copy(scale, calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format)); + return copy(scale, calendar(year, month, week, day, hour, minute, second, millisecond, format)); }; return scale; } function time() { - return calendar(year, month, sunday, day, hour, minute, second, millisecond, exports.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]); + return initRange.apply(calendar(year, month, sunday, day, hour, minute, second, millisecond, exports.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments); } function utcTime() { - return calendar(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, millisecond, exports.utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]); + return initRange.apply(calendar(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, millisecond, exports.utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]), arguments); } -function sequential(interpolator) { +function transformer$2() { var x0 = 0, x1 = 1, - k10 = 1, - clamp = false; + t0, + t1, + k10, + transform, + interpolator = identity$6, + clamp = false, + unknown; function scale(x) { - var t = (x - x0) * k10; - return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t); + return isNaN(x = +x) ? unknown : interpolator(k10 === 0 ? 0.5 : (x = (transform(x) - t0) * k10, clamp ? Math.max(0, Math.min(1, x)) : x)); } scale.domain = function(_) { - return arguments.length ? (x0 = +_[0], x1 = +_[1], k10 = x0 === x1 ? 0 : 1 / (x1 - x0), scale) : [x0, x1]; + return arguments.length ? (t0 = transform(x0 = +_[0]), t1 = transform(x1 = +_[1]), k10 = t0 === t1 ? 0 : 1 / (t1 - t0), scale) : [x0, x1]; }; scale.clamp = function(_) { @@ -13633,28 +14104,115 @@ return arguments.length ? (interpolator = _, scale) : interpolator; }; - scale.copy = function() { - return sequential(interpolator).domain([x0, x1]).clamp(clamp); + scale.unknown = function(_) { + return arguments.length ? (unknown = _, scale) : unknown; }; - return linearish(scale); + return function(t) { + transform = t, t0 = t(x0), t1 = t(x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0); + return scale; + }; } -function diverging(interpolator) { +function copy$1(source, target) { + return target + .domain(source.domain()) + .interpolator(source.interpolator()) + .clamp(source.clamp()) + .unknown(source.unknown()); +} + +function sequential() { + var scale = linearish(transformer$2()(identity$6)); + + scale.copy = function() { + return copy$1(scale, sequential()); + }; + + return initInterpolator.apply(scale, arguments); +} + +function sequentialLog() { + var scale = loggish(transformer$2()).domain([1, 10]); + + scale.copy = function() { + return copy$1(scale, sequentialLog()).base(scale.base()); + }; + + return initInterpolator.apply(scale, arguments); +} + +function sequentialSymlog() { + var scale = symlogish(transformer$2()); + + scale.copy = function() { + return copy$1(scale, sequentialSymlog()).constant(scale.constant()); + }; + + return initInterpolator.apply(scale, arguments); +} + +function sequentialPow() { + var scale = powish(transformer$2()); + + scale.copy = function() { + return copy$1(scale, sequentialPow()).exponent(scale.exponent()); + }; + + return initInterpolator.apply(scale, arguments); +} + +function sequentialSqrt() { + return sequentialPow.apply(null, arguments).exponent(0.5); +} + +function sequentialQuantile() { + var domain = [], + interpolator = identity$6; + + function scale(x) { + if (!isNaN(x = +x)) return interpolator((bisectRight(domain, x) - 1) / (domain.length - 1)); + } + + scale.domain = function(_) { + if (!arguments.length) return domain.slice(); + domain = []; + for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d); + domain.sort(ascending); + return scale; + }; + + scale.interpolator = function(_) { + return arguments.length ? (interpolator = _, scale) : interpolator; + }; + + scale.copy = function() { + return sequentialQuantile(interpolator).domain(domain); + }; + + return initInterpolator.apply(scale, arguments); +} + +function transformer$3() { var x0 = 0, x1 = 0.5, x2 = 1, - k10 = 1, - k21 = 1, - clamp = false; + t0, + t1, + t2, + k10, + k21, + interpolator = identity$6, + transform, + clamp = false, + unknown; function scale(x) { - var t = 0.5 + ((x = +x) - x1) * (x < x1 ? k10 : k21); - return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t); + return isNaN(x = +x) ? unknown : (x = 0.5 + ((x = +transform(x)) - t1) * (x < t1 ? k10 : k21), interpolator(clamp ? Math.max(0, Math.min(1, x)) : x)); } scale.domain = function(_) { - return arguments.length ? (x0 = +_[0], x1 = +_[1], x2 = +_[2], k10 = x0 === x1 ? 0 : 0.5 / (x1 - x0), k21 = x1 === x2 ? 0 : 0.5 / (x2 - x1), scale) : [x0, x1, x2]; + return arguments.length ? (t0 = transform(x0 = +_[0]), t1 = transform(x1 = +_[1]), t2 = transform(x2 = +_[2]), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1), scale) : [x0, x1, x2]; }; scale.clamp = function(_) { @@ -13665,11 +14223,58 @@ return arguments.length ? (interpolator = _, scale) : interpolator; }; - scale.copy = function() { - return diverging(interpolator).domain([x0, x1, x2]).clamp(clamp); + scale.unknown = function(_) { + return arguments.length ? (unknown = _, scale) : unknown; }; - return linearish(scale); + return function(t) { + transform = t, t0 = t(x0), t1 = t(x1), t2 = t(x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1); + return scale; + }; +} + +function diverging() { + var scale = linearish(transformer$3()(identity$6)); + + scale.copy = function() { + return copy$1(scale, diverging()); + }; + + return initInterpolator.apply(scale, arguments); +} + +function divergingLog() { + var scale = loggish(transformer$3()).domain([0.1, 1, 10]); + + scale.copy = function() { + return copy$1(scale, divergingLog()).base(scale.base()); + }; + + return initInterpolator.apply(scale, arguments); +} + +function divergingSymlog() { + var scale = symlogish(transformer$3()); + + scale.copy = function() { + return copy$1(scale, divergingSymlog()).constant(scale.constant()); + }; + + return initInterpolator.apply(scale, arguments); +} + +function divergingPow() { + var scale = powish(transformer$3()); + + scale.copy = function() { + return copy$1(scale, divergingPow()).exponent(scale.exponent()); + }; + + return initInterpolator.apply(scale, arguments); +} + +function divergingSqrt() { + return divergingPow.apply(null, arguments).exponent(0.5); } function colors(specifier) { @@ -13696,6 +14301,8 @@ var Set3 = colors("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"); +var Tableau10 = colors("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab"); + function ramp(scheme) { return rgbBasis(scheme[scheme.length - 1]); } @@ -14042,6 +14649,15 @@ var Oranges = ramp(scheme$q); +function cividis(t) { + t = Math.max(0, Math.min(1, t)); + return "rgb(" + + Math.max(0, Math.min(255, Math.round(-4.54 - t * (35.34 - t * (2381.73 - t * (6402.7 - t * (7024.72 - t * 2710.57))))))) + ", " + + Math.max(0, Math.min(255, Math.round(32.49 + t * (170.73 + t * (52.82 - t * (131.46 - t * (176.58 - t * 67.37))))))) + ", " + + Math.max(0, Math.min(255, Math.round(81.24 + t * (442.36 - t * (2482.43 - t * (6167.24 - t * (6614.94 - t * 2475.67))))))) + + ")"; +} + var cubehelix$3 = cubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0)); var warm = cubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8)); @@ -14072,6 +14688,15 @@ return c$1 + ""; } +function turbo(t) { + t = Math.max(0, Math.min(1, t)); + return "rgb(" + + Math.max(0, Math.min(255, Math.round(34.61 + t * (1172.33 - t * (10793.56 - t * (33300.12 - t * (38394.49 - t * 14825.05))))))) + ", " + + Math.max(0, Math.min(255, Math.round(23.31 + t * (557.33 + t * (1225.33 - t * (3574.96 - t * (1073.77 + t * 707.56))))))) + ", " + + Math.max(0, Math.min(255, Math.round(27.2 + t * (3211.1 - t * (15327.97 - t * (27814 - t * (22569.18 - t * 6838.66))))))) + + ")"; +} + function ramp$1(range) { var n = range.length; return function(t) { @@ -14137,7 +14762,9 @@ function intersect(x0, y0, x1, y1, x2, y2, x3, y3) { var x10 = x1 - x0, y10 = y1 - y0, x32 = x3 - x2, y32 = y3 - y2, - t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10); + t = y32 * x10 - x32 * y10; + if (t * t < epsilon$3) return; + t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t; return [x0 + t * x10, y0 + t * y10]; } @@ -14258,12 +14885,12 @@ var x11 = r1 * cos$2(a11), y11 = r1 * sin$2(a11), x00 = r0 * cos$2(a00), - y00 = r0 * sin$2(a00); + y00 = r0 * sin$2(a00), + oc; // Restrict the corner radius according to the sector angle. - if (da < pi$4) { - var oc = da0 > epsilon$3 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10], - ax = x01 - oc[0], + if (da < pi$4 && (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10))) { + var ax = x01 - oc[0], ay = y01 - oc[1], bx = x11 - oc[0], by = y11 - oc[1], @@ -14411,8 +15038,8 @@ } function line() { - var x$$1 = x$3, - y$$1 = y$3, + var x = x$3, + y = y$3, defined = constant$b(true), context = null, curve = curveLinear, @@ -14432,18 +15059,18 @@ if (defined0 = !defined0) output.lineStart(); else output.lineEnd(); } - if (defined0) output.point(+x$$1(d, i, data), +y$$1(d, i, data)); + if (defined0) output.point(+x(d, i, data), +y(d, i, data)); } if (buffer) return output = null, buffer + "" || null; } line.x = function(_) { - return arguments.length ? (x$$1 = typeof _ === "function" ? _ : constant$b(+_), line) : x$$1; + return arguments.length ? (x = typeof _ === "function" ? _ : constant$b(+_), line) : x; }; line.y = function(_) { - return arguments.length ? (y$$1 = typeof _ === "function" ? _ : constant$b(+_), line) : y$$1; + return arguments.length ? (y = typeof _ === "function" ? _ : constant$b(+_), line) : y; }; line.defined = function(_) { @@ -14569,12 +15196,12 @@ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; } -function identity$7(d) { +function identity$8(d) { return d; } function pie() { - var value = identity$7, + var value = identity$8, sortValues = descending$1, sort = null, startAngle = constant$b(0), @@ -14743,14 +15370,14 @@ function link$2(curve) { var source = linkSource, target = linkTarget, - x$$1 = x$3, - y$$1 = y$3, + x = x$3, + y = y$3, context = null; function link() { var buffer, argv = slice$6.call(arguments), s = source.apply(this, argv), t = target.apply(this, argv); if (!context) context = buffer = path(); - curve(context, +x$$1.apply(this, (argv[0] = s, argv)), +y$$1.apply(this, argv), +x$$1.apply(this, (argv[0] = t, argv)), +y$$1.apply(this, argv)); + curve(context, +x.apply(this, (argv[0] = s, argv)), +y.apply(this, argv), +x.apply(this, (argv[0] = t, argv)), +y.apply(this, argv)); if (buffer) return context = null, buffer + "" || null; } @@ -14763,11 +15390,11 @@ }; link.x = function(_) { - return arguments.length ? (x$$1 = typeof _ === "function" ? _ : constant$b(+_), link) : x$$1; + return arguments.length ? (x = typeof _ === "function" ? _ : constant$b(+_), link) : x; }; link.y = function(_) { - return arguments.length ? (y$$1 = typeof _ === "function" ? _ : constant$b(+_), link) : y$$1; + return arguments.length ? (y = typeof _ === "function" ? _ : constant$b(+_), link) : y; }; link.context = function(_) { @@ -15267,15 +15894,15 @@ var cardinalClosed = (function custom(tension) { - function cardinal$$1(context) { + function cardinal(context) { return new CardinalClosed(context, tension); } - cardinal$$1.tension = function(tension) { + cardinal.tension = function(tension) { return custom(+tension); }; - return cardinal$$1; + return cardinal; })(0); function CardinalOpen(context, tension) { @@ -15315,15 +15942,15 @@ var cardinalOpen = (function custom(tension) { - function cardinal$$1(context) { + function cardinal(context) { return new CardinalOpen(context, tension); } - cardinal$$1.tension = function(tension) { + cardinal.tension = function(tension) { return custom(+tension); }; - return cardinal$$1; + return cardinal; })(0); function point$4(that, x, y) { @@ -15472,15 +16099,15 @@ var catmullRomClosed = (function custom(alpha) { - function catmullRom$$1(context) { + function catmullRom(context) { return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0); } - catmullRom$$1.alpha = function(alpha) { + catmullRom.alpha = function(alpha) { return custom(+alpha); }; - return catmullRom$$1; + return catmullRom; })(0.5); function CatmullRomOpen(context, alpha) { @@ -15532,15 +16159,15 @@ var catmullRomOpen = (function custom(alpha) { - function catmullRom$$1(context) { + function catmullRom(context) { return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0); } - catmullRom$$1.alpha = function(alpha) { + catmullRom.alpha = function(alpha) { return custom(+alpha); }; - return catmullRom$$1; + return catmullRom; })(0.5); function LinearClosed(context) { @@ -15871,15 +16498,15 @@ } function diverging$1(series, order) { - if (!((n = series.length) > 1)) return; + if (!((n = series.length) > 0)) return; for (var i, j = 0, d, dy, yp, yn, n, m = series[order[0]].length; j < m; ++j) { for (yp = yn = 0, i = 0; i < n; ++i) { - if ((dy = (d = series[order[i]][j])[1] - d[0]) >= 0) { + if ((dy = (d = series[order[i]][j])[1] - d[0]) > 0) { d[0] = yp, d[1] = yp += dy; } else if (dy < 0) { d[1] = yn, d[0] = yn += dy; } else { - d[0] = yp; + d[0] = 0, d[1] = dy; } } } @@ -15917,6 +16544,17 @@ none$1(series, order); } +function appearance(series) { + var peaks = series.map(peak); + return none$2(series).sort(function(a, b) { return peaks[a] - peaks[b]; }); +} + +function peak(series) { + var i = -1, j = 0, n = series.length, vi, vj = -Infinity; + while (++i < n) if ((vi = +series[i][1]) > vj) vj = vi, j = i; + return j; +} + function ascending$3(series) { var sums = series.map(sum$2); return none$2(series).sort(function(a, b) { return sums[a] - sums[b]; }); @@ -15937,7 +16575,7 @@ i, j, sums = series.map(sum$2), - order = none$2(series).sort(function(a, b) { return sums[b] - sums[a]; }), + order = appearance(series), top = 0, bottom = 0, tops = [], @@ -16904,13 +17542,13 @@ }; function voronoi() { - var x$$1 = x$4, - y$$1 = y$4, + var x = x$4, + y = y$4, extent = null; function voronoi(data) { return new Diagram(data.map(function(d, i) { - var s = [Math.round(x$$1(d, i, data) / epsilon$4) * epsilon$4, Math.round(y$$1(d, i, data) / epsilon$4) * epsilon$4]; + var s = [Math.round(x(d, i, data) / epsilon$4) * epsilon$4, Math.round(y(d, i, data) / epsilon$4) * epsilon$4]; s.index = i; s.data = d; return s; @@ -16930,11 +17568,11 @@ }; voronoi.x = function(_) { - return arguments.length ? (x$$1 = typeof _ === "function" ? _ : constant$c(+_), voronoi) : x$$1; + return arguments.length ? (x = typeof _ === "function" ? _ : constant$c(+_), voronoi) : x; }; voronoi.y = function(_) { - return arguments.length ? (y$$1 = typeof _ === "function" ? _ : constant$c(+_), voronoi) : y$$1; + return arguments.length ? (y = typeof _ === "function" ? _ : constant$c(+_), voronoi) : y; }; voronoi.extent = function(_) { @@ -17003,12 +17641,13 @@ } }; -var identity$8 = new Transform(1, 0, 0); +var identity$9 = new Transform(1, 0, 0); transform$1.prototype = Transform.prototype; function transform$1(node) { - return node.__zoom || identity$8; + while (!node.__zoom) if (!(node = node.parentNode)) return identity$9; + return node.__zoom; } function nopropagation$2() { @@ -17022,32 +17661,32 @@ // Ignore right-click, since that should open the context menu. function defaultFilter$2() { - return !exports.event.button; + return !exports.event.ctrlKey && !exports.event.button; } function defaultExtent$1() { - var e = this, w, h; + var e = this; if (e instanceof SVGElement) { e = e.ownerSVGElement || e; - w = e.width.baseVal.value; - h = e.height.baseVal.value; - } else { - w = e.clientWidth; - h = e.clientHeight; + if (e.hasAttribute("viewBox")) { + e = e.viewBox.baseVal; + return [[e.x, e.y], [e.x + e.width, e.y + e.height]]; + } + return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]]; } - return [[0, 0], [w, h]]; + return [[0, 0], [e.clientWidth, e.clientHeight]]; } function defaultTransform() { - return this.__zoom || identity$8; + return this.__zoom || identity$9; } function defaultWheelDelta() { - return -exports.event.deltaY * (exports.event.deltaMode ? 120 : 1) / 500; + return -exports.event.deltaY * (exports.event.deltaMode === 1 ? 0.05 : exports.event.deltaMode ? 1 : 0.002); } -function defaultTouchable$1() { - return "ontouchstart" in this; +function defaultTouchable$2() { + return navigator.maxTouchPoints || ("ontouchstart" in this); } function defaultConstrain(transform, extent, translateExtent) { @@ -17066,12 +17705,11 @@ extent = defaultExtent$1, constrain = defaultConstrain, wheelDelta = defaultWheelDelta, - touchable = defaultTouchable$1, + touchable = defaultTouchable$2, scaleExtent = [0, Infinity], translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]], duration = 250, interpolate = interpolateZoom, - gestures = [], listeners = dispatch("start", "zoom", "end"), touchstarting, touchending, @@ -17079,8 +17717,8 @@ wheelDelay = 150, clickDistance2 = 0; - function zoom(selection$$1) { - selection$$1 + function zoom(selection) { + selection .property("__zoom", defaultTransform) .on("wheel.zoom", wheeled) .on("mousedown.zoom", mousedowned) @@ -17093,13 +17731,13 @@ .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)"); } - zoom.transform = function(collection, transform) { - var selection$$1 = collection.selection ? collection.selection() : collection; - selection$$1.property("__zoom", defaultTransform); - if (collection !== selection$$1) { - schedule(collection, transform); + zoom.transform = function(collection, transform, point) { + var selection = collection.selection ? collection.selection() : collection; + selection.property("__zoom", defaultTransform); + if (collection !== selection) { + schedule(collection, transform, point); } else { - selection$$1.interrupt().each(function() { + selection.interrupt().each(function() { gesture(this, arguments) .start() .zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform) @@ -17108,27 +17746,27 @@ } }; - zoom.scaleBy = function(selection$$1, k) { - zoom.scaleTo(selection$$1, function() { + zoom.scaleBy = function(selection, k, p) { + zoom.scaleTo(selection, function() { var k0 = this.__zoom.k, k1 = typeof k === "function" ? k.apply(this, arguments) : k; return k0 * k1; - }); + }, p); }; - zoom.scaleTo = function(selection$$1, k) { - zoom.transform(selection$$1, function() { + zoom.scaleTo = function(selection, k, p) { + zoom.transform(selection, function() { var e = extent.apply(this, arguments), t0 = this.__zoom, - p0 = centroid(e), + p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p, p1 = t0.invert(p0), k1 = typeof k === "function" ? k.apply(this, arguments) : k; return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent); - }); + }, p); }; - zoom.translateBy = function(selection$$1, x, y) { - zoom.transform(selection$$1, function() { + zoom.translateBy = function(selection, x, y) { + zoom.transform(selection, function() { return constrain(this.__zoom.translate( typeof x === "function" ? x.apply(this, arguments) : x, typeof y === "function" ? y.apply(this, arguments) : y @@ -17136,16 +17774,16 @@ }); }; - zoom.translateTo = function(selection$$1, x, y) { - zoom.transform(selection$$1, function() { + zoom.translateTo = function(selection, x, y, p) { + zoom.transform(selection, function() { var e = extent.apply(this, arguments), t = this.__zoom, - p = centroid(e); - return constrain(identity$8.translate(p[0], p[1]).scale(t.k).translate( + p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p; + return constrain(identity$9.translate(p0[0], p0[1]).scale(t.k).translate( typeof x === "function" ? -x.apply(this, arguments) : -x, typeof y === "function" ? -y.apply(this, arguments) : -y ), e, translateExtent); - }); + }, p); }; function scale(transform, k) { @@ -17162,8 +17800,8 @@ return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2]; } - function schedule(transition$$1, transform, center) { - transition$$1 + function schedule(transition, transform, point) { + transition .on("start.zoom", function() { gesture(this, arguments).start(); }) .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).end(); }) .tween("zoom", function() { @@ -17171,7 +17809,7 @@ args = arguments, g = gesture(that, args), e = extent.apply(that, args), - p = center || centroid(e), + p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point, w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), a = that.__zoom, b = typeof transform === "function" ? transform.apply(that, args) : transform, @@ -17184,27 +17822,22 @@ }); } - function gesture(that, args) { - for (var i = 0, n = gestures.length, g; i < n; ++i) { - if ((g = gestures[i]).that === that) { - return g; - } - } - return new Gesture(that, args); + function gesture(that, args, clean) { + return (!clean && that.__zooming) || new Gesture(that, args); } function Gesture(that, args) { this.that = that; this.args = args; - this.index = -1; this.active = 0; this.extent = extent.apply(that, args); + this.taps = 0; } Gesture.prototype = { start: function() { if (++this.active === 1) { - this.index = gestures.push(this) - 1; + this.that.__zooming = this; this.emit("start"); } return this; @@ -17219,8 +17852,7 @@ }, end: function() { if (--this.active === 0) { - gestures.splice(this.index, 1); - this.index = -1; + delete this.that.__zooming; this.emit("end"); } return this; @@ -17268,7 +17900,7 @@ function mousedowned() { if (touchending || !filter.apply(this, arguments)) return; - var g = gesture(this, arguments), + var g = gesture(this, arguments, true), v = select(exports.event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true), p = mouse(this), x0 = exports.event.clientX, @@ -17312,46 +17944,39 @@ function touchstarted() { if (!filter.apply(this, arguments)) return; - var g = gesture(this, arguments), - touches$$1 = exports.event.changedTouches, - started, - n = touches$$1.length, i, t, p; + var touches = exports.event.touches, + n = touches.length, + g = gesture(this, arguments, exports.event.changedTouches.length === n), + started, i, t, p; nopropagation$2(); for (i = 0; i < n; ++i) { - t = touches$$1[i], p = touch(this, touches$$1, t.identifier); + t = touches[i], p = touch(this, touches, t.identifier); p = [p, this.__zoom.invert(p), t.identifier]; - if (!g.touch0) g.touch0 = p, started = true; - else if (!g.touch1) g.touch1 = p; + if (!g.touch0) g.touch0 = p, started = true, g.taps = 1 + !!touchstarting; + else if (!g.touch1 && g.touch0[2] !== p[2]) g.touch1 = p, g.taps = 0; } - // If this is a dbltap, reroute to the (optional) dblclick.zoom handler. - if (touchstarting) { - touchstarting = clearTimeout(touchstarting); - if (!g.touch1) { - g.end(); - p = select(this).on("dblclick.zoom"); - if (p) p.apply(this, arguments); - return; - } - } + if (touchstarting) touchstarting = clearTimeout(touchstarting); if (started) { - touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay); + if (g.taps < 2) touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay); interrupt(this); g.start(); } } function touchmoved() { + if (!this.__zooming) return; var g = gesture(this, arguments), - touches$$1 = exports.event.changedTouches, - n = touches$$1.length, i, t, p, l; + touches = exports.event.changedTouches, + n = touches.length, i, t, p, l; noevent$2(); if (touchstarting) touchstarting = clearTimeout(touchstarting); + g.taps = 0; for (i = 0; i < n; ++i) { - t = touches$$1[i], p = touch(this, touches$$1, t.identifier); + t = touches[i], p = touch(this, touches, t.identifier); if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p; else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p; } @@ -17371,21 +17996,29 @@ } function touchended() { + if (!this.__zooming) return; var g = gesture(this, arguments), - touches$$1 = exports.event.changedTouches, - n = touches$$1.length, i, t; + touches = exports.event.changedTouches, + n = touches.length, i, t; nopropagation$2(); if (touchending) clearTimeout(touchending); touchending = setTimeout(function() { touchending = null; }, touchDelay); for (i = 0; i < n; ++i) { - t = touches$$1[i]; + t = touches[i]; if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0; else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1; } if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1; if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]); - else g.end(); + else { + g.end(); + // If this was a dbltap, reroute to the (optional) dblclick.zoom handler. + if (g.taps === 2) { + var p = select(this).on("dblclick.zoom"); + if (p) p.apply(this, arguments); + } + } } zoom.wheelDelta = function(_) { @@ -17436,125 +18069,111 @@ return zoom; } -exports.version = version; -exports.bisect = bisectRight; -exports.bisectRight = bisectRight; -exports.bisectLeft = bisectLeft; +exports.FormatSpecifier = FormatSpecifier; +exports.active = active; +exports.arc = arc; +exports.area = area$3; +exports.areaRadial = areaRadial; exports.ascending = ascending; -exports.bisector = bisector; -exports.cross = cross; -exports.descending = descending; -exports.deviation = deviation; -exports.extent = extent; -exports.histogram = histogram; -exports.thresholdFreedmanDiaconis = freedmanDiaconis; -exports.thresholdScott = scott; -exports.thresholdSturges = thresholdSturges; -exports.max = max; -exports.mean = mean; -exports.median = median; -exports.merge = merge; -exports.min = min; -exports.pairs = pairs; -exports.permute = permute; -exports.quantile = threshold; -exports.range = sequence; -exports.scan = scan; -exports.shuffle = shuffle; -exports.sum = sum; -exports.ticks = ticks; -exports.tickIncrement = tickIncrement; -exports.tickStep = tickStep; -exports.transpose = transpose; -exports.variance = variance; -exports.zip = zip; -exports.axisTop = axisTop; -exports.axisRight = axisRight; +exports.autoType = autoType; exports.axisBottom = axisBottom; exports.axisLeft = axisLeft; +exports.axisRight = axisRight; +exports.axisTop = axisTop; +exports.bisect = bisectRight; +exports.bisectLeft = bisectLeft; +exports.bisectRight = bisectRight; +exports.bisector = bisector; +exports.blob = blob; exports.brush = brush; +exports.brushSelection = brushSelection; exports.brushX = brushX; exports.brushY = brushY; -exports.brushSelection = brushSelection; +exports.buffer = buffer; exports.chord = chord; -exports.ribbon = ribbon; -exports.nest = nest; -exports.set = set$2; -exports.map = map$1; -exports.keys = keys; -exports.values = values; -exports.entries = entries; +exports.clientPoint = point; +exports.cluster = cluster; exports.color = color; -exports.rgb = rgb; -exports.hsl = hsl; -exports.lab = lab; -exports.hcl = hcl; -exports.lch = lch; -exports.gray = gray; -exports.cubehelix = cubehelix; -exports.contours = contours; exports.contourDensity = density; +exports.contours = contours; +exports.create = create; +exports.creator = creator; +exports.cross = cross; +exports.csv = csv$1; +exports.csvFormat = csvFormat; +exports.csvFormatBody = csvFormatBody; +exports.csvFormatRow = csvFormatRow; +exports.csvFormatRows = csvFormatRows; +exports.csvFormatValue = csvFormatValue; +exports.csvParse = csvParse; +exports.csvParseRows = csvParseRows; +exports.cubehelix = cubehelix; +exports.curveBasis = basis$2; +exports.curveBasisClosed = basisClosed$1; +exports.curveBasisOpen = basisOpen; +exports.curveBundle = bundle; +exports.curveCardinal = cardinal; +exports.curveCardinalClosed = cardinalClosed; +exports.curveCardinalOpen = cardinalOpen; +exports.curveCatmullRom = catmullRom; +exports.curveCatmullRomClosed = catmullRomClosed; +exports.curveCatmullRomOpen = catmullRomOpen; +exports.curveLinear = curveLinear; +exports.curveLinearClosed = linearClosed; +exports.curveMonotoneX = monotoneX; +exports.curveMonotoneY = monotoneY; +exports.curveNatural = natural; +exports.curveStep = step; +exports.curveStepAfter = stepAfter; +exports.curveStepBefore = stepBefore; +exports.customEvent = customEvent; +exports.descending = descending; +exports.deviation = deviation; exports.dispatch = dispatch; exports.drag = drag; exports.dragDisable = dragDisable; exports.dragEnable = yesdrag; +exports.dsv = dsv; exports.dsvFormat = dsvFormat; -exports.csvParse = csvParse; -exports.csvParseRows = csvParseRows; -exports.csvFormat = csvFormat; -exports.csvFormatRows = csvFormatRows; -exports.tsvParse = tsvParse; -exports.tsvParseRows = tsvParseRows; -exports.tsvFormat = tsvFormat; -exports.tsvFormatRows = tsvFormatRows; -exports.easeLinear = linear$1; -exports.easeQuad = quadInOut; -exports.easeQuadIn = quadIn; -exports.easeQuadOut = quadOut; -exports.easeQuadInOut = quadInOut; -exports.easeCubic = cubicInOut; -exports.easeCubicIn = cubicIn; -exports.easeCubicOut = cubicOut; -exports.easeCubicInOut = cubicInOut; -exports.easePoly = polyInOut; -exports.easePolyIn = polyIn; -exports.easePolyOut = polyOut; -exports.easePolyInOut = polyInOut; -exports.easeSin = sinInOut; -exports.easeSinIn = sinIn; -exports.easeSinOut = sinOut; -exports.easeSinInOut = sinInOut; -exports.easeExp = expInOut; -exports.easeExpIn = expIn; -exports.easeExpOut = expOut; -exports.easeExpInOut = expInOut; -exports.easeCircle = circleInOut; -exports.easeCircleIn = circleIn; -exports.easeCircleOut = circleOut; -exports.easeCircleInOut = circleInOut; -exports.easeBounce = bounceOut; -exports.easeBounceIn = bounceIn; -exports.easeBounceOut = bounceOut; -exports.easeBounceInOut = bounceInOut; exports.easeBack = backInOut; exports.easeBackIn = backIn; -exports.easeBackOut = backOut; exports.easeBackInOut = backInOut; +exports.easeBackOut = backOut; +exports.easeBounce = bounceOut; +exports.easeBounceIn = bounceIn; +exports.easeBounceInOut = bounceInOut; +exports.easeBounceOut = bounceOut; +exports.easeCircle = circleInOut; +exports.easeCircleIn = circleIn; +exports.easeCircleInOut = circleInOut; +exports.easeCircleOut = circleOut; +exports.easeCubic = cubicInOut; +exports.easeCubicIn = cubicIn; +exports.easeCubicInOut = cubicInOut; +exports.easeCubicOut = cubicOut; exports.easeElastic = elasticOut; exports.easeElasticIn = elasticIn; -exports.easeElasticOut = elasticOut; exports.easeElasticInOut = elasticInOut; -exports.blob = blob; -exports.buffer = buffer; -exports.dsv = dsv; -exports.csv = csv$1; -exports.tsv = tsv$1; -exports.image = image; -exports.json = json; -exports.text = text; -exports.xml = xml; -exports.html = html; -exports.svg = svg; +exports.easeElasticOut = elasticOut; +exports.easeExp = expInOut; +exports.easeExpIn = expIn; +exports.easeExpInOut = expInOut; +exports.easeExpOut = expOut; +exports.easeLinear = linear$1; +exports.easePoly = polyInOut; +exports.easePolyIn = polyIn; +exports.easePolyInOut = polyInOut; +exports.easePolyOut = polyOut; +exports.easeQuad = quadInOut; +exports.easeQuadIn = quadIn; +exports.easeQuadInOut = quadInOut; +exports.easeQuadOut = quadOut; +exports.easeSin = sinInOut; +exports.easeSinIn = sinIn; +exports.easeSinInOut = sinInOut; +exports.easeSinOut = sinOut; +exports.entries = entries; +exports.extent = extent; exports.forceCenter = center$1; exports.forceCollide = collide; exports.forceLink = link; @@ -17566,10 +18185,13 @@ exports.formatDefaultLocale = defaultLocale; exports.formatLocale = formatLocale; exports.formatSpecifier = formatSpecifier; -exports.precisionFixed = precisionFixed; -exports.precisionPrefix = precisionPrefix; -exports.precisionRound = precisionRound; +exports.geoAlbers = albers; +exports.geoAlbersUsa = albersUsa; exports.geoArea = area$1; +exports.geoAzimuthalEqualArea = azimuthalEqualArea; +exports.geoAzimuthalEqualAreaRaw = azimuthalEqualAreaRaw; +exports.geoAzimuthalEquidistant = azimuthalEquidistant; +exports.geoAzimuthalEquidistantRaw = azimuthalEquidistantRaw; exports.geoBounds = bounds; exports.geoCentroid = centroid; exports.geoCircle = circle; @@ -17577,221 +18199,257 @@ exports.geoClipCircle = clipCircle; exports.geoClipExtent = extent$1; exports.geoClipRectangle = clipRectangle; -exports.geoContains = contains$1; -exports.geoDistance = distance; -exports.geoGraticule = graticule; -exports.geoGraticule10 = graticule10; -exports.geoInterpolate = interpolate$1; -exports.geoLength = length$1; -exports.geoPath = index$1; -exports.geoAlbers = albers; -exports.geoAlbersUsa = albersUsa; -exports.geoAzimuthalEqualArea = azimuthalEqualArea; -exports.geoAzimuthalEqualAreaRaw = azimuthalEqualAreaRaw; -exports.geoAzimuthalEquidistant = azimuthalEquidistant; -exports.geoAzimuthalEquidistantRaw = azimuthalEquidistantRaw; exports.geoConicConformal = conicConformal; exports.geoConicConformalRaw = conicConformalRaw; exports.geoConicEqualArea = conicEqualArea; exports.geoConicEqualAreaRaw = conicEqualAreaRaw; exports.geoConicEquidistant = conicEquidistant; exports.geoConicEquidistantRaw = conicEquidistantRaw; +exports.geoContains = contains$1; +exports.geoDistance = distance; exports.geoEqualEarth = equalEarth; exports.geoEqualEarthRaw = equalEarthRaw; exports.geoEquirectangular = equirectangular; exports.geoEquirectangularRaw = equirectangularRaw; exports.geoGnomonic = gnomonic; exports.geoGnomonicRaw = gnomonicRaw; +exports.geoGraticule = graticule; +exports.geoGraticule10 = graticule10; exports.geoIdentity = identity$5; -exports.geoProjection = projection; -exports.geoProjectionMutator = projectionMutator; +exports.geoInterpolate = interpolate$1; +exports.geoLength = length$1; exports.geoMercator = mercator; exports.geoMercatorRaw = mercatorRaw; exports.geoNaturalEarth1 = naturalEarth1; exports.geoNaturalEarth1Raw = naturalEarth1Raw; exports.geoOrthographic = orthographic; exports.geoOrthographicRaw = orthographicRaw; +exports.geoPath = index$1; +exports.geoProjection = projection; +exports.geoProjectionMutator = projectionMutator; +exports.geoRotation = rotation; exports.geoStereographic = stereographic; exports.geoStereographicRaw = stereographicRaw; -exports.geoTransverseMercator = transverseMercator; -exports.geoTransverseMercatorRaw = transverseMercatorRaw; -exports.geoRotation = rotation; exports.geoStream = geoStream; exports.geoTransform = transform; -exports.cluster = cluster; +exports.geoTransverseMercator = transverseMercator; +exports.geoTransverseMercatorRaw = transverseMercatorRaw; +exports.gray = gray; +exports.hcl = hcl; exports.hierarchy = hierarchy; -exports.pack = index$2; -exports.packSiblings = siblings; -exports.packEnclose = enclose; -exports.partition = partition; -exports.stratify = stratify; -exports.tree = tree; -exports.treemap = index$3; -exports.treemapBinary = binary; -exports.treemapDice = treemapDice; -exports.treemapSlice = treemapSlice; -exports.treemapSliceDice = sliceDice; -exports.treemapSquarify = squarify; -exports.treemapResquarify = resquarify; +exports.histogram = histogram; +exports.hsl = hsl; +exports.html = html; +exports.image = image; exports.interpolate = interpolateValue; exports.interpolateArray = array$1; exports.interpolateBasis = basis$1; exports.interpolateBasisClosed = basisClosed; +exports.interpolateBlues = Blues; +exports.interpolateBrBG = BrBG; +exports.interpolateBuGn = BuGn; +exports.interpolateBuPu = BuPu; +exports.interpolateCividis = cividis; +exports.interpolateCool = cool; +exports.interpolateCubehelix = cubehelix$2; +exports.interpolateCubehelixDefault = cubehelix$3; +exports.interpolateCubehelixLong = cubehelixLong; exports.interpolateDate = date; exports.interpolateDiscrete = discrete; +exports.interpolateGnBu = GnBu; +exports.interpolateGreens = Greens; +exports.interpolateGreys = Greys; +exports.interpolateHcl = hcl$2; +exports.interpolateHclLong = hclLong; +exports.interpolateHsl = hsl$2; +exports.interpolateHslLong = hslLong; exports.interpolateHue = hue$1; +exports.interpolateInferno = inferno; +exports.interpolateLab = lab$1; +exports.interpolateMagma = magma; exports.interpolateNumber = interpolateNumber; +exports.interpolateNumberArray = numberArray; exports.interpolateObject = object; -exports.interpolateRound = interpolateRound; -exports.interpolateString = interpolateString; -exports.interpolateTransformCss = interpolateTransformCss; -exports.interpolateTransformSvg = interpolateTransformSvg; -exports.interpolateZoom = interpolateZoom; +exports.interpolateOrRd = OrRd; +exports.interpolateOranges = Oranges; +exports.interpolatePRGn = PRGn; +exports.interpolatePiYG = PiYG; +exports.interpolatePlasma = plasma; +exports.interpolatePuBu = PuBu; +exports.interpolatePuBuGn = PuBuGn; +exports.interpolatePuOr = PuOr; +exports.interpolatePuRd = PuRd; +exports.interpolatePurples = Purples; +exports.interpolateRainbow = rainbow; +exports.interpolateRdBu = RdBu; +exports.interpolateRdGy = RdGy; +exports.interpolateRdPu = RdPu; +exports.interpolateRdYlBu = RdYlBu; +exports.interpolateRdYlGn = RdYlGn; +exports.interpolateReds = Reds; exports.interpolateRgb = interpolateRgb; exports.interpolateRgbBasis = rgbBasis; exports.interpolateRgbBasisClosed = rgbBasisClosed; -exports.interpolateHsl = hsl$2; -exports.interpolateHslLong = hslLong; -exports.interpolateLab = lab$1; -exports.interpolateHcl = hcl$2; -exports.interpolateHclLong = hclLong; -exports.interpolateCubehelix = cubehelix$2; -exports.interpolateCubehelixLong = cubehelixLong; -exports.piecewise = piecewise; -exports.quantize = quantize; -exports.path = path; -exports.polygonArea = area$2; -exports.polygonCentroid = centroid$1; -exports.polygonHull = hull; -exports.polygonContains = contains$2; -exports.polygonLength = length$2; -exports.quadtree = quadtree; -exports.randomUniform = uniform; -exports.randomNormal = normal; -exports.randomLogNormal = logNormal; -exports.randomBates = bates; -exports.randomIrwinHall = irwinHall; -exports.randomExponential = exponential$1; -exports.scaleBand = band; -exports.scalePoint = point$1; -exports.scaleIdentity = identity$6; -exports.scaleLinear = linear$2; -exports.scaleLog = log$1; -exports.scaleOrdinal = ordinal; -exports.scaleImplicit = implicit; -exports.scalePow = pow$1; -exports.scaleSqrt = sqrt$1; -exports.scaleQuantile = quantile$$1; -exports.scaleQuantize = quantize$1; -exports.scaleThreshold = threshold$1; -exports.scaleTime = time; -exports.scaleUtc = utcTime; -exports.scaleSequential = sequential; -exports.scaleDiverging = diverging; -exports.schemeCategory10 = category10; -exports.schemeAccent = Accent; -exports.schemeDark2 = Dark2; -exports.schemePaired = Paired; -exports.schemePastel1 = Pastel1; -exports.schemePastel2 = Pastel2; -exports.schemeSet1 = Set1; -exports.schemeSet2 = Set2; -exports.schemeSet3 = Set3; -exports.interpolateBrBG = BrBG; -exports.schemeBrBG = scheme; -exports.interpolatePRGn = PRGn; -exports.schemePRGn = scheme$1; -exports.interpolatePiYG = PiYG; -exports.schemePiYG = scheme$2; -exports.interpolatePuOr = PuOr; -exports.schemePuOr = scheme$3; -exports.interpolateRdBu = RdBu; -exports.schemeRdBu = scheme$4; -exports.interpolateRdGy = RdGy; -exports.schemeRdGy = scheme$5; -exports.interpolateRdYlBu = RdYlBu; -exports.schemeRdYlBu = scheme$6; -exports.interpolateRdYlGn = RdYlGn; -exports.schemeRdYlGn = scheme$7; -exports.interpolateSpectral = Spectral; -exports.schemeSpectral = scheme$8; -exports.interpolateBuGn = BuGn; -exports.schemeBuGn = scheme$9; -exports.interpolateBuPu = BuPu; -exports.schemeBuPu = scheme$a; -exports.interpolateGnBu = GnBu; -exports.schemeGnBu = scheme$b; -exports.interpolateOrRd = OrRd; -exports.schemeOrRd = scheme$c; -exports.interpolatePuBuGn = PuBuGn; -exports.schemePuBuGn = scheme$d; -exports.interpolatePuBu = PuBu; -exports.schemePuBu = scheme$e; -exports.interpolatePuRd = PuRd; -exports.schemePuRd = scheme$f; -exports.interpolateRdPu = RdPu; -exports.schemeRdPu = scheme$g; -exports.interpolateYlGnBu = YlGnBu; -exports.schemeYlGnBu = scheme$h; -exports.interpolateYlGn = YlGn; -exports.schemeYlGn = scheme$i; -exports.interpolateYlOrBr = YlOrBr; -exports.schemeYlOrBr = scheme$j; -exports.interpolateYlOrRd = YlOrRd; -exports.schemeYlOrRd = scheme$k; -exports.interpolateBlues = Blues; -exports.schemeBlues = scheme$l; -exports.interpolateGreens = Greens; -exports.schemeGreens = scheme$m; -exports.interpolateGreys = Greys; -exports.schemeGreys = scheme$n; -exports.interpolatePurples = Purples; -exports.schemePurples = scheme$o; -exports.interpolateReds = Reds; -exports.schemeReds = scheme$p; -exports.interpolateOranges = Oranges; -exports.schemeOranges = scheme$q; -exports.interpolateCubehelixDefault = cubehelix$3; -exports.interpolateRainbow = rainbow; -exports.interpolateWarm = warm; -exports.interpolateCool = cool; +exports.interpolateRound = interpolateRound; exports.interpolateSinebow = sinebow; +exports.interpolateSpectral = Spectral; +exports.interpolateString = interpolateString; +exports.interpolateTransformCss = interpolateTransformCss; +exports.interpolateTransformSvg = interpolateTransformSvg; +exports.interpolateTurbo = turbo; exports.interpolateViridis = viridis; -exports.interpolateMagma = magma; -exports.interpolateInferno = inferno; -exports.interpolatePlasma = plasma; -exports.create = create; -exports.creator = creator; +exports.interpolateWarm = warm; +exports.interpolateYlGn = YlGn; +exports.interpolateYlGnBu = YlGnBu; +exports.interpolateYlOrBr = YlOrBr; +exports.interpolateYlOrRd = YlOrRd; +exports.interpolateZoom = interpolateZoom; +exports.interrupt = interrupt; +exports.interval = interval$1; +exports.isoFormat = formatIso; +exports.isoParse = parseIso; +exports.json = json; +exports.keys = keys; +exports.lab = lab; +exports.lch = lch; +exports.line = line; +exports.lineRadial = lineRadial$1; +exports.linkHorizontal = linkHorizontal; +exports.linkRadial = linkRadial; +exports.linkVertical = linkVertical; exports.local = local; -exports.matcher = matcher$1; +exports.map = map$1; +exports.matcher = matcher; +exports.max = max; +exports.mean = mean; +exports.median = median; +exports.merge = merge; +exports.min = min; exports.mouse = mouse; exports.namespace = namespace; exports.namespaces = namespaces; -exports.clientPoint = point; +exports.nest = nest; +exports.now = now; +exports.pack = index$2; +exports.packEnclose = enclose; +exports.packSiblings = siblings; +exports.pairs = pairs; +exports.partition = partition; +exports.path = path; +exports.permute = permute; +exports.pie = pie; +exports.piecewise = piecewise; +exports.pointRadial = pointRadial; +exports.polygonArea = area$2; +exports.polygonCentroid = centroid$1; +exports.polygonContains = contains$2; +exports.polygonHull = hull; +exports.polygonLength = length$2; +exports.precisionFixed = precisionFixed; +exports.precisionPrefix = precisionPrefix; +exports.precisionRound = precisionRound; +exports.quadtree = quadtree; +exports.quantile = threshold; +exports.quantize = quantize; +exports.radialArea = areaRadial; +exports.radialLine = lineRadial$1; +exports.randomBates = bates; +exports.randomExponential = exponential$1; +exports.randomIrwinHall = irwinHall; +exports.randomLogNormal = logNormal; +exports.randomNormal = normal; +exports.randomUniform = uniform; +exports.range = sequence; +exports.rgb = rgb; +exports.ribbon = ribbon; +exports.scaleBand = band; +exports.scaleDiverging = diverging; +exports.scaleDivergingLog = divergingLog; +exports.scaleDivergingPow = divergingPow; +exports.scaleDivergingSqrt = divergingSqrt; +exports.scaleDivergingSymlog = divergingSymlog; +exports.scaleIdentity = identity$7; +exports.scaleImplicit = implicit; +exports.scaleLinear = linear$2; +exports.scaleLog = log$1; +exports.scaleOrdinal = ordinal; +exports.scalePoint = point$1; +exports.scalePow = pow$1; +exports.scaleQuantile = quantile; +exports.scaleQuantize = quantize$1; +exports.scaleSequential = sequential; +exports.scaleSequentialLog = sequentialLog; +exports.scaleSequentialPow = sequentialPow; +exports.scaleSequentialQuantile = sequentialQuantile; +exports.scaleSequentialSqrt = sequentialSqrt; +exports.scaleSequentialSymlog = sequentialSymlog; +exports.scaleSqrt = sqrt$1; +exports.scaleSymlog = symlog; +exports.scaleThreshold = threshold$1; +exports.scaleTime = time; +exports.scaleUtc = utcTime; +exports.scan = scan; +exports.schemeAccent = Accent; +exports.schemeBlues = scheme$l; +exports.schemeBrBG = scheme; +exports.schemeBuGn = scheme$9; +exports.schemeBuPu = scheme$a; +exports.schemeCategory10 = category10; +exports.schemeDark2 = Dark2; +exports.schemeGnBu = scheme$b; +exports.schemeGreens = scheme$m; +exports.schemeGreys = scheme$n; +exports.schemeOrRd = scheme$c; +exports.schemeOranges = scheme$q; +exports.schemePRGn = scheme$1; +exports.schemePaired = Paired; +exports.schemePastel1 = Pastel1; +exports.schemePastel2 = Pastel2; +exports.schemePiYG = scheme$2; +exports.schemePuBu = scheme$e; +exports.schemePuBuGn = scheme$d; +exports.schemePuOr = scheme$3; +exports.schemePuRd = scheme$f; +exports.schemePurples = scheme$o; +exports.schemeRdBu = scheme$4; +exports.schemeRdGy = scheme$5; +exports.schemeRdPu = scheme$g; +exports.schemeRdYlBu = scheme$6; +exports.schemeRdYlGn = scheme$7; +exports.schemeReds = scheme$p; +exports.schemeSet1 = Set1; +exports.schemeSet2 = Set2; +exports.schemeSet3 = Set3; +exports.schemeSpectral = scheme$8; +exports.schemeTableau10 = Tableau10; +exports.schemeYlGn = scheme$i; +exports.schemeYlGnBu = scheme$h; +exports.schemeYlOrBr = scheme$j; +exports.schemeYlOrRd = scheme$k; exports.select = select; exports.selectAll = selectAll; exports.selection = selection; exports.selector = selector; exports.selectorAll = selectorAll; +exports.set = set$2; +exports.shuffle = shuffle; +exports.stack = stack; +exports.stackOffsetDiverging = diverging$1; +exports.stackOffsetExpand = expand; +exports.stackOffsetNone = none$1; +exports.stackOffsetSilhouette = silhouette; +exports.stackOffsetWiggle = wiggle; +exports.stackOrderAppearance = appearance; +exports.stackOrderAscending = ascending$3; +exports.stackOrderDescending = descending$2; +exports.stackOrderInsideOut = insideOut; +exports.stackOrderNone = none$2; +exports.stackOrderReverse = reverse; +exports.stratify = stratify; exports.style = styleValue; -exports.touch = touch; -exports.touches = touches; -exports.window = defaultView; -exports.customEvent = customEvent; -exports.arc = arc; -exports.area = area$3; -exports.line = line; -exports.pie = pie; -exports.areaRadial = areaRadial; -exports.radialArea = areaRadial; -exports.lineRadial = lineRadial$1; -exports.radialLine = lineRadial$1; -exports.pointRadial = pointRadial; -exports.linkHorizontal = linkHorizontal; -exports.linkVertical = linkVertical; -exports.linkRadial = linkRadial; +exports.sum = sum; +exports.svg = svg; exports.symbol = symbol; -exports.symbols = symbols; exports.symbolCircle = circle$2; exports.symbolCross = cross$2; exports.symbolDiamond = diamond; @@ -17799,113 +18457,112 @@ exports.symbolStar = star; exports.symbolTriangle = triangle; exports.symbolWye = wye; -exports.curveBasisClosed = basisClosed$1; -exports.curveBasisOpen = basisOpen; -exports.curveBasis = basis$2; -exports.curveBundle = bundle; -exports.curveCardinalClosed = cardinalClosed; -exports.curveCardinalOpen = cardinalOpen; -exports.curveCardinal = cardinal; -exports.curveCatmullRomClosed = catmullRomClosed; -exports.curveCatmullRomOpen = catmullRomOpen; -exports.curveCatmullRom = catmullRom; -exports.curveLinearClosed = linearClosed; -exports.curveLinear = curveLinear; -exports.curveMonotoneX = monotoneX; -exports.curveMonotoneY = monotoneY; -exports.curveNatural = natural; -exports.curveStep = step; -exports.curveStepAfter = stepAfter; -exports.curveStepBefore = stepBefore; -exports.stack = stack; -exports.stackOffsetExpand = expand; -exports.stackOffsetDiverging = diverging$1; -exports.stackOffsetNone = none$1; -exports.stackOffsetSilhouette = silhouette; -exports.stackOffsetWiggle = wiggle; -exports.stackOrderAscending = ascending$3; -exports.stackOrderDescending = descending$2; -exports.stackOrderInsideOut = insideOut; -exports.stackOrderNone = none$2; -exports.stackOrderReverse = reverse; +exports.symbols = symbols; +exports.text = text; +exports.thresholdFreedmanDiaconis = freedmanDiaconis; +exports.thresholdScott = scott; +exports.thresholdSturges = thresholdSturges; +exports.tickFormat = tickFormat; +exports.tickIncrement = tickIncrement; +exports.tickStep = tickStep; +exports.ticks = ticks; +exports.timeDay = day; +exports.timeDays = days; +exports.timeFormatDefaultLocale = defaultLocale$1; +exports.timeFormatLocale = formatLocale$1; +exports.timeFriday = friday; +exports.timeFridays = fridays; +exports.timeHour = hour; +exports.timeHours = hours; exports.timeInterval = newInterval; exports.timeMillisecond = millisecond; exports.timeMilliseconds = milliseconds; -exports.utcMillisecond = millisecond; -exports.utcMilliseconds = milliseconds; -exports.timeSecond = second; -exports.timeSeconds = seconds; -exports.utcSecond = second; -exports.utcSeconds = seconds; exports.timeMinute = minute; exports.timeMinutes = minutes; -exports.timeHour = hour; -exports.timeHours = hours; -exports.timeDay = day; -exports.timeDays = days; -exports.timeWeek = sunday; -exports.timeWeeks = sundays; -exports.timeSunday = sunday; -exports.timeSundays = sundays; exports.timeMonday = monday; exports.timeMondays = mondays; +exports.timeMonth = month; +exports.timeMonths = months; +exports.timeSaturday = saturday; +exports.timeSaturdays = saturdays; +exports.timeSecond = second; +exports.timeSeconds = seconds; +exports.timeSunday = sunday; +exports.timeSundays = sundays; +exports.timeThursday = thursday; +exports.timeThursdays = thursdays; exports.timeTuesday = tuesday; exports.timeTuesdays = tuesdays; exports.timeWednesday = wednesday; exports.timeWednesdays = wednesdays; -exports.timeThursday = thursday; -exports.timeThursdays = thursdays; -exports.timeFriday = friday; -exports.timeFridays = fridays; -exports.timeSaturday = saturday; -exports.timeSaturdays = saturdays; -exports.timeMonth = month; -exports.timeMonths = months; +exports.timeWeek = sunday; +exports.timeWeeks = sundays; exports.timeYear = year; exports.timeYears = years; -exports.utcMinute = utcMinute; -exports.utcMinutes = utcMinutes; -exports.utcHour = utcHour; -exports.utcHours = utcHours; +exports.timeout = timeout$1; +exports.timer = timer; +exports.timerFlush = timerFlush; +exports.touch = touch; +exports.touches = touches; +exports.transition = transition; +exports.transpose = transpose; +exports.tree = tree; +exports.treemap = index$3; +exports.treemapBinary = binary; +exports.treemapDice = treemapDice; +exports.treemapResquarify = resquarify; +exports.treemapSlice = treemapSlice; +exports.treemapSliceDice = sliceDice; +exports.treemapSquarify = squarify; +exports.tsv = tsv$1; +exports.tsvFormat = tsvFormat; +exports.tsvFormatBody = tsvFormatBody; +exports.tsvFormatRow = tsvFormatRow; +exports.tsvFormatRows = tsvFormatRows; +exports.tsvFormatValue = tsvFormatValue; +exports.tsvParse = tsvParse; +exports.tsvParseRows = tsvParseRows; exports.utcDay = utcDay; exports.utcDays = utcDays; -exports.utcWeek = utcSunday; -exports.utcWeeks = utcSundays; -exports.utcSunday = utcSunday; -exports.utcSundays = utcSundays; +exports.utcFriday = utcFriday; +exports.utcFridays = utcFridays; +exports.utcHour = utcHour; +exports.utcHours = utcHours; +exports.utcMillisecond = millisecond; +exports.utcMilliseconds = milliseconds; +exports.utcMinute = utcMinute; +exports.utcMinutes = utcMinutes; exports.utcMonday = utcMonday; exports.utcMondays = utcMondays; +exports.utcMonth = utcMonth; +exports.utcMonths = utcMonths; +exports.utcSaturday = utcSaturday; +exports.utcSaturdays = utcSaturdays; +exports.utcSecond = second; +exports.utcSeconds = seconds; +exports.utcSunday = utcSunday; +exports.utcSundays = utcSundays; +exports.utcThursday = utcThursday; +exports.utcThursdays = utcThursdays; exports.utcTuesday = utcTuesday; exports.utcTuesdays = utcTuesdays; exports.utcWednesday = utcWednesday; exports.utcWednesdays = utcWednesdays; -exports.utcThursday = utcThursday; -exports.utcThursdays = utcThursdays; -exports.utcFriday = utcFriday; -exports.utcFridays = utcFridays; -exports.utcSaturday = utcSaturday; -exports.utcSaturdays = utcSaturdays; -exports.utcMonth = utcMonth; -exports.utcMonths = utcMonths; +exports.utcWeek = utcSunday; +exports.utcWeeks = utcSundays; exports.utcYear = utcYear; exports.utcYears = utcYears; -exports.timeFormatDefaultLocale = defaultLocale$1; -exports.timeFormatLocale = formatLocale$1; -exports.isoFormat = formatIso; -exports.isoParse = parseIso; -exports.now = now; -exports.timer = timer; -exports.timerFlush = timerFlush; -exports.timeout = timeout$1; -exports.interval = interval$1; -exports.transition = transition; -exports.active = active; -exports.interrupt = interrupt; +exports.values = values; +exports.variance = variance; +exports.version = version; exports.voronoi = voronoi; +exports.window = defaultView; +exports.xml = xml; +exports.zip = zip; exports.zoom = zoom; +exports.zoomIdentity = identity$9; exports.zoomTransform = transform$1; -exports.zoomIdentity = identity$8; Object.defineProperty(exports, '__esModule', { value: true }); -}))); +}));
diff --git a/third_party/d3/src/d3.min.js b/third_party/d3/src/d3.min.js index 2a54e040..344d26cc 100644 --- a/third_party/d3/src/d3.min.js +++ b/third_party/d3/src/d3.min.js
@@ -1,2 +1,2 @@ -// https://d3js.org v5.7.0 Copyright 2018 Mike Bostock -!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})}(this,function(t){"use strict";function n(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function e(t){var e;return 1===t.length&&(e=t,t=function(t,r){return n(e(t),r)}),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}var r=e(n),i=r.right,o=r.left;function a(t,n){return[t,n]}function u(t){return null===t?NaN:+t}function f(t,n){var e,r,i=t.length,o=0,a=-1,f=0,c=0;if(null==n)for(;++a<i;)isNaN(e=u(t[a]))||(c+=(r=e-f)*(e-(f+=r/++o)));else for(;++a<i;)isNaN(e=u(n(t[a],a,t)))||(c+=(r=e-f)*(e-(f+=r/++o)));if(o>1)return c/(o-1)}function c(t,n){var e=f(t,n);return e?Math.sqrt(e):e}function s(t,n){var e,r,i,o=t.length,a=-1;if(null==n){for(;++a<o;)if(null!=(e=t[a])&&e>=e)for(r=i=e;++a<o;)null!=(e=t[a])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++a<o;)if(null!=(e=n(t[a],a,t))&&e>=e)for(r=i=e;++a<o;)null!=(e=n(t[a],a,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]}var l=Array.prototype,h=l.slice,d=l.map;function p(t){return function(){return t}}function v(t){return t}function g(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o}var y=Math.sqrt(50),_=Math.sqrt(10),b=Math.sqrt(2);function m(t,n,e){var r,i,o,a,u=-1;if(e=+e,(t=+t)===(n=+n)&&e>0)return[t];if((r=n<t)&&(i=t,t=n,n=i),0===(a=x(t,n,e))||!isFinite(a))return[];if(a>0)for(t=Math.ceil(t/a),n=Math.floor(n/a),o=new Array(i=Math.ceil(n-t+1));++u<i;)o[u]=(t+u)*a;else for(t=Math.floor(t*a),n=Math.ceil(n*a),o=new Array(i=Math.ceil(t-n+1));++u<i;)o[u]=(t-u)/a;return r&&o.reverse(),o}function x(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=y?10:o>=_?5:o>=b?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=y?10:o>=_?5:o>=b?2:1)}function w(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=y?i*=10:o>=_?i*=5:o>=b&&(i*=2),n<t?-i:i}function M(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1}function A(t,n,e){if(null==e&&(e=u),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),a=+e(t[o],o,t);return a+(+e(t[o+1],o+1,t)-a)*(i-o)}}function T(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r}function N(t){for(var n,e,r,i=t.length,o=-1,a=0;++o<i;)a+=t[o].length;for(e=new Array(a);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--a]=r[n];return e}function S(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r}function E(t){if(!(i=t.length))return[];for(var n=-1,e=S(t,k),r=new Array(e);++n<e;)for(var i,o=-1,a=r[n]=new Array(i);++o<i;)a[o]=t[o][n];return r}function k(t){return t.length}var C=Array.prototype.slice;function P(t){return t}var z=1,R=2,L=3,D=4,U=1e-6;function q(t){return"translate("+(t+.5)+",0)"}function O(t){return"translate(0,"+(t+.5)+")"}function Y(){return!this.__axis}function B(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,f=t===z||t===D?-1:1,c=t===D||t===R?"x":"y",s=t===z||t===L?q:O;function l(l){var h=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,d=null==i?n.tickFormat?n.tickFormat.apply(n,e):P:i,p=Math.max(o,0)+u,v=n.range(),g=+v[0]+.5,y=+v[v.length-1]+.5,_=(n.bandwidth?function(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}:function(t){return function(n){return+t(n)}})(n.copy()),b=l.selection?l.selection():l,m=b.selectAll(".domain").data([null]),x=b.selectAll(".tick").data(h,n).order(),w=x.exit(),M=x.enter().append("g").attr("class","tick"),A=x.select("line"),T=x.select("text");m=m.merge(m.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),x=x.merge(M),A=A.merge(M.append("line").attr("stroke","currentColor").attr(c+"2",f*o)),T=T.merge(M.append("text").attr("fill","currentColor").attr(c,f*p).attr("dy",t===z?"0em":t===L?"0.71em":"0.32em")),l!==b&&(m=m.transition(l),x=x.transition(l),A=A.transition(l),T=T.transition(l),w=w.transition(l).attr("opacity",U).attr("transform",function(t){return isFinite(t=_(t))?s(t):this.getAttribute("transform")}),M.attr("opacity",U).attr("transform",function(t){var n=this.parentNode.__axis;return s(n&&isFinite(n=n(t))?n:_(t))})),w.remove(),m.attr("d",t===D||t==R?a?"M"+f*a+","+g+"H0.5V"+y+"H"+f*a:"M0.5,"+g+"V"+y:a?"M"+g+","+f*a+"V0.5H"+y+"V"+f*a:"M"+g+",0.5H"+y),x.attr("opacity",1).attr("transform",function(t){return s(_(t))}),A.attr(c+"2",f*o),T.attr(c,f*p).text(d),b.filter(Y).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===R?"start":t===D?"end":"middle"),b.each(function(){this.__axis=_})}return l.scale=function(t){return arguments.length?(n=t,l):n},l.ticks=function(){return e=C.call(arguments),l},l.tickArguments=function(t){return arguments.length?(e=null==t?[]:C.call(t),l):e.slice()},l.tickValues=function(t){return arguments.length?(r=null==t?null:C.call(t),l):r&&r.slice()},l.tickFormat=function(t){return arguments.length?(i=t,l):i},l.tickSize=function(t){return arguments.length?(o=a=+t,l):o},l.tickSizeInner=function(t){return arguments.length?(o=+t,l):o},l.tickSizeOuter=function(t){return arguments.length?(a=+t,l):a},l.tickPadding=function(t){return arguments.length?(u=+t,l):u},l}var F={value:function(){}};function I(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r)throw new Error("illegal type: "+t);r[t]=[]}return new H(r)}function H(t){this._=t}function j(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function X(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=F,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}H.prototype=I.prototype={constructor:H,on:function(t,n){var e,r,i=this._,o=(r=i,(t+"").trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");if(e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),t&&!r.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}})),a=-1,u=o.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++a<u;)if(e=(t=o[a]).type)i[e]=X(i[e],t.name,n);else if(null==n)for(e in i)i[e]=X(i[e],t.name,null);return this}for(;++a<u;)if((e=(t=o[a]).type)&&(e=j(i[e],t.name)))return e},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new H(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var G="http://www.w3.org/1999/xhtml",V={svg:"http://www.w3.org/2000/svg",xhtml:G,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function $(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),V.hasOwnProperty(n)?{space:V[n],local:t}:t}function W(t){var n=$(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===G&&n.documentElement.namespaceURI===G?n.createElement(t):n.createElementNS(e,t)}})(n)}function Z(){}function Q(t){return null==t?Z:function(){return this.querySelector(t)}}function J(){return[]}function K(t){return null==t?J:function(){return this.querySelectorAll(t)}}var tt=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var nt=document.documentElement;if(!nt.matches){var et=nt.webkitMatchesSelector||nt.msMatchesSelector||nt.mozMatchesSelector||nt.oMatchesSelector;tt=function(t){return function(){return et.call(this,t)}}}}var rt=tt;function it(t){return new Array(t.length)}function ot(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}ot.prototype={constructor:ot,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var at="$";function ut(t,n,e,r,i,o){for(var a,u=0,f=n.length,c=o.length;u<c;++u)(a=n[u])?(a.__data__=o[u],r[u]=a):e[u]=new ot(t,o[u]);for(;u<f;++u)(a=n[u])&&(i[u]=a)}function ft(t,n,e,r,i,o,a){var u,f,c,s={},l=n.length,h=o.length,d=new Array(l);for(u=0;u<l;++u)(f=n[u])&&(d[u]=c=at+a.call(f,f.__data__,u,n),c in s?i[u]=f:s[c]=f);for(u=0;u<h;++u)(f=s[c=at+a.call(t,o[u],u,o)])?(r[u]=f,f.__data__=o[u],s[c]=null):e[u]=new ot(t,o[u]);for(u=0;u<l;++u)(f=n[u])&&s[d[u]]===f&&(i[u]=f)}function ct(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function st(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function lt(t,n){return t.style.getPropertyValue(n)||st(t).getComputedStyle(t,null).getPropertyValue(n)}function ht(t){return t.trim().split(/^|\s+/)}function dt(t){return t.classList||new pt(t)}function pt(t){this._node=t,this._names=ht(t.getAttribute("class")||"")}function vt(t,n){for(var e=dt(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function gt(t,n){for(var e=dt(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function yt(){this.textContent=""}function _t(){this.innerHTML=""}function bt(){this.nextSibling&&this.parentNode.appendChild(this)}function mt(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function xt(){return null}function wt(){var t=this.parentNode;t&&t.removeChild(this)}function Mt(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function At(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}pt.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Tt={};(t.event=null,"undefined"!=typeof document)&&("onmouseenter"in document.documentElement||(Tt={mouseenter:"mouseover",mouseleave:"mouseout"}));function Nt(t,n,e){return t=St(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function St(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function Et(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function kt(t,n,e){var r=Tt.hasOwnProperty(t.type)?Nt:St;return function(i,o,a){var u,f=this.__on,c=r(n,o,a);if(f)for(var s=0,l=f.length;s<l;++s)if((u=f[s]).type===t.type&&u.name===t.name)return this.removeEventListener(u.type,u.listener,u.capture),this.addEventListener(u.type,u.listener=c,u.capture=e),void(u.value=n);this.addEventListener(t.type,c,e),u={type:t.type,name:t.name,value:n,listener:c,capture:e},f?f.push(u):this.__on=[u]}}function Ct(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function Pt(t,n,e){var r=st(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}var zt=[null];function Rt(t,n){this._groups=t,this._parents=n}function Lt(){return new Rt([[document.documentElement]],zt)}function Dt(t){return"string"==typeof t?new Rt([[document.querySelector(t)]],[document.documentElement]):new Rt([[t]],zt)}Rt.prototype=Lt.prototype={constructor:Rt,select:function(t){"function"!=typeof t&&(t=Q(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a,u=n[i],f=u.length,c=r[i]=new Array(f),s=0;s<f;++s)(o=u[s])&&(a=t.call(o,o.__data__,s,u))&&("__data__"in o&&(a.__data__=o.__data__),c[s]=a);return new Rt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=K(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var a,u=n[o],f=u.length,c=0;c<f;++c)(a=u[c])&&(r.push(t.call(a,a.__data__,c,u)),i.push(a));return new Rt(r,i)},filter:function(t){"function"!=typeof t&&(t=rt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,f=r[i]=[],c=0;c<u;++c)(o=a[c])&&t.call(o,o.__data__,c,a)&&f.push(o);return new Rt(r,this._parents)},data:function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e,r=n?ft:ut,i=this._parents,o=this._groups;"function"!=typeof t&&(e=t,t=function(){return e});for(var a=o.length,u=new Array(a),f=new Array(a),c=new Array(a),s=0;s<a;++s){var l=i[s],h=o[s],d=h.length,p=t.call(l,l&&l.__data__,s,i),v=p.length,g=f[s]=new Array(v),y=u[s]=new Array(v);r(l,h,g,y,c[s]=new Array(d),p,n);for(var _,b,m=0,x=0;m<v;++m)if(_=g[m]){for(m>=x&&(x=m+1);!(b=y[x])&&++x<v;);_._next=b||null}}return(u=new Rt(u,i))._enter=f,u._exit=c,u},enter:function(){return new Rt(this._enter||this._groups.map(it),this._parents)},exit:function(){return new Rt(this._exit||this._groups.map(it),this._parents)},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var f,c=n[u],s=e[u],l=c.length,h=a[u]=new Array(l),d=0;d<l;++d)(f=c[d]||s[d])&&(h[d]=f);for(;u<r;++u)a[u]=n[u];return new Rt(a,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,a=i[o];--o>=0;)(r=i[o])&&(a&&a!==r.nextSibling&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=ct);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var a,u=e[o],f=u.length,c=i[o]=new Array(f),s=0;s<f;++s)(a=u[s])&&(c[s]=a);c.sort(n)}return new Rt(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var a=r[i];if(a)return a}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],a=0,u=o.length;a<u;++a)(i=o[a])&&t.call(i,i.__data__,a,o);return this},attr:function(t,n){var e=$(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}}:"function"==typeof n?e.local?function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}:function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}:e.local?function(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}:function(t,n){return function(){this.setAttribute(t,n)}})(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):lt(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=ht(t+"");if(arguments.length<2){for(var r=dt(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?function(t,n){return function(){(n.apply(this,arguments)?vt:gt)(this,t)}}:n?function(t){return function(){vt(this,t)}}:function(t){return function(){gt(this,t)}})(e,n))},text:function(t){return arguments.length?this.each(null==t?yt:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}:function(t){return function(){this.textContent=t}})(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?_t:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}:function(t){return function(){this.innerHTML=t}})(t)):this.node().innerHTML},raise:function(){return this.each(bt)},lower:function(){return this.each(mt)},append:function(t){var n="function"==typeof t?t:W(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:W(t),r=null==n?xt:"function"==typeof n?n:Q(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(wt)},clone:function(t){return this.select(t?At:Mt)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=function(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?kt:Et,null==e&&(e=!1),r=0;r<a;++r)this.each(u(o[r],n,e));return this}var u=this.node().__on;if(u)for(var f,c=0,s=u.length;c<s;++c)for(r=0,f=u[c];r<a;++r)if((i=o[r]).type===f.type&&i.name===f.name)return f.value},dispatch:function(t,n){return this.each(("function"==typeof n?function(t,n){return function(){return Pt(this,t,n.apply(this,arguments))}}:function(t,n){return function(){return Pt(this,t,n)}})(t,n))}};var Ut=0;function qt(){return new Ot}function Ot(){this._="@"+(++Ut).toString(36)}function Yt(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e}function Bt(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,[(r=r.matrixTransform(t.getScreenCTM().inverse())).x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]}function Ft(t){var n=Yt();return n.changedTouches&&(n=n.changedTouches[0]),Bt(t,n)}function It(t,n,e){arguments.length<3&&(e=n,n=Yt().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Bt(t,r);return null}function Ht(){t.event.stopImmediatePropagation()}function jt(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function Xt(t){var n=t.document.documentElement,e=Dt(t).on("dragstart.drag",jt,!0);"onselectstart"in n?e.on("selectstart.drag",jt,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")}function Gt(t,n){var e=t.document.documentElement,r=Dt(t).on("dragstart.drag",null);n&&(r.on("click.drag",jt,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function Vt(t){return function(){return t}}function $t(t,n,e,r,i,o,a,u,f,c){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=a,this.dx=u,this.dy=f,this._=c}function Wt(){return!t.event.button}function Zt(){return this.parentNode}function Qt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function Jt(){return"ontouchstart"in this}function Kt(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function tn(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function nn(){}Ot.prototype=qt.prototype={constructor:Ot,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}},$t.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var en="\\s*([+-]?\\d+)\\s*",rn="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",on="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",an=/^#([0-9a-f]{3})$/,un=/^#([0-9a-f]{6})$/,fn=new RegExp("^rgb\\("+[en,en,en]+"\\)$"),cn=new RegExp("^rgb\\("+[on,on,on]+"\\)$"),sn=new RegExp("^rgba\\("+[en,en,en,rn]+"\\)$"),ln=new RegExp("^rgba\\("+[on,on,on,rn]+"\\)$"),hn=new RegExp("^hsl\\("+[rn,on,on]+"\\)$"),dn=new RegExp("^hsla\\("+[rn,on,on,rn]+"\\)$"),pn={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function vn(t){var n;return t=(t+"").trim().toLowerCase(),(n=an.exec(t))?new mn((n=parseInt(n[1],16))>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=un.exec(t))?gn(parseInt(n[1],16)):(n=fn.exec(t))?new mn(n[1],n[2],n[3],1):(n=cn.exec(t))?new mn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=sn.exec(t))?yn(n[1],n[2],n[3],n[4]):(n=ln.exec(t))?yn(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=hn.exec(t))?wn(n[1],n[2]/100,n[3]/100,1):(n=dn.exec(t))?wn(n[1],n[2]/100,n[3]/100,n[4]):pn.hasOwnProperty(t)?gn(pn[t]):"transparent"===t?new mn(NaN,NaN,NaN,0):null}function gn(t){return new mn(t>>16&255,t>>8&255,255&t,1)}function yn(t,n,e,r){return r<=0&&(t=n=e=NaN),new mn(t,n,e,r)}function _n(t){return t instanceof nn||(t=vn(t)),t?new mn((t=t.rgb()).r,t.g,t.b,t.opacity):new mn}function bn(t,n,e,r){return 1===arguments.length?_n(t):new mn(t,n,e,null==r?1:r)}function mn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function xn(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function wn(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new An(t,n,e,r)}function Mn(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof An)return new An(t.h,t.s,t.l,t.opacity);if(t instanceof nn||(t=vn(t)),!t)return new An;if(t instanceof An)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,f=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e<r):e===o?(r-n)/u+2:(n-e)/u+4,u/=f<.5?o+i:2-o-i,a*=60):u=f>0&&f<1?0:a,new An(a,u,f,t.opacity)}(t):new An(t,n,e,null==r?1:r)}function An(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Tn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Kt(nn,vn,{displayable:function(){return this.rgb().displayable()},hex:function(){return this.rgb().hex()},toString:function(){return this.rgb()+""}}),Kt(mn,bn,tn(nn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new mn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new mn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},hex:function(){return"#"+xn(this.r)+xn(this.g)+xn(this.b)},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),Kt(An,Mn,tn(nn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new An(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new An(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new mn(Tn(t>=240?t-240:t+120,i,r),Tn(t,i,r),Tn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Nn=Math.PI/180,Sn=180/Math.PI,En=.96422,kn=1,Cn=.82521,Pn=4/29,zn=6/29,Rn=3*zn*zn,Ln=zn*zn*zn;function Dn(t){if(t instanceof qn)return new qn(t.l,t.a,t.b,t.opacity);if(t instanceof jn){if(isNaN(t.h))return new qn(t.l,0,0,t.opacity);var n=t.h*Nn;return new qn(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof mn||(t=_n(t));var e,r,i=Fn(t.r),o=Fn(t.g),a=Fn(t.b),u=On((.2225045*i+.7168786*o+.0606169*a)/kn);return i===o&&o===a?e=r=u:(e=On((.4360747*i+.3850649*o+.1430804*a)/En),r=On((.0139322*i+.0971045*o+.7141733*a)/Cn)),new qn(116*u-16,500*(e-u),200*(u-r),t.opacity)}function Un(t,n,e,r){return 1===arguments.length?Dn(t):new qn(t,n,e,null==r?1:r)}function qn(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function On(t){return t>Ln?Math.pow(t,1/3):t/Rn+Pn}function Yn(t){return t>zn?t*t*t:Rn*(t-Pn)}function Bn(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Fn(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function In(t){if(t instanceof jn)return new jn(t.h,t.c,t.l,t.opacity);if(t instanceof qn||(t=Dn(t)),0===t.a&&0===t.b)return new jn(NaN,0,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*Sn;return new jn(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function Hn(t,n,e,r){return 1===arguments.length?In(t):new jn(t,n,e,null==r?1:r)}function jn(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}Kt(qn,Un,tn(nn,{brighter:function(t){return new qn(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new qn(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new mn(Bn(3.1338561*(n=En*Yn(n))-1.6168667*(t=kn*Yn(t))-.4906146*(e=Cn*Yn(e))),Bn(-.9787684*n+1.9161415*t+.033454*e),Bn(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Kt(jn,Hn,tn(nn,{brighter:function(t){return new jn(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new jn(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return Dn(this).rgb()}}));var Xn=-.14861,Gn=1.78277,Vn=-.29227,$n=-.90649,Wn=1.97294,Zn=Wn*$n,Qn=Wn*Gn,Jn=Gn*Vn-$n*Xn;function Kn(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof te)return new te(t.h,t.s,t.l,t.opacity);t instanceof mn||(t=_n(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Jn*r+Zn*n-Qn*e)/(Jn+Zn-Qn),o=r-i,a=(Wn*(e-i)-Vn*o)/$n,u=Math.sqrt(a*a+o*o)/(Wn*i*(1-i)),f=u?Math.atan2(a,o)*Sn-120:NaN;return new te(f<0?f+360:f,u,i,t.opacity)}(t):new te(t,n,e,null==r?1:r)}function te(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function ne(t,n,e,r,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*n+(4-6*o+3*a)*e+(1+3*t+3*o-3*a)*r+a*i)/6}function ee(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r<n-1?t[r+2]:2*o-i;return ne((e-r/n)*n,a,i,o,u)}}function re(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],a=t[(r+1)%n],u=t[(r+2)%n];return ne((e-r/n)*n,i,o,a,u)}}function ie(t){return function(){return t}}function oe(t,n){return function(e){return t+e*n}}function ae(t,n){var e=n-t;return e?oe(t,e>180||e<-180?e-360*Math.round(e/360):e):ie(isNaN(t)?n:t)}function ue(t){return 1==(t=+t)?fe:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):ie(isNaN(n)?e:n)}}function fe(t,n){var e=n-t;return e?oe(t,e):ie(isNaN(t)?n:t)}Kt(te,Kn,tn(nn,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new te(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new te(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Nn,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new mn(255*(n+e*(Xn*r+Gn*i)),255*(n+e*(Vn*r+$n*i)),255*(n+e*(Wn*r)),this.opacity)}}));var ce=function t(n){var e=ue(n);function r(t,n){var r=e((t=bn(t)).r,(n=bn(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=fe(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function se(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;e<i;++e)r=bn(n[e]),o[e]=r.r||0,a[e]=r.g||0,u[e]=r.b||0;return o=t(o),a=t(a),u=t(u),r.opacity=1,function(t){return r.r=o(t),r.g=a(t),r.b=u(t),r+""}}}var le=se(ee),he=se(re);function de(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(i),a=new Array(r);for(e=0;e<i;++e)o[e]=me(t[e],n[e]);for(;e<r;++e)a[e]=n[e];return function(t){for(e=0;e<i;++e)a[e]=o[e](t);return a}}function pe(t,n){var e=new Date;return n-=t=+t,function(r){return e.setTime(t+n*r),e}}function ve(t,n){return n-=t=+t,function(e){return t+n*e}}function ge(t,n){var e,r={},i={};for(e in null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={}),n)e in t?r[e]=me(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}}var ye=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,_e=new RegExp(ye.source,"g");function be(t,n){var e,r,i,o=ye.lastIndex=_e.lastIndex=0,a=-1,u=[],f=[];for(t+="",n+="";(e=ye.exec(t))&&(r=_e.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,f.push({i:a,x:ve(e,r)})),o=_e.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?f[0]?function(t){return function(n){return t(n)+""}}(f[0].x):function(t){return function(){return t}}(n):(n=f.length,function(t){for(var e,r=0;r<n;++r)u[(e=f[r]).i]=e.x(t);return u.join("")})}function me(t,n){var e,r=typeof n;return null==n||"boolean"===r?ie(n):("number"===r?ve:"string"===r?(e=vn(n))?(n=e,ce):be:n instanceof vn?ce:n instanceof Date?pe:Array.isArray(n)?de:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?ge:ve)(t,n)}function xe(t,n){return n-=t=+t,function(e){return Math.round(t+n*e)}}var we,Me,Ae,Te,Ne=180/Math.PI,Se={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Ee(t,n,e,r,i,o){var a,u,f;return(a=Math.sqrt(t*t+n*n))&&(t/=a,n/=a),(f=t*e+n*r)&&(e-=t*f,r-=n*f),(u=Math.sqrt(e*e+r*r))&&(e/=u,r/=u,f/=u),t*r<n*e&&(t=-t,n=-n,f=-f,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*Ne,skewX:Math.atan(f)*Ne,scaleX:a,scaleY:u}}function ke(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}return function(o,a){var u=[],f=[];return o=t(o),a=t(a),function(t,r,i,o,a,u){if(t!==i||r!==o){var f=a.push("translate(",null,n,null,e);u.push({i:f-4,x:ve(t,i)},{i:f-2,x:ve(r,o)})}else(i||o)&&a.push("translate("+i+n+o+e)}(o.translateX,o.translateY,a.translateX,a.translateY,u,f),function(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:ve(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,f),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:ve(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,f),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:ve(t,e)},{i:u-2,x:ve(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,f),o=a=null,function(t){for(var n,e=-1,r=f.length;++e<r;)u[(n=f[e]).i]=n.x(t);return u.join("")}}}var Ce=ke(function(t){return"none"===t?Se:(we||(we=document.createElement("DIV"),Me=document.documentElement,Ae=document.defaultView),we.style.transform=t,t=Ae.getComputedStyle(Me.appendChild(we),null).getPropertyValue("transform"),Me.removeChild(we),Ee(+(t=t.slice(7,-1).split(","))[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),Pe=ke(function(t){return null==t?Se:(Te||(Te=document.createElementNS("http://www.w3.org/2000/svg","g")),Te.setAttribute("transform",t),(t=Te.transform.baseVal.consolidate())?Ee((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):Se)},", ",")",")"),ze=Math.SQRT2,Re=2,Le=4,De=1e-12;function Ue(t){return((t=Math.exp(t))+1/t)/2}function qe(t,n){var e,r,i=t[0],o=t[1],a=t[2],u=n[0],f=n[1],c=n[2],s=u-i,l=f-o,h=s*s+l*l;if(h<De)r=Math.log(c/a)/ze,e=function(t){return[i+t*s,o+t*l,a*Math.exp(ze*t*r)]};else{var d=Math.sqrt(h),p=(c*c-a*a+Le*h)/(2*a*Re*d),v=(c*c-a*a-Le*h)/(2*c*Re*d),g=Math.log(Math.sqrt(p*p+1)-p),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-g)/ze,e=function(t){var n,e=t*r,u=Ue(g),f=a/(Re*d)*(u*(n=ze*e+g,((n=Math.exp(2*n))-1)/(n+1))-function(t){return((t=Math.exp(t))-1/t)/2}(g));return[i+f*s,o+f*l,a*u/Ue(ze*e+g)]}}return e.duration=1e3*r,e}function Oe(t){return function(n,e){var r=t((n=Mn(n)).h,(e=Mn(e)).h),i=fe(n.s,e.s),o=fe(n.l,e.l),a=fe(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var Ye=Oe(ae),Be=Oe(fe);function Fe(t){return function(n,e){var r=t((n=Hn(n)).h,(e=Hn(e)).h),i=fe(n.c,e.c),o=fe(n.l,e.l),a=fe(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var Ie=Fe(ae),He=Fe(fe);function je(t){return function n(e){function r(n,r){var i=t((n=Kn(n)).h,(r=Kn(r)).h),o=fe(n.s,r.s),a=fe(n.l,r.l),u=fe(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=a(Math.pow(t,e)),n.opacity=u(t),n+""}}return e=+e,r.gamma=n,r}(1)}var Xe=je(ae),Ge=je(fe);var Ve,$e,We=0,Ze=0,Qe=0,Je=1e3,Ke=0,tr=0,nr=0,er="object"==typeof performance&&performance.now?performance:Date,rr="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function ir(){return tr||(rr(or),tr=er.now()+nr)}function or(){tr=0}function ar(){this._call=this._time=this._next=null}function ur(t,n,e){var r=new ar;return r.restart(t,n,e),r}function fr(){ir(),++We;for(var t,n=Ve;n;)(t=tr-n._time)>=0&&n._call.call(null,t),n=n._next;--We}function cr(){tr=(Ke=er.now())+nr,We=Ze=0;try{fr()}finally{We=0,function(){var t,n,e=Ve,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Ve=n);$e=t,lr(r)}(),tr=0}}function sr(){var t=er.now(),n=t-Ke;n>Je&&(nr-=n,Ke=t)}function lr(t){We||(Ze&&(Ze=clearTimeout(Ze)),t-tr>24?(t<1/0&&(Ze=setTimeout(cr,t-er.now()-nr)),Qe&&(Qe=clearInterval(Qe))):(Qe||(Ke=er.now(),Qe=setInterval(sr,Je)),We=1,rr(cr)))}function hr(t,n,e){var r=new ar;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r}ar.prototype=ur.prototype={constructor:ar,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?ir():+e)+(null==n?0:+n),this._next||$e===this||($e?$e._next=this:Ve=this,$e=this),this._call=t,this._time=e,lr()},stop:function(){this._call&&(this._call=null,this._time=1/0,lr())}};var dr=I("start","end","interrupt"),pr=[],vr=0,gr=1,yr=2,_r=3,br=4,mr=5,xr=6;function wr(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(f){var c,s,l,h;if(e.state!==gr)return u();for(c in i)if((h=i[c]).name===e.name){if(h.state===_r)return hr(o);h.state===br?(h.state=xr,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[c]):+c<n&&(h.state=xr,h.timer.stop(),delete i[c])}if(hr(function(){e.state===_r&&(e.state=br,e.timer.restart(a,e.delay,e.time),a(f))}),e.state=yr,e.on.call("start",t,t.__data__,e.index,e.group),e.state===yr){for(e.state=_r,r=new Array(l=e.tween.length),c=0,s=-1;c<l;++c)(h=e.tween[c].value.call(t,t.__data__,e.index,e.group))&&(r[++s]=h);r.length=s+1}}function a(n){for(var i=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(u),e.state=mr,1),o=-1,a=r.length;++o<a;)r[o].call(null,i);e.state===mr&&(e.on.call("end",t,t.__data__,e.index,e.group),u())}function u(){for(var r in e.state=xr,e.timer.stop(),delete i[n],i)return;delete t.__transition}i[n]=e,e.timer=ur(function(t){e.state=gr,e.timer.restart(o,e.delay,e.time),e.delay<=t&&o(t-e.delay)},0,e.time)}(t,e,{name:n,index:r,group:i,on:dr,tween:pr,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:vr})}function Mr(t,n){var e=Tr(t,n);if(e.state>vr)throw new Error("too late; already scheduled");return e}function Ar(t,n){var e=Tr(t,n);if(e.state>yr)throw new Error("too late; already started");return e}function Tr(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Nr(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>yr&&e.state<mr,e.state=xr,e.timer.stop(),r&&e.on.call("interrupt",t,t.__data__,e.index,e.group),delete o[i]):a=!1;a&&delete t.__transition}}function Sr(t,n,e){var r=t._id;return t.each(function(){var t=Ar(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return Tr(t,r).value[n]}}function Er(t,n){var e;return("number"==typeof n?ve:n instanceof vn?ce:(e=vn(n))?(n=e,ce):be)(t,n)}var kr=Lt.prototype.constructor;var Cr=0;function Pr(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function zr(t){return Lt().transition(t)}function Rr(){return++Cr}var Lr=Lt.prototype;function Dr(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function Ur(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}Pr.prototype=zr.prototype={constructor:Pr,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=Q(t));for(var r=this._groups,i=r.length,o=new Array(i),a=0;a<i;++a)for(var u,f,c=r[a],s=c.length,l=o[a]=new Array(s),h=0;h<s;++h)(u=c[h])&&(f=t.call(u,u.__data__,h,c))&&("__data__"in u&&(f.__data__=u.__data__),l[h]=f,wr(l[h],n,e,h,l,Tr(u,e)));return new Pr(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=K(t));for(var r=this._groups,i=r.length,o=[],a=[],u=0;u<i;++u)for(var f,c=r[u],s=c.length,l=0;l<s;++l)if(f=c[l]){for(var h,d=t.call(f,f.__data__,l,c),p=Tr(f,e),v=0,g=d.length;v<g;++v)(h=d[v])&&wr(h,n,e,v,d,p);o.push(d),a.push(f)}return new Pr(o,a,n,e)},filter:function(t){"function"!=typeof t&&(t=rt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,f=r[i]=[],c=0;c<u;++c)(o=a[c])&&t.call(o,o.__data__,c,a)&&f.push(o);return new Pr(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var f,c=n[u],s=e[u],l=c.length,h=a[u]=new Array(l),d=0;d<l;++d)(f=c[d]||s[d])&&(h[d]=f);for(;u<r;++u)a[u]=n[u];return new Pr(a,this._parents,this._name,this._id)},selection:function(){return new kr(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Rr(),r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],f=u.length,c=0;c<f;++c)if(a=u[c]){var s=Tr(a,n);wr(a,t,e,c,u,{time:s.time+s.delay+s.duration,delay:0,duration:s.duration,ease:s.ease})}return new Pr(r,this._parents,t,e)},call:Lr.call,nodes:Lr.nodes,node:Lr.node,size:Lr.size,empty:Lr.empty,each:Lr.each,on:function(t,n){var e=this._id;return arguments.length<2?Tr(this.node(),e).on.on(t):this.each(function(t,n,e){var r,i,o=function(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?Mr:Ar;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=$(t),r="transform"===e?Pe:Er;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var a,u=e(this);if(null!=u)return(a=this.getAttributeNS(t.space,t.local))===u?null:a===r&&u===i?o:o=n(r=a,i=u);this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var a,u=e(this);if(null!=u)return(a=this.getAttribute(t))===u?null:a===r&&u===i?o:o=n(r=a,i=u);this.removeAttribute(t)}})(e,r,Sr(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}:function(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}})(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=$(t);return this.tween(e,(r.local?function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}:function(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?Ce:Er;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=lt(this,t),a=(this.style.removeProperty(t),lt(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,function(t){return function(){this.style.removeProperty(t)}}(t)):this.styleTween(t,"function"==typeof n?function(t,n,e){var r,i,o;return function(){var a=lt(this,t),u=e(this);return null==u&&(this.style.removeProperty(t),u=lt(this,t)),a===u?null:a===r&&u===i?o:o=n(r=a,i=u)}}(t,r,Sr(this,"style."+t,n)):function(t,n,e){var r,i;return function(){var o=lt(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(Sr(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},remove:function(){return this.on("end.remove",(t=this._id,function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}));var t},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Tr(this.node(),e).tween,o=0,a=i.length;o<a;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?function(t,n){var e,r;return function(){var i=Ar(this,t),o=i.tween;if(o!==e)for(var a=0,u=(r=e=o).length;a<u;++a)if(r[a].name===n){(r=r.slice()).splice(a,1);break}i.tween=r}}:function(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=Ar(this,t),a=o.tween;if(a!==r){i=(r=a).slice();for(var u={name:n,value:e},f=0,c=i.length;f<c;++f)if(i[f].name===n){i[f]=u;break}f===c&&i.push(u)}o.tween=i}})(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){Mr(this,t).delay=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){Mr(this,t).delay=n}})(n,t)):Tr(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){Ar(this,t).duration=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){Ar(this,t).duration=n}})(n,t)):Tr(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(function(t,n){if("function"!=typeof n)throw new Error;return function(){Ar(this,t).ease=n}}(n,t)):Tr(this.node(),n).ease}};var qr=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Or=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Yr=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Br=Math.PI,Fr=Br/2;function Ir(t){return(1-Math.cos(Br*t))/2}function Hr(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function jr(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var Xr=4/11,Gr=6/11,Vr=8/11,$r=.75,Wr=9/11,Zr=10/11,Qr=.9375,Jr=21/22,Kr=63/64,ti=1/Xr/Xr;function ni(t){return(t=+t)<Xr?ti*t*t:t<Vr?ti*(t-=Gr)*t+$r:t<Zr?ti*(t-=Wr)*t+Qr:ti*(t-=Jr)*t+Kr}var ei=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),ri=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),ii=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),oi=2*Math.PI,ai=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=oi);function i(t){return n*Math.pow(2,10*--t)*Math.sin((r-t)/e)}return i.amplitude=function(n){return t(n,e*oi)},i.period=function(e){return t(n,e)},i}(1,.3),ui=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=oi);function i(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+r)/e)}return i.amplitude=function(n){return t(n,e*oi)},i.period=function(e){return t(n,e)},i}(1,.3),fi=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=oi);function i(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((r-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((r+t)/e))/2}return i.amplitude=function(n){return t(n,e*oi)},i.period=function(e){return t(n,e)},i}(1,.3),ci={time:null,delay:0,duration:250,ease:Ur};function si(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return ci.time=ir(),ci;return e}Lt.prototype.interrupt=function(t){return this.each(function(){Nr(this,t)})},Lt.prototype.transition=function(t){var n,e;t instanceof Pr?(n=t._id,t=t._name):(n=Rr(),(e=ci).time=ir(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],f=u.length,c=0;c<f;++c)(a=u[c])&&wr(a,t,n,c,u,e||si(a,n));return new Pr(r,this._parents,t,n)};var li=[null];function hi(t){return function(){return t}}function di(t,n,e){this.target=t,this.type=n,this.selection=e}function pi(){t.event.stopImmediatePropagation()}function vi(){t.event.preventDefault(),t.event.stopImmediatePropagation()}var gi={name:"drag"},yi={name:"space"},_i={name:"handle"},bi={name:"center"},mi={name:"x",handles:["e","w"].map(Ei),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},xi={name:"y",handles:["n","s"].map(Ei),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},wi={name:"xy",handles:["n","e","s","w","nw","ne","se","sw"].map(Ei),input:function(t){return t},output:function(t){return t}},Mi={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ai={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ti={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},Ni={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Si={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function Ei(t){return{type:t}}function ki(){return!t.event.button}function Ci(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function Pi(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function zi(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function Ri(n){var e,r=Ci,i=ki,o=I(u,"start","brush","end"),a=6;function u(t){var e=t.property("__brush",h).selectAll(".overlay").data([Ei("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Mi.overlay).merge(e).each(function(){var t=Pi(this).extent;Dt(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([Ei("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Mi.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=t.selectAll(".handle").data(n.handles,function(t){return t.type});r.exit().remove(),r.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Mi[t.type]}),t.each(f).attr("fill","none").attr("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush touchstart.brush",l)}function f(){var t=Dt(this),n=Pi(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-a/2:n[0][0]-a/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-a/2:n[0][1]-a/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+a:a}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+a:a})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function c(t,n){return t.__brush.emitter||new s(t,n)}function s(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function l(){if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return vi()}else if(e)return;if(i.apply(this,arguments)){var r,o,a,u,s,l,h,d,p,v,g,y,_,b=this,m=t.event.target.__data__.type,x="selection"===(t.event.metaKey?m="overlay":m)?gi:t.event.altKey?bi:_i,w=n===xi?null:Ni[m],M=n===mi?null:Si[m],A=Pi(b),T=A.extent,N=A.selection,S=T[0][0],E=T[0][1],k=T[1][0],C=T[1][1],P=w&&M&&t.event.shiftKey,z=Ft(b),R=z,L=c(b,arguments).beforestart();"overlay"===m?A.selection=N=[[r=n===xi?S:z[0],a=n===mi?E:z[1]],[s=n===xi?k:r,h=n===mi?C:a]]:(r=N[0][0],a=N[0][1],s=N[1][0],h=N[1][1]),o=r,u=a,l=s,d=h;var D=Dt(b).attr("pointer-events","none"),U=D.selectAll(".overlay").attr("cursor",Mi[m]);if(t.event.touches)D.on("touchmove.brush",O,!0).on("touchend.brush touchcancel.brush",B,!0);else{var q=Dt(t.event.view).on("keydown.brush",function(){switch(t.event.keyCode){case 16:P=w&&M;break;case 18:x===_i&&(w&&(s=l-p*w,r=o+p*w),M&&(h=d-v*M,a=u+v*M),x=bi,Y());break;case 32:x!==_i&&x!==bi||(w<0?s=l-p:w>0&&(r=o-p),M<0?h=d-v:M>0&&(a=u-v),x=yi,U.attr("cursor",Mi.selection),Y());break;default:return}vi()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:P&&(y=_=P=!1,Y());break;case 18:x===bi&&(w<0?s=l:w>0&&(r=o),M<0?h=d:M>0&&(a=u),x=_i,Y());break;case 32:x===yi&&(t.event.altKey?(w&&(s=l-p*w,r=o+p*w),M&&(h=d-v*M,a=u+v*M),x=bi):(w<0?s=l:w>0&&(r=o),M<0?h=d:M>0&&(a=u),x=_i),U.attr("cursor",Mi[m]),Y());break;default:return}vi()},!0).on("mousemove.brush",O,!0).on("mouseup.brush",B,!0);Xt(t.event.view)}pi(),Nr(b),f.call(b),L.start()}function O(){var t=Ft(b);!P||y||_||(Math.abs(t[0]-R[0])>Math.abs(t[1]-R[1])?_=!0:y=!0),R=t,g=!0,vi(),Y()}function Y(){var t;switch(p=R[0]-z[0],v=R[1]-z[1],x){case yi:case gi:w&&(p=Math.max(S-r,Math.min(k-s,p)),o=r+p,l=s+p),M&&(v=Math.max(E-a,Math.min(C-h,v)),u=a+v,d=h+v);break;case _i:w<0?(p=Math.max(S-r,Math.min(k-r,p)),o=r+p,l=s):w>0&&(p=Math.max(S-s,Math.min(k-s,p)),o=r,l=s+p),M<0?(v=Math.max(E-a,Math.min(C-a,v)),u=a+v,d=h):M>0&&(v=Math.max(E-h,Math.min(C-h,v)),u=a,d=h+v);break;case bi:w&&(o=Math.max(S,Math.min(k,r-p*w)),l=Math.max(S,Math.min(k,s+p*w))),M&&(u=Math.max(E,Math.min(C,a-v*M)),d=Math.max(E,Math.min(C,h+v*M)))}l<o&&(w*=-1,t=r,r=s,s=t,t=o,o=l,l=t,m in Ai&&U.attr("cursor",Mi[m=Ai[m]])),d<u&&(M*=-1,t=a,a=h,h=t,t=u,u=d,d=t,m in Ti&&U.attr("cursor",Mi[m=Ti[m]])),A.selection&&(N=A.selection),y&&(o=N[0][0],l=N[1][0]),_&&(u=N[0][1],d=N[1][1]),N[0][0]===o&&N[0][1]===u&&N[1][0]===l&&N[1][1]===d||(A.selection=[[o,u],[l,d]],f.call(b),L.brush())}function B(){if(pi(),t.event.touches){if(t.event.touches.length)return;e&&clearTimeout(e),e=setTimeout(function(){e=null},500),D.on("touchmove.brush touchend.brush touchcancel.brush",null)}else Gt(t.event.view,g),q.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);D.attr("pointer-events","all"),U.attr("cursor",Mi.overlay),A.selection&&(N=A.selection),zi(N)&&(A.selection=null,f.call(b)),L.end()}}function h(){var t=this.__brush||{selection:null};return t.extent=r.apply(this,arguments),t.dim=n,t}return u.move=function(t,e){t.selection?t.on("start.brush",function(){c(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){c(this,arguments).end()}).tween("brush",function(){var t=this,r=t.__brush,i=c(t,arguments),o=r.selection,a=n.input("function"==typeof e?e.apply(this,arguments):e,r.extent),u=me(o,a);function s(n){r.selection=1===n&&zi(a)?null:u(n),f.call(t),i.brush()}return o&&a?s:s(1)}):t.each(function(){var t=arguments,r=this.__brush,i=n.input("function"==typeof e?e.apply(this,t):e,r.extent),o=c(this,t).beforestart();Nr(this),r.selection=null==i||zi(i)?null:i,f.call(this),o.start().brush().end()})},s.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit("start")),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){Ct(new di(u,t,n.output(this.state.selection)),o.apply,o,[t,this.that,this.args])}},u.extent=function(t){return arguments.length?(r="function"==typeof t?t:hi([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),u):r},u.filter=function(t){return arguments.length?(i="function"==typeof t?t:hi(!!t),u):i},u.handleSize=function(t){return arguments.length?(a=+t,u):a},u.on=function(){var t=o.on.apply(o,arguments);return t===o?u:t},u}var Li=Math.cos,Di=Math.sin,Ui=Math.PI,qi=Ui/2,Oi=2*Ui,Yi=Math.max;var Bi=Array.prototype.slice;function Fi(t){return function(){return t}}var Ii=Math.PI,Hi=2*Ii,ji=Hi-1e-6;function Xi(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function Gi(){return new Xi}function Vi(t){return t.source}function $i(t){return t.target}function Wi(t){return t.radius}function Zi(t){return t.startAngle}function Qi(t){return t.endAngle}Xi.prototype=Gi.prototype={constructor:Xi,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,a=this._y1,u=e-t,f=r-n,c=o-t,s=a-n,l=c*c+s*s;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(s*u-f*c)>1e-6&&i){var h=e-o,d=r-a,p=u*u+f*f,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(l),_=i*Math.tan((Ii-Math.acos((p+l-v)/(2*g*y)))/2),b=_/y,m=_/g;Math.abs(b-1)>1e-6&&(this._+="L"+(t+b*c)+","+(n+b*s)),this._+="A"+i+","+i+",0,0,"+ +(s*h>c*d)+","+(this._x1=t+m*u)+","+(this._y1=n+m*f)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var a=(e=+e)*Math.cos(r),u=e*Math.sin(r),f=t+a,c=n+u,s=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+f+","+c:(Math.abs(this._x1-f)>1e-6||Math.abs(this._y1-c)>1e-6)&&(this._+="L"+f+","+c),e&&(l<0&&(l=l%Hi+Hi),l>ji?this._+="A"+e+","+e+",0,1,"+s+","+(t-a)+","+(n-u)+"A"+e+","+e+",0,1,"+s+","+(this._x1=f)+","+(this._y1=c):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Ii)+","+s+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};function Ji(){}function Ki(t,n){var e=new Ji;if(t instanceof Ji)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var a in t)e.set(a,t[a]);return e}function to(){return{}}function no(t,n,e){t[n]=e}function eo(){return Ki()}function ro(t,n,e){t.set(n,e)}function io(){}Ji.prototype=Ki.prototype={constructor:Ji,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var oo=Ki.prototype;function ao(t,n){var e=new io;if(t instanceof io)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}io.prototype=ao.prototype={constructor:io,has:oo.has,add:function(t){return this["$"+(t+="")]=t,this},remove:oo.remove,clear:oo.clear,values:oo.keys,size:oo.size,empty:oo.empty,each:oo.each};var uo=Array.prototype.slice;function fo(t,n){return t-n}function co(t){return function(){return t}}function so(t,n){for(var e,r=-1,i=n.length;++r<i;)if(e=lo(t,n[r]))return e;return 0}function lo(t,n){for(var e=n[0],r=n[1],i=-1,o=0,a=t.length,u=a-1;o<a;u=o++){var f=t[o],c=f[0],s=f[1],l=t[u],h=l[0],d=l[1];if(ho(f,l,n))return 0;s>r!=d>r&&e<(h-c)*(r-s)/(d-s)+c&&(i=-i)}return i}function ho(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function po(){}var vo=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function go(){var t=1,n=1,e=M,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(fo);else{var r=s(t),i=r[0],a=r[1];n=w(i,a,n),n=g(Math.floor(i/n)*n,Math.floor(a/n)*n,n)}return n.map(function(n){return o(t,n)})}function o(e,i){var o=[],u=[];return function(e,r,i){var o,u,f,c,s,l,h=new Array,d=new Array;o=u=-1,c=e[0]>=r,vo[c<<1].forEach(p);for(;++o<t-1;)f=c,c=e[o+1]>=r,vo[f|c<<1].forEach(p);vo[c<<0].forEach(p);for(;++u<n-1;){for(o=-1,c=e[u*t+t]>=r,s=e[u*t]>=r,vo[c<<1|s<<2].forEach(p);++o<t-1;)f=c,c=e[u*t+t+o+1]>=r,l=s,s=e[u*t+o+1]>=r,vo[f|c<<1|s<<2|l<<3].forEach(p);vo[c|s<<3].forEach(p)}o=-1,s=e[u*t]>=r,vo[s<<2].forEach(p);for(;++o<t-1;)l=s,s=e[u*t+o+1]>=r,vo[s<<2|l<<3].forEach(p);function p(t){var n,e,r=[t[0][0]+o,t[0][1]+u],f=[t[1][0]+o,t[1][1]+u],c=a(r),s=a(f);(n=d[c])?(e=h[s])?(delete d[n.end],delete h[e.start],n===e?(n.ring.push(f),i(n.ring)):h[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete d[n.end],n.ring.push(f),d[n.end=s]=n):(n=h[s])?(e=d[c])?(delete h[n.start],delete d[e.end],n===e?(n.ring.push(f),i(n.ring)):h[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete h[n.start],n.ring.unshift(r),h[n.start=c]=n):h[c]=d[s]={start:c,end:s,ring:[r,f]}}vo[s<<3].forEach(p)}(e,i,function(t){r(t,e,i),function(t){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];++n<e;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return r}(t)>0?o.push([t]):u.push(t)}),u.forEach(function(t){for(var n,e=0,r=o.length;e<r;++e)if(-1!==so((n=o[e])[0],t))return void n.push(t)}),{type:"MultiPolygon",value:i,coordinates:o}}function a(n){return 2*n[0]+n[1]*(t+1)*4}function u(e,r,i){e.forEach(function(e){var o,a=e[0],u=e[1],f=0|a,c=0|u,s=r[c*t+f];a>0&&a<t&&f===a&&(o=r[c*t+f-1],e[0]=a+(i-o)/(s-o)-.5),u>0&&u<n&&c===u&&(o=r[(c-1)*t+f],e[1]=u+(i-o)/(s-o)-.5)})}return i.contour=o,i.size=function(e){if(!arguments.length)return[t,n];var r=Math.ceil(e[0]),o=Math.ceil(e[1]);if(!(r>0&&o>0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?co(uo.call(t)):co(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:po,i):r===u},i}function yo(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<i;++a)for(var u=0,f=0;u<r+e;++u)u<r&&(f+=t.data[u+a*r]),u>=e&&(u>=o&&(f-=t.data[u-o+a*r]),n.data[u-e+a*r]=f/Math.min(u+1,r-1+o-u,o))}function _o(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<r;++a)for(var u=0,f=0;u<i+e;++u)u<i&&(f+=t.data[a+u*r]),u>=e&&(u>=o&&(f-=t.data[a+(u-o)*r]),n.data[a+(u-e)*r]=f/Math.min(u+1,i-1+o-u,o))}function bo(t){return t[0]}function mo(t){return t[1]}function xo(){return 1}var wo={},Mo={},Ao=34,To=10,No=13;function So(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}")}function Eo(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,f=o<=0,c=!1;function s(){if(f)return Mo;if(c)return c=!1,wo;var n,r,i=a;if(t.charCodeAt(i)===Ao){for(;a++<o&&t.charCodeAt(a)!==Ao||t.charCodeAt(++a)===Ao;);return(n=a)>=o?f=!0:(r=t.charCodeAt(a++))===To?c=!0:r===No&&(c=!0,t.charCodeAt(a)===To&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;a<o;){if((r=t.charCodeAt(n=a++))===To)c=!0;else if(r===No)c=!0,t.charCodeAt(a)===To&&++a;else if(r!==e)continue;return t.slice(i,n)}return f=!0,t.slice(i,o)}for(t.charCodeAt(o-1)===To&&--o,t.charCodeAt(o-1)===No&&--o;(r=s())!==Mo;){for(var l=[];r!==wo&&r!==Mo;)l.push(r),r=s();n&&null==(l=n(l,u++))||i.push(l)}return i}function i(n){return n.map(o).join(t)}function o(t){return null==t?"":n.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,n){var e,i,o=r(t,function(t,r){if(e)return e(t,r-1);i=t,e=n?function(t,n){var e=So(t);return function(r,i){return n(e(r),i,t)}}(t,n):So(t)});return o.columns=i||[],o},parseRows:r,format:function(n,e){return null==e&&(e=function(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}(n)),[e.map(o).join(t)].concat(n.map(function(n){return e.map(function(t){return o(n[t])}).join(t)})).join("\n")},formatRows:function(t){return t.map(i).join("\n")}}}var ko=Eo(","),Co=ko.parse,Po=ko.parseRows,zo=ko.format,Ro=ko.formatRows,Lo=Eo("\t"),Do=Lo.parse,Uo=Lo.parseRows,qo=Lo.format,Oo=Lo.formatRows;function Yo(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function Bo(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function Fo(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function Io(t,n){return fetch(t,n).then(Fo)}function Ho(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),Io(n,e).then(function(n){return t(n,r)})}}var jo=Ho(Co),Xo=Ho(Do);function Go(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.json()}function Vo(t){return function(n,e){return Io(n,e).then(function(n){return(new DOMParser).parseFromString(n,t)})}}var $o=Vo("application/xml"),Wo=Vo("text/html"),Zo=Vo("image/svg+xml");function Qo(t){return function(){return t}}function Jo(){return 1e-6*(Math.random()-.5)}function Ko(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,f,c,s,l,h,d=t._root,p={data:r},v=t._x0,g=t._y0,y=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((c=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a,i=d,!(d=d[l=s<<1|c]))return i[l]=p,t;if(u=+t._x.call(null,d.data),f=+t._y.call(null,d.data),n===u&&e===f)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(c=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a}while((l=s<<1|c)==(h=(f>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function ta(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function na(t){return t[0]}function ea(t){return t[1]}function ra(t,n,e){var r=new ia(null==n?na:n,null==e?ea:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function ia(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function oa(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var aa=ra.prototype=ia.prototype;function ua(t){return t.x+t.vx}function fa(t){return t.y+t.vy}function ca(t){return t.index}function sa(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function la(t){return t.x}function ha(t){return t.y}aa.copy=function(){var t,n,e=new ia(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=oa(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=oa(n));return e},aa.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Ko(this.cover(n,e),n,e,t)},aa.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),f=1/0,c=1/0,s=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(a[e]=r,u[e]=i,r<f&&(f=r),r>s&&(s=r),i<c&&(c=i),i>l&&(l=i));for(s<f&&(f=this._x0,s=this._x1),l<c&&(c=this._y0,l=this._y1),this.cover(f,c).cover(s,l),e=0;e<o;++e)Ko(this,a[e],u[e],t[e]);return this},aa.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var a,u,f=i-e,c=this._root;switch(u=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{(a=new Array(4))[u]=c,c=a}while(o=r+(f*=2),t>(i=e+f)||n>o);break;case 1:do{(a=new Array(4))[u]=c,c=a}while(o=r+(f*=2),(e=i-f)>t||n>o);break;case 2:do{(a=new Array(4))[u]=c,c=a}while(r=o-(f*=2),t>(i=e+f)||r>n);break;case 3:do{(a=new Array(4))[u]=c,c=a}while(r=o-(f*=2),(e=i-f)>t||r>n)}this._root&&this._root.length&&(this._root=c)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},aa.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},aa.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},aa.find=function(t,n,e){var r,i,o,a,u,f,c,s=this._x0,l=this._y0,h=this._x1,d=this._y1,p=[],v=this._root;for(v&&p.push(new ta(v,s,l,h,d)),null==e?e=1/0:(s=t-e,l=n-e,h=t+e,d=n+e,e*=e);f=p.pop();)if(!(!(v=f.node)||(i=f.x0)>h||(o=f.y0)>d||(a=f.x1)<s||(u=f.y1)<l))if(v.length){var g=(i+a)/2,y=(o+u)/2;p.push(new ta(v[3],g,y,a,u),new ta(v[2],i,y,g,u),new ta(v[1],g,o,a,y),new ta(v[0],i,o,g,y)),(c=(n>=y)<<1|t>=g)&&(f=p[p.length-1],p[p.length-1]=p[p.length-1-c],p[p.length-1-c]=f)}else{var _=t-+this._x.call(null,v.data),b=n-+this._y.call(null,v.data),m=_*_+b*b;if(m<e){var x=Math.sqrt(e=m);s=t-x,l=n-x,h=t+x,d=n+x,r=v.data}}return r},aa.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(a=+this._y.call(null,t)))return this;var n,e,r,i,o,a,u,f,c,s,l,h,d=this._root,p=this._x0,v=this._y0,g=this._x1,y=this._y1;if(!d)return this;if(d.length)for(;;){if((c=o>=(u=(p+g)/2))?p=u:g=u,(s=a>=(f=(v+y)/2))?v=f:y=f,n=d,!(d=d[l=s<<1|c]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},aa.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},aa.root=function(){return this._root},aa.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},aa.visit=function(t){var n,e,r,i,o,a,u=[],f=this._root;for(f&&u.push(new ta(f,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(f=n.node,r=n.x0,i=n.y0,o=n.x1,a=n.y1)&&f.length){var c=(r+o)/2,s=(i+a)/2;(e=f[3])&&u.push(new ta(e,c,s,o,a)),(e=f[2])&&u.push(new ta(e,r,s,c,a)),(e=f[1])&&u.push(new ta(e,c,i,o,s)),(e=f[0])&&u.push(new ta(e,r,i,c,s))}return this},aa.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new ta(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,a=n.x0,u=n.y0,f=n.x1,c=n.y1,s=(a+f)/2,l=(u+c)/2;(o=i[0])&&e.push(new ta(o,a,u,s,l)),(o=i[1])&&e.push(new ta(o,s,u,f,l)),(o=i[2])&&e.push(new ta(o,a,l,s,c)),(o=i[3])&&e.push(new ta(o,s,l,f,c))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},aa.x=function(t){return arguments.length?(this._x=t,this):this._x},aa.y=function(t){return arguments.length?(this._y=t,this):this._y};var da=10,pa=Math.PI*(3-Math.sqrt(5));function va(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]}function ga(t){return(t=va(Math.abs(t)))?t[1]:NaN}var ya,_a=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function ba(t){return new ma(t)}function ma(t){if(!(n=_a.exec(t)))throw new Error("invalid format: "+t);var n;this.fill=n[1]||" ",this.align=n[2]||">",this.sign=n[3]||"-",this.symbol=n[4]||"",this.zero=!!n[5],this.width=n[6]&&+n[6],this.comma=!!n[7],this.precision=n[8]&&+n[8].slice(1),this.trim=!!n[9],this.type=n[10]||""}function xa(t,n){var e=va(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}ba.prototype=ma.prototype,ma.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var wa={"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return xa(100*t,n)},r:xa,s:function(t,n){var e=va(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(ya=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+va(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}};function Ma(t){return t}var Aa,Ta=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Na(t){var n,e,r=t.grouping&&t.thousands?(n=t.grouping,e=t.thousands,function(t,r){for(var i=t.length,o=[],a=0,u=n[0],f=0;i>0&&u>0&&(f+u+1>r&&(u=Math.max(1,r-f)),o.push(t.substring(i-=u,i+u)),!((f+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}):Ma,i=t.currency,o=t.decimal,a=t.numerals?function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}}(t.numerals):Ma,u=t.percent||"%";function f(t){var n=(t=ba(t)).fill,e=t.align,f=t.sign,c=t.symbol,s=t.zero,l=t.width,h=t.comma,d=t.precision,p=t.trim,v=t.type;"n"===v?(h=!0,v="g"):wa[v]||(null==d&&(d=12),p=!0,v="g"),(s||"0"===n&&"="===e)&&(s=!0,n="0",e="=");var g="$"===c?i[0]:"#"===c&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",y="$"===c?i[1]:/[%p]/.test(v)?u:"",_=wa[v],b=/[defgprs%]/.test(v);function m(t){var i,u,c,m=g,x=y;if("c"===v)x=_(t)+x,t="";else{var w=(t=+t)<0;if(t=_(Math.abs(t),d),p&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r<e;++r)switch(t[r]){case".":i=n=r;break;case"0":0===i&&(i=r),n=r;break;default:if(i>0){if(!+t[r])break t;i=0}}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),w&&0==+t&&(w=!1),m=(w?"("===f?f:"-":"-"===f||"("===f?"":f)+m,x=("s"===v?Ta[8+ya/3]:"")+x+(w&&"("===f?")":""),b)for(i=-1,u=t.length;++i<u;)if(48>(c=t.charCodeAt(i))||c>57){x=(46===c?o+t.slice(i+1):t.slice(i))+x,t=t.slice(0,i);break}}h&&!s&&(t=r(t,1/0));var M=m.length+t.length+x.length,A=M<l?new Array(l-M+1).join(n):"";switch(h&&s&&(t=r(A+t,A.length?l-x.length:1/0),A=""),e){case"<":t=m+t+x+A;break;case"=":t=m+A+t+x;break;case"^":t=A.slice(0,M=A.length>>1)+m+t+x+A.slice(M);break;default:t=A+m+t+x}return a(t)}return d=null==d?6:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),m.toString=function(){return t+""},m}return{format:f,formatPrefix:function(t,n){var e=f(((t=ba(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(ga(n)/3))),i=Math.pow(10,-r),o=Ta[8+r/3];return function(t){return e(i*t)+o}}}}function Sa(n){return Aa=Na(n),t.format=Aa.format,t.formatPrefix=Aa.formatPrefix,Aa}function Ea(t){return Math.max(0,-ga(Math.abs(t)))}function ka(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(ga(n)/3)))-ga(Math.abs(t)))}function Ca(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,ga(n)-ga(t))+1}function Pa(){return new za}function za(){this.reset()}Sa({decimal:".",thousands:",",grouping:[3],currency:["$",""]}),za.prototype={constructor:za,reset:function(){this.s=this.t=0},add:function(t){La(Ra,t,this.t),La(this,Ra.s,this.s),this.s?this.t+=Ra.t:this.s=Ra.t},valueOf:function(){return this.s}};var Ra=new za;function La(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}var Da=1e-6,Ua=1e-12,qa=Math.PI,Oa=qa/2,Ya=qa/4,Ba=2*qa,Fa=180/qa,Ia=qa/180,Ha=Math.abs,ja=Math.atan,Xa=Math.atan2,Ga=Math.cos,Va=Math.ceil,$a=Math.exp,Wa=Math.log,Za=Math.pow,Qa=Math.sin,Ja=Math.sign||function(t){return t>0?1:t<0?-1:0},Ka=Math.sqrt,tu=Math.tan;function nu(t){return t>1?0:t<-1?qa:Math.acos(t)}function eu(t){return t>1?Oa:t<-1?-Oa:Math.asin(t)}function ru(t){return(t=Qa(t/2))*t}function iu(){}function ou(t,n){t&&uu.hasOwnProperty(t.type)&&uu[t.type](t,n)}var au={Feature:function(t,n){ou(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)ou(e[r].geometry,n)}},uu={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){fu(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)fu(e[r],n,0)},Polygon:function(t,n){cu(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)cu(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)ou(e[r],n)}};function fu(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function cu(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)fu(t[e],n,1);n.polygonEnd()}function su(t,n){t&&au.hasOwnProperty(t.type)?au[t.type](t,n):ou(t,n)}var lu,hu,du,pu,vu,gu=Pa(),yu=Pa(),_u={point:iu,lineStart:iu,lineEnd:iu,polygonStart:function(){gu.reset(),_u.lineStart=bu,_u.lineEnd=mu},polygonEnd:function(){var t=+gu;yu.add(t<0?Ba+t:t),this.lineStart=this.lineEnd=this.point=iu},sphere:function(){yu.add(Ba)}};function bu(){_u.point=xu}function mu(){wu(lu,hu)}function xu(t,n){_u.point=wu,lu=t,hu=n,du=t*=Ia,pu=Ga(n=(n*=Ia)/2+Ya),vu=Qa(n)}function wu(t,n){var e=(t*=Ia)-du,r=e>=0?1:-1,i=r*e,o=Ga(n=(n*=Ia)/2+Ya),a=Qa(n),u=vu*a,f=pu*o+u*Ga(i),c=u*r*Qa(i);gu.add(Xa(c,f)),du=t,pu=o,vu=a}function Mu(t){return[Xa(t[1],t[0]),eu(t[2])]}function Au(t){var n=t[0],e=t[1],r=Ga(e);return[r*Ga(n),r*Qa(n),Qa(e)]}function Tu(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Nu(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Su(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function Eu(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function ku(t){var n=Ka(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var Cu,Pu,zu,Ru,Lu,Du,Uu,qu,Ou,Yu,Bu,Fu,Iu,Hu,ju,Xu,Gu,Vu,$u,Wu,Zu,Qu,Ju,Ku,tf,nf,ef=Pa(),rf={point:of,lineStart:uf,lineEnd:ff,polygonStart:function(){rf.point=cf,rf.lineStart=sf,rf.lineEnd=lf,ef.reset(),_u.polygonStart()},polygonEnd:function(){_u.polygonEnd(),rf.point=of,rf.lineStart=uf,rf.lineEnd=ff,gu<0?(Cu=-(zu=180),Pu=-(Ru=90)):ef>Da?Ru=90:ef<-Da&&(Pu=-90),Yu[0]=Cu,Yu[1]=zu}};function of(t,n){Ou.push(Yu=[Cu=t,zu=t]),n<Pu&&(Pu=n),n>Ru&&(Ru=n)}function af(t,n){var e=Au([t*Ia,n*Ia]);if(qu){var r=Nu(qu,e),i=Nu([r[1],-r[0],0],r);ku(i),i=Mu(i);var o,a=t-Lu,u=a>0?1:-1,f=i[0]*Fa*u,c=Ha(a)>180;c^(u*Lu<f&&f<u*t)?(o=i[1]*Fa)>Ru&&(Ru=o):c^(u*Lu<(f=(f+360)%360-180)&&f<u*t)?(o=-i[1]*Fa)<Pu&&(Pu=o):(n<Pu&&(Pu=n),n>Ru&&(Ru=n)),c?t<Lu?hf(Cu,t)>hf(Cu,zu)&&(zu=t):hf(t,zu)>hf(Cu,zu)&&(Cu=t):zu>=Cu?(t<Cu&&(Cu=t),t>zu&&(zu=t)):t>Lu?hf(Cu,t)>hf(Cu,zu)&&(zu=t):hf(t,zu)>hf(Cu,zu)&&(Cu=t)}else Ou.push(Yu=[Cu=t,zu=t]);n<Pu&&(Pu=n),n>Ru&&(Ru=n),qu=e,Lu=t}function uf(){rf.point=af}function ff(){Yu[0]=Cu,Yu[1]=zu,rf.point=of,qu=null}function cf(t,n){if(qu){var e=t-Lu;ef.add(Ha(e)>180?e+(e>0?360:-360):e)}else Du=t,Uu=n;_u.point(t,n),af(t,n)}function sf(){_u.lineStart()}function lf(){cf(Du,Uu),_u.lineEnd(),Ha(ef)>Da&&(Cu=-(zu=180)),Yu[0]=Cu,Yu[1]=zu,qu=null}function hf(t,n){return(n-=t)<0?n+360:n}function df(t,n){return t[0]-n[0]}function pf(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var vf={sphere:iu,point:gf,lineStart:_f,lineEnd:xf,polygonStart:function(){vf.lineStart=wf,vf.lineEnd=Mf},polygonEnd:function(){vf.lineStart=_f,vf.lineEnd=xf}};function gf(t,n){t*=Ia;var e=Ga(n*=Ia);yf(e*Ga(t),e*Qa(t),Qa(n))}function yf(t,n,e){Iu+=(t-Iu)/++Bu,Hu+=(n-Hu)/Bu,ju+=(e-ju)/Bu}function _f(){vf.point=bf}function bf(t,n){t*=Ia;var e=Ga(n*=Ia);Ku=e*Ga(t),tf=e*Qa(t),nf=Qa(n),vf.point=mf,yf(Ku,tf,nf)}function mf(t,n){t*=Ia;var e=Ga(n*=Ia),r=e*Ga(t),i=e*Qa(t),o=Qa(n),a=Xa(Ka((a=tf*o-nf*i)*a+(a=nf*r-Ku*o)*a+(a=Ku*i-tf*r)*a),Ku*r+tf*i+nf*o);Fu+=a,Xu+=a*(Ku+(Ku=r)),Gu+=a*(tf+(tf=i)),Vu+=a*(nf+(nf=o)),yf(Ku,tf,nf)}function xf(){vf.point=gf}function wf(){vf.point=Af}function Mf(){Tf(Qu,Ju),vf.point=gf}function Af(t,n){Qu=t,Ju=n,t*=Ia,n*=Ia,vf.point=Tf;var e=Ga(n);Ku=e*Ga(t),tf=e*Qa(t),nf=Qa(n),yf(Ku,tf,nf)}function Tf(t,n){t*=Ia;var e=Ga(n*=Ia),r=e*Ga(t),i=e*Qa(t),o=Qa(n),a=tf*o-nf*i,u=nf*r-Ku*o,f=Ku*i-tf*r,c=Ka(a*a+u*u+f*f),s=eu(c),l=c&&-s/c;$u+=l*a,Wu+=l*u,Zu+=l*f,Fu+=s,Xu+=s*(Ku+(Ku=r)),Gu+=s*(tf+(tf=i)),Vu+=s*(nf+(nf=o)),yf(Ku,tf,nf)}function Nf(t){return function(){return t}}function Sf(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e}function Ef(t,n){return[t>qa?t-Ba:t<-qa?t+Ba:t,n]}function kf(t,n,e){return(t%=Ba)?n||e?Sf(Pf(t),zf(n,e)):Pf(t):n||e?zf(n,e):Ef}function Cf(t){return function(n,e){return[(n+=t)>qa?n-Ba:n<-qa?n+Ba:n,e]}}function Pf(t){var n=Cf(t);return n.invert=Cf(-t),n}function zf(t,n){var e=Ga(t),r=Qa(t),i=Ga(n),o=Qa(n);function a(t,n){var a=Ga(n),u=Ga(t)*a,f=Qa(t)*a,c=Qa(n),s=c*e+u*r;return[Xa(f*i-s*o,u*e-c*r),eu(s*i+f*o)]}return a.invert=function(t,n){var a=Ga(n),u=Ga(t)*a,f=Qa(t)*a,c=Qa(n),s=c*i-f*o;return[Xa(f*i+c*o,u*e+s*r),eu(s*e-u*r)]},a}function Rf(t){function n(n){return(n=t(n[0]*Ia,n[1]*Ia))[0]*=Fa,n[1]*=Fa,n}return t=kf(t[0]*Ia,t[1]*Ia,t.length>2?t[2]*Ia:0),n.invert=function(n){return(n=t.invert(n[0]*Ia,n[1]*Ia))[0]*=Fa,n[1]*=Fa,n},n}function Lf(t,n,e,r,i,o){if(e){var a=Ga(n),u=Qa(n),f=r*e;null==i?(i=n+r*Ba,o=n-f/2):(i=Df(a,i),o=Df(a,o),(r>0?i<o:i>o)&&(i+=r*Ba));for(var c,s=i;r>0?s>o:s<o;s-=f)c=Mu([a,-u*Ga(s),-u*Qa(s)]),t.point(c[0],c[1])}}function Df(t,n){(n=Au(n))[0]-=t,ku(n);var e=nu(-n[1]);return((-n[2]<0?-e:e)+Ba-Da)%Ba}function Uf(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:iu,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function qf(t,n){return Ha(t[0]-n[0])<Da&&Ha(t[1]-n[1])<Da}function Of(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Yf(t,n,e,r,i){var o,a,u=[],f=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],a=t[n];if(qf(r,a)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else u.push(e=new Of(r,t,null,!0)),f.push(e.o=new Of(r,null,e,!1)),u.push(e=new Of(a,t,null,!1)),f.push(e.o=new Of(a,null,e,!0))}}),u.length){for(f.sort(n),Bf(u),Bf(f),o=0,a=f.length;o<a;++o)f[o].e=e=!e;for(var c,s,l=u[0];;){for(var h=l,d=!0;h.v;)if((h=h.n)===l)return;c=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(d)for(o=0,a=c.length;o<a;++o)i.point((s=c[o])[0],s[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(d)for(c=h.p.z,o=c.length-1;o>=0;--o)i.point((s=c[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}c=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function Bf(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}Ef.invert=Ef;var Ff=Pa();function If(t,n){var e=n[0],r=n[1],i=Qa(r),o=[Qa(e),-Ga(e),0],a=0,u=0;Ff.reset(),1===i?r=Oa+Da:-1===i&&(r=-Oa-Da);for(var f=0,c=t.length;f<c;++f)if(l=(s=t[f]).length)for(var s,l,h=s[l-1],d=h[0],p=h[1]/2+Ya,v=Qa(p),g=Ga(p),y=0;y<l;++y,d=b,v=x,g=w,h=_){var _=s[y],b=_[0],m=_[1]/2+Ya,x=Qa(m),w=Ga(m),M=b-d,A=M>=0?1:-1,T=A*M,N=T>qa,S=v*x;if(Ff.add(Xa(S*A*Qa(T),g*w+S*Ga(T))),a+=N?M+A*Ba:M,N^d>=e^b>=e){var E=Nu(Au(h),Au(_));ku(E);var k=Nu(o,E);ku(k);var C=(N^M>=0?-1:1)*eu(k[2]);(r>C||r===C&&(E[0]||E[1]))&&(u+=N^M>=0?1:-1)}}return(a<-Da||a<Da&&Ff<-Da)^1&u}function Hf(t,n,e,r){return function(i){var o,a,u,f=n(i),c=Uf(),s=n(c),l=!1,h={point:d,lineStart:v,lineEnd:g,polygonStart:function(){h.point=y,h.lineStart=_,h.lineEnd=b,a=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=v,h.lineEnd=g,a=N(a);var t=If(o,r);a.length?(l||(i.polygonStart(),l=!0),Yf(a,Xf,t,e,i)):t&&(l||(i.polygonStart(),l=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),l&&(i.polygonEnd(),l=!1),a=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){f.point(t,n)}function v(){h.point=p,f.lineStart()}function g(){h.point=d,f.lineEnd()}function y(t,n){u.push([t,n]),s.point(t,n)}function _(){s.lineStart(),u=[]}function b(){y(u[0][0],u[0][1]),s.lineEnd();var t,n,e,r,f=s.clean(),h=c.result(),d=h.length;if(u.pop(),o.push(u),u=null,d)if(1&f){if((n=(e=h[0]).length-1)>0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t<n;++t)i.point((r=e[t])[0],r[1]);i.lineEnd()}}else d>1&&2&f&&h.push(h.pop().concat(h.shift())),a.push(h.filter(jf))}return h}}function jf(t){return t.length>1}function Xf(t,n){return((t=t.x)[0]<0?t[1]-Oa-Da:Oa-t[1])-((n=n.x)[0]<0?n[1]-Oa-Da:Oa-n[1])}var Gf=Hf(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?qa:-qa,f=Ha(o-e);Ha(f-qa)<Da?(t.point(e,r=(r+a)/2>0?Oa:-Oa),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&f>=qa&&(Ha(e-i)<Da&&(e-=i*Da),Ha(o-u)<Da&&(o-=u*Da),r=function(t,n,e,r){var i,o,a=Qa(t-e);return Ha(a)>Da?ja((Qa(n)*(o=Ga(r))*Qa(e)-Qa(r)*(i=Ga(n))*Qa(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*Oa,r.point(-qa,i),r.point(0,i),r.point(qa,i),r.point(qa,0),r.point(qa,-i),r.point(0,-i),r.point(-qa,-i),r.point(-qa,0),r.point(-qa,i);else if(Ha(t[0]-n[0])>Da){var o=t[0]<n[0]?qa:-qa;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-qa,-Oa]);function Vf(t){var n=Ga(t),e=6*Ia,r=n>0,i=Ha(n)>Da;function o(t,e){return Ga(t)*Ga(e)>n}function a(t,e,r){var i=[1,0,0],o=Nu(Au(t),Au(e)),a=Tu(o,o),u=o[0],f=a-u*u;if(!f)return!r&&t;var c=n*a/f,s=-n*u/f,l=Nu(i,o),h=Eu(i,c);Su(h,Eu(o,s));var d=l,p=Tu(h,d),v=Tu(d,d),g=p*p-v*(Tu(h,h)-1);if(!(g<0)){var y=Ka(g),_=Eu(d,(-p-y)/v);if(Su(_,h),_=Mu(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x<m&&(b=m,m=x,x=b);var A=x-m,T=Ha(A-qa)<Da;if(!T&&M<w&&(b=w,w=M,M=b),T||A<Da?T?w+M>0^_[1]<(Ha(_[0]-m)<Da?w:M):w<=_[1]&&_[1]<=M:A>qa^(m<=_[0]&&_[0]<=x)){var N=Eu(d,(-p+y)/v);return Su(N,h),[_,Mu(N)]}}}function u(n,e){var i=r?t:qa-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return Hf(o,function(t){var n,e,f,c,s;return{lineStart:function(){c=f=!1,s=1},point:function(l,h){var d,p=[l,h],v=o(l,h),g=r?v?0:u(l,h):v?u(l+(l<0?qa:-qa),h):0;if(!n&&(c=f=v)&&t.lineStart(),v!==f&&(!(d=a(n,p))||qf(n,d)||qf(p,d))&&(p[0]+=Da,p[1]+=Da,v=o(p[0],p[1])),v!==f)s=0,v?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1]),t.lineEnd()),n=d;else if(i&&n&&r^v){var y;g&e||!(y=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&qf(n,p)||t.point(p[0],p[1]),n=p,f=v,e=g},lineEnd:function(){f&&t.lineEnd(),n=null},clean:function(){return s|(c&&f)<<1}}},function(n,r,i,o){Lf(o,t,e,i,n,r)},r?[0,-t]:[-qa,t-qa])}var $f=1e9,Wf=-$f;function Zf(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,c){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||f(i,o)<0^u>0)do{c.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else c.point(o[0],o[1])}function a(r,i){return Ha(r[0]-t)<Da?i>0?0:3:Ha(r[0]-e)<Da?i>0?2:1:Ha(r[1]-n)<Da?i>0?1:0:i>0?3:2}function u(t,n){return f(t.x,n.x)}function f(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var f,c,s,l,h,d,p,v,g,y,_,b=a,m=Uf(),x={point:w,lineStart:function(){x.point=M,c&&c.push(s=[]);y=!0,g=!1,p=v=NaN},lineEnd:function(){f&&(M(l,h),d&&g&&m.rejoin(),f.push(m.result()));x.point=w,g&&b.lineEnd()},polygonStart:function(){b=m,f=[],c=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=c.length;e<i;++e)for(var o,a,u=c[e],f=1,s=u.length,l=u[0],h=l[0],d=l[1];f<s;++f)o=h,a=d,l=u[f],h=l[0],d=l[1],a<=r?d>r&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(f=N(f)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&Yf(f,u,n,o,a),a.polygonEnd());b=a,f=c=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(c&&s.push([o,a]),y)l=o,h=a,d=u,y=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&g)b.point(o,a);else{var f=[p=Math.max(Wf,Math.min($f,p)),v=Math.max(Wf,Math.min($f,v))],m=[o=Math.max(Wf,Math.min($f,o)),a=Math.max(Wf,Math.min($f,a))];!function(t,n,e,r,i,o){var a,u=t[0],f=t[1],c=0,s=1,l=n[0]-u,h=n[1]-f;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a<c)return;a<s&&(s=a)}else if(l>0){if(a>s)return;a>c&&(c=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>c&&(c=a)}else if(l>0){if(a<c)return;a<s&&(s=a)}if(a=r-f,h||!(a>0)){if(a/=h,h<0){if(a<c)return;a<s&&(s=a)}else if(h>0){if(a>s)return;a>c&&(c=a)}if(a=o-f,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>c&&(c=a)}else if(h>0){if(a<c)return;a<s&&(s=a)}return c>0&&(t[0]=u+c*l,t[1]=f+c*h),s<1&&(n[0]=u+s*l,n[1]=f+s*h),!0}}}}}(f,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(g||(b.lineStart(),b.point(f[0],f[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,v=a,g=u}return x}}var Qf,Jf,Kf,tc=Pa(),nc={sphere:iu,point:iu,lineStart:function(){nc.point=rc,nc.lineEnd=ec},lineEnd:iu,polygonStart:iu,polygonEnd:iu};function ec(){nc.point=nc.lineEnd=iu}function rc(t,n){Qf=t*=Ia,Jf=Qa(n*=Ia),Kf=Ga(n),nc.point=ic}function ic(t,n){t*=Ia;var e=Qa(n*=Ia),r=Ga(n),i=Ha(t-Qf),o=Ga(i),a=r*Qa(i),u=Kf*e-Jf*r*o,f=Jf*e+Kf*r*o;tc.add(Xa(Ka(a*a+u*u),f)),Qf=t,Jf=e,Kf=r}function oc(t){return tc.reset(),su(t,nc),+tc}var ac=[null,null],uc={type:"LineString",coordinates:ac};function fc(t,n){return ac[0]=t,ac[1]=n,oc(uc)}var cc={Feature:function(t,n){return lc(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(lc(e[r].geometry,n))return!0;return!1}},sc={Sphere:function(){return!0},Point:function(t,n){return hc(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(hc(e[r],n))return!0;return!1},LineString:function(t,n){return dc(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(dc(e[r],n))return!0;return!1},Polygon:function(t,n){return pc(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(pc(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(lc(e[r],n))return!0;return!1}};function lc(t,n){return!(!t||!sc.hasOwnProperty(t.type))&&sc[t.type](t,n)}function hc(t,n){return 0===fc(t,n)}function dc(t,n){var e=fc(t[0],t[1]);return fc(t[0],n)+fc(n,t[1])<=e+Da}function pc(t,n){return!!If(t.map(vc),gc(n))}function vc(t){return(t=t.map(gc)).pop(),t}function gc(t){return[t[0]*Ia,t[1]*Ia]}function yc(t,n,e){var r=g(t,n-Da,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function _c(t,n,e){var r=g(t,n-Da,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function bc(){var t,n,e,r,i,o,a,u,f,c,s,l,h=10,d=h,p=90,v=360,y=2.5;function _(){return{type:"MultiLineString",coordinates:b()}}function b(){return g(Va(r/p)*p,e,p).map(s).concat(g(Va(u/v)*v,a,v).map(l)).concat(g(Va(n/h)*h,t,h).filter(function(t){return Ha(t%p)>Da}).map(f)).concat(g(Va(o/d)*d,i,d).filter(function(t){return Ha(t%v)>Da}).map(c))}return _.lines=function(){return b().map(function(t){return{type:"LineString",coordinates:t}})},_.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},_.extent=function(t){return arguments.length?_.extentMajor(t).extentMinor(t):_.extentMinor()},_.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),_.precision(y)):[[r,u],[e,a]]},_.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),_.precision(y)):[[n,o],[t,i]]},_.step=function(t){return arguments.length?_.stepMajor(t).stepMinor(t):_.stepMinor()},_.stepMajor=function(t){return arguments.length?(p=+t[0],v=+t[1],_):[p,v]},_.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],_):[h,d]},_.precision=function(h){return arguments.length?(y=+h,f=yc(o,i,90),c=_c(n,t,y),s=yc(u,a,90),l=_c(r,e,y),_):y},_.extentMajor([[-180,-90+Da],[180,90-Da]]).extentMinor([[-180,-80-Da],[180,80+Da]])}function mc(t){return t}var xc,wc,Mc,Ac,Tc=Pa(),Nc=Pa(),Sc={point:iu,lineStart:iu,lineEnd:iu,polygonStart:function(){Sc.lineStart=Ec,Sc.lineEnd=Pc},polygonEnd:function(){Sc.lineStart=Sc.lineEnd=Sc.point=iu,Tc.add(Ha(Nc)),Nc.reset()},result:function(){var t=Tc/2;return Tc.reset(),t}};function Ec(){Sc.point=kc}function kc(t,n){Sc.point=Cc,xc=Mc=t,wc=Ac=n}function Cc(t,n){Nc.add(Ac*t-Mc*n),Mc=t,Ac=n}function Pc(){Cc(xc,wc)}var zc=1/0,Rc=zc,Lc=-zc,Dc=Lc,Uc={point:function(t,n){t<zc&&(zc=t);t>Lc&&(Lc=t);n<Rc&&(Rc=n);n>Dc&&(Dc=n)},lineStart:iu,lineEnd:iu,polygonStart:iu,polygonEnd:iu,result:function(){var t=[[zc,Rc],[Lc,Dc]];return Lc=Dc=-(Rc=zc=1/0),t}};var qc,Oc,Yc,Bc,Fc=0,Ic=0,Hc=0,jc=0,Xc=0,Gc=0,Vc=0,$c=0,Wc=0,Zc={point:Qc,lineStart:Jc,lineEnd:ns,polygonStart:function(){Zc.lineStart=es,Zc.lineEnd=rs},polygonEnd:function(){Zc.point=Qc,Zc.lineStart=Jc,Zc.lineEnd=ns},result:function(){var t=Wc?[Vc/Wc,$c/Wc]:Gc?[jc/Gc,Xc/Gc]:Hc?[Fc/Hc,Ic/Hc]:[NaN,NaN];return Fc=Ic=Hc=jc=Xc=Gc=Vc=$c=Wc=0,t}};function Qc(t,n){Fc+=t,Ic+=n,++Hc}function Jc(){Zc.point=Kc}function Kc(t,n){Zc.point=ts,Qc(Yc=t,Bc=n)}function ts(t,n){var e=t-Yc,r=n-Bc,i=Ka(e*e+r*r);jc+=i*(Yc+t)/2,Xc+=i*(Bc+n)/2,Gc+=i,Qc(Yc=t,Bc=n)}function ns(){Zc.point=Qc}function es(){Zc.point=is}function rs(){os(qc,Oc)}function is(t,n){Zc.point=os,Qc(qc=Yc=t,Oc=Bc=n)}function os(t,n){var e=t-Yc,r=n-Bc,i=Ka(e*e+r*r);jc+=i*(Yc+t)/2,Xc+=i*(Bc+n)/2,Gc+=i,Vc+=(i=Bc*t-Yc*n)*(Yc+t),$c+=i*(Bc+n),Wc+=3*i,Qc(Yc=t,Bc=n)}function as(t){this._context=t}as.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,Ba)}},result:iu};var us,fs,cs,ss,ls,hs=Pa(),ds={point:iu,lineStart:function(){ds.point=ps},lineEnd:function(){us&&vs(fs,cs),ds.point=iu},polygonStart:function(){us=!0},polygonEnd:function(){us=null},result:function(){var t=+hs;return hs.reset(),t}};function ps(t,n){ds.point=vs,fs=ss=t,cs=ls=n}function vs(t,n){ss-=t,ls-=n,hs.add(Ka(ss*ss+ls*ls)),ss=t,ls=n}function gs(){this._string=[]}function ys(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function _s(t){return function(n){var e=new bs;for(var r in t)e[r]=t[r];return e.stream=n,e}}function bs(){}function ms(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),su(e,t.stream(Uc)),n(Uc.result()),null!=r&&t.clipExtent(r),t}function xs(t,n,e){return ms(t,function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),a=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,u=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([a,u])},e)}function ws(t,n,e){return xs(t,[[0,0],n],e)}function Ms(t,n,e){return ms(t,function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,a=-i*e[0][1];t.scale(150*i).translate([o,a])},e)}function As(t,n,e){return ms(t,function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],a=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,a])},e)}gs.prototype={_radius:4.5,_circle:ys(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=ys(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}},bs.prototype={constructor:bs,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Ts=16,Ns=Ga(30*Ia);function Ss(t,n){return+n?function(t,n){function e(r,i,o,a,u,f,c,s,l,h,d,p,v,g){var y=c-r,_=s-i,b=y*y+_*_;if(b>4*n&&v--){var m=a+h,x=u+d,w=f+p,M=Ka(m*m+x*x+w*w),A=eu(w/=M),T=Ha(Ha(w)-1)<Da||Ha(o-l)<Da?(o+l)/2:Xa(x,m),N=t(T,A),S=N[0],E=N[1],k=S-r,C=E-i,P=_*k-y*C;(P*P/b>n||Ha((y*k+_*C)/b-.5)>.3||a*h+u*d+f*p<Ns)&&(e(r,i,o,a,u,f,S,E,T,m/=M,x/=M,w,v,g),g.point(S,E),e(S,E,T,m,x,w,c,s,l,h,d,p,v,g))}}return function(n){var r,i,o,a,u,f,c,s,l,h,d,p,v={point:g,lineStart:y,lineEnd:b,polygonStart:function(){n.polygonStart(),v.lineStart=m},polygonEnd:function(){n.polygonEnd(),v.lineStart=y}};function g(e,r){e=t(e,r),n.point(e[0],e[1])}function y(){s=NaN,v.point=_,n.lineStart()}function _(r,i){var o=Au([r,i]),a=t(r,i);e(s,l,c,h,d,p,s=a[0],l=a[1],c=r,h=o[0],d=o[1],p=o[2],Ts,n),n.point(s,l)}function b(){v.point=g,n.lineEnd()}function m(){y(),v.point=x,v.lineEnd=w}function x(t,n){_(r=t,n),i=s,o=l,a=h,u=d,f=p,v.point=_}function w(){e(s,l,c,h,d,p,i,o,r,a,u,f,Ts,n),v.lineEnd=b,b()}return v}}(t,n):function(t){return _s({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}(t)}var Es=_s({point:function(t,n){this.stream.point(t*Ia,n*Ia)}});function ks(t,n,e,r){var i=Ga(r),o=Qa(r),a=i*t,u=o*t,f=i/t,c=o/t,s=(o*e-i*n)/t,l=(o*n+i*e)/t;function h(t,r){return[a*t-u*r+n,e-u*t-a*r]}return h.invert=function(t,n){return[f*t-c*n+s,l-c*t-f*n]},h}function Cs(t){return Ps(function(){return t})()}function Ps(t){var n,e,r,i,o,a,u,f,c,s,l=150,h=480,d=250,p=0,v=0,g=0,y=0,_=0,b=0,m=null,x=Gf,w=null,M=mc,A=.5;function T(t){return f(t[0]*Ia,t[1]*Ia)}function N(t){return(t=f.invert(t[0],t[1]))&&[t[0]*Fa,t[1]*Fa]}function S(){var t=ks(l,0,0,b).apply(null,n(p,v)),r=(b?ks:function(t,n,e){function r(r,i){return[n+t*r,e-t*i]}return r.invert=function(r,i){return[(r-n)/t,(e-i)/t]},r})(l,h-t[0],d-t[1],b);return e=kf(g,y,_),u=Sf(n,r),f=Sf(e,u),a=Ss(u,A),E()}function E(){return c=s=null,T}return T.stream=function(t){return c&&s===t?c:c=Es(function(t){return _s({point:function(n,e){var r=t(n,e);return this.stream.point(r[0],r[1])}})}(e)(x(a(M(s=t)))))},T.preclip=function(t){return arguments.length?(x=t,m=void 0,E()):x},T.postclip=function(t){return arguments.length?(M=t,w=r=i=o=null,E()):M},T.clipAngle=function(t){return arguments.length?(x=+t?Vf(m=t*Ia):(m=null,Gf),E()):m*Fa},T.clipExtent=function(t){return arguments.length?(M=null==t?(w=r=i=o=null,mc):Zf(w=+t[0][0],r=+t[0][1],i=+t[1][0],o=+t[1][1]),E()):null==w?null:[[w,r],[i,o]]},T.scale=function(t){return arguments.length?(l=+t,S()):l},T.translate=function(t){return arguments.length?(h=+t[0],d=+t[1],S()):[h,d]},T.center=function(t){return arguments.length?(p=t[0]%360*Ia,v=t[1]%360*Ia,S()):[p*Fa,v*Fa]},T.rotate=function(t){return arguments.length?(g=t[0]%360*Ia,y=t[1]%360*Ia,_=t.length>2?t[2]%360*Ia:0,S()):[g*Fa,y*Fa,_*Fa]},T.angle=function(t){return arguments.length?(b=t%360*Ia,S()):b*Fa},T.precision=function(t){return arguments.length?(a=Ss(u,A=t*t),E()):Ka(A)},T.fitExtent=function(t,n){return xs(T,t,n)},T.fitSize=function(t,n){return ws(T,t,n)},T.fitWidth=function(t,n){return Ms(T,t,n)},T.fitHeight=function(t,n){return As(T,t,n)},function(){return n=t.apply(this,arguments),T.invert=n.invert&&N,S()}}function zs(t){var n=0,e=qa/3,r=Ps(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*Ia,e=t[1]*Ia):[n*Fa,e*Fa]},i}function Rs(t,n){var e=Qa(t),r=(e+Qa(n))/2;if(Ha(r)<Da)return function(t){var n=Ga(t);function e(t,e){return[t*n,Qa(e)/n]}return e.invert=function(t,e){return[t/n,eu(e*n)]},e}(t);var i=1+e*(2*r-e),o=Ka(i)/r;function a(t,n){var e=Ka(i-2*r*Qa(n))/r;return[e*Qa(t*=r),o-e*Ga(t)]}return a.invert=function(t,n){var e=o-n;return[Xa(t,Ha(e))/r*Ja(e),eu((i-(t*t+e*e)*r*r)/(2*r))]},a}function Ls(){return zs(Rs).scale(155.424).center([0,33.6442])}function Ds(){return Ls().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])}function Us(t){return function(n,e){var r=Ga(n),i=Ga(e),o=t(r*i);return[o*i*Qa(n),o*Qa(e)]}}function qs(t){return function(n,e){var r=Ka(n*n+e*e),i=t(r),o=Qa(i),a=Ga(i);return[Xa(n*o,r*a),eu(r&&e*o/r)]}}var Os=Us(function(t){return Ka(2/(1+t))});Os.invert=qs(function(t){return 2*eu(t/2)});var Ys=Us(function(t){return(t=nu(t))&&t/Qa(t)});function Bs(t,n){return[t,Wa(tu((Oa+n)/2))]}function Fs(t){var n,e,r,i=Cs(t),o=i.center,a=i.scale,u=i.translate,f=i.clipExtent,c=null;function s(){var o=qa*a(),u=i(Rf(i.rotate()).invert([0,0]));return f(null==c?[[u[0]-o,u[1]-o],[u[0]+o,u[1]+o]]:t===Bs?[[Math.max(u[0]-o,c),n],[Math.min(u[0]+o,e),r]]:[[c,Math.max(u[1]-o,n)],[e,Math.min(u[1]+o,r)]])}return i.scale=function(t){return arguments.length?(a(t),s()):a()},i.translate=function(t){return arguments.length?(u(t),s()):u()},i.center=function(t){return arguments.length?(o(t),s()):o()},i.clipExtent=function(t){return arguments.length?(null==t?c=n=e=r=null:(c=+t[0][0],n=+t[0][1],e=+t[1][0],r=+t[1][1]),s()):null==c?null:[[c,n],[e,r]]},s()}function Is(t){return tu((Oa+t)/2)}function Hs(t,n){var e=Ga(t),r=t===n?Qa(t):Wa(e/Ga(n))/Wa(Is(n)/Is(t)),i=e*Za(Is(t),r)/r;if(!r)return Bs;function o(t,n){i>0?n<-Oa+Da&&(n=-Oa+Da):n>Oa-Da&&(n=Oa-Da);var e=i/Za(Is(n),r);return[e*Qa(r*t),i-e*Ga(r*t)]}return o.invert=function(t,n){var e=i-n,o=Ja(r)*Ka(t*t+e*e);return[Xa(t,Ha(e))/r*Ja(e),2*ja(Za(i/o,1/r))-Oa]},o}function js(t,n){return[t,n]}function Xs(t,n){var e=Ga(t),r=t===n?Qa(t):(e-Ga(n))/(n-t),i=e/r+t;if(Ha(r)<Da)return js;function o(t,n){var e=i-n,o=r*t;return[e*Qa(o),i-e*Ga(o)]}return o.invert=function(t,n){var e=i-n;return[Xa(t,Ha(e))/r*Ja(e),i-Ja(r)*Ka(t*t+e*e)]},o}Ys.invert=qs(function(t){return t}),Bs.invert=function(t,n){return[t,2*ja($a(n))-Oa]},js.invert=js;var Gs=1.340264,Vs=-.081106,$s=893e-6,Ws=.003796,Zs=Ka(3)/2;function Qs(t,n){var e=eu(Zs*Qa(n)),r=e*e,i=r*r*r;return[t*Ga(e)/(Zs*(Gs+3*Vs*r+i*(7*$s+9*Ws*r))),e*(Gs+Vs*r+i*($s+Ws*r))]}function Js(t,n){var e=Ga(n),r=Ga(t)*e;return[e*Qa(t)/r,Qa(n)/r]}function Ks(t,n,e,r){return 1===t&&1===n&&0===e&&0===r?mc:_s({point:function(i,o){this.stream.point(i*t+e,o*n+r)}})}function tl(t,n){var e=n*n,r=e*e;return[t*(.8707-.131979*e+r*(r*(.003971*e-.001529*r)-.013791)),n*(1.007226+e*(.015085+r*(.028874*e-.044475-.005916*r)))]}function nl(t,n){return[Ga(n)*Qa(t),Qa(n)]}function el(t,n){var e=Ga(n),r=1+Ga(t)*e;return[e*Qa(t)/r,Qa(n)/r]}function rl(t,n){return[Wa(tu((Oa+n)/2)),-t]}function il(t,n){return t.parent===n.parent?1:2}function ol(t,n){return t+n.x}function al(t,n){return Math.max(t,n.y)}function ul(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function fl(t,n){var e,r,i,o,a,u=new hl(t),f=+t.value&&(u.value=t.value),c=[u];for(null==n&&(n=cl);e=c.pop();)if(f&&(e.value=+e.data.value),(i=n(e.data))&&(a=i.length))for(e.children=new Array(a),o=a-1;o>=0;--o)c.push(r=e.children[o]=new hl(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(ll)}function cl(t){return t.children}function sl(t){t.data=t.data.data}function ll(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function hl(t){this.data=t,this.depth=this.height=0,this.parent=null}Qs.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(Gs+Vs*i+o*($s+Ws*i))-n)/(Gs+3*Vs*i+o*(7*$s+9*Ws*i)))*r)*i*i,!(Ha(e)<Ua));++a);return[Zs*t*(Gs+3*Vs*i+o*(7*$s+9*Ws*i))/Ga(r),eu(Qa(r)/Zs)]},Js.invert=qs(ja),tl.invert=function(t,n){var e,r=n,i=25;do{var o=r*r,a=o*o;r-=e=(r*(1.007226+o*(.015085+a*(.028874*o-.044475-.005916*a)))-n)/(1.007226+o*(.045255+a*(.259866*o-.311325-.005916*11*a)))}while(Ha(e)>Da&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},nl.invert=qs(eu),el.invert=qs(function(t){return 2*ja(t)}),rl.invert=function(t,n){return[-n,2*ja($a(t))-Oa]},hl.prototype=fl.prototype={constructor:hl,count:function(){return this.eachAfter(ul)},each:function(t){var n,e,r,i,o=this,a=[o];do{for(n=a.reverse(),a=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)a.push(e[r])}while(a.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],a=[];i=o.pop();)if(a.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=a.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return fl(this).eachBefore(sl)}};var dl=Array.prototype.slice;function pl(t){for(var n,e,r=0,i=(t=function(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}(dl.call(t))).length,o=[];r<i;)n=t[r],e&&yl(e,n)?++r:(e=bl(o=vl(o,n)),r=0);return e}function vl(t,n){var e,r;if(_l(n,t))return[n];for(e=0;e<t.length;++e)if(gl(n,t[e])&&_l(ml(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(gl(ml(t[e],t[r]),n)&&gl(ml(t[e],n),t[r])&&gl(ml(t[r],n),t[e])&&_l(xl(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function gl(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function yl(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function _l(t,n){for(var e=0;e<n.length;++e)if(!yl(t,n[e]))return!1;return!0}function bl(t){switch(t.length){case 1:return{x:(n=t[0]).x,y:n.y,r:n.r};case 2:return ml(t[0],t[1]);case 3:return xl(t[0],t[1],t[2])}var n}function ml(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,a=n.y,u=n.r,f=o-e,c=a-r,s=u-i,l=Math.sqrt(f*f+c*c);return{x:(e+o+f/l*s)/2,y:(r+a+c/l*s)/2,r:(l+i+u)/2}}function xl(t,n,e){var r=t.x,i=t.y,o=t.r,a=n.x,u=n.y,f=n.r,c=e.x,s=e.y,l=e.r,h=r-a,d=r-c,p=i-u,v=i-s,g=f-o,y=l-o,_=r*r+i*i-o*o,b=_-a*a-u*u+f*f,m=_-c*c-s*s+l*l,x=d*p-h*v,w=(p*m-v*b)/(2*x)-r,M=(v*g-p*y)/x,A=(d*b-h*m)/(2*x)-i,T=(h*y-d*g)/x,N=M*M+T*T-1,S=2*(o+w*M+A*T),E=w*w+A*A-o*o,k=-(N?(S+Math.sqrt(S*S-4*N*E))/(2*N):E/S);return{x:r+w+M*k,y:i+A+T*k,r:k}}function wl(t,n,e){var r,i,o,a,u=t.x-n.x,f=t.y-n.y,c=u*u+f*f;c?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(c+a-i)/(2*c),o=Math.sqrt(Math.max(0,a/c-r*r)),e.x=t.x-r*u-o*f,e.y=t.y-r*f+o*u):(r=(c+i-a)/(2*c),o=Math.sqrt(Math.max(0,i/c-r*r)),e.x=n.x+r*u-o*f,e.y=n.y+r*f+o*u)):(e.x=n.x+e.r,e.y=n.y)}function Ml(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function Al(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function Tl(t){this._=t,this.next=null,this.previous=null}function Nl(t){if(!(i=t.length))return 0;var n,e,r,i,o,a,u,f,c,s,l;if((n=t[0]).x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;wl(e,n,r=t[2]),n=new Tl(n),e=new Tl(e),r=new Tl(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(u=3;u<i;++u){wl(n._,e._,r=t[u]),r=new Tl(r),f=e.next,c=n.previous,s=e._.r,l=n._.r;do{if(s<=l){if(Ml(f._,r._)){e=f,n.next=e,e.previous=n,--u;continue t}s+=f._.r,f=f.next}else{if(Ml(c._,r._)){(n=c).next=e,e.previous=n,--u;continue t}l+=c._.r,c=c.previous}}while(f!==c.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=Al(n);(r=r.next)!==e;)(a=Al(r))<o&&(n=r,o=a);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=pl(n),u=0;u<i;++u)(n=t[u]).x-=r.x,n.y-=r.y;return r.r}function Sl(t){if("function"!=typeof t)throw new Error;return t}function El(){return 0}function kl(t){return function(){return t}}function Cl(t){return Math.sqrt(t.value)}function Pl(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function zl(t,n){return function(e){if(r=e.children){var r,i,o,a=r.length,u=t(e)*n||0;if(u)for(i=0;i<a;++i)r[i].r+=u;if(o=Nl(r),u)for(i=0;i<a;++i)r[i].r-=u;e.r=o+u}}}function Rl(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Ll(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function Dl(t,n,e,r,i){for(var o,a=t.children,u=-1,f=a.length,c=t.value&&(r-n)/t.value;++u<f;)(o=a[u]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*c}var Ul="$",ql={depth:-1},Ol={};function Yl(t){return t.id}function Bl(t){return t.parentId}function Fl(t,n){return t.parent===n.parent?1:2}function Il(t){var n=t.children;return n?n[0]:t.t}function Hl(t){var n=t.children;return n?n[n.length-1]:t.t}function jl(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function Xl(t,n,e){return t.a.parent===n.parent?t.a:e}function Gl(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Vl(t,n,e,r,i){for(var o,a=t.children,u=-1,f=a.length,c=t.value&&(i-e)/t.value;++u<f;)(o=a[u]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*c}Gl.prototype=Object.create(hl.prototype);var $l=(1+Math.sqrt(5))/2;function Wl(t,n,e,r,i,o){for(var a,u,f,c,s,l,h,d,p,v,g,y=[],_=n.children,b=0,m=0,x=_.length,w=n.value;b<x;){f=i-e,c=o-r;do{s=_[m++].value}while(!s&&m<x);for(l=h=s,g=s*s*(v=Math.max(c/f,f/c)/(w*t)),p=Math.max(h/g,g/l);m<x;++m){if(s+=u=_[m].value,u<l&&(l=u),u>h&&(h=u),g=s*s*v,(d=Math.max(h/g,g/l))>p){s-=u;break}p=d}y.push(a={value:s,dice:f<c,children:_.slice(b,m)}),a.dice?Dl(a,e,r,i,w?r+=c*s/w:o):Vl(a,e,r,w?e+=f*s/w:i,o),w-=s,b=m}return y}var Zl=function t(n){function e(t,e,r,i,o){Wl(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}($l);var Ql=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,f,c,s,l=-1,h=a.length,d=t.value;++l<h;){for(f=(u=a[l]).children,c=u.value=0,s=f.length;c<s;++c)u.value+=f[c].value;u.dice?Dl(u,e,r,i,r+=(o-r)*u.value/d):Vl(u,e,r,e+=(i-e)*u.value/d,o),d-=u.value}else t._squarify=a=Wl(n,t,e,r,i,o),a.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}($l);function Jl(t,n){return t[0]-n[0]||t[1]-n[1]}function Kl(t){for(var n,e,r,i=t.length,o=[0,1],a=2,u=2;u<i;++u){for(;a>1&&(n=t[o[a-2]],e=t[o[a-1]],r=t[u],(e[0]-n[0])*(r[1]-n[1])-(e[1]-n[1])*(r[0]-n[0])<=0);)--a;o[a++]=u}return o.slice(0,a)}function th(){return Math.random()}var nh=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(th),eh=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(th),rh=function t(n){function e(){var t=eh.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(th),ih=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(th),oh=function t(n){function e(t){var e=ih.source(n)(t);return function(){return e()/t}}return e.source=t,e}(th),ah=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(th),uh=Array.prototype,fh=uh.map,ch=uh.slice,sh={name:"implicit"};function lh(t){var n=Ki(),e=[],r=sh;function i(i){var o=i+"",a=n.get(o);if(!a){if(r!==sh)return r;n.set(o,a=e.push(i))}return t[(a-1)%t.length]}return t=null==t?[]:ch.call(t),i.domain=function(t){if(!arguments.length)return e.slice();e=[],n=Ki();for(var r,o,a=-1,u=t.length;++a<u;)n.has(o=(r=t[a])+"")||n.set(o,e.push(r));return i},i.range=function(n){return arguments.length?(t=ch.call(n),i):t.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return lh().domain(e).range(t).unknown(r)},i}function hh(){var t,n,e=lh().unknown(void 0),r=e.domain,i=e.range,o=[0,1],a=!1,u=0,f=0,c=.5;function s(){var e=r().length,s=o[1]<o[0],l=o[s-0],h=o[1-s];t=(h-l)/Math.max(1,e-u+2*f),a&&(t=Math.floor(t)),l+=(h-l-t*(e-u))*c,n=t*(1-u),a&&(l=Math.round(l),n=Math.round(n));var d=g(e).map(function(n){return l+t*n});return i(s?d.reverse():d)}return delete e.unknown,e.domain=function(t){return arguments.length?(r(t),s()):r()},e.range=function(t){return arguments.length?(o=[+t[0],+t[1]],s()):o.slice()},e.rangeRound=function(t){return o=[+t[0],+t[1]],a=!0,s()},e.bandwidth=function(){return n},e.step=function(){return t},e.round=function(t){return arguments.length?(a=!!t,s()):a},e.padding=function(t){return arguments.length?(u=f=Math.max(0,Math.min(1,t)),s()):u},e.paddingInner=function(t){return arguments.length?(u=Math.max(0,Math.min(1,t)),s()):u},e.paddingOuter=function(t){return arguments.length?(f=Math.max(0,Math.min(1,t)),s()):f},e.align=function(t){return arguments.length?(c=Math.max(0,Math.min(1,t)),s()):c},e.copy=function(){return hh().domain(r()).range(o).round(a).paddingInner(u).paddingOuter(f).align(c)},s()}function dh(t){return function(){return t}}function ph(t){return+t}var vh=[0,1];function gh(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:dh(n)}function yh(t,n,e,r){var i=t[0],o=t[1],a=n[0],u=n[1];return o<i?(i=e(o,i),a=r(u,a)):(i=e(i,o),a=r(a,u)),function(t){return a(i(t))}}function _h(t,n,e,r){var o=Math.min(t.length,n.length)-1,a=new Array(o),u=new Array(o),f=-1;for(t[o]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++f<o;)a[f]=e(t[f],t[f+1]),u[f]=r(n[f],n[f+1]);return function(n){var e=i(t,n,1,o)-1;return u[e](a[e](n))}}function bh(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function mh(t,n){var e,r,i,o=vh,a=vh,u=me,f=!1;function c(){return e=Math.min(o.length,a.length)>2?_h:yh,r=i=null,s}function s(n){return(r||(r=e(o,a,f?function(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}(t):t,u)))(+n)}return s.invert=function(t){return(i||(i=e(a,o,gh,f?function(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}(n):n)))(+t)},s.domain=function(t){return arguments.length?(o=fh.call(t,ph),c()):o.slice()},s.range=function(t){return arguments.length?(a=ch.call(t),c()):a.slice()},s.rangeRound=function(t){return a=ch.call(t),u=xe,c()},s.clamp=function(t){return arguments.length?(f=!!t,c()):f},s.interpolate=function(t){return arguments.length?(u=t,c()):u},c()}function xh(n){var e=n.domain;return n.ticks=function(t){var n=e();return m(n[0],n[n.length-1],null==t?10:t)},n.tickFormat=function(n,r){return function(n,e,r){var i,o=n[0],a=n[n.length-1],u=w(o,a,null==e?10:e);switch((r=ba(null==r?",f":r)).type){case"s":var f=Math.max(Math.abs(o),Math.abs(a));return null!=r.precision||isNaN(i=ka(u,f))||(r.precision=i),t.formatPrefix(r,f);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(i=Ca(u,Math.max(Math.abs(o),Math.abs(a))))||(r.precision=i-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(i=Ea(u))||(r.precision=i-2*("%"===r.type))}return t.format(r)}(e(),n,r)},n.nice=function(t){null==t&&(t=10);var r,i=e(),o=0,a=i.length-1,u=i[o],f=i[a];return f<u&&(r=u,u=f,f=r,r=o,o=a,a=r),(r=x(u,f,t))>0?r=x(u=Math.floor(u/r)*r,f=Math.ceil(f/r)*r,t):r<0&&(r=x(u=Math.ceil(u*r)/r,f=Math.floor(f*r)/r,t)),r>0?(i[o]=Math.floor(u/r)*r,i[a]=Math.ceil(f/r)*r,e(i)):r<0&&(i[o]=Math.ceil(u*r)/r,i[a]=Math.floor(f*r)/r,e(i)),n},n}function wh(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a<o&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function Mh(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:dh(n)}function Ah(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function Th(t){return isFinite(t)?+("1e"+t):t<0?0:t}function Nh(t){return 10===t?Th:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function Sh(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function Eh(t){return function(n){return-t(-n)}}function kh(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function Ch(){var t=1,n=mh(function(n,e){return(e=kh(e,t)-(n=kh(n,t)))?function(r){return(kh(r,t)-n)/e}:dh(e)},function(n,e){return e=kh(e,t)-(n=kh(n,t)),function(r){return kh(n+e*r,1/t)}}),e=n.domain;return n.exponent=function(n){return arguments.length?(t=+n,e(e())):t},n.copy=function(){return bh(n,Ch().exponent(t))},xh(n)}var Ph=new Date,zh=new Date;function Rh(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var a,u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(a=new Date(+e)),n(e,o),t(e)}while(a<e&&e<r);return u},i.filter=function(e){return Rh(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return Ph.setTime(+n),zh.setTime(+r),t(Ph),t(zh),Math.floor(e(Ph,zh))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var Lh=Rh(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});Lh.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Rh(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):Lh:null};var Dh=Lh.range,Uh=6e4,qh=6048e5,Oh=Rh(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),Yh=Oh.range,Bh=Rh(function(t){t.setTime(Math.floor(t/Uh)*Uh)},function(t,n){t.setTime(+t+n*Uh)},function(t,n){return(n-t)/Uh},function(t){return t.getMinutes()}),Fh=Bh.range,Ih=Rh(function(t){var n=t.getTimezoneOffset()*Uh%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),Hh=Ih.range,jh=Rh(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Uh)/864e5},function(t){return t.getDate()-1}),Xh=jh.range;function Gh(t){return Rh(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Uh)/qh})}var Vh=Gh(0),$h=Gh(1),Wh=Gh(2),Zh=Gh(3),Qh=Gh(4),Jh=Gh(5),Kh=Gh(6),td=Vh.range,nd=$h.range,ed=Wh.range,rd=Zh.range,id=Qh.range,od=Jh.range,ad=Kh.range,ud=Rh(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),fd=ud.range,cd=Rh(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});cd.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Rh(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var sd=cd.range,ld=Rh(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*Uh)},function(t,n){return(n-t)/Uh},function(t){return t.getUTCMinutes()}),hd=ld.range,dd=Rh(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),pd=dd.range,vd=Rh(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),gd=vd.range;function yd(t){return Rh(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/qh})}var _d=yd(0),bd=yd(1),md=yd(2),xd=yd(3),wd=yd(4),Md=yd(5),Ad=yd(6),Td=_d.range,Nd=bd.range,Sd=md.range,Ed=xd.range,kd=wd.range,Cd=Md.range,Pd=Ad.range,zd=Rh(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),Rd=zd.range,Ld=Rh(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});Ld.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Rh(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Dd=Ld.range;function Ud(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function qd(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Od(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function Yd(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,a=t.shortDays,u=t.months,f=t.shortMonths,c=Vd(i),s=$d(i),l=Vd(o),h=$d(o),d=Vd(a),p=$d(a),v=Vd(u),g=$d(u),y=Vd(f),_=$d(f),b={a:function(t){return a[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return f[t.getMonth()]},B:function(t){return u[t.getMonth()]},c:null,d:pp,e:pp,f:bp,H:vp,I:gp,j:yp,L:_p,m:mp,M:xp,p:function(t){return i[+(t.getHours()>=12)]},Q:Wp,s:Zp,S:wp,u:Mp,U:Ap,V:Tp,w:Np,W:Sp,x:null,X:null,y:Ep,Y:kp,Z:Cp,"%":$p},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return f[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:Pp,e:Pp,f:Up,H:zp,I:Rp,j:Lp,L:Dp,m:qp,M:Op,p:function(t){return i[+(t.getUTCHours()>=12)]},Q:Wp,s:Zp,S:Yp,u:Bp,U:Fp,V:Ip,w:Hp,W:jp,x:null,X:null,y:Xp,Y:Gp,Z:Vp,"%":$p},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=y.exec(n.slice(e));return r?(t.m=_[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=g[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,e,r){return A(t,n,e,r)},d:ip,e:ip,f:sp,H:ap,I:ap,j:op,L:cp,m:rp,M:up,p:function(t,n,e){var r=c.exec(n.slice(e));return r?(t.p=s[r[0].toLowerCase()],e+r[0].length):-1},Q:hp,s:dp,S:fp,u:Zd,U:Qd,V:Jd,w:Wd,W:Kd,x:function(t,n,r){return A(t,e,n,r)},X:function(t,n,e){return A(t,r,n,e)},y:np,Y:tp,Z:ep,"%":lp};function w(t,n){return function(e){var r,i,o,a=[],u=-1,f=0,c=t.length;for(e instanceof Date||(e=new Date(+e));++u<c;)37===t.charCodeAt(u)&&(a.push(t.slice(f,u)),null!=(i=Fd[r=t.charAt(++u)])?r=t.charAt(++u):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),a.push(r),f=u+1);return a.push(t.slice(f,u)),a.join("")}}function M(t,n){return function(e){var r,i,o=Od(1900);if(A(o,t,e+="",0)!=e.length)return null;if("Q"in o)return new Date(o.Q);if("p"in o&&(o.H=o.H%12+12*o.p),"V"in o){if(o.V<1||o.V>53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=qd(Od(o.y))).getUTCDay(),r=i>4||0===i?bd.ceil(r):bd(r),r=vd.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=n(Od(o.y))).getDay(),r=i>4||0===i?$h.ceil(r):$h(r),r=jh.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?qd(Od(o.y)).getUTCDay():n(Od(o.y)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,qd(o)):n(o)}}function A(t,n,e,r){for(var i,o,a=0,u=n.length,f=e.length;a<u;){if(r>=f)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in Fd?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",Ud);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t,qd);return n.toString=function(){return t},n}}}var Bd,Fd={"-":"",_:" ",0:"0"},Id=/^\s*\d+/,Hd=/^%/,jd=/[\\^$*+?|[\]().{}]/g;function Xd(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function Gd(t){return t.replace(jd,"\\$&")}function Vd(t){return new RegExp("^(?:"+t.map(Gd).join("|")+")","i")}function $d(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Wd(t,n,e){var r=Id.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Zd(t,n,e){var r=Id.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Qd(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function Jd(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function Kd(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function tp(t,n,e){var r=Id.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function np(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function ep(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function rp(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function ip(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function op(t,n,e){var r=Id.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function ap(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function up(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function fp(t,n,e){var r=Id.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function cp(t,n,e){var r=Id.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function sp(t,n,e){var r=Id.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function lp(t,n,e){var r=Hd.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function hp(t,n,e){var r=Id.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function dp(t,n,e){var r=Id.exec(n.slice(e));return r?(t.Q=1e3*+r[0],e+r[0].length):-1}function pp(t,n){return Xd(t.getDate(),n,2)}function vp(t,n){return Xd(t.getHours(),n,2)}function gp(t,n){return Xd(t.getHours()%12||12,n,2)}function yp(t,n){return Xd(1+jh.count(cd(t),t),n,3)}function _p(t,n){return Xd(t.getMilliseconds(),n,3)}function bp(t,n){return _p(t,n)+"000"}function mp(t,n){return Xd(t.getMonth()+1,n,2)}function xp(t,n){return Xd(t.getMinutes(),n,2)}function wp(t,n){return Xd(t.getSeconds(),n,2)}function Mp(t){var n=t.getDay();return 0===n?7:n}function Ap(t,n){return Xd(Vh.count(cd(t),t),n,2)}function Tp(t,n){var e=t.getDay();return t=e>=4||0===e?Qh(t):Qh.ceil(t),Xd(Qh.count(cd(t),t)+(4===cd(t).getDay()),n,2)}function Np(t){return t.getDay()}function Sp(t,n){return Xd($h.count(cd(t),t),n,2)}function Ep(t,n){return Xd(t.getFullYear()%100,n,2)}function kp(t,n){return Xd(t.getFullYear()%1e4,n,4)}function Cp(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Xd(n/60|0,"0",2)+Xd(n%60,"0",2)}function Pp(t,n){return Xd(t.getUTCDate(),n,2)}function zp(t,n){return Xd(t.getUTCHours(),n,2)}function Rp(t,n){return Xd(t.getUTCHours()%12||12,n,2)}function Lp(t,n){return Xd(1+vd.count(Ld(t),t),n,3)}function Dp(t,n){return Xd(t.getUTCMilliseconds(),n,3)}function Up(t,n){return Dp(t,n)+"000"}function qp(t,n){return Xd(t.getUTCMonth()+1,n,2)}function Op(t,n){return Xd(t.getUTCMinutes(),n,2)}function Yp(t,n){return Xd(t.getUTCSeconds(),n,2)}function Bp(t){var n=t.getUTCDay();return 0===n?7:n}function Fp(t,n){return Xd(_d.count(Ld(t),t),n,2)}function Ip(t,n){var e=t.getUTCDay();return t=e>=4||0===e?wd(t):wd.ceil(t),Xd(wd.count(Ld(t),t)+(4===Ld(t).getUTCDay()),n,2)}function Hp(t){return t.getUTCDay()}function jp(t,n){return Xd(bd.count(Ld(t),t),n,2)}function Xp(t,n){return Xd(t.getUTCFullYear()%100,n,2)}function Gp(t,n){return Xd(t.getUTCFullYear()%1e4,n,4)}function Vp(){return"+0000"}function $p(){return"%"}function Wp(t){return+t}function Zp(t){return Math.floor(+t/1e3)}function Qp(n){return Bd=Yd(n),t.timeFormat=Bd.format,t.timeParse=Bd.parse,t.utcFormat=Bd.utcFormat,t.utcParse=Bd.utcParse,Bd}Qp({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Jp=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ");var Kp=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),tv=1e3,nv=60*tv,ev=60*nv,rv=24*ev,iv=7*rv,ov=30*rv,av=365*rv;function uv(t){return new Date(t)}function fv(t){return t instanceof Date?+t:+new Date(+t)}function cv(t,n,r,i,o,a,u,f,c){var s=mh(gh,ve),l=s.invert,h=s.domain,d=c(".%L"),p=c(":%S"),v=c("%I:%M"),g=c("%I %p"),y=c("%a %d"),_=c("%b %d"),b=c("%B"),m=c("%Y"),x=[[u,1,tv],[u,5,5*tv],[u,15,15*tv],[u,30,30*tv],[a,1,nv],[a,5,5*nv],[a,15,15*nv],[a,30,30*nv],[o,1,ev],[o,3,3*ev],[o,6,6*ev],[o,12,12*ev],[i,1,rv],[i,2,2*rv],[r,1,iv],[n,1,ov],[n,3,3*ov],[t,1,av]];function M(e){return(u(e)<e?d:a(e)<e?p:o(e)<e?v:i(e)<e?g:n(e)<e?r(e)<e?y:_:t(e)<e?b:m)(e)}function A(n,r,i,o){if(null==n&&(n=10),"number"==typeof n){var a=Math.abs(i-r)/n,u=e(function(t){return t[2]}).right(x,a);u===x.length?(o=w(r/av,i/av,n),n=t):u?(o=(u=x[a/x[u-1][2]<x[u][2]/a?u-1:u])[1],n=u[0]):(o=Math.max(w(r,i,n),1),n=f)}return null==o?n:n.every(o)}return s.invert=function(t){return new Date(l(t))},s.domain=function(t){return arguments.length?h(fh.call(t,fv)):h().map(uv)},s.ticks=function(t,n){var e,r=h(),i=r[0],o=r[r.length-1],a=o<i;return a&&(e=i,i=o,o=e),e=(e=A(t,i,o,n))?e.range(i,o+1):[],a?e.reverse():e},s.tickFormat=function(t,n){return null==n?M:c(n)},s.nice=function(t,n){var e=h();return(t=A(t,e[0],e[e.length-1],n))?h(wh(e,t)):s},s.copy=function(){return bh(s,cv(t,n,r,i,o,a,u,f,c))},s}function sv(t){for(var n=t.length/6|0,e=new Array(n),r=0;r<n;)e[r]="#"+t.slice(6*r,6*++r);return e}var lv=sv("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),hv=sv("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"),dv=sv("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"),pv=sv("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"),vv=sv("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"),gv=sv("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"),yv=sv("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"),_v=sv("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"),bv=sv("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f");function mv(t){return le(t[t.length-1])}var xv=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(sv),wv=mv(xv),Mv=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(sv),Av=mv(Mv),Tv=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(sv),Nv=mv(Tv),Sv=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(sv),Ev=mv(Sv),kv=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(sv),Cv=mv(kv),Pv=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(sv),zv=mv(Pv),Rv=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(sv),Lv=mv(Rv),Dv=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(sv),Uv=mv(Dv),qv=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(sv),Ov=mv(qv),Yv=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(sv),Bv=mv(Yv),Fv=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(sv),Iv=mv(Fv),Hv=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(sv),jv=mv(Hv),Xv=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(sv),Gv=mv(Xv),Vv=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(sv),$v=mv(Vv),Wv=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(sv),Zv=mv(Wv),Qv=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(sv),Jv=mv(Qv),Kv=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(sv),tg=mv(Kv),ng=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(sv),eg=mv(ng),rg=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(sv),ig=mv(rg),og=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(sv),ag=mv(og),ug=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(sv),fg=mv(ug),cg=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(sv),sg=mv(cg),lg=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(sv),hg=mv(lg),dg=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(sv),pg=mv(dg),vg=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(sv),gg=mv(vg),yg=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(sv),_g=mv(yg),bg=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(sv),mg=mv(bg),xg=Ge(Kn(300,.5,0),Kn(-240,.5,1)),wg=Ge(Kn(-100,.75,.35),Kn(80,1.5,.8)),Mg=Ge(Kn(260,.75,.35),Kn(80,1.5,.8)),Ag=Kn();var Tg=bn(),Ng=Math.PI/3,Sg=2*Math.PI/3;function Eg(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var kg=Eg(sv("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),Cg=Eg(sv("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),Pg=Eg(sv("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),zg=Eg(sv("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function Rg(t){return function(){return t}}var Lg=Math.abs,Dg=Math.atan2,Ug=Math.cos,qg=Math.max,Og=Math.min,Yg=Math.sin,Bg=Math.sqrt,Fg=1e-12,Ig=Math.PI,Hg=Ig/2,jg=2*Ig;function Xg(t){return t>=1?Hg:t<=-1?-Hg:Math.asin(t)}function Gg(t){return t.innerRadius}function Vg(t){return t.outerRadius}function $g(t){return t.startAngle}function Wg(t){return t.endAngle}function Zg(t){return t&&t.padAngle}function Qg(t,n,e,r,i,o,a){var u=t-e,f=n-r,c=(a?o:-o)/Bg(u*u+f*f),s=c*f,l=-c*u,h=t+s,d=n+l,p=e+s,v=r+l,g=(h+p)/2,y=(d+v)/2,_=p-h,b=v-d,m=_*_+b*b,x=i-o,w=h*v-p*d,M=(b<0?-1:1)*Bg(qg(0,x*x*m-w*w)),A=(w*b-_*M)/m,T=(-w*_-b*M)/m,N=(w*b+_*M)/m,S=(-w*_+b*M)/m,E=A-g,k=T-y,C=N-g,P=S-y;return E*E+k*k>C*C+P*P&&(A=N,T=S),{cx:A,cy:T,x01:-s,y01:-l,x11:A*(i/x-1),y11:T*(i/x-1)}}function Jg(t){this._context=t}function Kg(t){return new Jg(t)}function ty(t){return t[0]}function ny(t){return t[1]}function ey(){var t=ty,n=ny,e=Rg(!0),r=null,i=Kg,o=null;function a(a){var u,f,c,s=a.length,l=!1;for(null==r&&(o=i(c=Gi())),u=0;u<=s;++u)!(u<s&&e(f=a[u],u,a))===l&&((l=!l)?o.lineStart():o.lineEnd()),l&&o.point(+t(f,u,a),+n(f,u,a));if(c)return o=null,c+""||null}return a.x=function(n){return arguments.length?(t="function"==typeof n?n:Rg(+n),a):t},a.y=function(t){return arguments.length?(n="function"==typeof t?t:Rg(+t),a):n},a.defined=function(t){return arguments.length?(e="function"==typeof t?t:Rg(!!t),a):e},a.curve=function(t){return arguments.length?(i=t,null!=r&&(o=i(r)),a):i},a.context=function(t){return arguments.length?(null==t?r=o=null:o=i(r=t),a):r},a}function ry(){var t=ty,n=null,e=Rg(0),r=ny,i=Rg(!0),o=null,a=Kg,u=null;function f(f){var c,s,l,h,d,p=f.length,v=!1,g=new Array(p),y=new Array(p);for(null==o&&(u=a(d=Gi())),c=0;c<=p;++c){if(!(c<p&&i(h=f[c],c,f))===v)if(v=!v)s=c,u.areaStart(),u.lineStart();else{for(u.lineEnd(),u.lineStart(),l=c-1;l>=s;--l)u.point(g[l],y[l]);u.lineEnd(),u.areaEnd()}v&&(g[c]=+t(h,c,f),y[c]=+e(h,c,f),u.point(n?+n(h,c,f):g[c],r?+r(h,c,f):y[c]))}if(d)return u=null,d+""||null}function c(){return ey().defined(i).curve(a).context(o)}return f.x=function(e){return arguments.length?(t="function"==typeof e?e:Rg(+e),n=null,f):t},f.x0=function(n){return arguments.length?(t="function"==typeof n?n:Rg(+n),f):t},f.x1=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:Rg(+t),f):n},f.y=function(t){return arguments.length?(e="function"==typeof t?t:Rg(+t),r=null,f):e},f.y0=function(t){return arguments.length?(e="function"==typeof t?t:Rg(+t),f):e},f.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:Rg(+t),f):r},f.lineX0=f.lineY0=function(){return c().x(t).y(e)},f.lineY1=function(){return c().x(t).y(r)},f.lineX1=function(){return c().x(n).y(e)},f.defined=function(t){return arguments.length?(i="function"==typeof t?t:Rg(!!t),f):i},f.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),f):a},f.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),f):o},f}function iy(t,n){return n<t?-1:n>t?1:n>=t?0:NaN}function oy(t){return t}Jg.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var ay=fy(Kg);function uy(t){this._curve=t}function fy(t){function n(n){return new uy(t(n))}return n._curve=t,n}function cy(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(fy(t)):n()._curve},t}function sy(){return cy(ey().curve(ay))}function ly(){var t=ry().curve(ay),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return cy(e())},delete t.lineX0,t.lineEndAngle=function(){return cy(r())},delete t.lineX1,t.lineInnerRadius=function(){return cy(i())},delete t.lineY0,t.lineOuterRadius=function(){return cy(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(fy(t)):n()._curve},t}function hy(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}uy.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var dy=Array.prototype.slice;function py(t){return t.source}function vy(t){return t.target}function gy(t){var n=py,e=vy,r=ty,i=ny,o=null;function a(){var a,u=dy.call(arguments),f=n.apply(this,u),c=e.apply(this,u);if(o||(o=a=Gi()),t(o,+r.apply(this,(u[0]=f,u)),+i.apply(this,u),+r.apply(this,(u[0]=c,u)),+i.apply(this,u)),a)return o=null,a+""||null}return a.source=function(t){return arguments.length?(n=t,a):n},a.target=function(t){return arguments.length?(e=t,a):e},a.x=function(t){return arguments.length?(r="function"==typeof t?t:Rg(+t),a):r},a.y=function(t){return arguments.length?(i="function"==typeof t?t:Rg(+t),a):i},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a}function yy(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function _y(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function by(t,n,e,r,i){var o=hy(n,e),a=hy(n,e=(e+i)/2),u=hy(r,e),f=hy(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(a[0],a[1],u[0],u[1],f[0],f[1])}var my={draw:function(t,n){var e=Math.sqrt(n/Ig);t.moveTo(e,0),t.arc(0,0,e,0,jg)}},xy={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},wy=Math.sqrt(1/3),My=2*wy,Ay={draw:function(t,n){var e=Math.sqrt(n/My),r=e*wy;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},Ty=Math.sin(Ig/10)/Math.sin(7*Ig/10),Ny=Math.sin(jg/10)*Ty,Sy=-Math.cos(jg/10)*Ty,Ey={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=Ny*e,i=Sy*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var a=jg*o/5,u=Math.cos(a),f=Math.sin(a);t.lineTo(f*e,-u*e),t.lineTo(u*r-f*i,f*r+u*i)}t.closePath()}},ky={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Cy=Math.sqrt(3),Py={draw:function(t,n){var e=-Math.sqrt(n/(3*Cy));t.moveTo(0,2*e),t.lineTo(-Cy*e,-e),t.lineTo(Cy*e,-e),t.closePath()}},zy=Math.sqrt(3)/2,Ry=1/Math.sqrt(12),Ly=3*(Ry/2+1),Dy={draw:function(t,n){var e=Math.sqrt(n/Ly),r=e/2,i=e*Ry,o=r,a=e*Ry+e,u=-o,f=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,f),t.lineTo(-.5*r-zy*i,zy*r+-.5*i),t.lineTo(-.5*o-zy*a,zy*o+-.5*a),t.lineTo(-.5*u-zy*f,zy*u+-.5*f),t.lineTo(-.5*r+zy*i,-.5*i-zy*r),t.lineTo(-.5*o+zy*a,-.5*a-zy*o),t.lineTo(-.5*u+zy*f,-.5*f-zy*u),t.closePath()}},Uy=[my,xy,Ay,ky,Ey,Py,Dy];function qy(){}function Oy(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Yy(t){this._context=t}function By(t){this._context=t}function Fy(t){this._context=t}function Iy(t,n){this._basis=new Yy(t),this._beta=n}Yy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Oy(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Oy(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},By.prototype={areaStart:qy,areaEnd:qy,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Oy(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Fy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Oy(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Iy.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,f=-1;++f<=e;)r=f/e,this._basis.point(this._beta*t[f]+(1-this._beta)*(i+r*a),this._beta*n[f]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Hy=function t(n){function e(t){return 1===n?new Yy(t):new Iy(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function jy(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function Xy(t,n){this._context=t,this._k=(1-n)/6}Xy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:jy(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:jy(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gy=function t(n){function e(t){return new Xy(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Vy(t,n){this._context=t,this._k=(1-n)/6}Vy.prototype={areaStart:qy,areaEnd:qy,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:jy(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var $y=function t(n){function e(t){return new Vy(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Wy(t,n){this._context=t,this._k=(1-n)/6}Wy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:jy(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zy=function t(n){function e(t){return new Wy(t,n)}return e.tension=function(n){return t(+n)},e}(0);function Qy(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>Fg){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,f=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/f,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/f}if(t._l23_a>Fg){var c=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*c+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*c+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function Jy(t,n){this._context=t,this._alpha=n}Jy.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:Qy(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Ky=function t(n){function e(t){return n?new Jy(t,n):new Xy(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function t_(t,n){this._context=t,this._alpha=n}t_.prototype={areaStart:qy,areaEnd:qy,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Qy(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var n_=function t(n){function e(t){return n?new t_(t,n):new Vy(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function e_(t,n){this._context=t,this._alpha=n}e_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Qy(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var r_=function t(n){function e(t){return n?new e_(t,n):new Wy(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function i_(t){this._context=t}function o_(t){return t<0?-1:1}function a_(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(o_(o)+o_(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function u_(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function f_(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function c_(t){this._context=t}function s_(t){this._context=new l_(t)}function l_(t){this._context=t}function h_(t){this._context=t}function d_(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,a[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,a[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,a[n]-=e*a[n-1];for(i[r-1]=a[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function p_(t,n){this._context=t,this._t=n}function v_(t,n){if((i=t.length)>1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o<i;++o)for(r=a,a=t[n[o]],e=0;e<u;++e)a[e][1]+=a[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]}function g_(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e}function y_(t,n){return t[n]}function __(t){var n=t.map(b_);return g_(t).sort(function(t,e){return n[t]-n[e]})}function b_(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function m_(t){return function(){return t}}function x_(t){return t[0]}function w_(t){return t[1]}function M_(){this._=null}function A_(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function T_(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function N_(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function S_(t){for(;t.L;)t=t.L;return t}function E_(t,n,e,r){var i=[null,null],o=J_.push(i)-1;return i.left=t,i.right=n,e&&C_(i,t,n,e),r&&C_(i,n,t,r),Z_[t.index].halfedges.push(o),Z_[n.index].halfedges.push(o),i}function k_(t,n,e){var r=[n,e];return r.left=t,r}function C_(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function P_(t,n,e,r,i){var o,a=t[0],u=t[1],f=a[0],c=a[1],s=0,l=1,h=u[0]-f,d=u[1]-c;if(o=n-f,h||!(o>0)){if(o/=h,h<0){if(o<s)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>s&&(s=o)}if(o=r-f,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>s&&(s=o)}else if(h>0){if(o<s)return;o<l&&(l=o)}if(o=e-c,d||!(o>0)){if(o/=d,d<0){if(o<s)return;o<l&&(l=o)}else if(d>0){if(o>l)return;o>s&&(s=o)}if(o=i-c,d||!(o<0)){if(o/=d,d<0){if(o>l)return;o>s&&(s=o)}else if(d>0){if(o<s)return;o<l&&(l=o)}return!(s>0||l<1)||(s>0&&(t[0]=[f+s*h,c+s*d]),l<1&&(t[1]=[f+l*h,c+l*d]),!0)}}}}}function z_(t,n,e,r,i){var o=t[1];if(o)return!0;var a,u,f=t[0],c=t.left,s=t.right,l=c[0],h=c[1],d=s[0],p=s[1],v=(l+d)/2,g=(h+p)/2;if(p===h){if(v<n||v>=r)return;if(l>d){if(f){if(f[1]>=i)return}else f=[v,e];o=[v,i]}else{if(f){if(f[1]<e)return}else f=[v,i];o=[v,e]}}else if(u=g-(a=(l-d)/(p-h))*v,a<-1||a>1)if(l>d){if(f){if(f[1]>=i)return}else f=[(e-u)/a,e];o=[(i-u)/a,i]}else{if(f){if(f[1]<e)return}else f=[(i-u)/a,i];o=[(e-u)/a,e]}else if(h<p){if(f){if(f[0]>=r)return}else f=[n,a*n+u];o=[r,a*r+u]}else{if(f){if(f[0]<n)return}else f=[r,a*r+u];o=[n,a*n+u]}return t[0]=f,t[1]=o,!0}function R_(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function L_(t,n){return n[+(n.left!==t.site)]}function D_(t,n){return n[+(n.left===t.site)]}i_.prototype={areaStart:qy,areaEnd:qy,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}},c_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:f_(this,this._t0,u_(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(n=+n,(t=+t)!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,f_(this,u_(this,e=a_(this,t,n)),e);break;default:f_(this,this._t0,e=a_(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(s_.prototype=Object.create(c_.prototype)).point=function(t,n){c_.prototype.point.call(this,n,t)},l_.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},h_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=d_(t),i=d_(n),o=0,a=1;a<e;++o,++a)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[a],n[a]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}},p_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}},M_.prototype={constructor:M_,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=S_(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(T_(this,e),e=(t=e).U),e.C=!1,r.C=!0,N_(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(N_(this,e),e=(t=e).U),e.C=!1,r.C=!0,T_(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,a=t.R;if(e=o?a?S_(a):o:a,i?i.L===t?i.L=e:i.R=e:this._=e,o&&a?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==a?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=a,a.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,T_(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,N_(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,T_(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,N_(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,T_(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,N_(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var U_,q_=[];function O_(){A_(this),this.x=this.y=this.arc=this.site=this.cy=null}function Y_(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var a=i[0],u=i[1],f=r[0]-a,c=r[1]-u,s=o[0]-a,l=o[1]-u,h=2*(f*l-c*s);if(!(h>=-tb)){var d=f*f+c*c,p=s*s+l*l,v=(l*d-c*p)/h,g=(f*p-s*d)/h,y=q_.pop()||new O_;y.arc=t,y.site=i,y.x=v+a,y.y=(y.cy=g+u)+Math.sqrt(v*v+g*g),t.circle=y;for(var _=null,b=Q_._;b;)if(y.y<b.y||y.y===b.y&&y.x<=b.x){if(!b.L){_=b.P;break}b=b.L}else{if(!b.R){_=b;break}b=b.R}Q_.insert(_,y),_||(U_=y)}}}}function B_(t){var n=t.circle;n&&(n.P||(U_=n.N),Q_.remove(n),q_.push(n),A_(n),t.circle=null)}var F_=[];function I_(){A_(this),this.edge=this.site=this.circle=null}function H_(t){var n=F_.pop()||new I_;return n.site=t,n}function j_(t){B_(t),W_.remove(t),F_.push(t),A_(t)}function X_(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,a=t.N,u=[t];j_(t);for(var f=o;f.circle&&Math.abs(e-f.circle.x)<K_&&Math.abs(r-f.circle.cy)<K_;)o=f.P,u.unshift(f),j_(f),f=o;u.unshift(f),B_(f);for(var c=a;c.circle&&Math.abs(e-c.circle.x)<K_&&Math.abs(r-c.circle.cy)<K_;)a=c.N,u.push(c),j_(c),c=a;u.push(c),B_(c);var s,l=u.length;for(s=1;s<l;++s)c=u[s],f=u[s-1],C_(c.edge,f.site,c.site,i);f=u[0],(c=u[l-1]).edge=E_(f.site,c.site,null,i),Y_(f),Y_(c)}function G_(t){for(var n,e,r,i,o=t[0],a=t[1],u=W_._;u;)if((r=V_(u,a)-o)>K_)u=u.L;else{if(!((i=o-$_(u,a))>K_)){r>-K_?(n=u.P,e=u):i>-K_?(n=u,e=u.N):n=e=u;break}if(!u.R){n=u;break}u=u.R}!function(t){Z_[t.index]={site:t,halfedges:[]}}(t);var f=H_(t);if(W_.insert(n,f),n||e){if(n===e)return B_(n),e=H_(n.site),W_.insert(f,e),f.edge=e.edge=E_(n.site,f.site),Y_(n),void Y_(e);if(e){B_(n),B_(e);var c=n.site,s=c[0],l=c[1],h=t[0]-s,d=t[1]-l,p=e.site,v=p[0]-s,g=p[1]-l,y=2*(h*g-d*v),_=h*h+d*d,b=v*v+g*g,m=[(g*_-d*b)/y+s,(h*b-v*_)/y+l];C_(e.edge,c,p,m),f.edge=E_(c,t,null,m),e.edge=E_(t,p,null,m),Y_(n),Y_(e)}else f.edge=E_(n.site,f.site)}}function V_(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var a=t.P;if(!a)return-1/0;var u=(e=a.site)[0],f=e[1],c=f-n;if(!c)return u;var s=u-r,l=1/o-1/c,h=s/c;return l?(-h+Math.sqrt(h*h-2*l*(s*s/(-2*c)-f+c/2+i-o/2)))/l+r:(r+u)/2}function $_(t,n){var e=t.N;if(e)return V_(e,n);var r=t.site;return r[1]===n?r[0]:1/0}var W_,Z_,Q_,J_,K_=1e-6,tb=1e-12;function nb(t,n){return n[1]-t[1]||n[0]-t[0]}function eb(t,n){var e,r,i,o=t.sort(nb).pop();for(J_=[],Z_=new Array(t.length),W_=new M_,Q_=new M_;;)if(i=U_,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(G_(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;X_(i.arc)}if(function(){for(var t,n,e,r,i=0,o=Z_.length;i<o;++i)if((t=Z_[i])&&(r=(n=t.halfedges).length)){var a=new Array(r),u=new Array(r);for(e=0;e<r;++e)a[e]=e,u[e]=R_(t,J_[n[e]]);for(a.sort(function(t,n){return u[n]-u[t]}),e=0;e<r;++e)u[e]=n[a[e]];for(e=0;e<r;++e)n[e]=u[e]}}(),n){var a=+n[0][0],u=+n[0][1],f=+n[1][0],c=+n[1][1];!function(t,n,e,r){for(var i,o=J_.length;o--;)z_(i=J_[o],t,n,e,r)&&P_(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>K_||Math.abs(i[0][1]-i[1][1])>K_)||delete J_[o]}(a,u,f,c),function(t,n,e,r){var i,o,a,u,f,c,s,l,h,d,p,v,g=Z_.length,y=!0;for(i=0;i<g;++i)if(o=Z_[i]){for(a=o.site,u=(f=o.halfedges).length;u--;)J_[f[u]]||f.splice(u,1);for(u=0,c=f.length;u<c;)p=(d=D_(o,J_[f[u]]))[0],v=d[1],l=(s=L_(o,J_[f[++u%c]]))[0],h=s[1],(Math.abs(p-l)>K_||Math.abs(v-h)>K_)&&(f.splice(u,0,J_.push(k_(a,d,Math.abs(p-t)<K_&&r-v>K_?[t,Math.abs(l-t)<K_?h:r]:Math.abs(v-r)<K_&&e-p>K_?[Math.abs(h-r)<K_?l:e,r]:Math.abs(p-e)<K_&&v-n>K_?[e,Math.abs(l-e)<K_?h:n]:Math.abs(v-n)<K_&&p-t>K_?[Math.abs(h-n)<K_?l:t,n]:null))-1),++c);c&&(y=!1)}if(y){var _,b,m,x=1/0;for(i=0,y=null;i<g;++i)(o=Z_[i])&&(m=(_=(a=o.site)[0]-t)*_+(b=a[1]-n)*b)<x&&(x=m,y=o);if(y){var w=[t,n],M=[t,r],A=[e,r],T=[e,n];y.halfedges.push(J_.push(k_(a=y.site,w,M))-1,J_.push(k_(a,M,A))-1,J_.push(k_(a,A,T))-1,J_.push(k_(a,T,w))-1)}}for(i=0;i<g;++i)(o=Z_[i])&&(o.halfedges.length||delete Z_[i])}(a,u,f,c)}this.edges=J_,this.cells=Z_,W_=Q_=J_=Z_=null}function rb(t){return function(){return t}}function ib(t,n,e){this.target=t,this.type=n,this.transform=e}function ob(t,n,e){this.k=t,this.x=n,this.y=e}eb.prototype={constructor:eb,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return L_(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,a,u,f,c,s=e.site,l=-1,h=n[i[o-1]],d=h.left===s?h.right:h.left;++l<o;)a=d,d=(h=n[i[l]]).left===s?h.right:h.left,a&&d&&r<a.index&&r<d.index&&(f=a,c=d,((u=s)[0]-c[0])*(f[1]-u[1])-(u[0]-f[0])*(c[1]-u[1])<0)&&t.push([s.data,a.data,d.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,a=o._found||0,u=o.cells.length;!(i=o.cells[a]);)if(++a>=u)return null;var f=t-i.site[0],c=n-i.site[1],s=f*f+c*c;do{i=o.cells[r=a],a=null,i.halfedges.forEach(function(e){var r=o.edges[e],u=r.left;if(u!==i.site&&u||(u=r.right)){var f=t-u[0],c=n-u[1],l=f*f+c*c;l<s&&(s=l,a=u.index)}})}while(null!==a);return o._found=r,null==e||s<=e*e?i.site:null}},ob.prototype={constructor:ob,scale:function(t){return 1===t?this:new ob(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ob(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var ab=new ob(1,0,0);function ub(t){return t.__zoom||ab}function fb(){t.event.stopImmediatePropagation()}function cb(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function sb(){return!t.event.button}function lb(){var t,n,e=this;return e instanceof SVGElement?(t=(e=e.ownerSVGElement||e).width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function hb(){return this.__zoom||ab}function db(){return-t.event.deltaY*(t.event.deltaMode?120:1)/500}function pb(){return"ontouchstart"in this}function vb(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}ub.prototype=ob.prototype,t.version="5.7.0",t.bisect=i,t.bisectRight=i,t.bisectLeft=o,t.ascending=n,t.bisector=e,t.cross=function(t,n,e){var r,i,o,u,f=t.length,c=n.length,s=new Array(f*c);for(null==e&&(e=a),r=o=0;r<f;++r)for(u=t[r],i=0;i<c;++i,++o)s[o]=e(u,n[i]);return s},t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=c,t.extent=s,t.histogram=function(){var t=v,n=s,e=M;function r(r){var o,a,u=r.length,f=new Array(u);for(o=0;o<u;++o)f[o]=t(r[o],o,r);var c=n(f),s=c[0],l=c[1],h=e(f,s,l);Array.isArray(h)||(h=w(s,l,h),h=g(Math.ceil(s/h)*h,l,h));for(var d=h.length;h[0]<=s;)h.shift(),--d;for(;h[d-1]>l;)h.pop(),--d;var p,v=new Array(d+1);for(o=0;o<=d;++o)(p=v[o]=[]).x0=o>0?h[o-1]:s,p.x1=o<d?h[o]:l;for(o=0;o<u;++o)s<=(a=f[o])&&a<=l&&v[i(h,a,0,d)].push(r[o]);return v}return r.value=function(n){return arguments.length?(t="function"==typeof n?n:p(n),r):t},r.domain=function(t){return arguments.length?(n="function"==typeof t?t:p([t[0],t[1]]),r):n},r.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?p(h.call(t)):p(t),r):e},r},t.thresholdFreedmanDiaconis=function(t,e,r){return t=d.call(t,u).sort(n),Math.ceil((r-e)/(2*(A(t,.75)-A(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*c(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=M,t.max=T,t.mean=function(t,n){var e,r=t.length,i=r,o=-1,a=0;if(null==n)for(;++o<r;)isNaN(e=u(t[o]))?--i:a+=e;else for(;++o<r;)isNaN(e=u(n(t[o],o,t)))?--i:a+=e;if(i)return a/i},t.median=function(t,e){var r,i=t.length,o=-1,a=[];if(null==e)for(;++o<i;)isNaN(r=u(t[o]))||a.push(r);else for(;++o<i;)isNaN(r=u(e(t[o],o,t)))||a.push(r);return A(a.sort(n),.5)},t.merge=N,t.min=S,t.pairs=function(t,n){null==n&&(n=a);for(var e=0,r=t.length-1,i=t[0],o=new Array(r<0?0:r);e<r;)o[e]=n(i,i=t[++e]);return o},t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.quantile=A,t.range=g,t.scan=function(t,e){if(r=t.length){var r,i,o=0,a=0,u=t[a];for(null==e&&(e=n);++o<r;)(e(i=t[o],u)<0||0!==e(u,u))&&(u=i,a=o);return 0===e(u,u)?a:void 0}},t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.ticks=m,t.tickIncrement=x,t.tickStep=w,t.transpose=E,t.variance=f,t.zip=function(){return E(arguments)},t.axisTop=function(t){return B(z,t)},t.axisRight=function(t){return B(R,t)},t.axisBottom=function(t){return B(L,t)},t.axisLeft=function(t){return B(D,t)},t.brush=function(){return Ri(wi)},t.brushX=function(){return Ri(mi)},t.brushY=function(){return Ri(xi)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.chord=function(){var t=0,n=null,e=null,r=null;function i(i){var o,a,u,f,c,s,l=i.length,h=[],d=g(l),p=[],v=[],y=v.groups=new Array(l),_=new Array(l*l);for(o=0,c=-1;++c<l;){for(a=0,s=-1;++s<l;)a+=i[c][s];h.push(a),p.push(g(l)),o+=a}for(n&&d.sort(function(t,e){return n(h[t],h[e])}),e&&p.forEach(function(t,n){t.sort(function(t,r){return e(i[n][t],i[n][r])})}),f=(o=Yi(0,Oi-t*l)/o)?t:Oi/l,a=0,c=-1;++c<l;){for(u=a,s=-1;++s<l;){var b=d[c],m=p[b][s],x=i[b][m],w=a,M=a+=x*o;_[m*l+b]={index:b,subindex:m,startAngle:w,endAngle:M,value:x}}y[b]={index:b,startAngle:u,endAngle:a,value:h[b]},a+=f}for(c=-1;++c<l;)for(s=c-1;++s<l;){var A=_[s*l+c],T=_[c*l+s];(A.value||T.value)&&v.push(A.value<T.value?{source:T,target:A}:{source:A,target:T})}return r?v.sort(r):v}return i.padAngle=function(n){return arguments.length?(t=Yi(0,n),i):t},i.sortGroups=function(t){return arguments.length?(n=t,i):n},i.sortSubgroups=function(t){return arguments.length?(e=t,i):e},i.sortChords=function(t){return arguments.length?(null==t?r=null:(n=t,r=function(t,e){return n(t.source.value+t.target.value,e.source.value+e.target.value)})._=t,i):r&&r._;var n},i},t.ribbon=function(){var t=Vi,n=$i,e=Wi,r=Zi,i=Qi,o=null;function a(){var a,u=Bi.call(arguments),f=t.apply(this,u),c=n.apply(this,u),s=+e.apply(this,(u[0]=f,u)),l=r.apply(this,u)-qi,h=i.apply(this,u)-qi,d=s*Li(l),p=s*Di(l),v=+e.apply(this,(u[0]=c,u)),g=r.apply(this,u)-qi,y=i.apply(this,u)-qi;if(o||(o=a=Gi()),o.moveTo(d,p),o.arc(0,0,s,l,h),l===g&&h===y||(o.quadraticCurveTo(0,0,v*Li(g),v*Di(g)),o.arc(0,0,v,g,y)),o.quadraticCurveTo(0,0,d,p),o.closePath(),a)return o=null,a+""||null}return a.radius=function(t){return arguments.length?(e="function"==typeof t?t:Fi(+t),a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Fi(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Fi(+t),a):i},a.source=function(n){return arguments.length?(t=n,a):t},a.target=function(t){return arguments.length?(n=t,a):n},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a},t.nest=function(){var t,n,e,r=[],i=[];function o(e,i,a,u){if(i>=r.length)return null!=t&&e.sort(t),null!=n?n(e):e;for(var f,c,s,l=-1,h=e.length,d=r[i++],p=Ki(),v=a();++l<h;)(s=p.get(f=d(c=e[l])+""))?s.push(c):p.set(f,[c]);return p.each(function(t,n){u(v,n,o(t,i,a,u))}),v}return e={object:function(t){return o(t,0,to,no)},map:function(t){return o(t,0,eo,ro)},entries:function(t){return function t(e,o){if(++o>r.length)return e;var a,u=i[o-1];return null!=n&&o>=r.length?a=e.entries():(a=[],e.each(function(n,e){a.push({key:e,values:t(n,o)})})),null!=u?a.sort(function(t,n){return u(t.key,n.key)}):a}(o(t,0,eo,ro),0)},key:function(t){return r.push(t),e},sortKeys:function(t){return i[r.length-1]=t,e},sortValues:function(n){return t=n,e},rollup:function(t){return n=t,e}}},t.set=ao,t.map=Ki,t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.color=vn,t.rgb=bn,t.hsl=Mn,t.lab=Un,t.hcl=Hn,t.lch=function(t,n,e,r){return 1===arguments.length?In(t):new jn(e,n,t,null==r?1:r)},t.gray=function(t,n){return new qn(t,0,0,null==n?1:n)},t.cubehelix=Kn,t.contours=go,t.contourDensity=function(){var t=bo,n=mo,e=xo,r=960,i=500,o=20,a=2,u=3*o,f=r+2*u>>a,c=i+2*u>>a,s=co(20);function l(r){var i=new Float32Array(f*c),l=new Float32Array(f*c);r.forEach(function(r,o,s){var l=+t(r,o,s)+u>>a,h=+n(r,o,s)+u>>a,d=+e(r,o,s);l>=0&&l<f&&h>=0&&h<c&&(i[l+h*f]+=d)}),yo({width:f,height:c,data:i},{width:f,height:c,data:l},o>>a),_o({width:f,height:c,data:l},{width:f,height:c,data:i},o>>a),yo({width:f,height:c,data:i},{width:f,height:c,data:l},o>>a),_o({width:f,height:c,data:l},{width:f,height:c,data:i},o>>a),yo({width:f,height:c,data:i},{width:f,height:c,data:l},o>>a),_o({width:f,height:c,data:l},{width:f,height:c,data:i},o>>a);var d=s(i);if(!Array.isArray(d)){var p=T(i);d=w(0,p,d),(d=g(0,Math.floor(p/d)*d,d)).shift()}return go().thresholds(d).size([f,c])(i).map(h)}function h(t){return t.value*=Math.pow(2,-2*a),t.coordinates.forEach(d),t}function d(t){t.forEach(p)}function p(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function y(){return f=r+2*(u=3*o)>>a,c=i+2*u>>a,l}return l.x=function(n){return arguments.length?(t="function"==typeof n?n:co(+n),l):t},l.y=function(t){return arguments.length?(n="function"==typeof t?t:co(+t),l):n},l.weight=function(t){return arguments.length?(e="function"==typeof t?t:co(+t),l):e},l.size=function(t){if(!arguments.length)return[r,i];var n=Math.ceil(t[0]),e=Math.ceil(t[1]);if(!(n>=0||n>=0))throw new Error("invalid size");return r=n,i=e,y()},l.cellSize=function(t){if(!arguments.length)return 1<<a;if(!((t=+t)>=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),y()},l.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?co(uo.call(t)):co(t),l):s},l.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=Math.round((Math.sqrt(4*t*t+1)-1)/2),y()},l},t.dispatch=I,t.drag=function(){var n,e,r,i,o=Wt,a=Zt,u=Qt,f=Jt,c={},s=I("start","drag","end"),l=0,h=0;function d(t){t.on("mousedown.drag",p).filter(f).on("touchstart.drag",y).on("touchmove.drag",_).on("touchend.drag touchcancel.drag",b).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function p(){if(!i&&o.apply(this,arguments)){var u=m("mouse",a.apply(this,arguments),Ft,this,arguments);u&&(Dt(t.event.view).on("mousemove.drag",v,!0).on("mouseup.drag",g,!0),Xt(t.event.view),Ht(),r=!1,n=t.event.clientX,e=t.event.clientY,u("start"))}}function v(){if(jt(),!r){var i=t.event.clientX-n,o=t.event.clientY-e;r=i*i+o*o>h}c.mouse("drag")}function g(){Dt(t.event.view).on("mousemove.drag mouseup.drag",null),Gt(t.event.view,r),jt(),c.mouse("end")}function y(){if(o.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=a.apply(this,arguments),u=r.length;for(n=0;n<u;++n)(e=m(r[n].identifier,i,It,this,arguments))&&(Ht(),e("start"))}}function _(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=c[r[n].identifier])&&(jt(),e("drag"))}function b(){var n,e,r=t.event.changedTouches,o=r.length;for(i&&clearTimeout(i),i=setTimeout(function(){i=null},500),n=0;n<o;++n)(e=c[r[n].identifier])&&(Ht(),e("end"))}function m(n,e,r,i,o){var a,f,h,p=r(e,n),v=s.copy();if(Ct(new $t(d,"beforestart",a,n,l,p[0],p[1],0,0,v),function(){return null!=(t.event.subject=a=u.apply(i,o))&&(f=a.x-p[0]||0,h=a.y-p[1]||0,!0)}))return function t(u){var s,g=p;switch(u){case"start":c[n]=t,s=l++;break;case"end":delete c[n],--l;case"drag":p=r(e,n),s=l}Ct(new $t(d,u,a,n,s,p[0]+f,p[1]+h,p[0]-g[0],p[1]-g[1],v),v.apply,v,[u,i,o])}}return d.filter=function(t){return arguments.length?(o="function"==typeof t?t:Vt(!!t),d):o},d.container=function(t){return arguments.length?(a="function"==typeof t?t:Vt(t),d):a},d.subject=function(t){return arguments.length?(u="function"==typeof t?t:Vt(t),d):u},d.touchable=function(t){return arguments.length?(f="function"==typeof t?t:Vt(!!t),d):f},d.on=function(){var t=s.on.apply(s,arguments);return t===s?d:t},d.clickDistance=function(t){return arguments.length?(h=(t=+t)*t,d):Math.sqrt(h)},d},t.dragDisable=Xt,t.dragEnable=Gt,t.dsvFormat=Eo,t.csvParse=Co,t.csvParseRows=Po,t.csvFormat=zo,t.csvFormatRows=Ro,t.tsvParse=Do,t.tsvParseRows=Uo,t.tsvFormat=qo,t.tsvFormatRows=Oo,t.easeLinear=function(t){return+t},t.easeQuad=Dr,t.easeQuadIn=function(t){return t*t},t.easeQuadOut=function(t){return t*(2-t)},t.easeQuadInOut=Dr,t.easeCubic=Ur,t.easeCubicIn=function(t){return t*t*t},t.easeCubicOut=function(t){return--t*t*t+1},t.easeCubicInOut=Ur,t.easePoly=Yr,t.easePolyIn=qr,t.easePolyOut=Or,t.easePolyInOut=Yr,t.easeSin=Ir,t.easeSinIn=function(t){return 1-Math.cos(t*Fr)},t.easeSinOut=function(t){return Math.sin(t*Fr)},t.easeSinInOut=Ir,t.easeExp=Hr,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeExpInOut=Hr,t.easeCircle=jr,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCircleInOut=jr,t.easeBounce=ni,t.easeBounceIn=function(t){return 1-ni(1-t)},t.easeBounceOut=ni,t.easeBounceInOut=function(t){return((t*=2)<=1?1-ni(1-t):ni(t-1)+1)/2},t.easeBack=ii,t.easeBackIn=ei,t.easeBackOut=ri,t.easeBackInOut=ii,t.easeElastic=ui,t.easeElasticIn=ai,t.easeElasticOut=ui,t.easeElasticInOut=fi,t.blob=function(t,n){return fetch(t,n).then(Yo)},t.buffer=function(t,n){return fetch(t,n).then(Bo)},t.dsv=function(t,n,e,r){3===arguments.length&&"function"==typeof e&&(r=e,e=void 0);var i=Eo(t);return Io(n,e).then(function(t){return i.parse(t,r)})},t.csv=jo,t.tsv=Xo,t.image=function(t,n){return new Promise(function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t})},t.json=function(t,n){return fetch(t,n).then(Go)},t.text=Io,t.xml=$o,t.html=Wo,t.svg=Zo,t.forceCenter=function(t,n){var e;function r(){var r,i,o=e.length,a=0,u=0;for(r=0;r<o;++r)a+=(i=e[r]).x,u+=i.y;for(a=a/o-t,u=u/o-n,r=0;r<o;++r)(i=e[r]).x-=a,i.y-=u}return null==t&&(t=0),null==n&&(n=0),r.initialize=function(t){e=t},r.x=function(n){return arguments.length?(t=+n,r):t},r.y=function(t){return arguments.length?(n=+t,r):n},r},t.forceCollide=function(t){var n,e,r=1,i=1;function o(){for(var t,o,u,f,c,s,l,h=n.length,d=0;d<i;++d)for(o=ra(n,ua,fa).visitAfter(a),t=0;t<h;++t)u=n[t],s=e[u.index],l=s*s,f=u.x+u.vx,c=u.y+u.vy,o.visit(p);function p(t,n,e,i,o){var a=t.data,h=t.r,d=s+h;if(!a)return n>f+d||i<f-d||e>c+d||o<c-d;if(a.index>u.index){var p=f-a.x-a.vx,v=c-a.y-a.vy,g=p*p+v*v;g<d*d&&(0===p&&(g+=(p=Jo())*p),0===v&&(g+=(v=Jo())*v),g=(d-(g=Math.sqrt(g)))/g*r,u.vx+=(p*=g)*(d=(h*=h)/(l+h)),u.vy+=(v*=g)*d,a.vx-=p*(d=1-d),a.vy-=v*d)}}}function a(t){if(t.data)return t.r=e[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function u(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r<o;++r)i=n[r],e[i.index]=+t(i,r,n)}}return"function"!=typeof t&&(t=Qo(null==t?1:+t)),o.initialize=function(t){n=t,u()},o.iterations=function(t){return arguments.length?(i=+t,o):i},o.strength=function(t){return arguments.length?(r=+t,o):r},o.radius=function(n){return arguments.length?(t="function"==typeof n?n:Qo(+n),u(),o):t},o},t.forceLink=function(t){var n,e,r,i,o,a=ca,u=function(t){return 1/Math.min(i[t.source.index],i[t.target.index])},f=Qo(30),c=1;function s(r){for(var i=0,a=t.length;i<c;++i)for(var u,f,s,l,h,d,p,v=0;v<a;++v)f=(u=t[v]).source,l=(s=u.target).x+s.vx-f.x-f.vx||Jo(),h=s.y+s.vy-f.y-f.vy||Jo(),l*=d=((d=Math.sqrt(l*l+h*h))-e[v])/d*r*n[v],h*=d,s.vx-=l*(p=o[v]),s.vy-=h*p,f.vx+=l*(p=1-p),f.vy+=h*p}function l(){if(r){var u,f,c=r.length,s=t.length,l=Ki(r,a);for(u=0,i=new Array(c);u<s;++u)(f=t[u]).index=u,"object"!=typeof f.source&&(f.source=sa(l,f.source)),"object"!=typeof f.target&&(f.target=sa(l,f.target)),i[f.source.index]=(i[f.source.index]||0)+1,i[f.target.index]=(i[f.target.index]||0)+1;for(u=0,o=new Array(s);u<s;++u)f=t[u],o[u]=i[f.source.index]/(i[f.source.index]+i[f.target.index]);n=new Array(s),h(),e=new Array(s),d()}}function h(){if(r)for(var e=0,i=t.length;e<i;++e)n[e]=+u(t[e],e,t)}function d(){if(r)for(var n=0,i=t.length;n<i;++n)e[n]=+f(t[n],n,t)}return null==t&&(t=[]),s.initialize=function(t){r=t,l()},s.links=function(n){return arguments.length?(t=n,l(),s):t},s.id=function(t){return arguments.length?(a=t,s):a},s.iterations=function(t){return arguments.length?(c=+t,s):c},s.strength=function(t){return arguments.length?(u="function"==typeof t?t:Qo(+t),h(),s):u},s.distance=function(t){return arguments.length?(f="function"==typeof t?t:Qo(+t),d(),s):f},s},t.forceManyBody=function(){var t,n,e,r,i=Qo(-30),o=1,a=1/0,u=.81;function f(r){var i,o=t.length,a=ra(t,la,ha).visitAfter(s);for(e=r,i=0;i<o;++i)n=t[i],a.visit(l)}function c(){if(t){var n,e,o=t.length;for(r=new Array(o),n=0;n<o;++n)e=t[n],r[e.index]=+i(e,n,t)}}function s(t){var n,e,i,o,a,u=0,f=0;if(t.length){for(i=o=a=0;a<4;++a)(n=t[a])&&(e=Math.abs(n.value))&&(u+=n.value,f+=e,i+=e*n.x,o+=e*n.y);t.x=i/f,t.y=o/f}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=r[n.data.index]}while(n=n.next)}t.value=u}function l(t,i,f,c){if(!t.value)return!0;var s=t.x-n.x,l=t.y-n.y,h=c-i,d=s*s+l*l;if(h*h/u<d)return d<a&&(0===s&&(d+=(s=Jo())*s),0===l&&(d+=(l=Jo())*l),d<o&&(d=Math.sqrt(o*d)),n.vx+=s*t.value*e/d,n.vy+=l*t.value*e/d),!0;if(!(t.length||d>=a)){(t.data!==n||t.next)&&(0===s&&(d+=(s=Jo())*s),0===l&&(d+=(l=Jo())*l),d<o&&(d=Math.sqrt(o*d)));do{t.data!==n&&(h=r[t.data.index]*e/d,n.vx+=s*h,n.vy+=l*h)}while(t=t.next)}}return f.initialize=function(n){t=n,c()},f.strength=function(t){return arguments.length?(i="function"==typeof t?t:Qo(+t),c(),f):i},f.distanceMin=function(t){return arguments.length?(o=t*t,f):Math.sqrt(o)},f.distanceMax=function(t){return arguments.length?(a=t*t,f):Math.sqrt(a)},f.theta=function(t){return arguments.length?(u=t*t,f):Math.sqrt(u)},f},t.forceRadial=function(t,n,e){var r,i,o,a=Qo(.1);function u(t){for(var a=0,u=r.length;a<u;++a){var f=r[a],c=f.x-n||1e-6,s=f.y-e||1e-6,l=Math.sqrt(c*c+s*s),h=(o[a]-l)*i[a]*t/l;f.vx+=c*h,f.vy+=s*h}}function f(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)o[n]=+t(r[n],n,r),i[n]=isNaN(o[n])?0:+a(r[n],n,r)}}return"function"!=typeof t&&(t=Qo(+t)),null==n&&(n=0),null==e&&(e=0),u.initialize=function(t){r=t,f()},u.strength=function(t){return arguments.length?(a="function"==typeof t?t:Qo(+t),f(),u):a},u.radius=function(n){return arguments.length?(t="function"==typeof n?n:Qo(+n),f(),u):t},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(t){return arguments.length?(e=+t,u):e},u},t.forceSimulation=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,u=Ki(),f=ur(s),c=I("tick","end");function s(){l(),c.call("tick",n),e<r&&(f.stop(),c.call("end",n))}function l(){var n,r,f=t.length;for(e+=(o-e)*i,u.each(function(t){t(e)}),n=0;n<f;++n)null==(r=t[n]).fx?r.x+=r.vx*=a:(r.x=r.fx,r.vx=0),null==r.fy?r.y+=r.vy*=a:(r.y=r.fy,r.vy=0)}function h(){for(var n,e=0,r=t.length;e<r;++e){if((n=t[e]).index=e,isNaN(n.x)||isNaN(n.y)){var i=da*Math.sqrt(e),o=e*pa;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function d(n){return n.initialize&&n.initialize(t),n}return null==t&&(t=[]),h(),n={tick:l,restart:function(){return f.restart(s),n},stop:function(){return f.stop(),n},nodes:function(e){return arguments.length?(t=e,h(),u.each(d),n):t},alpha:function(t){return arguments.length?(e=+t,n):e},alphaMin:function(t){return arguments.length?(r=+t,n):r},alphaDecay:function(t){return arguments.length?(i=+t,n):+i},alphaTarget:function(t){return arguments.length?(o=+t,n):o},velocityDecay:function(t){return arguments.length?(a=1-t,n):1-a},force:function(t,e){return arguments.length>1?(null==e?u.remove(t):u.set(t,d(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,f,c=0,s=t.length;for(null==r?r=1/0:r*=r,c=0;c<s;++c)(a=(i=n-(u=t[c]).x)*i+(o=e-u.y)*o)<r&&(f=u,r=a);return f},on:function(t,e){return arguments.length>1?(c.on(t,e),n):c.on(t)}}},t.forceX=function(t){var n,e,r,i=Qo(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vx+=(r[o]-i.x)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=Qo(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:Qo(+t),a(),o):i},o.x=function(n){return arguments.length?(t="function"==typeof n?n:Qo(+n),a(),o):t},o},t.forceY=function(t){var n,e,r,i=Qo(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vy+=(r[o]-i.y)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=Qo(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:Qo(+t),a(),o):i},o.y=function(n){return arguments.length?(t="function"==typeof n?n:Qo(+n),a(),o):t},o},t.formatDefaultLocale=Sa,t.formatLocale=Na,t.formatSpecifier=ba,t.precisionFixed=Ea,t.precisionPrefix=ka,t.precisionRound=Ca,t.geoArea=function(t){return yu.reset(),su(t,_u),2*yu},t.geoBounds=function(t){var n,e,r,i,o,a,u;if(Ru=zu=-(Cu=Pu=1/0),Ou=[],su(t,rf),e=Ou.length){for(Ou.sort(df),n=1,o=[r=Ou[0]];n<e;++n)pf(r,(i=Ou[n])[0])||pf(r,i[1])?(hf(r[0],i[1])>hf(r[0],r[1])&&(r[1]=i[1]),hf(i[0],r[1])>hf(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=hf(r[1],i[0]))>a&&(a=u,Cu=i[0],zu=r[1])}return Ou=Yu=null,Cu===1/0||Pu===1/0?[[NaN,NaN],[NaN,NaN]]:[[Cu,Pu],[zu,Ru]]},t.geoCentroid=function(t){Bu=Fu=Iu=Hu=ju=Xu=Gu=Vu=$u=Wu=Zu=0,su(t,vf);var n=$u,e=Wu,r=Zu,i=n*n+e*e+r*r;return i<Ua&&(n=Xu,e=Gu,r=Vu,Fu<Da&&(n=Iu,e=Hu,r=ju),(i=n*n+e*e+r*r)<Ua)?[NaN,NaN]:[Xa(e,n)*Fa,eu(r/Ka(i))*Fa]},t.geoCircle=function(){var t,n,e=Nf([0,0]),r=Nf(90),i=Nf(6),o={point:function(e,r){t.push(e=n(e,r)),e[0]*=Fa,e[1]*=Fa}};function a(){var a=e.apply(this,arguments),u=r.apply(this,arguments)*Ia,f=i.apply(this,arguments)*Ia;return t=[],n=kf(-a[0]*Ia,-a[1]*Ia,0).invert,Lf(o,u,f,1),a={type:"Polygon",coordinates:[t]},t=n=null,a}return a.center=function(t){return arguments.length?(e="function"==typeof t?t:Nf([+t[0],+t[1]]),a):e},a.radius=function(t){return arguments.length?(r="function"==typeof t?t:Nf(+t),a):r},a.precision=function(t){return arguments.length?(i="function"==typeof t?t:Nf(+t),a):i},a},t.geoClipAntimeridian=Gf,t.geoClipCircle=Vf,t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,a=500;return e={stream:function(e){return t&&n===e?t:t=Zf(r,i,o,a)(n=e)},extent:function(u){return arguments.length?(r=+u[0][0],i=+u[0][1],o=+u[1][0],a=+u[1][1],t=n=null,e):[[r,i],[o,a]]}}},t.geoClipRectangle=Zf,t.geoContains=function(t,n){return(t&&cc.hasOwnProperty(t.type)?cc[t.type]:lc)(t,n)},t.geoDistance=fc,t.geoGraticule=bc,t.geoGraticule10=function(){return bc()()},t.geoInterpolate=function(t,n){var e=t[0]*Ia,r=t[1]*Ia,i=n[0]*Ia,o=n[1]*Ia,a=Ga(r),u=Qa(r),f=Ga(o),c=Qa(o),s=a*Ga(e),l=a*Qa(e),h=f*Ga(i),d=f*Qa(i),p=2*eu(Ka(ru(o-r)+a*f*ru(i-e))),v=Qa(p),g=p?function(t){var n=Qa(t*=p)/v,e=Qa(p-t)/v,r=e*s+n*h,i=e*l+n*d,o=e*u+n*c;return[Xa(i,r)*Fa,Xa(o,Ka(r*r+i*i))*Fa]}:function(){return[e*Fa,r*Fa]};return g.distance=p,g},t.geoLength=oc,t.geoPath=function(t,n){var e,r,i=4.5;function o(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),su(t,e(r))),r.result()}return o.area=function(t){return su(t,e(Sc)),Sc.result()},o.measure=function(t){return su(t,e(ds)),ds.result()},o.bounds=function(t){return su(t,e(Uc)),Uc.result()},o.centroid=function(t){return su(t,e(Zc)),Zc.result()},o.projection=function(n){return arguments.length?(e=null==n?(t=null,mc):(t=n).stream,o):t},o.context=function(t){return arguments.length?(r=null==t?(n=null,new gs):new as(n=t),"function"!=typeof i&&r.pointRadius(i),o):n},o.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),o):i},o.projection(t).context(n)},t.geoAlbers=Ds,t.geoAlbersUsa=function(){var t,n,e,r,i,o,a=Ds(),u=Ls().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=Ls().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(t,n){o=[t,n]}};function s(t){var n=t[0],a=t[1];return o=null,e.point(n,a),o||(r.point(n,a),o)||(i.point(n,a),o)}function l(){return t=n=null,s}return s.invert=function(t){var n=a.scale(),e=a.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),f.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++e<i;)r[e].point(t,n)},sphere:function(){for(var t=-1;++t<i;)r[t].sphere()},lineStart:function(){for(var t=-1;++t<i;)r[t].lineStart()},lineEnd:function(){for(var t=-1;++t<i;)r[t].lineEnd()},polygonStart:function(){for(var t=-1;++t<i;)r[t].polygonStart()},polygonEnd:function(){for(var t=-1;++t<i;)r[t].polygonEnd()}});var r,i},s.precision=function(t){return arguments.length?(a.precision(t),u.precision(t),f.precision(t),l()):a.precision()},s.scale=function(t){return arguments.length?(a.scale(t),u.scale(.35*t),f.scale(t),s.translate(a.translate())):a.scale()},s.translate=function(t){if(!arguments.length)return a.translate();var n=a.scale(),o=+t[0],s=+t[1];return e=a.translate(t).clipExtent([[o-.455*n,s-.238*n],[o+.455*n,s+.238*n]]).stream(c),r=u.translate([o-.307*n,s+.201*n]).clipExtent([[o-.425*n+Da,s+.12*n+Da],[o-.214*n-Da,s+.234*n-Da]]).stream(c),i=f.translate([o-.205*n,s+.212*n]).clipExtent([[o-.214*n+Da,s+.166*n+Da],[o-.115*n-Da,s+.234*n-Da]]).stream(c),l()},s.fitExtent=function(t,n){return xs(s,t,n)},s.fitSize=function(t,n){return ws(s,t,n)},s.fitWidth=function(t,n){return Ms(s,t,n)},s.fitHeight=function(t,n){return As(s,t,n)},s.scale(1070)},t.geoAzimuthalEqualArea=function(){return Cs(Os).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Os,t.geoAzimuthalEquidistant=function(){return Cs(Ys).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=Ys,t.geoConicConformal=function(){return zs(Hs).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=Hs,t.geoConicEqualArea=Ls,t.geoConicEqualAreaRaw=Rs,t.geoConicEquidistant=function(){return zs(Xs).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=Xs,t.geoEqualEarth=function(){return Cs(Qs).scale(177.158)},t.geoEqualEarthRaw=Qs,t.geoEquirectangular=function(){return Cs(js).scale(152.63)},t.geoEquirectangularRaw=js,t.geoGnomonic=function(){return Cs(Js).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Js,t.geoIdentity=function(){var t,n,e,r,i,o,a=1,u=0,f=0,c=1,s=1,l=mc,h=null,d=mc;function p(){return r=i=null,o}return o={stream:function(t){return r&&i===t?r:r=l(d(i=t))},postclip:function(r){return arguments.length?(d=r,h=t=n=e=null,p()):d},clipExtent:function(r){return arguments.length?(d=null==r?(h=t=n=e=null,mc):Zf(h=+r[0][0],t=+r[0][1],n=+r[1][0],e=+r[1][1]),p()):null==h?null:[[h,t],[n,e]]},scale:function(t){return arguments.length?(l=Ks((a=+t)*c,a*s,u,f),p()):a},translate:function(t){return arguments.length?(l=Ks(a*c,a*s,u=+t[0],f=+t[1]),p()):[u,f]},reflectX:function(t){return arguments.length?(l=Ks(a*(c=t?-1:1),a*s,u,f),p()):c<0},reflectY:function(t){return arguments.length?(l=Ks(a*c,a*(s=t?-1:1),u,f),p()):s<0},fitExtent:function(t,n){return xs(o,t,n)},fitSize:function(t,n){return ws(o,t,n)},fitWidth:function(t,n){return Ms(o,t,n)},fitHeight:function(t,n){return As(o,t,n)}}},t.geoProjection=Cs,t.geoProjectionMutator=Ps,t.geoMercator=function(){return Fs(Bs).scale(961/Ba)},t.geoMercatorRaw=Bs,t.geoNaturalEarth1=function(){return Cs(tl).scale(175.295)},t.geoNaturalEarth1Raw=tl,t.geoOrthographic=function(){return Cs(nl).scale(249.5).clipAngle(90+Da)},t.geoOrthographicRaw=nl,t.geoStereographic=function(){return Cs(el).scale(250).clipAngle(142)},t.geoStereographicRaw=el,t.geoTransverseMercator=function(){var t=Fs(rl),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=rl,t.geoRotation=Rf,t.geoStream=su,t.geoTransform=function(t){return{stream:_s(t)}},t.cluster=function(){var t=il,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter(function(n){var e=n.children;e?(n.x=function(t){return t.reduce(ol,0)/t.length}(e),n.y=function(t){return 1+t.reduce(al,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)});var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),f=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),c=u.x-t(u,f)/2,s=f.x+t(f,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-c)/(s-c)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.hierarchy=fl,t.pack=function(){var t=null,n=1,e=1,r=El;function i(i){return i.x=n/2,i.y=e/2,t?i.eachBefore(Pl(t)).eachAfter(zl(r,.5)).eachBefore(Rl(1)):i.eachBefore(Pl(Cl)).eachAfter(zl(El,1)).eachAfter(zl(r,i.r/Math.min(n,e))).eachBefore(Rl(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=null==(e=n)?null:Sl(e),i):t;var e},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:kl(+t),i):r},i},t.packSiblings=function(t){return Nl(t),t},t.packEnclose=pl,t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&Dl(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a<i&&(i=a=(i+a)/2),u<o&&(o=u=(o+u)/2),r.x0=i,r.y0=o,r.x1=a,r.y1=u}}(n,o)),r&&i.eachBefore(Ll),i}return i.round=function(t){return arguments.length?(r=!!t,i):r},i.size=function(e){return arguments.length?(t=+e[0],n=+e[1],i):[t,n]},i.padding=function(t){return arguments.length?(e=+t,i):e},i},t.stratify=function(){var t=Yl,n=Bl;function e(e){var r,i,o,a,u,f,c,s=e.length,l=new Array(s),h={};for(i=0;i<s;++i)r=e[i],u=l[i]=new hl(r),null!=(f=t(r,i,e))&&(f+="")&&(h[c=Ul+(u.id=f)]=c in h?Ol:u);for(i=0;i<s;++i)if(u=l[i],null!=(f=n(e[i],i,e))&&(f+="")){if(!(a=h[Ul+f]))throw new Error("missing: "+f);if(a===Ol)throw new Error("ambiguous: "+f);a.children?a.children.push(u):a.children=[u],u.parent=a}else{if(o)throw new Error("multiple roots");o=u}if(!o)throw new Error("no root");if(o.parent=ql,o.eachBefore(function(t){t.depth=t.parent.depth+1,--s}).eachBefore(ll),o.parent=null,s>0)throw new Error("cycle");return o}return e.id=function(n){return arguments.length?(t=Sl(n),e):t},e.parentId=function(t){return arguments.length?(n=Sl(t),e):n},e},t.tree=function(){var t=Fl,n=1,e=1,r=null;function i(i){var f=function(t){for(var n,e,r,i,o,a=new Gl(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new Gl(r[i],i)),e.parent=n;return(a.parent=new Gl(null,0)).children=[a],a}(i);if(f.eachAfter(o),f.parent.m=-f.z,f.eachBefore(a),r)i.eachBefore(u);else{var c=i,s=i,l=i;i.eachBefore(function(t){t.x<c.x&&(c=t),t.x>s.x&&(s=t),t.depth>l.depth&&(l=t)});var h=c===s?1:t(c,s)/2,d=h-c.x,p=n/(s.x+h+d),v=e/(l.depth||1);i.eachBefore(function(t){t.x=(t.x+d)*p,t.y=t.depth*v})}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,f=o.parent.children[0],c=o.m,s=a.m,l=u.m,h=f.m;u=Hl(u),o=Il(o),u&&o;)f=Il(f),(a=Hl(a)).a=n,(i=u.z+l-o.z-c+t(u._,o._))>0&&(jl(Xl(u,n,r),n,i),c+=i,s+=i),l+=u.m,c+=o.m,h+=f.m,s+=a.m;u&&!Hl(a)&&(a.t=u,a.m+=l-s),o&&!Il(f)&&(f.t=o,f.m+=c-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=Zl,n=!1,e=1,r=1,i=[0],o=El,a=El,u=El,f=El,c=El;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(Ll),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l<r&&(r=l=(r+l)/2),h<s&&(s=h=(s+h)/2),n.x0=r,n.y0=s,n.x1=l,n.y1=h,n.children&&(e=i[n.depth+1]=o(n)/2,r+=c(n)-e,s+=a(n)-e,(l-=u(n)-e)<r&&(r=l=(r+l)/2),(h-=f(n)-e)<s&&(s=h=(s+h)/2),t(n,r,s,l,h))}return s.round=function(t){return arguments.length?(n=!!t,s):n},s.size=function(t){return arguments.length?(e=+t[0],r=+t[1],s):[e,r]},s.tile=function(n){return arguments.length?(t=Sl(n),s):t},s.padding=function(t){return arguments.length?s.paddingInner(t).paddingOuter(t):s.paddingInner()},s.paddingInner=function(t){return arguments.length?(o="function"==typeof t?t:kl(+t),s):o},s.paddingOuter=function(t){return arguments.length?s.paddingTop(t).paddingRight(t).paddingBottom(t).paddingLeft(t):s.paddingTop()},s.paddingTop=function(t){return arguments.length?(a="function"==typeof t?t:kl(+t),s):a},s.paddingRight=function(t){return arguments.length?(u="function"==typeof t?t:kl(+t),s):u},s.paddingBottom=function(t){return arguments.length?(f="function"==typeof t?t:kl(+t),s):f},s.paddingLeft=function(t){return arguments.length?(c="function"==typeof t?t:kl(+t),s):c},s},t.treemapBinary=function(t,n,e,r,i){var o,a,u=t.children,f=u.length,c=new Array(f+1);for(c[0]=a=o=0;o<f;++o)c[o+1]=a+=u[o].value;!function t(n,e,r,i,o,a,f){if(n>=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=f)}for(var l=c[n],h=r/2+l,d=n+1,p=e-1;d<p;){var v=d+p>>>1;c[v]<h?d=v+1:p=v}h-c[d-1]<c[d]-h&&n+1<d&&--d;var g=c[d]-l,y=r-g;if(a-i>f-o){var _=(i*y+a*g)/r;t(n,d,g,i,o,_,f),t(d,e,y,_,o,a,f)}else{var b=(o*y+f*g)/r;t(n,d,g,i,o,a,b),t(d,e,y,i,b,a,f)}}(0,f,t.value,n,e,r,i)},t.treemapDice=Dl,t.treemapSlice=Vl,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Vl:Dl)(t,n,e,r,i)},t.treemapSquarify=Zl,t.treemapResquarify=Ql,t.interpolate=me,t.interpolateArray=de,t.interpolateBasis=ee,t.interpolateBasisClosed=re,t.interpolateDate=pe,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateHue=function(t,n){var e=ae(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateNumber=ve,t.interpolateObject=ge,t.interpolateRound=xe,t.interpolateString=be,t.interpolateTransformCss=Ce,t.interpolateTransformSvg=Pe,t.interpolateZoom=qe,t.interpolateRgb=ce,t.interpolateRgbBasis=le,t.interpolateRgbBasisClosed=he,t.interpolateHsl=Ye,t.interpolateHslLong=Be,t.interpolateLab=function(t,n){var e=fe((t=Un(t)).l,(n=Un(n)).l),r=fe(t.a,n.a),i=fe(t.b,n.b),o=fe(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateHcl=Ie,t.interpolateHclLong=He,t.interpolateCubehelix=Xe,t.interpolateCubehelixLong=Ge,t.piecewise=function(t,n){for(var e=0,r=n.length-1,i=n[0],o=new Array(r<0?0:r);e<r;)o[e]=t(i,i=n[++e]);return function(t){var n=Math.max(0,Math.min(r-1,Math.floor(t*=r)));return o[n](t-n)}},t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.path=Gi,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,a=0,u=t[i-1],f=0;++r<i;)n=u,u=t[r],f+=e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o/(f*=3),a/f]},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Jl),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=Kl(r),a=Kl(i),u=a[0]===o[0],f=a[a.length-1]===o[o.length-1],c=[];for(n=o.length-1;n>=0;--n)c.push(t[r[o[n]][2]]);for(n=+u;n<a.length-f;++n)c.push(t[r[a[n]][2]]);return c},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],a=n[0],u=n[1],f=o[0],c=o[1],s=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>u!=c>u&&a<(f-e)*(u-r)/(c-r)+e&&(s=!s),f=e,c=r;return s},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],a=o[0],u=o[1],f=0;++r<i;)n=a,e=u,n-=a=(o=t[r])[0],e-=u=o[1],f+=Math.sqrt(n*n+e*e);return f},t.quadtree=ra,t.randomUniform=nh,t.randomNormal=eh,t.randomLogNormal=rh,t.randomBates=oh,t.randomIrwinHall=ih,t.randomExponential=ah,t.scaleBand=hh,t.scalePoint=function(){return function t(n){var e=n.copy;return n.padding=n.paddingOuter,delete n.paddingInner,delete n.paddingOuter,n.copy=function(){return t(e())},n}(hh().paddingInner(1))},t.scaleIdentity=function t(){var n=[0,1];function e(t){return+t}return e.invert=e,e.domain=e.range=function(t){return arguments.length?(n=fh.call(t,ph),e):n.slice()},e.copy=function(){return t().domain(n)},xh(e)},t.scaleLinear=function t(){var n=mh(gh,ve);return n.copy=function(){return bh(n,t())},xh(n)},t.scaleLog=function n(){var e=mh(Mh,Ah).domain([1,10]),r=e.domain,i=10,o=Sh(10),a=Nh(10);function u(){return o=Sh(i),a=Nh(i),r()[0]<0&&(o=Eh(o),a=Eh(a)),e}return e.base=function(t){return arguments.length?(i=+t,u()):i},e.domain=function(t){return arguments.length?(r(t),u()):r()},e.ticks=function(t){var n,e=r(),u=e[0],f=e[e.length-1];(n=f<u)&&(h=u,u=f,f=h);var c,s,l,h=o(u),d=o(f),p=null==t?10:+t,v=[];if(!(i%1)&&d-h<p){if(h=Math.round(h)-1,d=Math.round(d)+1,u>0){for(;h<d;++h)for(s=1,c=a(h);s<i;++s)if(!((l=c*s)<u)){if(l>f)break;v.push(l)}}else for(;h<d;++h)for(s=i-1,c=a(h);s>=1;--s)if(!((l=c*s)<u)){if(l>f)break;v.push(l)}}else v=m(h,d,Math.min(d-h,p)).map(a);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?".0e":","),"function"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var u=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/a(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=u?r(t):""}},e.nice=function(){return r(wh(r(),{floor:function(t){return a(Math.floor(o(t)))},ceil:function(t){return a(Math.ceil(o(t)))}}))},e.copy=function(){return bh(e,n().base(i))},e},t.scaleOrdinal=lh,t.scaleImplicit=sh,t.scalePow=Ch,t.scaleSqrt=function(){return Ch().exponent(.5)},t.scaleQuantile=function t(){var e=[],r=[],o=[];function a(){var t=0,n=Math.max(1,r.length);for(o=new Array(n-1);++t<n;)o[t-1]=A(e,t/n);return u}function u(t){if(!isNaN(t=+t))return r[i(o,t)]}return u.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?o[n-1]:e[0],n<o.length?o[n]:e[e.length-1]]},u.domain=function(t){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=t.length;i<o;++i)null==(r=t[i])||isNaN(r=+r)||e.push(r);return e.sort(n),a()},u.range=function(t){return arguments.length?(r=ch.call(t),a()):r.slice()},u.quantiles=function(){return o.slice()},u.copy=function(){return t().domain(e).range(r)},u},t.scaleQuantize=function t(){var n=0,e=1,r=1,o=[.5],a=[0,1];function u(t){if(t<=t)return a[i(o,t,0,r)]}function f(){var t=-1;for(o=new Array(r);++t<r;)o[t]=((t+1)*e-(t-r)*n)/(r+1);return u}return u.domain=function(t){return arguments.length?(n=+t[0],e=+t[1],f()):[n,e]},u.range=function(t){return arguments.length?(r=(a=ch.call(t)).length-1,f()):a.slice()},u.invertExtent=function(t){var i=a.indexOf(t);return i<0?[NaN,NaN]:i<1?[n,o[0]]:i>=r?[o[r-1],e]:[o[i-1],o[i]]},u.copy=function(){return t().domain([n,e]).range(a)},xh(u)},t.scaleThreshold=function t(){var n=[.5],e=[0,1],r=1;function o(t){if(t<=t)return e[i(n,t,0,r)]}return o.domain=function(t){return arguments.length?(n=ch.call(t),r=Math.min(n.length,e.length-1),o):n.slice()},o.range=function(t){return arguments.length?(e=ch.call(t),r=Math.min(n.length,e.length-1),o):e.slice()},o.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},o.copy=function(){return t().domain(n).range(e)},o},t.scaleTime=function(){return cv(cd,ud,Vh,jh,Ih,Bh,Oh,Lh,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},t.scaleUtc=function(){return cv(Ld,zd,_d,vd,dd,ld,Oh,Lh,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},t.scaleSequential=function t(n){var e=0,r=1,i=1,o=!1;function a(t){var r=(t-e)*i;return n(o?Math.max(0,Math.min(1,r)):r)}return a.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],i=e===r?0:1/(r-e),a):[e,r]},a.clamp=function(t){return arguments.length?(o=!!t,a):o},a.interpolator=function(t){return arguments.length?(n=t,a):n},a.copy=function(){return t(n).domain([e,r]).clamp(o)},xh(a)},t.scaleDiverging=function t(n){var e=0,r=.5,i=1,o=1,a=1,u=!1;function f(t){var e=.5+((t=+t)-r)*(t<r?o:a);return n(u?Math.max(0,Math.min(1,e)):e)}return f.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],i=+t[2],o=e===r?0:.5/(r-e),a=r===i?0:.5/(i-r),f):[e,r,i]},f.clamp=function(t){return arguments.length?(u=!!t,f):u},f.interpolator=function(t){return arguments.length?(n=t,f):n},f.copy=function(){return t(n).domain([e,r,i]).clamp(u)},xh(f)},t.schemeCategory10=lv,t.schemeAccent=hv,t.schemeDark2=dv,t.schemePaired=pv,t.schemePastel1=vv,t.schemePastel2=gv,t.schemeSet1=yv,t.schemeSet2=_v,t.schemeSet3=bv,t.interpolateBrBG=wv,t.schemeBrBG=xv,t.interpolatePRGn=Av,t.schemePRGn=Mv,t.interpolatePiYG=Nv,t.schemePiYG=Tv,t.interpolatePuOr=Ev,t.schemePuOr=Sv,t.interpolateRdBu=Cv,t.schemeRdBu=kv,t.interpolateRdGy=zv,t.schemeRdGy=Pv,t.interpolateRdYlBu=Lv,t.schemeRdYlBu=Rv,t.interpolateRdYlGn=Uv,t.schemeRdYlGn=Dv,t.interpolateSpectral=Ov,t.schemeSpectral=qv,t.interpolateBuGn=Bv,t.schemeBuGn=Yv,t.interpolateBuPu=Iv,t.schemeBuPu=Fv,t.interpolateGnBu=jv,t.schemeGnBu=Hv,t.interpolateOrRd=Gv,t.schemeOrRd=Xv,t.interpolatePuBuGn=$v,t.schemePuBuGn=Vv,t.interpolatePuBu=Zv,t.schemePuBu=Wv,t.interpolatePuRd=Jv,t.schemePuRd=Qv,t.interpolateRdPu=tg,t.schemeRdPu=Kv,t.interpolateYlGnBu=eg,t.schemeYlGnBu=ng,t.interpolateYlGn=ig,t.schemeYlGn=rg,t.interpolateYlOrBr=ag,t.schemeYlOrBr=og,t.interpolateYlOrRd=fg,t.schemeYlOrRd=ug,t.interpolateBlues=sg,t.schemeBlues=cg,t.interpolateGreens=hg,t.schemeGreens=lg,t.interpolateGreys=pg,t.schemeGreys=dg,t.interpolatePurples=gg,t.schemePurples=vg,t.interpolateReds=_g,t.schemeReds=yg,t.interpolateOranges=mg,t.schemeOranges=bg,t.interpolateCubehelixDefault=xg,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return Ag.h=360*t-100,Ag.s=1.5-1.5*n,Ag.l=.8-.9*n,Ag+""},t.interpolateWarm=wg,t.interpolateCool=Mg,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,Tg.r=255*(n=Math.sin(t))*n,Tg.g=255*(n=Math.sin(t+Ng))*n,Tg.b=255*(n=Math.sin(t+Sg))*n,Tg+""},t.interpolateViridis=kg,t.interpolateMagma=Cg,t.interpolateInferno=Pg,t.interpolatePlasma=zg,t.create=function(t){return Dt(W(t).call(document.documentElement))},t.creator=W,t.local=qt,t.matcher=rt,t.mouse=Ft,t.namespace=$,t.namespaces=V,t.clientPoint=Bt,t.select=Dt,t.selectAll=function(t){return"string"==typeof t?new Rt([document.querySelectorAll(t)],[document.documentElement]):new Rt([null==t?[]:t],zt)},t.selection=Lt,t.selector=Q,t.selectorAll=K,t.style=lt,t.touch=It,t.touches=function(t,n){null==n&&(n=Yt().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Bt(t,n[e]);return i},t.window=st,t.customEvent=Ct,t.arc=function(){var t=Gg,n=Vg,e=Rg(0),r=null,i=$g,o=Wg,a=Zg,u=null;function f(){var f,c,s,l=+t.apply(this,arguments),h=+n.apply(this,arguments),d=i.apply(this,arguments)-Hg,p=o.apply(this,arguments)-Hg,v=Lg(p-d),g=p>d;if(u||(u=f=Gi()),h<l&&(c=h,h=l,l=c),h>Fg)if(v>jg-Fg)u.moveTo(h*Ug(d),h*Yg(d)),u.arc(0,0,h,d,p,!g),l>Fg&&(u.moveTo(l*Ug(p),l*Yg(p)),u.arc(0,0,l,p,d,g));else{var y,_,b=d,m=p,x=d,w=p,M=v,A=v,T=a.apply(this,arguments)/2,N=T>Fg&&(r?+r.apply(this,arguments):Bg(l*l+h*h)),S=Og(Lg(h-l)/2,+e.apply(this,arguments)),E=S,k=S;if(N>Fg){var C=Xg(N/l*Yg(T)),P=Xg(N/h*Yg(T));(M-=2*C)>Fg?(x+=C*=g?1:-1,w-=C):(M=0,x=w=(d+p)/2),(A-=2*P)>Fg?(b+=P*=g?1:-1,m-=P):(A=0,b=m=(d+p)/2)}var z=h*Ug(b),R=h*Yg(b),L=l*Ug(w),D=l*Yg(w);if(S>Fg){var U=h*Ug(m),q=h*Yg(m),O=l*Ug(x),Y=l*Yg(x);if(v<Ig){var B=M>Fg?function(t,n,e,r,i,o,a,u){var f=e-t,c=r-n,s=a-i,l=u-o,h=(s*(n-o)-l*(t-i))/(l*f-s*c);return[t+h*f,n+h*c]}(z,R,O,Y,U,q,L,D):[L,D],F=z-B[0],I=R-B[1],H=U-B[0],j=q-B[1],X=1/Yg(((s=(F*H+I*j)/(Bg(F*F+I*I)*Bg(H*H+j*j)))>1?0:s<-1?Ig:Math.acos(s))/2),G=Bg(B[0]*B[0]+B[1]*B[1]);E=Og(S,(l-G)/(X-1)),k=Og(S,(h-G)/(X+1))}}A>Fg?k>Fg?(y=Qg(O,Y,z,R,h,k,g),_=Qg(U,q,L,D,h,k,g),u.moveTo(y.cx+y.x01,y.cy+y.y01),k<S?u.arc(y.cx,y.cy,k,Dg(y.y01,y.x01),Dg(_.y01,_.x01),!g):(u.arc(y.cx,y.cy,k,Dg(y.y01,y.x01),Dg(y.y11,y.x11),!g),u.arc(0,0,h,Dg(y.cy+y.y11,y.cx+y.x11),Dg(_.cy+_.y11,_.cx+_.x11),!g),u.arc(_.cx,_.cy,k,Dg(_.y11,_.x11),Dg(_.y01,_.x01),!g))):(u.moveTo(z,R),u.arc(0,0,h,b,m,!g)):u.moveTo(z,R),l>Fg&&M>Fg?E>Fg?(y=Qg(L,D,U,q,l,-E,g),_=Qg(z,R,O,Y,l,-E,g),u.lineTo(y.cx+y.x01,y.cy+y.y01),E<S?u.arc(y.cx,y.cy,E,Dg(y.y01,y.x01),Dg(_.y01,_.x01),!g):(u.arc(y.cx,y.cy,E,Dg(y.y01,y.x01),Dg(y.y11,y.x11),!g),u.arc(0,0,l,Dg(y.cy+y.y11,y.cx+y.x11),Dg(_.cy+_.y11,_.cx+_.x11),g),u.arc(_.cx,_.cy,E,Dg(_.y11,_.x11),Dg(_.y01,_.x01),!g))):u.arc(0,0,l,w,x,g):u.lineTo(L,D)}else u.moveTo(0,0);if(u.closePath(),f)return u=null,f+""||null}return f.centroid=function(){var e=(+t.apply(this,arguments)+ +n.apply(this,arguments))/2,r=(+i.apply(this,arguments)+ +o.apply(this,arguments))/2-Ig/2;return[Ug(r)*e,Yg(r)*e]},f.innerRadius=function(n){return arguments.length?(t="function"==typeof n?n:Rg(+n),f):t},f.outerRadius=function(t){return arguments.length?(n="function"==typeof t?t:Rg(+t),f):n},f.cornerRadius=function(t){return arguments.length?(e="function"==typeof t?t:Rg(+t),f):e},f.padRadius=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:Rg(+t),f):r},f.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:Rg(+t),f):i},f.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:Rg(+t),f):o},f.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:Rg(+t),f):a},f.context=function(t){return arguments.length?(u=null==t?null:t,f):u},f},t.area=ry,t.line=ey,t.pie=function(){var t=oy,n=iy,e=null,r=Rg(0),i=Rg(jg),o=Rg(0);function a(a){var u,f,c,s,l,h=a.length,d=0,p=new Array(h),v=new Array(h),g=+r.apply(this,arguments),y=Math.min(jg,Math.max(-jg,i.apply(this,arguments)-g)),_=Math.min(Math.abs(y)/h,o.apply(this,arguments)),b=_*(y<0?-1:1);for(u=0;u<h;++u)(l=v[p[u]=u]=+t(a[u],u,a))>0&&(d+=l);for(null!=n?p.sort(function(t,e){return n(v[t],v[e])}):null!=e&&p.sort(function(t,n){return e(a[t],a[n])}),u=0,c=d?(y-h*b)/d:0;u<h;++u,g=s)f=p[u],s=g+((l=v[f])>0?l*c:0)+b,v[f]={data:a[f],index:u,value:l,startAngle:g,endAngle:s,padAngle:_};return v}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:Rg(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Rg(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Rg(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:Rg(+t),a):o},a},t.areaRadial=ly,t.radialArea=ly,t.lineRadial=sy,t.radialLine=sy,t.pointRadial=hy,t.linkHorizontal=function(){return gy(yy)},t.linkVertical=function(){return gy(_y)},t.linkRadial=function(){var t=gy(by);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.symbol=function(){var t=Rg(my),n=Rg(64),e=null;function r(){var r;if(e||(e=r=Gi()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),r)return e=null,r+""||null}return r.type=function(n){return arguments.length?(t="function"==typeof n?n:Rg(n),r):t},r.size=function(t){return arguments.length?(n="function"==typeof t?t:Rg(+t),r):n},r.context=function(t){return arguments.length?(e=null==t?null:t,r):e},r},t.symbols=Uy,t.symbolCircle=my,t.symbolCross=xy,t.symbolDiamond=Ay,t.symbolSquare=ky,t.symbolStar=Ey,t.symbolTriangle=Py,t.symbolWye=Dy,t.curveBasisClosed=function(t){return new By(t)},t.curveBasisOpen=function(t){return new Fy(t)},t.curveBasis=function(t){return new Yy(t)},t.curveBundle=Hy,t.curveCardinalClosed=$y,t.curveCardinalOpen=Zy,t.curveCardinal=Gy,t.curveCatmullRomClosed=n_,t.curveCatmullRomOpen=r_,t.curveCatmullRom=Ky,t.curveLinearClosed=function(t){return new i_(t)},t.curveLinear=Kg,t.curveMonotoneX=function(t){return new c_(t)},t.curveMonotoneY=function(t){return new s_(t)},t.curveNatural=function(t){return new h_(t)},t.curveStep=function(t){return new p_(t,.5)},t.curveStepAfter=function(t){return new p_(t,1)},t.curveStepBefore=function(t){return new p_(t,0)},t.stack=function(){var t=Rg([]),n=g_,e=v_,r=y_;function i(i){var o,a,u=t.apply(this,arguments),f=i.length,c=u.length,s=new Array(c);for(o=0;o<c;++o){for(var l,h=u[o],d=s[o]=new Array(f),p=0;p<f;++p)d[p]=l=[0,+r(i[p],h,p,i)],l.data=i[p];d.key=h}for(o=0,a=n(s);o<c;++o)s[a[o]].index=o;return e(s,a),s}return i.keys=function(n){return arguments.length?(t="function"==typeof n?n:Rg(dy.call(n)),i):t},i.value=function(t){return arguments.length?(r="function"==typeof t?t:Rg(+t),i):r},i.order=function(t){return arguments.length?(n=null==t?g_:"function"==typeof t?t:Rg(dy.call(t)),i):n},i.offset=function(t){return arguments.length?(e=null==t?v_:t,i):e},i},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o<a;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}v_(t,n)}},t.stackOffsetDiverging=function(t,n){if((u=t.length)>1)for(var e,r,i,o,a,u,f=0,c=t[n[0]].length;f<c;++f)for(o=a=0,e=0;e<u;++e)(i=(r=t[n[e]][f])[1]-r[0])>=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):r[0]=o},t.stackOffsetNone=v_,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var a=0,u=0;a<e;++a)u+=t[a][r][1]||0;i[r][1]+=i[r][0]=-u/2}v_(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;a<r;++a){for(var u=0,f=0,c=0;u<i;++u){for(var s=t[n[u]],l=s[a][1]||0,h=(l-(s[a-1][1]||0))/2,d=0;d<u;++d){var p=t[n[d]];h+=(p[a][1]||0)-(p[a-1][1]||0)}f+=l,c+=h*l}e[a-1][1]+=e[a-1][0]=o,f&&(o-=c/f)}e[a-1][1]+=e[a-1][0]=o,v_(t,n)}},t.stackOrderAscending=__,t.stackOrderDescending=function(t){return __(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(b_),o=g_(t).sort(function(t,n){return i[n]-i[t]}),a=0,u=0,f=[],c=[];for(n=0;n<r;++n)e=o[n],a<u?(a+=i[e],f.push(e)):(u+=i[e],c.push(e));return c.reverse().concat(f)},t.stackOrderNone=g_,t.stackOrderReverse=function(t){return g_(t).reverse()},t.timeInterval=Rh,t.timeMillisecond=Lh,t.timeMilliseconds=Dh,t.utcMillisecond=Lh,t.utcMilliseconds=Dh,t.timeSecond=Oh,t.timeSeconds=Yh,t.utcSecond=Oh,t.utcSeconds=Yh,t.timeMinute=Bh,t.timeMinutes=Fh,t.timeHour=Ih,t.timeHours=Hh,t.timeDay=jh,t.timeDays=Xh,t.timeWeek=Vh,t.timeWeeks=td,t.timeSunday=Vh,t.timeSundays=td,t.timeMonday=$h,t.timeMondays=nd,t.timeTuesday=Wh,t.timeTuesdays=ed,t.timeWednesday=Zh,t.timeWednesdays=rd,t.timeThursday=Qh,t.timeThursdays=id,t.timeFriday=Jh,t.timeFridays=od,t.timeSaturday=Kh,t.timeSaturdays=ad,t.timeMonth=ud,t.timeMonths=fd,t.timeYear=cd,t.timeYears=sd,t.utcMinute=ld,t.utcMinutes=hd,t.utcHour=dd,t.utcHours=pd,t.utcDay=vd,t.utcDays=gd,t.utcWeek=_d,t.utcWeeks=Td,t.utcSunday=_d,t.utcSundays=Td,t.utcMonday=bd,t.utcMondays=Nd,t.utcTuesday=md,t.utcTuesdays=Sd,t.utcWednesday=xd,t.utcWednesdays=Ed,t.utcThursday=wd,t.utcThursdays=kd,t.utcFriday=Md,t.utcFridays=Cd,t.utcSaturday=Ad,t.utcSaturdays=Pd,t.utcMonth=zd,t.utcMonths=Rd,t.utcYear=Ld,t.utcYears=Dd,t.timeFormatDefaultLocale=Qp,t.timeFormatLocale=Yd,t.isoFormat=Jp,t.isoParse=Kp,t.now=ir,t.timer=ur,t.timerFlush=fr,t.timeout=hr,t.interval=function(t,n,e){var r=new ar,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?ir():+e,r.restart(function o(a){a+=i,r.restart(o,i+=n,e),t(a)},n,e),r)},t.transition=zr,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>gr&&e.name===n)return new Pr([[t]],li,n,+r);return null},t.interrupt=Nr,t.voronoi=function(){var t=x_,n=w_,e=null;function r(r){return new eb(r.map(function(e,i){var o=[Math.round(t(e,i,r)/K_)*K_,Math.round(n(e,i,r)/K_)*K_];return o.index=i,o.data=e,o}),e)}return r.polygons=function(t){return r(t).polygons()},r.links=function(t){return r(t).links()},r.triangles=function(t){return r(t).triangles()},r.x=function(n){return arguments.length?(t="function"==typeof n?n:m_(+n),r):t},r.y=function(t){return arguments.length?(n="function"==typeof t?t:m_(+t),r):n},r.extent=function(t){return arguments.length?(e=null==t?null:[[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]],r):e&&[[e[0][0],e[0][1]],[e[1][0],e[1][1]]]},r.size=function(t){return arguments.length?(e=null==t?null:[[0,0],[+t[0],+t[1]]],r):e&&[e[1][0]-e[0][0],e[1][1]-e[0][1]]},r},t.zoom=function(){var n,e,r=sb,i=lb,o=vb,a=db,u=pb,f=[0,1/0],c=[[-1/0,-1/0],[1/0,1/0]],s=250,l=qe,h=[],d=I("start","zoom","end"),p=500,v=150,g=0;function y(t){t.property("__zoom",hb).on("wheel.zoom",A).on("mousedown.zoom",T).on("dblclick.zoom",N).filter(u).on("touchstart.zoom",S).on("touchmove.zoom",E).on("touchend.zoom touchcancel.zoom",k).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function _(t,n){return(n=Math.max(f[0],Math.min(f[1],n)))===t.k?t:new ob(n,t.x,t.y)}function b(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ob(t.k,r,i)}function m(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function x(t,n,e){t.on("start.zoom",function(){w(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){w(this,arguments).end()}).tween("zoom",function(){var t=arguments,r=w(this,t),o=i.apply(this,t),a=e||m(o),u=Math.max(o[1][0]-o[0][0],o[1][1]-o[0][1]),f=this.__zoom,c="function"==typeof n?n.apply(this,t):n,s=l(f.invert(a).concat(u/f.k),c.invert(a).concat(u/c.k));return function(t){if(1===t)t=c;else{var n=s(t),e=u/n[2];t=new ob(e,a[0]-n[0]*e,a[1]-n[1]*e)}r.zoom(null,t)}})}function w(t,n){for(var e,r=0,i=h.length;r<i;++r)if((e=h[r]).that===t)return e;return new M(t,n)}function M(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=i.apply(t,n)}function A(){if(r.apply(this,arguments)){var t=w(this,arguments),n=this.__zoom,e=Math.max(f[0],Math.min(f[1],n.k*Math.pow(2,a.apply(this,arguments)))),i=Ft(this);if(t.wheel)t.mouse[0][0]===i[0]&&t.mouse[0][1]===i[1]||(t.mouse[1]=n.invert(t.mouse[0]=i)),clearTimeout(t.wheel);else{if(n.k===e)return;t.mouse=[i,n.invert(i)],Nr(this),t.start()}cb(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},v),t.zoom("mouse",o(b(_(n,e),t.mouse[0],t.mouse[1]),t.extent,c))}}function T(){if(!e&&r.apply(this,arguments)){var n=w(this,arguments),i=Dt(t.event.view).on("mousemove.zoom",function(){if(cb(),!n.moved){var e=t.event.clientX-u,r=t.event.clientY-f;n.moved=e*e+r*r>g}n.zoom("mouse",o(b(n.that.__zoom,n.mouse[0]=Ft(n.that),n.mouse[1]),n.extent,c))},!0).on("mouseup.zoom",function(){i.on("mousemove.zoom mouseup.zoom",null),Gt(t.event.view,n.moved),cb(),n.end()},!0),a=Ft(this),u=t.event.clientX,f=t.event.clientY;Xt(t.event.view),fb(),n.mouse=[a,this.__zoom.invert(a)],Nr(this),n.start()}}function N(){if(r.apply(this,arguments)){var n=this.__zoom,e=Ft(this),a=n.invert(e),u=n.k*(t.event.shiftKey?.5:2),f=o(b(_(n,u),e,a),i.apply(this,arguments),c);cb(),s>0?Dt(this).transition().duration(s).call(x,f,e):Dt(this).call(y.transform,f)}}function S(){if(r.apply(this,arguments)){var e,i,o,a,u=w(this,arguments),f=t.event.changedTouches,c=f.length;for(fb(),i=0;i<c;++i)a=[a=It(this,f,(o=f[i]).identifier),this.__zoom.invert(a),o.identifier],u.touch0?u.touch1||(u.touch1=a):(u.touch0=a,e=!0);if(n&&(n=clearTimeout(n),!u.touch1))return u.end(),void((a=Dt(this).on("dblclick.zoom"))&&a.apply(this,arguments));e&&(n=setTimeout(function(){n=null},p),Nr(this),u.start())}}function E(){var e,r,i,a,u=w(this,arguments),f=t.event.changedTouches,s=f.length;for(cb(),n&&(n=clearTimeout(n)),e=0;e<s;++e)i=It(this,f,(r=f[e]).identifier),u.touch0&&u.touch0[2]===r.identifier?u.touch0[0]=i:u.touch1&&u.touch1[2]===r.identifier&&(u.touch1[0]=i);if(r=u.that.__zoom,u.touch1){var l=u.touch0[0],h=u.touch0[1],d=u.touch1[0],p=u.touch1[1],v=(v=d[0]-l[0])*v+(v=d[1]-l[1])*v,g=(g=p[0]-h[0])*g+(g=p[1]-h[1])*g;r=_(r,Math.sqrt(v/g)),i=[(l[0]+d[0])/2,(l[1]+d[1])/2],a=[(h[0]+p[0])/2,(h[1]+p[1])/2]}else{if(!u.touch0)return;i=u.touch0[0],a=u.touch0[1]}u.zoom("touch",o(b(r,i,a),u.extent,c))}function k(){var n,r,i=w(this,arguments),o=t.event.changedTouches,a=o.length;for(fb(),e&&clearTimeout(e),e=setTimeout(function(){e=null},p),n=0;n<a;++n)r=o[n],i.touch0&&i.touch0[2]===r.identifier?delete i.touch0:i.touch1&&i.touch1[2]===r.identifier&&delete i.touch1;i.touch1&&!i.touch0&&(i.touch0=i.touch1,delete i.touch1),i.touch0?i.touch0[1]=this.__zoom.invert(i.touch0[0]):i.end()}return y.transform=function(t,n){var e=t.selection?t.selection():t;e.property("__zoom",hb),t!==e?x(t,n):e.interrupt().each(function(){w(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},y.scaleBy=function(t,n){y.scaleTo(t,function(){return this.__zoom.k*("function"==typeof n?n.apply(this,arguments):n)})},y.scaleTo=function(t,n){y.transform(t,function(){var t=i.apply(this,arguments),e=this.__zoom,r=m(t),a=e.invert(r),u="function"==typeof n?n.apply(this,arguments):n;return o(b(_(e,u),r,a),t,c)})},y.translateBy=function(t,n,e){y.transform(t,function(){return o(this.__zoom.translate("function"==typeof n?n.apply(this,arguments):n,"function"==typeof e?e.apply(this,arguments):e),i.apply(this,arguments),c)})},y.translateTo=function(t,n,e){y.transform(t,function(){var t=i.apply(this,arguments),r=this.__zoom,a=m(t);return o(ab.translate(a[0],a[1]).scale(r.k).translate("function"==typeof n?-n.apply(this,arguments):-n,"function"==typeof e?-e.apply(this,arguments):-e),t,c)})},M.prototype={start:function(){return 1==++this.active&&(this.index=h.push(this)-1,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(h.splice(this.index,1),this.index=-1,this.emit("end")),this},emit:function(t){Ct(new ib(y,t,this.that.__zoom),d.apply,d,[t,this.that,this.args])}},y.wheelDelta=function(t){return arguments.length?(a="function"==typeof t?t:rb(+t),y):a},y.filter=function(t){return arguments.length?(r="function"==typeof t?t:rb(!!t),y):r},y.touchable=function(t){return arguments.length?(u="function"==typeof t?t:rb(!!t),y):u},y.extent=function(t){return arguments.length?(i="function"==typeof t?t:rb([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),y):i},y.scaleExtent=function(t){return arguments.length?(f[0]=+t[0],f[1]=+t[1],y):[f[0],f[1]]},y.translateExtent=function(t){return arguments.length?(c[0][0]=+t[0][0],c[1][0]=+t[1][0],c[0][1]=+t[0][1],c[1][1]=+t[1][1],y):[[c[0][0],c[0][1]],[c[1][0],c[1][1]]]},y.constrain=function(t){return arguments.length?(o=t,y):o},y.duration=function(t){return arguments.length?(s=+t,y):s},y.interpolate=function(t){return arguments.length?(l=t,y):l},y.on=function(){var t=d.on.apply(d,arguments);return t===d?y:t},y.clickDistance=function(t){return arguments.length?(g=(t=+t)*t,y):Math.sqrt(g)},y},t.zoomTransform=ub,t.zoomIdentity=ab,Object.defineProperty(t,"__esModule",{value:!0})}); +// https://d3js.org v5.16.0 Copyright 2020 Mike Bostock +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).d3=t.d3||{})}(this,function(t){"use strict";function n(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function e(t){var e;return 1===t.length&&(e=t,t=function(t,r){return n(e(t),r)}),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}var r=e(n),i=r.right,o=r.left;function a(t,n){return[t,n]}function u(t){return null===t?NaN:+t}function c(t,n){var e,r,i=t.length,o=0,a=-1,c=0,f=0;if(null==n)for(;++a<i;)isNaN(e=u(t[a]))||(f+=(r=e-c)*(e-(c+=r/++o)));else for(;++a<i;)isNaN(e=u(n(t[a],a,t)))||(f+=(r=e-c)*(e-(c+=r/++o)));if(o>1)return f/(o-1)}function f(t,n){var e=c(t,n);return e?Math.sqrt(e):e}function s(t,n){var e,r,i,o=t.length,a=-1;if(null==n){for(;++a<o;)if(null!=(e=t[a])&&e>=e)for(r=i=e;++a<o;)null!=(e=t[a])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++a<o;)if(null!=(e=n(t[a],a,t))&&e>=e)for(r=i=e;++a<o;)null!=(e=n(t[a],a,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]}var l=Array.prototype,h=l.slice,d=l.map;function p(t){return function(){return t}}function v(t){return t}function g(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o}var y=Math.sqrt(50),_=Math.sqrt(10),b=Math.sqrt(2);function m(t,n,e){var r,i,o,a,u=-1;if(e=+e,(t=+t)===(n=+n)&&e>0)return[t];if((r=n<t)&&(i=t,t=n,n=i),0===(a=x(t,n,e))||!isFinite(a))return[];if(a>0)for(t=Math.ceil(t/a),n=Math.floor(n/a),o=new Array(i=Math.ceil(n-t+1));++u<i;)o[u]=(t+u)*a;else for(t=Math.floor(t*a),n=Math.ceil(n*a),o=new Array(i=Math.ceil(t-n+1));++u<i;)o[u]=(t-u)/a;return r&&o.reverse(),o}function x(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=y?10:o>=_?5:o>=b?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=y?10:o>=_?5:o>=b?2:1)}function w(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=y?i*=10:o>=_?i*=5:o>=b&&(i*=2),n<t?-i:i}function M(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1}function N(t,n,e){if(null==e&&(e=u),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),a=+e(t[o],o,t);return a+(+e(t[o+1],o+1,t)-a)*(i-o)}}function T(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r}function A(t){for(var n,e,r,i=t.length,o=-1,a=0;++o<i;)a+=t[o].length;for(e=new Array(a);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--a]=r[n];return e}function S(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r}function k(t){if(!(i=t.length))return[];for(var n=-1,e=S(t,E),r=new Array(e);++n<e;)for(var i,o=-1,a=r[n]=new Array(i);++o<i;)a[o]=t[o][n];return r}function E(t){return t.length}var C=Array.prototype.slice;function P(t){return t}var z=1,R=2,D=3,q=4,L=1e-6;function U(t){return"translate("+(t+.5)+",0)"}function O(t){return"translate(0,"+(t+.5)+")"}function B(){return!this.__axis}function F(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,c=t===z||t===q?-1:1,f=t===q||t===R?"x":"y",s=t===z||t===D?U:O;function l(l){var h=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,d=null==i?n.tickFormat?n.tickFormat.apply(n,e):P:i,p=Math.max(o,0)+u,v=n.range(),g=+v[0]+.5,y=+v[v.length-1]+.5,_=(n.bandwidth?function(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}:function(t){return function(n){return+t(n)}})(n.copy()),b=l.selection?l.selection():l,m=b.selectAll(".domain").data([null]),x=b.selectAll(".tick").data(h,n).order(),w=x.exit(),M=x.enter().append("g").attr("class","tick"),N=x.select("line"),T=x.select("text");m=m.merge(m.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),x=x.merge(M),N=N.merge(M.append("line").attr("stroke","currentColor").attr(f+"2",c*o)),T=T.merge(M.append("text").attr("fill","currentColor").attr(f,c*p).attr("dy",t===z?"0em":t===D?"0.71em":"0.32em")),l!==b&&(m=m.transition(l),x=x.transition(l),N=N.transition(l),T=T.transition(l),w=w.transition(l).attr("opacity",L).attr("transform",function(t){return isFinite(t=_(t))?s(t):this.getAttribute("transform")}),M.attr("opacity",L).attr("transform",function(t){var n=this.parentNode.__axis;return s(n&&isFinite(n=n(t))?n:_(t))})),w.remove(),m.attr("d",t===q||t==R?a?"M"+c*a+","+g+"H0.5V"+y+"H"+c*a:"M0.5,"+g+"V"+y:a?"M"+g+","+c*a+"V0.5H"+y+"V"+c*a:"M"+g+",0.5H"+y),x.attr("opacity",1).attr("transform",function(t){return s(_(t))}),N.attr(f+"2",c*o),T.attr(f,c*p).text(d),b.filter(B).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===R?"start":t===q?"end":"middle"),b.each(function(){this.__axis=_})}return l.scale=function(t){return arguments.length?(n=t,l):n},l.ticks=function(){return e=C.call(arguments),l},l.tickArguments=function(t){return arguments.length?(e=null==t?[]:C.call(t),l):e.slice()},l.tickValues=function(t){return arguments.length?(r=null==t?null:C.call(t),l):r&&r.slice()},l.tickFormat=function(t){return arguments.length?(i=t,l):i},l.tickSize=function(t){return arguments.length?(o=a=+t,l):o},l.tickSizeInner=function(t){return arguments.length?(o=+t,l):o},l.tickSizeOuter=function(t){return arguments.length?(a=+t,l):a},l.tickPadding=function(t){return arguments.length?(u=+t,l):u},l}var Y={value:function(){}};function I(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r||/[\s.]/.test(t))throw new Error("illegal type: "+t);r[t]=[]}return new H(r)}function H(t){this._=t}function j(t,n){return t.trim().split(/^|\s+/).map(function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}function X(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function V(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Y,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}H.prototype=I.prototype={constructor:H,on:function(t,n){var e,r=this._,i=j(t+"",r),o=-1,a=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<a;)if(e=(t=i[o]).type)r[e]=V(r[e],t.name,n);else if(null==n)for(e in r)r[e]=V(r[e],t.name,null);return this}for(;++o<a;)if((e=(t=i[o]).type)&&(e=X(r[e],t.name)))return e},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new H(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var G="http://www.w3.org/1999/xhtml",$={svg:"http://www.w3.org/2000/svg",xhtml:G,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function W(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),$.hasOwnProperty(n)?{space:$[n],local:t}:t}function Z(t){var n=W(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===G&&n.documentElement.namespaceURI===G?n.createElement(t):n.createElementNS(e,t)}})(n)}function Q(){}function K(t){return null==t?Q:function(){return this.querySelector(t)}}function J(){return[]}function tt(t){return null==t?J:function(){return this.querySelectorAll(t)}}function nt(t){return function(){return this.matches(t)}}function et(t){return new Array(t.length)}function rt(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}rt.prototype={constructor:rt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var it="$";function ot(t,n,e,r,i,o){for(var a,u=0,c=n.length,f=o.length;u<f;++u)(a=n[u])?(a.__data__=o[u],r[u]=a):e[u]=new rt(t,o[u]);for(;u<c;++u)(a=n[u])&&(i[u]=a)}function at(t,n,e,r,i,o,a){var u,c,f,s={},l=n.length,h=o.length,d=new Array(l);for(u=0;u<l;++u)(c=n[u])&&(d[u]=f=it+a.call(c,c.__data__,u,n),f in s?i[u]=c:s[f]=c);for(u=0;u<h;++u)(c=s[f=it+a.call(t,o[u],u,o)])?(r[u]=c,c.__data__=o[u],s[f]=null):e[u]=new rt(t,o[u]);for(u=0;u<l;++u)(c=n[u])&&s[d[u]]===c&&(i[u]=c)}function ut(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function ct(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function ft(t,n){return t.style.getPropertyValue(n)||ct(t).getComputedStyle(t,null).getPropertyValue(n)}function st(t){return t.trim().split(/^|\s+/)}function lt(t){return t.classList||new ht(t)}function ht(t){this._node=t,this._names=st(t.getAttribute("class")||"")}function dt(t,n){for(var e=lt(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function pt(t,n){for(var e=lt(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function vt(){this.textContent=""}function gt(){this.innerHTML=""}function yt(){this.nextSibling&&this.parentNode.appendChild(this)}function _t(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function bt(){return null}function mt(){var t=this.parentNode;t&&t.removeChild(this)}function xt(){var t=this.cloneNode(!1),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function wt(){var t=this.cloneNode(!0),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}ht.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Mt={};(t.event=null,"undefined"!=typeof document)&&("onmouseenter"in document.documentElement||(Mt={mouseenter:"mouseover",mouseleave:"mouseout"}));function Nt(t,n,e){return t=Tt(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function Tt(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function At(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function St(t,n,e){var r=Mt.hasOwnProperty(t.type)?Nt:Tt;return function(i,o,a){var u,c=this.__on,f=r(n,o,a);if(c)for(var s=0,l=c.length;s<l;++s)if((u=c[s]).type===t.type&&u.name===t.name)return this.removeEventListener(u.type,u.listener,u.capture),this.addEventListener(u.type,u.listener=f,u.capture=e),void(u.value=n);this.addEventListener(t.type,f,e),u={type:t.type,name:t.name,value:n,listener:f,capture:e},c?c.push(u):this.__on=[u]}}function kt(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function Et(t,n,e){var r=ct(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}var Ct=[null];function Pt(t,n){this._groups=t,this._parents=n}function zt(){return new Pt([[document.documentElement]],Ct)}function Rt(t){return"string"==typeof t?new Pt([[document.querySelector(t)]],[document.documentElement]):new Pt([[t]],Ct)}Pt.prototype=zt.prototype={constructor:Pt,select:function(t){"function"!=typeof t&&(t=K(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a,u=n[i],c=u.length,f=r[i]=new Array(c),s=0;s<c;++s)(o=u[s])&&(a=t.call(o,o.__data__,s,u))&&("__data__"in o&&(a.__data__=o.__data__),f[s]=a);return new Pt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=tt(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var a,u=n[o],c=u.length,f=0;f<c;++f)(a=u[f])&&(r.push(t.call(a,a.__data__,f,u)),i.push(a));return new Pt(r,i)},filter:function(t){"function"!=typeof t&&(t=nt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new Pt(r,this._parents)},data:function(t,n){if(!t)return d=new Array(this.size()),f=-1,this.each(function(t){d[++f]=t}),d;var e=n?at:ot,r=this._parents,i=this._groups;"function"!=typeof t&&(t=function(t){return function(){return t}}(t));for(var o=i.length,a=new Array(o),u=new Array(o),c=new Array(o),f=0;f<o;++f){var s=r[f],l=i[f],h=l.length,d=t.call(s,s&&s.__data__,f,r),p=d.length,v=u[f]=new Array(p),g=a[f]=new Array(p);e(s,l,v,g,c[f]=new Array(h),d,n);for(var y,_,b=0,m=0;b<p;++b)if(y=v[b]){for(b>=m&&(m=b+1);!(_=g[m])&&++m<p;);y._next=_||null}}return(a=new Pt(a,r))._enter=u,a._exit=c,a},enter:function(){return new Pt(this._enter||this._groups.map(et),this._parents)},exit:function(){return new Pt(this._exit||this._groups.map(et),this._parents)},join:function(t,n,e){var r=this.enter(),i=this,o=this.exit();return r="function"==typeof t?t(r):r.append(t+""),null!=n&&(i=n(i)),null==e?o.remove():e(o),r&&i?r.merge(i).order():i},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new Pt(a,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,a=i[o];--o>=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=ut);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var a,u=e[o],c=u.length,f=i[o]=new Array(c),s=0;s<c;++s)(a=u[s])&&(f[s]=a);f.sort(n)}return new Pt(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var a=r[i];if(a)return a}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],a=0,u=o.length;a<u;++a)(i=o[a])&&t.call(i,i.__data__,a,o);return this},attr:function(t,n){var e=W(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}}:"function"==typeof n?e.local?function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}:function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}:e.local?function(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}:function(t,n){return function(){this.setAttribute(t,n)}})(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):ft(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=st(t+"");if(arguments.length<2){for(var r=lt(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?function(t,n){return function(){(n.apply(this,arguments)?dt:pt)(this,t)}}:n?function(t){return function(){dt(this,t)}}:function(t){return function(){pt(this,t)}})(e,n))},text:function(t){return arguments.length?this.each(null==t?vt:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}:function(t){return function(){this.textContent=t}})(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?gt:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}:function(t){return function(){this.innerHTML=t}})(t)):this.node().innerHTML},raise:function(){return this.each(yt)},lower:function(){return this.each(_t)},append:function(t){var n="function"==typeof t?t:Z(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:Z(t),r=null==n?bt:"function"==typeof n?n:K(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(mt)},clone:function(t){return this.select(t?wt:xt)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=function(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?St:At,null==e&&(e=!1),r=0;r<a;++r)this.each(u(o[r],n,e));return this}var u=this.node().__on;if(u)for(var c,f=0,s=u.length;f<s;++f)for(r=0,c=u[f];r<a;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value},dispatch:function(t,n){return this.each(("function"==typeof n?function(t,n){return function(){return Et(this,t,n.apply(this,arguments))}}:function(t,n){return function(){return Et(this,t,n)}})(t,n))}};var Dt=0;function qt(){return new Lt}function Lt(){this._="@"+(++Dt).toString(36)}function Ut(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e}function Ot(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,[(r=r.matrixTransform(t.getScreenCTM().inverse())).x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]}function Bt(t){var n=Ut();return n.changedTouches&&(n=n.changedTouches[0]),Ot(t,n)}function Ft(t,n,e){arguments.length<3&&(e=n,n=Ut().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Ot(t,r);return null}function Yt(){t.event.stopImmediatePropagation()}function It(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function Ht(t){var n=t.document.documentElement,e=Rt(t).on("dragstart.drag",It,!0);"onselectstart"in n?e.on("selectstart.drag",It,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")}function jt(t,n){var e=t.document.documentElement,r=Rt(t).on("dragstart.drag",null);n&&(r.on("click.drag",It,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function Xt(t){return function(){return t}}function Vt(t,n,e,r,i,o,a,u,c,f){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=a,this.dx=u,this.dy=c,this._=f}function Gt(){return!t.event.ctrlKey&&!t.event.button}function $t(){return this.parentNode}function Wt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function Zt(){return navigator.maxTouchPoints||"ontouchstart"in this}function Qt(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function Kt(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Jt(){}Lt.prototype=qt.prototype={constructor:Lt,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}},Vt.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var tn="\\s*([+-]?\\d+)\\s*",nn="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",en="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",rn=/^#([0-9a-f]{3,8})$/,on=new RegExp("^rgb\\("+[tn,tn,tn]+"\\)$"),an=new RegExp("^rgb\\("+[en,en,en]+"\\)$"),un=new RegExp("^rgba\\("+[tn,tn,tn,nn]+"\\)$"),cn=new RegExp("^rgba\\("+[en,en,en,nn]+"\\)$"),fn=new RegExp("^hsl\\("+[nn,en,en]+"\\)$"),sn=new RegExp("^hsla\\("+[nn,en,en,nn]+"\\)$"),ln={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function hn(){return this.rgb().formatHex()}function dn(){return this.rgb().formatRgb()}function pn(t){var n,e;return t=(t+"").trim().toLowerCase(),(n=rn.exec(t))?(e=n[1].length,n=parseInt(n[1],16),6===e?vn(n):3===e?new bn(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?gn(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?gn(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=on.exec(t))?new bn(n[1],n[2],n[3],1):(n=an.exec(t))?new bn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=un.exec(t))?gn(n[1],n[2],n[3],n[4]):(n=cn.exec(t))?gn(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=fn.exec(t))?Mn(n[1],n[2]/100,n[3]/100,1):(n=sn.exec(t))?Mn(n[1],n[2]/100,n[3]/100,n[4]):ln.hasOwnProperty(t)?vn(ln[t]):"transparent"===t?new bn(NaN,NaN,NaN,0):null}function vn(t){return new bn(t>>16&255,t>>8&255,255&t,1)}function gn(t,n,e,r){return r<=0&&(t=n=e=NaN),new bn(t,n,e,r)}function yn(t){return t instanceof Jt||(t=pn(t)),t?new bn((t=t.rgb()).r,t.g,t.b,t.opacity):new bn}function _n(t,n,e,r){return 1===arguments.length?yn(t):new bn(t,n,e,null==r?1:r)}function bn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function mn(){return"#"+wn(this.r)+wn(this.g)+wn(this.b)}function xn(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function wn(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Mn(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new An(t,n,e,r)}function Nn(t){if(t instanceof An)return new An(t.h,t.s,t.l,t.opacity);if(t instanceof Jt||(t=pn(t)),!t)return new An;if(t instanceof An)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,c=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e<r):e===o?(r-n)/u+2:(n-e)/u+4,u/=c<.5?o+i:2-o-i,a*=60):u=c>0&&c<1?0:a,new An(a,u,c,t.opacity)}function Tn(t,n,e,r){return 1===arguments.length?Nn(t):new An(t,n,e,null==r?1:r)}function An(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Sn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Qt(Jt,pn,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:hn,formatHex:hn,formatHsl:function(){return Nn(this).formatHsl()},formatRgb:dn,toString:dn}),Qt(bn,_n,Kt(Jt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new bn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new bn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:mn,formatHex:mn,formatRgb:xn,toString:xn})),Qt(An,Tn,Kt(Jt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new An(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new An(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new bn(Sn(t>=240?t-240:t+120,i,r),Sn(t,i,r),Sn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));var kn=Math.PI/180,En=180/Math.PI,Cn=.96422,Pn=1,zn=.82521,Rn=4/29,Dn=6/29,qn=3*Dn*Dn,Ln=Dn*Dn*Dn;function Un(t){if(t instanceof Bn)return new Bn(t.l,t.a,t.b,t.opacity);if(t instanceof Vn)return Gn(t);t instanceof bn||(t=yn(t));var n,e,r=Hn(t.r),i=Hn(t.g),o=Hn(t.b),a=Fn((.2225045*r+.7168786*i+.0606169*o)/Pn);return r===i&&i===o?n=e=a:(n=Fn((.4360747*r+.3850649*i+.1430804*o)/Cn),e=Fn((.0139322*r+.0971045*i+.7141733*o)/zn)),new Bn(116*a-16,500*(n-a),200*(a-e),t.opacity)}function On(t,n,e,r){return 1===arguments.length?Un(t):new Bn(t,n,e,null==r?1:r)}function Bn(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Fn(t){return t>Ln?Math.pow(t,1/3):t/qn+Rn}function Yn(t){return t>Dn?t*t*t:qn*(t-Rn)}function In(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Hn(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function jn(t){if(t instanceof Vn)return new Vn(t.h,t.c,t.l,t.opacity);if(t instanceof Bn||(t=Un(t)),0===t.a&&0===t.b)return new Vn(NaN,0<t.l&&t.l<100?0:NaN,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*En;return new Vn(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function Xn(t,n,e,r){return 1===arguments.length?jn(t):new Vn(t,n,e,null==r?1:r)}function Vn(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function Gn(t){if(isNaN(t.h))return new Bn(t.l,0,0,t.opacity);var n=t.h*kn;return new Bn(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}Qt(Bn,On,Kt(Jt,{brighter:function(t){return new Bn(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Bn(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new bn(In(3.1338561*(n=Cn*Yn(n))-1.6168667*(t=Pn*Yn(t))-.4906146*(e=zn*Yn(e))),In(-.9787684*n+1.9161415*t+.033454*e),In(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Qt(Vn,Xn,Kt(Jt,{brighter:function(t){return new Vn(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Vn(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return Gn(this).rgb()}}));var $n=-.14861,Wn=1.78277,Zn=-.29227,Qn=-.90649,Kn=1.97294,Jn=Kn*Qn,te=Kn*Wn,ne=Wn*Zn-Qn*$n;function ee(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof re)return new re(t.h,t.s,t.l,t.opacity);t instanceof bn||(t=yn(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(ne*r+Jn*n-te*e)/(ne+Jn-te),o=r-i,a=(Kn*(e-i)-Zn*o)/Qn,u=Math.sqrt(a*a+o*o)/(Kn*i*(1-i)),c=u?Math.atan2(a,o)*En-120:NaN;return new re(c<0?c+360:c,u,i,t.opacity)}(t):new re(t,n,e,null==r?1:r)}function re(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function ie(t,n,e,r,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*n+(4-6*o+3*a)*e+(1+3*t+3*o-3*a)*r+a*i)/6}function oe(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r<n-1?t[r+2]:2*o-i;return ie((e-r/n)*n,a,i,o,u)}}function ae(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],a=t[(r+1)%n],u=t[(r+2)%n];return ie((e-r/n)*n,i,o,a,u)}}function ue(t){return function(){return t}}function ce(t,n){return function(e){return t+e*n}}function fe(t,n){var e=n-t;return e?ce(t,e>180||e<-180?e-360*Math.round(e/360):e):ue(isNaN(t)?n:t)}function se(t){return 1==(t=+t)?le:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):ue(isNaN(n)?e:n)}}function le(t,n){var e=n-t;return e?ce(t,e):ue(isNaN(t)?n:t)}Qt(re,ee,Kt(Jt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new re(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new re(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*kn,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new bn(255*(n+e*($n*r+Wn*i)),255*(n+e*(Zn*r+Qn*i)),255*(n+e*(Kn*r)),this.opacity)}}));var he=function t(n){var e=se(n);function r(t,n){var r=e((t=_n(t)).r,(n=_n(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=le(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function de(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;e<i;++e)r=_n(n[e]),o[e]=r.r||0,a[e]=r.g||0,u[e]=r.b||0;return o=t(o),a=t(a),u=t(u),r.opacity=1,function(t){return r.r=o(t),r.g=a(t),r.b=u(t),r+""}}}var pe=de(oe),ve=de(ae);function ge(t,n){n||(n=[]);var e,r=t?Math.min(n.length,t.length):0,i=n.slice();return function(o){for(e=0;e<r;++e)i[e]=t[e]*(1-o)+n[e]*o;return i}}function ye(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function _e(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(i),a=new Array(r);for(e=0;e<i;++e)o[e]=Te(t[e],n[e]);for(;e<r;++e)a[e]=n[e];return function(t){for(e=0;e<i;++e)a[e]=o[e](t);return a}}function be(t,n){var e=new Date;return t=+t,n=+n,function(r){return e.setTime(t*(1-r)+n*r),e}}function me(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}function xe(t,n){var e,r={},i={};for(e in null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={}),n)e in t?r[e]=Te(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}}var we=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,Me=new RegExp(we.source,"g");function Ne(t,n){var e,r,i,o=we.lastIndex=Me.lastIndex=0,a=-1,u=[],c=[];for(t+="",n+="";(e=we.exec(t))&&(r=Me.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,c.push({i:a,x:me(e,r)})),o=Me.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?c[0]?function(t){return function(n){return t(n)+""}}(c[0].x):function(t){return function(){return t}}(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)u[(e=c[r]).i]=e.x(t);return u.join("")})}function Te(t,n){var e,r=typeof n;return null==n||"boolean"===r?ue(n):("number"===r?me:"string"===r?(e=pn(n))?(n=e,he):Ne:n instanceof pn?he:n instanceof Date?be:ye(n)?ge:Array.isArray(n)?_e:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?xe:me)(t,n)}function Ae(t,n){return t=+t,n=+n,function(e){return Math.round(t*(1-e)+n*e)}}var Se,ke,Ee,Ce,Pe=180/Math.PI,ze={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Re(t,n,e,r,i,o){var a,u,c;return(a=Math.sqrt(t*t+n*n))&&(t/=a,n/=a),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(u=Math.sqrt(e*e+r*r))&&(e/=u,r/=u,c/=u),t*r<n*e&&(t=-t,n=-n,c=-c,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*Pe,skewX:Math.atan(c)*Pe,scaleX:a,scaleY:u}}function De(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}return function(o,a){var u=[],c=[];return o=t(o),a=t(a),function(t,r,i,o,a,u){if(t!==i||r!==o){var c=a.push("translate(",null,n,null,e);u.push({i:c-4,x:me(t,i)},{i:c-2,x:me(r,o)})}else(i||o)&&a.push("translate("+i+n+o+e)}(o.translateX,o.translateY,a.translateX,a.translateY,u,c),function(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:me(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:me(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,c),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:me(t,e)},{i:u-2,x:me(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,c),o=a=null,function(t){for(var n,e=-1,r=c.length;++e<r;)u[(n=c[e]).i]=n.x(t);return u.join("")}}}var qe=De(function(t){return"none"===t?ze:(Se||(Se=document.createElement("DIV"),ke=document.documentElement,Ee=document.defaultView),Se.style.transform=t,t=Ee.getComputedStyle(ke.appendChild(Se),null).getPropertyValue("transform"),ke.removeChild(Se),Re(+(t=t.slice(7,-1).split(","))[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),Le=De(function(t){return null==t?ze:(Ce||(Ce=document.createElementNS("http://www.w3.org/2000/svg","g")),Ce.setAttribute("transform",t),(t=Ce.transform.baseVal.consolidate())?Re((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):ze)},", ",")",")"),Ue=Math.SQRT2,Oe=2,Be=4,Fe=1e-12;function Ye(t){return((t=Math.exp(t))+1/t)/2}function Ie(t,n){var e,r,i=t[0],o=t[1],a=t[2],u=n[0],c=n[1],f=n[2],s=u-i,l=c-o,h=s*s+l*l;if(h<Fe)r=Math.log(f/a)/Ue,e=function(t){return[i+t*s,o+t*l,a*Math.exp(Ue*t*r)]};else{var d=Math.sqrt(h),p=(f*f-a*a+Be*h)/(2*a*Oe*d),v=(f*f-a*a-Be*h)/(2*f*Oe*d),g=Math.log(Math.sqrt(p*p+1)-p),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-g)/Ue,e=function(t){var n=t*r,e=Ye(g),u=a/(Oe*d)*(e*function(t){return((t=Math.exp(2*t))-1)/(t+1)}(Ue*n+g)-function(t){return((t=Math.exp(t))-1/t)/2}(g));return[i+u*s,o+u*l,a*e/Ye(Ue*n+g)]}}return e.duration=1e3*r,e}function He(t){return function(n,e){var r=t((n=Tn(n)).h,(e=Tn(e)).h),i=le(n.s,e.s),o=le(n.l,e.l),a=le(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var je=He(fe),Xe=He(le);function Ve(t){return function(n,e){var r=t((n=Xn(n)).h,(e=Xn(e)).h),i=le(n.c,e.c),o=le(n.l,e.l),a=le(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var Ge=Ve(fe),$e=Ve(le);function We(t){return function n(e){function r(n,r){var i=t((n=ee(n)).h,(r=ee(r)).h),o=le(n.s,r.s),a=le(n.l,r.l),u=le(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=a(Math.pow(t,e)),n.opacity=u(t),n+""}}return e=+e,r.gamma=n,r}(1)}var Ze=We(fe),Qe=We(le);var Ke,Je,tr=0,nr=0,er=0,rr=1e3,ir=0,or=0,ar=0,ur="object"==typeof performance&&performance.now?performance:Date,cr="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function fr(){return or||(cr(sr),or=ur.now()+ar)}function sr(){or=0}function lr(){this._call=this._time=this._next=null}function hr(t,n,e){var r=new lr;return r.restart(t,n,e),r}function dr(){fr(),++tr;for(var t,n=Ke;n;)(t=or-n._time)>=0&&n._call.call(null,t),n=n._next;--tr}function pr(){or=(ir=ur.now())+ar,tr=nr=0;try{dr()}finally{tr=0,function(){var t,n,e=Ke,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Ke=n);Je=t,gr(r)}(),or=0}}function vr(){var t=ur.now(),n=t-ir;n>rr&&(ar-=n,ir=t)}function gr(t){tr||(nr&&(nr=clearTimeout(nr)),t-or>24?(t<1/0&&(nr=setTimeout(pr,t-ur.now()-ar)),er&&(er=clearInterval(er))):(er||(ir=ur.now(),er=setInterval(vr,rr)),tr=1,cr(pr)))}function yr(t,n,e){var r=new lr;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r}lr.prototype=hr.prototype={constructor:lr,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?fr():+e)+(null==n?0:+n),this._next||Je===this||(Je?Je._next=this:Ke=this,Je=this),this._call=t,this._time=e,gr()},stop:function(){this._call&&(this._call=null,this._time=1/0,gr())}};var _r=I("start","end","cancel","interrupt"),br=[],mr=0,xr=1,wr=2,Mr=3,Nr=4,Tr=5,Ar=6;function Sr(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(c){var f,s,l,h;if(e.state!==xr)return u();for(f in i)if((h=i[f]).name===e.name){if(h.state===Mr)return yr(o);h.state===Nr?(h.state=Ar,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[f]):+f<n&&(h.state=Ar,h.timer.stop(),h.on.call("cancel",t,t.__data__,h.index,h.group),delete i[f])}if(yr(function(){e.state===Mr&&(e.state=Nr,e.timer.restart(a,e.delay,e.time),a(c))}),e.state=wr,e.on.call("start",t,t.__data__,e.index,e.group),e.state===wr){for(e.state=Mr,r=new Array(l=e.tween.length),f=0,s=-1;f<l;++f)(h=e.tween[f].value.call(t,t.__data__,e.index,e.group))&&(r[++s]=h);r.length=s+1}}function a(n){for(var i=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(u),e.state=Tr,1),o=-1,a=r.length;++o<a;)r[o].call(t,i);e.state===Tr&&(e.on.call("end",t,t.__data__,e.index,e.group),u())}function u(){for(var r in e.state=Ar,e.timer.stop(),delete i[n],i)return;delete t.__transition}i[n]=e,e.timer=hr(function(t){e.state=xr,e.timer.restart(o,e.delay,e.time),e.delay<=t&&o(t-e.delay)},0,e.time)}(t,e,{name:n,index:r,group:i,on:_r,tween:br,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:mr})}function kr(t,n){var e=Cr(t,n);if(e.state>mr)throw new Error("too late; already scheduled");return e}function Er(t,n){var e=Cr(t,n);if(e.state>Mr)throw new Error("too late; already running");return e}function Cr(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Pr(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>wr&&e.state<Tr,e.state=Ar,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):a=!1;a&&delete t.__transition}}function zr(t,n,e){var r=t._id;return t.each(function(){var t=Er(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return Cr(t,r).value[n]}}function Rr(t,n){var e;return("number"==typeof n?me:n instanceof pn?he:(e=pn(n))?(n=e,he):Ne)(t,n)}var Dr=zt.prototype.constructor;function qr(t){return function(){this.style.removeProperty(t)}}var Lr=0;function Ur(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function Or(t){return zt().transition(t)}function Br(){return++Lr}var Fr=zt.prototype;function Yr(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function Ir(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}Ur.prototype=Or.prototype={constructor:Ur,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=K(t));for(var r=this._groups,i=r.length,o=new Array(i),a=0;a<i;++a)for(var u,c,f=r[a],s=f.length,l=o[a]=new Array(s),h=0;h<s;++h)(u=f[h])&&(c=t.call(u,u.__data__,h,f))&&("__data__"in u&&(c.__data__=u.__data__),l[h]=c,Sr(l[h],n,e,h,l,Cr(u,e)));return new Ur(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=tt(t));for(var r=this._groups,i=r.length,o=[],a=[],u=0;u<i;++u)for(var c,f=r[u],s=f.length,l=0;l<s;++l)if(c=f[l]){for(var h,d=t.call(c,c.__data__,l,f),p=Cr(c,e),v=0,g=d.length;v<g;++v)(h=d[v])&&Sr(h,n,e,v,d,p);o.push(d),a.push(c)}return new Ur(o,a,n,e)},filter:function(t){"function"!=typeof t&&(t=nt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new Ur(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new Ur(a,this._parents,this._name,this._id)},selection:function(){return new Dr(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Br(),r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)if(a=u[f]){var s=Cr(a,n);Sr(a,t,e,f,u,{time:s.time+s.delay+s.duration,delay:0,duration:s.duration,ease:s.ease})}return new Ur(r,this._parents,t,e)},call:Fr.call,nodes:Fr.nodes,node:Fr.node,size:Fr.size,empty:Fr.empty,each:Fr.each,on:function(t,n){var e=this._id;return arguments.length<2?Cr(this.node(),e).on.on(t):this.each(function(t,n,e){var r,i,o=function(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?kr:Er;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=W(t),r="transform"===e?Le:Rr;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttributeNS(t.space,t.local))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttribute(t))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttribute(t)}})(e,r,zr(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttributeNS(t.space,t.local);return a===o?null:a===r?i:i=n(r=a,e)}}:function(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttribute(t);return a===o?null:a===r?i:i=n(r=a,e)}})(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=W(t);return this.tween(e,(r.local?function(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttributeNS(t.space,t.local,n.call(this,e))}}(t,i)),e}return i._value=n,i}:function(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttribute(t,n.call(this,e))}}(t,i)),e}return i._value=n,i})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?qe:Rr;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=ft(this,t),a=(this.style.removeProperty(t),ft(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,qr(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=ft(this,t),u=e(this),c=u+"";return null==u&&(this.style.removeProperty(t),c=u=ft(this,t)),a===c?null:a===r&&c===i?o:(i=c,o=n(r=a,u))}}(t,r,zr(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var c=Er(this,t),f=c.on,s=null==c.value[a]?o||(o=qr(n)):void 0;f===e&&i===s||(r=(e=f).copy()).on(u,i=s),c.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=ft(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}(t,o,e)),r}return o._value=n,o}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(zr(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var n="text";if(arguments.length<1)return(n=this.tween(n))&&n._value;if(null==t)return this.tween(n,null);if("function"!=typeof t)throw new Error;return this.tween(n,function(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&function(t){return function(n){this.textContent=t.call(this,n)}}(r)),n}return r._value=t,r}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Cr(this.node(),e).tween,o=0,a=i.length;o<a;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?function(t,n){var e,r;return function(){var i=Er(this,t),o=i.tween;if(o!==e)for(var a=0,u=(r=e=o).length;a<u;++a)if(r[a].name===n){(r=r.slice()).splice(a,1);break}i.tween=r}}:function(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=Er(this,t),a=o.tween;if(a!==r){i=(r=a).slice();for(var u={name:n,value:e},c=0,f=i.length;c<f;++c)if(i[c].name===n){i[c]=u;break}c===f&&i.push(u)}o.tween=i}})(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){kr(this,t).delay=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){kr(this,t).delay=n}})(n,t)):Cr(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){Er(this,t).duration=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){Er(this,t).duration=n}})(n,t)):Cr(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(function(t,n){if("function"!=typeof n)throw new Error;return function(){Er(this,t).ease=n}}(n,t)):Cr(this.node(),n).ease},end:function(){var t,n,e=this,r=e._id,i=e.size();return new Promise(function(o,a){var u={value:a},c={value:function(){0==--i&&o()}};e.each(function(){var e=Er(this,r),i=e.on;i!==t&&((n=(t=i).copy())._.cancel.push(u),n._.interrupt.push(u),n._.end.push(c)),e.on=n})})}};var Hr=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),jr=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Xr=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Vr=Math.PI,Gr=Vr/2;function $r(t){return(1-Math.cos(Vr*t))/2}function Wr(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function Zr(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var Qr=4/11,Kr=6/11,Jr=8/11,ti=.75,ni=9/11,ei=10/11,ri=.9375,ii=21/22,oi=63/64,ai=1/Qr/Qr;function ui(t){return(t=+t)<Qr?ai*t*t:t<Jr?ai*(t-=Kr)*t+ti:t<ei?ai*(t-=ni)*t+ri:ai*(t-=ii)*t+oi}var ci=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),fi=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),si=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),li=2*Math.PI,hi=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=li);function i(t){return n*Math.pow(2,10*--t)*Math.sin((r-t)/e)}return i.amplitude=function(n){return t(n,e*li)},i.period=function(e){return t(n,e)},i}(1,.3),di=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=li);function i(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+r)/e)}return i.amplitude=function(n){return t(n,e*li)},i.period=function(e){return t(n,e)},i}(1,.3),pi=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=li);function i(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((r-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((r+t)/e))/2}return i.amplitude=function(n){return t(n,e*li)},i.period=function(e){return t(n,e)},i}(1,.3),vi={time:null,delay:0,duration:250,ease:Ir};function gi(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return vi.time=fr(),vi;return e}zt.prototype.interrupt=function(t){return this.each(function(){Pr(this,t)})},zt.prototype.transition=function(t){var n,e;t instanceof Ur?(n=t._id,t=t._name):(n=Br(),(e=vi).time=fr(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)(a=u[f])&&Sr(a,t,n,f,u,e||gi(a,n));return new Ur(r,this._parents,t,n)};var yi=[null];function _i(t){return function(){return t}}function bi(t,n,e){this.target=t,this.type=n,this.selection=e}function mi(){t.event.stopImmediatePropagation()}function xi(){t.event.preventDefault(),t.event.stopImmediatePropagation()}var wi={name:"drag"},Mi={name:"space"},Ni={name:"handle"},Ti={name:"center"};function Ai(t){return[+t[0],+t[1]]}function Si(t){return[Ai(t[0]),Ai(t[1])]}var ki={name:"x",handles:["w","e"].map(Li),input:function(t,n){return null==t?null:[[+t[0],n[0][1]],[+t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Ei={name:"y",handles:["n","s"].map(Li),input:function(t,n){return null==t?null:[[n[0][0],+t[0]],[n[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Ci={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(Li),input:function(t){return null==t?null:Si(t)},output:function(t){return t}},Pi={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},zi={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ri={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},Di={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},qi={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function Li(t){return{type:t}}function Ui(){return!t.event.ctrlKey&&!t.event.button}function Oi(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function Bi(){return navigator.maxTouchPoints||"ontouchstart"in this}function Fi(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function Yi(n){var e,r=Oi,i=Ui,o=Bi,a=!0,u=I("start","brush","end"),c=6;function f(t){var e=t.property("__brush",g).selectAll(".overlay").data([Li("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Pi.overlay).merge(e).each(function(){var t=Fi(this).extent;Rt(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([Li("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Pi.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=t.selectAll(".handle").data(n.handles,function(t){return t.type});r.exit().remove(),r.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Pi[t.type]}),t.each(s).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",d).filter(o).on("touchstart.brush",d).on("touchmove.brush",p).on("touchend.brush touchcancel.brush",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function s(){var t=Rt(this),n=Fi(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-c/2:n[0][0]-c/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-c/2:n[0][1]-c/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+c:c}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+c:c})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function l(t,n,e){return!e&&t.__brush.emitter||new h(t,n)}function h(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function d(){if((!e||t.event.touches)&&i.apply(this,arguments)){var r,o,u,c,f,h,d,p,v,g,y,_,b=this,m=t.event.target.__data__.type,x="selection"===(a&&t.event.metaKey?m="overlay":m)?wi:a&&t.event.altKey?Ti:Ni,w=n===Ei?null:Di[m],M=n===ki?null:qi[m],N=Fi(b),T=N.extent,A=N.selection,S=T[0][0],k=T[0][1],E=T[1][0],C=T[1][1],P=0,z=0,R=w&&M&&a&&t.event.shiftKey,D=t.event.touches?(_=t.event.changedTouches[0].identifier,function(n){return Ft(n,t.event.touches,_)}):Bt,q=D(b),L=q,U=l(b,arguments,!0).beforestart();"overlay"===m?(A&&(v=!0),N.selection=A=[[r=n===Ei?S:q[0],u=n===ki?k:q[1]],[f=n===Ei?E:r,d=n===ki?C:u]]):(r=A[0][0],u=A[0][1],f=A[1][0],d=A[1][1]),o=r,c=u,h=f,p=d;var O=Rt(b).attr("pointer-events","none"),B=O.selectAll(".overlay").attr("cursor",Pi[m]);if(t.event.touches)U.moved=Y,U.ended=H;else{var F=Rt(t.event.view).on("mousemove.brush",Y,!0).on("mouseup.brush",H,!0);a&&F.on("keydown.brush",function(){switch(t.event.keyCode){case 16:R=w&&M;break;case 18:x===Ni&&(w&&(f=h-P*w,r=o+P*w),M&&(d=p-z*M,u=c+z*M),x=Ti,I());break;case 32:x!==Ni&&x!==Ti||(w<0?f=h-P:w>0&&(r=o-P),M<0?d=p-z:M>0&&(u=c-z),x=Mi,B.attr("cursor",Pi.selection),I());break;default:return}xi()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:R&&(g=y=R=!1,I());break;case 18:x===Ti&&(w<0?f=h:w>0&&(r=o),M<0?d=p:M>0&&(u=c),x=Ni,I());break;case 32:x===Mi&&(t.event.altKey?(w&&(f=h-P*w,r=o+P*w),M&&(d=p-z*M,u=c+z*M),x=Ti):(w<0?f=h:w>0&&(r=o),M<0?d=p:M>0&&(u=c),x=Ni),B.attr("cursor",Pi[m]),I());break;default:return}xi()},!0),Ht(t.event.view)}mi(),Pr(b),s.call(b),U.start()}function Y(){var t=D(b);!R||g||y||(Math.abs(t[0]-L[0])>Math.abs(t[1]-L[1])?y=!0:g=!0),L=t,v=!0,xi(),I()}function I(){var t;switch(P=L[0]-q[0],z=L[1]-q[1],x){case Mi:case wi:w&&(P=Math.max(S-r,Math.min(E-f,P)),o=r+P,h=f+P),M&&(z=Math.max(k-u,Math.min(C-d,z)),c=u+z,p=d+z);break;case Ni:w<0?(P=Math.max(S-r,Math.min(E-r,P)),o=r+P,h=f):w>0&&(P=Math.max(S-f,Math.min(E-f,P)),o=r,h=f+P),M<0?(z=Math.max(k-u,Math.min(C-u,z)),c=u+z,p=d):M>0&&(z=Math.max(k-d,Math.min(C-d,z)),c=u,p=d+z);break;case Ti:w&&(o=Math.max(S,Math.min(E,r-P*w)),h=Math.max(S,Math.min(E,f+P*w))),M&&(c=Math.max(k,Math.min(C,u-z*M)),p=Math.max(k,Math.min(C,d+z*M)))}h<o&&(w*=-1,t=r,r=f,f=t,t=o,o=h,h=t,m in zi&&B.attr("cursor",Pi[m=zi[m]])),p<c&&(M*=-1,t=u,u=d,d=t,t=c,c=p,p=t,m in Ri&&B.attr("cursor",Pi[m=Ri[m]])),N.selection&&(A=N.selection),g&&(o=A[0][0],h=A[1][0]),y&&(c=A[0][1],p=A[1][1]),A[0][0]===o&&A[0][1]===c&&A[1][0]===h&&A[1][1]===p||(N.selection=[[o,c],[h,p]],s.call(b),U.brush())}function H(){if(mi(),t.event.touches){if(t.event.touches.length)return;e&&clearTimeout(e),e=setTimeout(function(){e=null},500)}else jt(t.event.view,v),F.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);O.attr("pointer-events","all"),B.attr("cursor",Pi.overlay),N.selection&&(A=N.selection),function(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}(A)&&(N.selection=null,s.call(b)),U.end()}}function p(){l(this,arguments).moved()}function v(){l(this,arguments).ended()}function g(){var t=this.__brush||{selection:null};return t.extent=Si(r.apply(this,arguments)),t.dim=n,t}return f.move=function(t,e){t.selection?t.on("start.brush",function(){l(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){l(this,arguments).end()}).tween("brush",function(){var t=this,r=t.__brush,i=l(t,arguments),o=r.selection,a=n.input("function"==typeof e?e.apply(this,arguments):e,r.extent),u=Te(o,a);function c(n){r.selection=1===n&&null===a?null:u(n),s.call(t),i.brush()}return null!==o&&null!==a?c:c(1)}):t.each(function(){var t=this,r=arguments,i=t.__brush,o=n.input("function"==typeof e?e.apply(t,r):e,i.extent),a=l(t,r).beforestart();Pr(t),i.selection=null===o?null:o,s.call(t),a.start().brush().end()})},f.clear=function(t){f.move(t,null)},h.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting?(this.starting=!1,this.emit("start")):this.emit("brush"),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){kt(new bi(f,t,n.output(this.state.selection)),u.apply,u,[t,this.that,this.args])}},f.extent=function(t){return arguments.length?(r="function"==typeof t?t:_i(Si(t)),f):r},f.filter=function(t){return arguments.length?(i="function"==typeof t?t:_i(!!t),f):i},f.touchable=function(t){return arguments.length?(o="function"==typeof t?t:_i(!!t),f):o},f.handleSize=function(t){return arguments.length?(c=+t,f):c},f.keyModifiers=function(t){return arguments.length?(a=!!t,f):a},f.on=function(){var t=u.on.apply(u,arguments);return t===u?f:t},f}var Ii=Math.cos,Hi=Math.sin,ji=Math.PI,Xi=ji/2,Vi=2*ji,Gi=Math.max;function $i(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}var Wi=Array.prototype.slice;function Zi(t){return function(){return t}}var Qi=Math.PI,Ki=2*Qi,Ji=Ki-1e-6;function to(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function no(){return new to}function eo(t){return t.source}function ro(t){return t.target}function io(t){return t.radius}function oo(t){return t.startAngle}function ao(t){return t.endAngle}to.prototype=no.prototype={constructor:to,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,a=this._y1,u=e-t,c=r-n,f=o-t,s=a-n,l=f*f+s*s;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(s*u-c*f)>1e-6&&i){var h=e-o,d=r-a,p=u*u+c*c,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(l),_=i*Math.tan((Qi-Math.acos((p+l-v)/(2*g*y)))/2),b=_/y,m=_/g;Math.abs(b-1)>1e-6&&(this._+="L"+(t+b*f)+","+(n+b*s)),this._+="A"+i+","+i+",0,0,"+ +(s*h>f*d)+","+(this._x1=t+m*u)+","+(this._y1=n+m*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n,o=!!o;var a=(e=+e)*Math.cos(r),u=e*Math.sin(r),c=t+a,f=n+u,s=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+f:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-f)>1e-6)&&(this._+="L"+c+","+f),e&&(l<0&&(l=l%Ki+Ki),l>Ji?this._+="A"+e+","+e+",0,1,"+s+","+(t-a)+","+(n-u)+"A"+e+","+e+",0,1,"+s+","+(this._x1=c)+","+(this._y1=f):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Qi)+","+s+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};function uo(){}function co(t,n){var e=new uo;if(t instanceof uo)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var a in t)e.set(a,t[a]);return e}function fo(){return{}}function so(t,n,e){t[n]=e}function lo(){return co()}function ho(t,n,e){t.set(n,e)}function po(){}uo.prototype=co.prototype={constructor:uo,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var vo=co.prototype;function go(t,n){var e=new po;if(t instanceof po)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}po.prototype=go.prototype={constructor:po,has:vo.has,add:function(t){return this["$"+(t+="")]=t,this},remove:vo.remove,clear:vo.clear,values:vo.keys,size:vo.size,empty:vo.empty,each:vo.each};var yo=Array.prototype.slice;function _o(t,n){return t-n}function bo(t){return function(){return t}}function mo(t,n){for(var e,r=-1,i=n.length;++r<i;)if(e=xo(t,n[r]))return e;return 0}function xo(t,n){for(var e=n[0],r=n[1],i=-1,o=0,a=t.length,u=a-1;o<a;u=o++){var c=t[o],f=c[0],s=c[1],l=t[u],h=l[0],d=l[1];if(wo(c,l,n))return 0;s>r!=d>r&&e<(h-f)*(r-s)/(d-s)+f&&(i=-i)}return i}function wo(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function Mo(){}var No=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function To(){var t=1,n=1,e=M,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(_o);else{var r=s(t),i=r[0],a=r[1];n=w(i,a,n),n=g(Math.floor(i/n)*n,Math.floor(a/n)*n,n)}return n.map(function(n){return o(t,n)})}function o(e,i){var o=[],u=[];return function(e,r,i){var o,u,c,f,s,l,h=new Array,d=new Array;o=u=-1,f=e[0]>=r,No[f<<1].forEach(p);for(;++o<t-1;)c=f,f=e[o+1]>=r,No[c|f<<1].forEach(p);No[f<<0].forEach(p);for(;++u<n-1;){for(o=-1,f=e[u*t+t]>=r,s=e[u*t]>=r,No[f<<1|s<<2].forEach(p);++o<t-1;)c=f,f=e[u*t+t+o+1]>=r,l=s,s=e[u*t+o+1]>=r,No[c|f<<1|s<<2|l<<3].forEach(p);No[f|s<<3].forEach(p)}o=-1,s=e[u*t]>=r,No[s<<2].forEach(p);for(;++o<t-1;)l=s,s=e[u*t+o+1]>=r,No[s<<2|l<<3].forEach(p);function p(t){var n,e,r=[t[0][0]+o,t[0][1]+u],c=[t[1][0]+o,t[1][1]+u],f=a(r),s=a(c);(n=d[f])?(e=h[s])?(delete d[n.end],delete h[e.start],n===e?(n.ring.push(c),i(n.ring)):h[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete d[n.end],n.ring.push(c),d[n.end=s]=n):(n=h[s])?(e=d[f])?(delete h[n.start],delete d[e.end],n===e?(n.ring.push(c),i(n.ring)):h[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete h[n.start],n.ring.unshift(r),h[n.start=f]=n):h[f]=d[s]={start:f,end:s,ring:[r,c]}}No[s<<3].forEach(p)}(e,i,function(t){r(t,e,i),function(t){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];++n<e;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return r}(t)>0?o.push([t]):u.push(t)}),u.forEach(function(t){for(var n,e=0,r=o.length;e<r;++e)if(-1!==mo((n=o[e])[0],t))return void n.push(t)}),{type:"MultiPolygon",value:i,coordinates:o}}function a(n){return 2*n[0]+n[1]*(t+1)*4}function u(e,r,i){e.forEach(function(e){var o,a=e[0],u=e[1],c=0|a,f=0|u,s=r[f*t+c];a>0&&a<t&&c===a&&(o=r[f*t+c-1],e[0]=a+(i-o)/(s-o)-.5),u>0&&u<n&&f===u&&(o=r[(f-1)*t+c],e[1]=u+(i-o)/(s-o)-.5)})}return i.contour=o,i.size=function(e){if(!arguments.length)return[t,n];var r=Math.ceil(e[0]),o=Math.ceil(e[1]);if(!(r>0&&o>0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?bo(yo.call(t)):bo(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:Mo,i):r===u},i}function Ao(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<i;++a)for(var u=0,c=0;u<r+e;++u)u<r&&(c+=t.data[u+a*r]),u>=e&&(u>=o&&(c-=t.data[u-o+a*r]),n.data[u-e+a*r]=c/Math.min(u+1,r-1+o-u,o))}function So(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<r;++a)for(var u=0,c=0;u<i+e;++u)u<i&&(c+=t.data[a+u*r]),u>=e&&(u>=o&&(c-=t.data[a+(u-o)*r]),n.data[a+(u-e)*r]=c/Math.min(u+1,i-1+o-u,o))}function ko(t){return t[0]}function Eo(t){return t[1]}function Co(){return 1}var Po={},zo={},Ro=34,Do=10,qo=13;function Lo(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+'] || ""'}).join(",")+"}")}function Uo(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function Oo(t,n){var e=t+"",r=e.length;return r<n?new Array(n-r+1).join(0)+e:e}function Bo(t){var n=t.getUTCHours(),e=t.getUTCMinutes(),r=t.getUTCSeconds(),i=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":function(t){return t<0?"-"+Oo(-t,6):t>9999?"+"+Oo(t,6):Oo(t,4)}(t.getUTCFullYear())+"-"+Oo(t.getUTCMonth()+1,2)+"-"+Oo(t.getUTCDate(),2)+(i?"T"+Oo(n,2)+":"+Oo(e,2)+":"+Oo(r,2)+"."+Oo(i,3)+"Z":r?"T"+Oo(n,2)+":"+Oo(e,2)+":"+Oo(r,2)+"Z":e||n?"T"+Oo(n,2)+":"+Oo(e,2)+"Z":"")}function Fo(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,c=o<=0,f=!1;function s(){if(c)return zo;if(f)return f=!1,Po;var n,r,i=a;if(t.charCodeAt(i)===Ro){for(;a++<o&&t.charCodeAt(a)!==Ro||t.charCodeAt(++a)===Ro;);return(n=a)>=o?c=!0:(r=t.charCodeAt(a++))===Do?f=!0:r===qo&&(f=!0,t.charCodeAt(a)===Do&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;a<o;){if((r=t.charCodeAt(n=a++))===Do)f=!0;else if(r===qo)f=!0,t.charCodeAt(a)===Do&&++a;else if(r!==e)continue;return t.slice(i,n)}return c=!0,t.slice(i,o)}for(t.charCodeAt(o-1)===Do&&--o,t.charCodeAt(o-1)===qo&&--o;(r=s())!==zo;){for(var l=[];r!==Po&&r!==zo;)l.push(r),r=s();n&&null==(l=n(l,u++))||i.push(l)}return i}function i(n,e){return n.map(function(n){return e.map(function(t){return a(n[t])}).join(t)})}function o(n){return n.map(a).join(t)}function a(t){return null==t?"":t instanceof Date?Bo(t):n.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,n){var e,i,o=r(t,function(t,r){if(e)return e(t,r-1);i=t,e=n?function(t,n){var e=Lo(t);return function(r,i){return n(e(r),i,t)}}(t,n):Lo(t)});return o.columns=i||[],o},parseRows:r,format:function(n,e){return null==e&&(e=Uo(n)),[e.map(a).join(t)].concat(i(n,e)).join("\n")},formatBody:function(t,n){return null==n&&(n=Uo(t)),i(t,n).join("\n")},formatRows:function(t){return t.map(o).join("\n")},formatRow:o,formatValue:a}}var Yo=Fo(","),Io=Yo.parse,Ho=Yo.parseRows,jo=Yo.format,Xo=Yo.formatBody,Vo=Yo.formatRows,Go=Yo.formatRow,$o=Yo.formatValue,Wo=Fo("\t"),Zo=Wo.parse,Qo=Wo.parseRows,Ko=Wo.format,Jo=Wo.formatBody,ta=Wo.formatRows,na=Wo.formatRow,ea=Wo.formatValue;var ra=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();function ia(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function oa(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function aa(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function ua(t,n){return fetch(t,n).then(aa)}function ca(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),ua(n,e).then(function(n){return t(n,r)})}}var fa=ca(Io),sa=ca(Zo);function la(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.json()}function ha(t){return function(n,e){return ua(n,e).then(function(n){return(new DOMParser).parseFromString(n,t)})}}var da=ha("application/xml"),pa=ha("text/html"),va=ha("image/svg+xml");function ga(t){return function(){return t}}function ya(){return 1e-6*(Math.random()-.5)}function _a(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,c,f,s,l,h,d=t._root,p={data:r},v=t._x0,g=t._y0,y=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((f=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a,i=d,!(d=d[l=s<<1|f]))return i[l]=p,t;if(u=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===u&&e===c)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(f=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a}while((l=s<<1|f)==(h=(c>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function ba(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function ma(t){return t[0]}function xa(t){return t[1]}function wa(t,n,e){var r=new Ma(null==n?ma:n,null==e?xa:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ma(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Na(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var Ta=wa.prototype=Ma.prototype;function Aa(t){return t.x+t.vx}function Sa(t){return t.y+t.vy}function ka(t){return t.index}function Ea(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Ca(t){return t.x}function Pa(t){return t.y}Ta.copy=function(){var t,n,e=new Ma(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Na(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=Na(n));return e},Ta.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return _a(this.cover(n,e),n,e,t)},Ta.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),c=1/0,f=1/0,s=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(a[e]=r,u[e]=i,r<c&&(c=r),r>s&&(s=r),i<f&&(f=i),i>l&&(l=i));if(c>s||f>l)return this;for(this.cover(c,f).cover(s,l),e=0;e<o;++e)_a(this,a[e],u[e],t[e]);return this},Ta.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{for(var a,u,c=i-e,f=this._root;e>t||t>=i||r>n||n>=o;)switch(u=(n<r)<<1|t<e,(a=new Array(4))[u]=f,f=a,c*=2,u){case 0:i=e+c,o=r+c;break;case 1:e=i-c,o=r+c;break;case 2:i=e+c,r=o-c;break;case 3:e=i-c,r=o-c}this._root&&this._root.length&&(this._root=f)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},Ta.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},Ta.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},Ta.find=function(t,n,e){var r,i,o,a,u,c,f,s=this._x0,l=this._y0,h=this._x1,d=this._y1,p=[],v=this._root;for(v&&p.push(new ba(v,s,l,h,d)),null==e?e=1/0:(s=t-e,l=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>d||(a=c.x1)<s||(u=c.y1)<l))if(v.length){var g=(i+a)/2,y=(o+u)/2;p.push(new ba(v[3],g,y,a,u),new ba(v[2],i,y,g,u),new ba(v[1],g,o,a,y),new ba(v[0],i,o,g,y)),(f=(n>=y)<<1|t>=g)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-f],p[p.length-1-f]=c)}else{var _=t-+this._x.call(null,v.data),b=n-+this._y.call(null,v.data),m=_*_+b*b;if(m<e){var x=Math.sqrt(e=m);s=t-x,l=n-x,h=t+x,d=n+x,r=v.data}}return r},Ta.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(a=+this._y.call(null,t)))return this;var n,e,r,i,o,a,u,c,f,s,l,h,d=this._root,p=this._x0,v=this._y0,g=this._x1,y=this._y1;if(!d)return this;if(d.length)for(;;){if((f=o>=(u=(p+g)/2))?p=u:g=u,(s=a>=(c=(v+y)/2))?v=c:y=c,n=d,!(d=d[l=s<<1|f]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},Ta.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},Ta.root=function(){return this._root},Ta.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},Ta.visit=function(t){var n,e,r,i,o,a,u=[],c=this._root;for(c&&u.push(new ba(c,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,a=n.y1)&&c.length){var f=(r+o)/2,s=(i+a)/2;(e=c[3])&&u.push(new ba(e,f,s,o,a)),(e=c[2])&&u.push(new ba(e,r,s,f,a)),(e=c[1])&&u.push(new ba(e,f,i,o,s)),(e=c[0])&&u.push(new ba(e,r,i,f,s))}return this},Ta.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new ba(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,a=n.x0,u=n.y0,c=n.x1,f=n.y1,s=(a+c)/2,l=(u+f)/2;(o=i[0])&&e.push(new ba(o,a,u,s,l)),(o=i[1])&&e.push(new ba(o,s,u,c,l)),(o=i[2])&&e.push(new ba(o,a,l,s,f)),(o=i[3])&&e.push(new ba(o,s,l,c,f))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},Ta.x=function(t){return arguments.length?(this._x=t,this):this._x},Ta.y=function(t){return arguments.length?(this._y=t,this):this._y};var za=10,Ra=Math.PI*(3-Math.sqrt(5));function Da(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]}function qa(t){return(t=Da(Math.abs(t)))?t[1]:NaN}var La,Ua=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Oa(t){if(!(n=Ua.exec(t)))throw new Error("invalid format: "+t);var n;return new Ba({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function Ba(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function Fa(t,n){var e=Da(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Oa.prototype=Ba.prototype,Ba.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var Ya={"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return Fa(100*t,n)},r:Fa,s:function(t,n){var e=Da(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(La=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+Da(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}};function Ia(t){return t}var Ha,ja=Array.prototype.map,Xa=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Va(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?Ia:(n=ja.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),o.push(t.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?Ia:function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}}(ja.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",f=void 0===t.minus?"-":t.minus+"",s=void 0===t.nan?"NaN":t.nan+"";function l(t){var n=(t=Oa(t)).fill,e=t.align,l=t.sign,h=t.symbol,d=t.zero,p=t.width,v=t.comma,g=t.precision,y=t.trim,_=t.type;"n"===_?(v=!0,_="g"):Ya[_]||(void 0===g&&(g=12),y=!0,_="g"),(d||"0"===n&&"="===e)&&(d=!0,n="0",e="=");var b="$"===h?i:"#"===h&&/[boxX]/.test(_)?"0"+_.toLowerCase():"",m="$"===h?o:/[%p]/.test(_)?c:"",x=Ya[_],w=/[defgprs%]/.test(_);function M(t){var i,o,c,h=b,M=m;if("c"===_)M=x(t)+M,t="";else{var N=(t=+t)<0||1/t<0;if(t=isNaN(t)?s:x(Math.abs(t),g),y&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r<e;++r)switch(t[r]){case".":i=n=r;break;case"0":0===i&&(i=r),n=r;break;default:if(!+t[r])break t;i>0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),N&&0==+t&&"+"!==l&&(N=!1),h=(N?"("===l?l:f:"-"===l||"("===l?"":l)+h,M=("s"===_?Xa[8+La/3]:"")+M+(N&&"("===l?")":""),w)for(i=-1,o=t.length;++i<o;)if(48>(c=t.charCodeAt(i))||c>57){M=(46===c?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}v&&!d&&(t=r(t,1/0));var T=h.length+t.length+M.length,A=T<p?new Array(p-T+1).join(n):"";switch(v&&d&&(t=r(A+t,A.length?p-M.length:1/0),A=""),e){case"<":t=h+t+M+A;break;case"=":t=h+A+t+M;break;case"^":t=A.slice(0,T=A.length>>1)+h+t+M+A.slice(T);break;default:t=A+h+t+M}return u(t)}return g=void 0===g?6:/[gprs]/.test(_)?Math.max(1,Math.min(21,g)):Math.max(0,Math.min(20,g)),M.toString=function(){return t+""},M}return{format:l,formatPrefix:function(t,n){var e=l(((t=Oa(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(qa(n)/3))),i=Math.pow(10,-r),o=Xa[8+r/3];return function(t){return e(i*t)+o}}}}function Ga(n){return Ha=Va(n),t.format=Ha.format,t.formatPrefix=Ha.formatPrefix,Ha}function $a(t){return Math.max(0,-qa(Math.abs(t)))}function Wa(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(qa(n)/3)))-qa(Math.abs(t)))}function Za(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,qa(n)-qa(t))+1}function Qa(){return new Ka}function Ka(){this.reset()}Ga({decimal:".",thousands:",",grouping:[3],currency:["$",""],minus:"-"}),Ka.prototype={constructor:Ka,reset:function(){this.s=this.t=0},add:function(t){tu(Ja,t,this.t),tu(this,Ja.s,this.s),this.s?this.t+=Ja.t:this.s=Ja.t},valueOf:function(){return this.s}};var Ja=new Ka;function tu(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}var nu=1e-6,eu=1e-12,ru=Math.PI,iu=ru/2,ou=ru/4,au=2*ru,uu=180/ru,cu=ru/180,fu=Math.abs,su=Math.atan,lu=Math.atan2,hu=Math.cos,du=Math.ceil,pu=Math.exp,vu=Math.log,gu=Math.pow,yu=Math.sin,_u=Math.sign||function(t){return t>0?1:t<0?-1:0},bu=Math.sqrt,mu=Math.tan;function xu(t){return t>1?0:t<-1?ru:Math.acos(t)}function wu(t){return t>1?iu:t<-1?-iu:Math.asin(t)}function Mu(t){return(t=yu(t/2))*t}function Nu(){}function Tu(t,n){t&&Su.hasOwnProperty(t.type)&&Su[t.type](t,n)}var Au={Feature:function(t,n){Tu(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)Tu(e[r].geometry,n)}},Su={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){ku(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)ku(e[r],n,0)},Polygon:function(t,n){Eu(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Eu(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)Tu(e[r],n)}};function ku(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function Eu(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)ku(t[e],n,1);n.polygonEnd()}function Cu(t,n){t&&Au.hasOwnProperty(t.type)?Au[t.type](t,n):Tu(t,n)}var Pu,zu,Ru,Du,qu,Lu=Qa(),Uu=Qa(),Ou={point:Nu,lineStart:Nu,lineEnd:Nu,polygonStart:function(){Lu.reset(),Ou.lineStart=Bu,Ou.lineEnd=Fu},polygonEnd:function(){var t=+Lu;Uu.add(t<0?au+t:t),this.lineStart=this.lineEnd=this.point=Nu},sphere:function(){Uu.add(au)}};function Bu(){Ou.point=Yu}function Fu(){Iu(Pu,zu)}function Yu(t,n){Ou.point=Iu,Pu=t,zu=n,Ru=t*=cu,Du=hu(n=(n*=cu)/2+ou),qu=yu(n)}function Iu(t,n){var e=(t*=cu)-Ru,r=e>=0?1:-1,i=r*e,o=hu(n=(n*=cu)/2+ou),a=yu(n),u=qu*a,c=Du*o+u*hu(i),f=u*r*yu(i);Lu.add(lu(f,c)),Ru=t,Du=o,qu=a}function Hu(t){return[lu(t[1],t[0]),wu(t[2])]}function ju(t){var n=t[0],e=t[1],r=hu(e);return[r*hu(n),r*yu(n),yu(e)]}function Xu(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Vu(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Gu(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function $u(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function Wu(t){var n=bu(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var Zu,Qu,Ku,Ju,tc,nc,ec,rc,ic,oc,ac,uc,cc,fc,sc,lc,hc,dc,pc,vc,gc,yc,_c,bc,mc,xc,wc=Qa(),Mc={point:Nc,lineStart:Ac,lineEnd:Sc,polygonStart:function(){Mc.point=kc,Mc.lineStart=Ec,Mc.lineEnd=Cc,wc.reset(),Ou.polygonStart()},polygonEnd:function(){Ou.polygonEnd(),Mc.point=Nc,Mc.lineStart=Ac,Mc.lineEnd=Sc,Lu<0?(Zu=-(Ku=180),Qu=-(Ju=90)):wc>nu?Ju=90:wc<-nu&&(Qu=-90),oc[0]=Zu,oc[1]=Ku},sphere:function(){Zu=-(Ku=180),Qu=-(Ju=90)}};function Nc(t,n){ic.push(oc=[Zu=t,Ku=t]),n<Qu&&(Qu=n),n>Ju&&(Ju=n)}function Tc(t,n){var e=ju([t*cu,n*cu]);if(rc){var r=Vu(rc,e),i=Vu([r[1],-r[0],0],r);Wu(i),i=Hu(i);var o,a=t-tc,u=a>0?1:-1,c=i[0]*uu*u,f=fu(a)>180;f^(u*tc<c&&c<u*t)?(o=i[1]*uu)>Ju&&(Ju=o):f^(u*tc<(c=(c+360)%360-180)&&c<u*t)?(o=-i[1]*uu)<Qu&&(Qu=o):(n<Qu&&(Qu=n),n>Ju&&(Ju=n)),f?t<tc?Pc(Zu,t)>Pc(Zu,Ku)&&(Ku=t):Pc(t,Ku)>Pc(Zu,Ku)&&(Zu=t):Ku>=Zu?(t<Zu&&(Zu=t),t>Ku&&(Ku=t)):t>tc?Pc(Zu,t)>Pc(Zu,Ku)&&(Ku=t):Pc(t,Ku)>Pc(Zu,Ku)&&(Zu=t)}else ic.push(oc=[Zu=t,Ku=t]);n<Qu&&(Qu=n),n>Ju&&(Ju=n),rc=e,tc=t}function Ac(){Mc.point=Tc}function Sc(){oc[0]=Zu,oc[1]=Ku,Mc.point=Nc,rc=null}function kc(t,n){if(rc){var e=t-tc;wc.add(fu(e)>180?e+(e>0?360:-360):e)}else nc=t,ec=n;Ou.point(t,n),Tc(t,n)}function Ec(){Ou.lineStart()}function Cc(){kc(nc,ec),Ou.lineEnd(),fu(wc)>nu&&(Zu=-(Ku=180)),oc[0]=Zu,oc[1]=Ku,rc=null}function Pc(t,n){return(n-=t)<0?n+360:n}function zc(t,n){return t[0]-n[0]}function Rc(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var Dc={sphere:Nu,point:qc,lineStart:Uc,lineEnd:Fc,polygonStart:function(){Dc.lineStart=Yc,Dc.lineEnd=Ic},polygonEnd:function(){Dc.lineStart=Uc,Dc.lineEnd=Fc}};function qc(t,n){t*=cu;var e=hu(n*=cu);Lc(e*hu(t),e*yu(t),yu(n))}function Lc(t,n,e){cc+=(t-cc)/++ac,fc+=(n-fc)/ac,sc+=(e-sc)/ac}function Uc(){Dc.point=Oc}function Oc(t,n){t*=cu;var e=hu(n*=cu);bc=e*hu(t),mc=e*yu(t),xc=yu(n),Dc.point=Bc,Lc(bc,mc,xc)}function Bc(t,n){t*=cu;var e=hu(n*=cu),r=e*hu(t),i=e*yu(t),o=yu(n),a=lu(bu((a=mc*o-xc*i)*a+(a=xc*r-bc*o)*a+(a=bc*i-mc*r)*a),bc*r+mc*i+xc*o);uc+=a,lc+=a*(bc+(bc=r)),hc+=a*(mc+(mc=i)),dc+=a*(xc+(xc=o)),Lc(bc,mc,xc)}function Fc(){Dc.point=qc}function Yc(){Dc.point=Hc}function Ic(){jc(yc,_c),Dc.point=qc}function Hc(t,n){yc=t,_c=n,t*=cu,n*=cu,Dc.point=jc;var e=hu(n);bc=e*hu(t),mc=e*yu(t),xc=yu(n),Lc(bc,mc,xc)}function jc(t,n){t*=cu;var e=hu(n*=cu),r=e*hu(t),i=e*yu(t),o=yu(n),a=mc*o-xc*i,u=xc*r-bc*o,c=bc*i-mc*r,f=bu(a*a+u*u+c*c),s=wu(f),l=f&&-s/f;pc+=l*a,vc+=l*u,gc+=l*c,uc+=s,lc+=s*(bc+(bc=r)),hc+=s*(mc+(mc=i)),dc+=s*(xc+(xc=o)),Lc(bc,mc,xc)}function Xc(t){return function(){return t}}function Vc(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e}function Gc(t,n){return[fu(t)>ru?t+Math.round(-t/au)*au:t,n]}function $c(t,n,e){return(t%=au)?n||e?Vc(Zc(t),Qc(n,e)):Zc(t):n||e?Qc(n,e):Gc}function Wc(t){return function(n,e){return[(n+=t)>ru?n-au:n<-ru?n+au:n,e]}}function Zc(t){var n=Wc(t);return n.invert=Wc(-t),n}function Qc(t,n){var e=hu(t),r=yu(t),i=hu(n),o=yu(n);function a(t,n){var a=hu(n),u=hu(t)*a,c=yu(t)*a,f=yu(n),s=f*e+u*r;return[lu(c*i-s*o,u*e-f*r),wu(s*i+c*o)]}return a.invert=function(t,n){var a=hu(n),u=hu(t)*a,c=yu(t)*a,f=yu(n),s=f*i-c*o;return[lu(c*i+f*o,u*e+s*r),wu(s*e-u*r)]},a}function Kc(t){function n(n){return(n=t(n[0]*cu,n[1]*cu))[0]*=uu,n[1]*=uu,n}return t=$c(t[0]*cu,t[1]*cu,t.length>2?t[2]*cu:0),n.invert=function(n){return(n=t.invert(n[0]*cu,n[1]*cu))[0]*=uu,n[1]*=uu,n},n}function Jc(t,n,e,r,i,o){if(e){var a=hu(n),u=yu(n),c=r*e;null==i?(i=n+r*au,o=n-c/2):(i=tf(a,i),o=tf(a,o),(r>0?i<o:i>o)&&(i+=r*au));for(var f,s=i;r>0?s>o:s<o;s-=c)f=Hu([a,-u*hu(s),-u*yu(s)]),t.point(f[0],f[1])}}function tf(t,n){(n=ju(n))[0]-=t,Wu(n);var e=xu(-n[1]);return((-n[2]<0?-e:e)+au-nu)%au}function nf(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:Nu,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function ef(t,n){return fu(t[0]-n[0])<nu&&fu(t[1]-n[1])<nu}function rf(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function of(t,n,e,r,i){var o,a,u=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],a=t[n];if(ef(r,a)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else u.push(e=new rf(r,t,null,!0)),c.push(e.o=new rf(r,null,e,!1)),u.push(e=new rf(a,t,null,!1)),c.push(e.o=new rf(a,null,e,!0))}}),u.length){for(c.sort(n),af(u),af(c),o=0,a=c.length;o<a;++o)c[o].e=e=!e;for(var f,s,l=u[0];;){for(var h=l,d=!0;h.v;)if((h=h.n)===l)return;f=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(d)for(o=0,a=f.length;o<a;++o)i.point((s=f[o])[0],s[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(d)for(f=h.p.z,o=f.length-1;o>=0;--o)i.point((s=f[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}f=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function af(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}Gc.invert=Gc;var uf=Qa();function cf(t){return fu(t[0])<=ru?t[0]:_u(t[0])*((fu(t[0])+ru)%au-ru)}function ff(t,n){var e=cf(n),r=n[1],i=yu(r),o=[yu(e),-hu(e),0],a=0,u=0;uf.reset(),1===i?r=iu+nu:-1===i&&(r=-iu-nu);for(var c=0,f=t.length;c<f;++c)if(l=(s=t[c]).length)for(var s,l,h=s[l-1],d=cf(h),p=h[1]/2+ou,v=yu(p),g=hu(p),y=0;y<l;++y,d=b,v=x,g=w,h=_){var _=s[y],b=cf(_),m=_[1]/2+ou,x=yu(m),w=hu(m),M=b-d,N=M>=0?1:-1,T=N*M,A=T>ru,S=v*x;if(uf.add(lu(S*N*yu(T),g*w+S*hu(T))),a+=A?M+N*au:M,A^d>=e^b>=e){var k=Vu(ju(h),ju(_));Wu(k);var E=Vu(o,k);Wu(E);var C=(A^M>=0?-1:1)*wu(E[2]);(r>C||r===C&&(k[0]||k[1]))&&(u+=A^M>=0?1:-1)}}return(a<-nu||a<nu&&uf<-nu)^1&u}function sf(t,n,e,r){return function(i){var o,a,u,c=n(i),f=nf(),s=n(f),l=!1,h={point:d,lineStart:v,lineEnd:g,polygonStart:function(){h.point=y,h.lineStart=_,h.lineEnd=b,a=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=v,h.lineEnd=g,a=A(a);var t=ff(o,r);a.length?(l||(i.polygonStart(),l=!0),of(a,hf,t,e,i)):t&&(l||(i.polygonStart(),l=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),l&&(i.polygonEnd(),l=!1),a=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){c.point(t,n)}function v(){h.point=p,c.lineStart()}function g(){h.point=d,c.lineEnd()}function y(t,n){u.push([t,n]),s.point(t,n)}function _(){s.lineStart(),u=[]}function b(){y(u[0][0],u[0][1]),s.lineEnd();var t,n,e,r,c=s.clean(),h=f.result(),d=h.length;if(u.pop(),o.push(u),u=null,d)if(1&c){if((n=(e=h[0]).length-1)>0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t<n;++t)i.point((r=e[t])[0],r[1]);i.lineEnd()}}else d>1&&2&c&&h.push(h.pop().concat(h.shift())),a.push(h.filter(lf))}return h}}function lf(t){return t.length>1}function hf(t,n){return((t=t.x)[0]<0?t[1]-iu-nu:iu-t[1])-((n=n.x)[0]<0?n[1]-iu-nu:iu-n[1])}var df=sf(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?ru:-ru,c=fu(o-e);fu(c-ru)<nu?(t.point(e,r=(r+a)/2>0?iu:-iu),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&c>=ru&&(fu(e-i)<nu&&(e-=i*nu),fu(o-u)<nu&&(o-=u*nu),r=function(t,n,e,r){var i,o,a=yu(t-e);return fu(a)>nu?su((yu(n)*(o=hu(r))*yu(e)-yu(r)*(i=hu(n))*yu(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*iu,r.point(-ru,i),r.point(0,i),r.point(ru,i),r.point(ru,0),r.point(ru,-i),r.point(0,-i),r.point(-ru,-i),r.point(-ru,0),r.point(-ru,i);else if(fu(t[0]-n[0])>nu){var o=t[0]<n[0]?ru:-ru;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-ru,-iu]);function pf(t){var n=hu(t),e=6*cu,r=n>0,i=fu(n)>nu;function o(t,e){return hu(t)*hu(e)>n}function a(t,e,r){var i=[1,0,0],o=Vu(ju(t),ju(e)),a=Xu(o,o),u=o[0],c=a-u*u;if(!c)return!r&&t;var f=n*a/c,s=-n*u/c,l=Vu(i,o),h=$u(i,f);Gu(h,$u(o,s));var d=l,p=Xu(h,d),v=Xu(d,d),g=p*p-v*(Xu(h,h)-1);if(!(g<0)){var y=bu(g),_=$u(d,(-p-y)/v);if(Gu(_,h),_=Hu(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x<m&&(b=m,m=x,x=b);var N=x-m,T=fu(N-ru)<nu;if(!T&&M<w&&(b=w,w=M,M=b),T||N<nu?T?w+M>0^_[1]<(fu(_[0]-m)<nu?w:M):w<=_[1]&&_[1]<=M:N>ru^(m<=_[0]&&_[0]<=x)){var A=$u(d,(-p+y)/v);return Gu(A,h),[_,Hu(A)]}}}function u(n,e){var i=r?t:ru-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return sf(o,function(t){var n,e,c,f,s;return{lineStart:function(){f=c=!1,s=1},point:function(l,h){var d,p=[l,h],v=o(l,h),g=r?v?0:u(l,h):v?u(l+(l<0?ru:-ru),h):0;if(!n&&(f=c=v)&&t.lineStart(),v!==c&&(!(d=a(n,p))||ef(n,d)||ef(p,d))&&(p[0]+=nu,p[1]+=nu,v=o(p[0],p[1])),v!==c)s=0,v?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1]),t.lineEnd()),n=d;else if(i&&n&&r^v){var y;g&e||!(y=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&ef(n,p)||t.point(p[0],p[1]),n=p,c=v,e=g},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return s|(f&&c)<<1}}},function(n,r,i,o){Jc(o,t,e,i,n,r)},r?[0,-t]:[-ru,t-ru])}var vf=1e9,gf=-vf;function yf(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,f){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||c(i,o)<0^u>0)do{f.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else f.point(o[0],o[1])}function a(r,i){return fu(r[0]-t)<nu?i>0?0:3:fu(r[0]-e)<nu?i>0?2:1:fu(r[1]-n)<nu?i>0?1:0:i>0?3:2}function u(t,n){return c(t.x,n.x)}function c(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var c,f,s,l,h,d,p,v,g,y,_,b=a,m=nf(),x={point:w,lineStart:function(){x.point=M,f&&f.push(s=[]);y=!0,g=!1,p=v=NaN},lineEnd:function(){c&&(M(l,h),d&&g&&m.rejoin(),c.push(m.result()));x.point=w,g&&b.lineEnd()},polygonStart:function(){b=m,c=[],f=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=f.length;e<i;++e)for(var o,a,u=f[e],c=1,s=u.length,l=u[0],h=l[0],d=l[1];c<s;++c)o=h,a=d,l=u[c],h=l[0],d=l[1],a<=r?d>r&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(c=A(c)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&of(c,u,n,o,a),a.polygonEnd());b=a,c=f=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(f&&s.push([o,a]),y)l=o,h=a,d=u,y=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&g)b.point(o,a);else{var c=[p=Math.max(gf,Math.min(vf,p)),v=Math.max(gf,Math.min(vf,v))],m=[o=Math.max(gf,Math.min(vf,o)),a=Math.max(gf,Math.min(vf,a))];!function(t,n,e,r,i,o){var a,u=t[0],c=t[1],f=0,s=1,l=n[0]-u,h=n[1]-c;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a<f)return;a<s&&(s=a)}else if(l>0){if(a>s)return;a>f&&(f=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>f&&(f=a)}else if(l>0){if(a<f)return;a<s&&(s=a)}if(a=r-c,h||!(a>0)){if(a/=h,h<0){if(a<f)return;a<s&&(s=a)}else if(h>0){if(a>s)return;a>f&&(f=a)}if(a=o-c,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>f&&(f=a)}else if(h>0){if(a<f)return;a<s&&(s=a)}return f>0&&(t[0]=u+f*l,t[1]=c+f*h),s<1&&(n[0]=u+s*l,n[1]=c+s*h),!0}}}}}(c,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(g||(b.lineStart(),b.point(c[0],c[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,v=a,g=u}return x}}var _f,bf,mf,xf=Qa(),wf={sphere:Nu,point:Nu,lineStart:function(){wf.point=Nf,wf.lineEnd=Mf},lineEnd:Nu,polygonStart:Nu,polygonEnd:Nu};function Mf(){wf.point=wf.lineEnd=Nu}function Nf(t,n){_f=t*=cu,bf=yu(n*=cu),mf=hu(n),wf.point=Tf}function Tf(t,n){t*=cu;var e=yu(n*=cu),r=hu(n),i=fu(t-_f),o=hu(i),a=r*yu(i),u=mf*e-bf*r*o,c=bf*e+mf*r*o;xf.add(lu(bu(a*a+u*u),c)),_f=t,bf=e,mf=r}function Af(t){return xf.reset(),Cu(t,wf),+xf}var Sf=[null,null],kf={type:"LineString",coordinates:Sf};function Ef(t,n){return Sf[0]=t,Sf[1]=n,Af(kf)}var Cf={Feature:function(t,n){return zf(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(zf(e[r].geometry,n))return!0;return!1}},Pf={Sphere:function(){return!0},Point:function(t,n){return Rf(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Rf(e[r],n))return!0;return!1},LineString:function(t,n){return Df(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Df(e[r],n))return!0;return!1},Polygon:function(t,n){return qf(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(qf(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(zf(e[r],n))return!0;return!1}};function zf(t,n){return!(!t||!Pf.hasOwnProperty(t.type))&&Pf[t.type](t,n)}function Rf(t,n){return 0===Ef(t,n)}function Df(t,n){for(var e,r,i,o=0,a=t.length;o<a;o++){if(0===(r=Ef(t[o],n)))return!0;if(o>0&&(i=Ef(t[o],t[o-1]))>0&&e<=i&&r<=i&&(e+r-i)*(1-Math.pow((e-r)/i,2))<eu*i)return!0;e=r}return!1}function qf(t,n){return!!ff(t.map(Lf),Uf(n))}function Lf(t){return(t=t.map(Uf)).pop(),t}function Uf(t){return[t[0]*cu,t[1]*cu]}function Of(t,n,e){var r=g(t,n-nu,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function Bf(t,n,e){var r=g(t,n-nu,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function Ff(){var t,n,e,r,i,o,a,u,c,f,s,l,h=10,d=h,p=90,v=360,y=2.5;function _(){return{type:"MultiLineString",coordinates:b()}}function b(){return g(du(r/p)*p,e,p).map(s).concat(g(du(u/v)*v,a,v).map(l)).concat(g(du(n/h)*h,t,h).filter(function(t){return fu(t%p)>nu}).map(c)).concat(g(du(o/d)*d,i,d).filter(function(t){return fu(t%v)>nu}).map(f))}return _.lines=function(){return b().map(function(t){return{type:"LineString",coordinates:t}})},_.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},_.extent=function(t){return arguments.length?_.extentMajor(t).extentMinor(t):_.extentMinor()},_.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),_.precision(y)):[[r,u],[e,a]]},_.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),_.precision(y)):[[n,o],[t,i]]},_.step=function(t){return arguments.length?_.stepMajor(t).stepMinor(t):_.stepMinor()},_.stepMajor=function(t){return arguments.length?(p=+t[0],v=+t[1],_):[p,v]},_.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],_):[h,d]},_.precision=function(h){return arguments.length?(y=+h,c=Of(o,i,90),f=Bf(n,t,y),s=Of(u,a,90),l=Bf(r,e,y),_):y},_.extentMajor([[-180,-90+nu],[180,90-nu]]).extentMinor([[-180,-80-nu],[180,80+nu]])}function Yf(t){return t}var If,Hf,jf,Xf,Vf=Qa(),Gf=Qa(),$f={point:Nu,lineStart:Nu,lineEnd:Nu,polygonStart:function(){$f.lineStart=Wf,$f.lineEnd=Kf},polygonEnd:function(){$f.lineStart=$f.lineEnd=$f.point=Nu,Vf.add(fu(Gf)),Gf.reset()},result:function(){var t=Vf/2;return Vf.reset(),t}};function Wf(){$f.point=Zf}function Zf(t,n){$f.point=Qf,If=jf=t,Hf=Xf=n}function Qf(t,n){Gf.add(Xf*t-jf*n),jf=t,Xf=n}function Kf(){Qf(If,Hf)}var Jf=1/0,ts=Jf,ns=-Jf,es=ns,rs={point:function(t,n){t<Jf&&(Jf=t);t>ns&&(ns=t);n<ts&&(ts=n);n>es&&(es=n)},lineStart:Nu,lineEnd:Nu,polygonStart:Nu,polygonEnd:Nu,result:function(){var t=[[Jf,ts],[ns,es]];return ns=es=-(ts=Jf=1/0),t}};var is,os,as,us,cs=0,fs=0,ss=0,ls=0,hs=0,ds=0,ps=0,vs=0,gs=0,ys={point:_s,lineStart:bs,lineEnd:ws,polygonStart:function(){ys.lineStart=Ms,ys.lineEnd=Ns},polygonEnd:function(){ys.point=_s,ys.lineStart=bs,ys.lineEnd=ws},result:function(){var t=gs?[ps/gs,vs/gs]:ds?[ls/ds,hs/ds]:ss?[cs/ss,fs/ss]:[NaN,NaN];return cs=fs=ss=ls=hs=ds=ps=vs=gs=0,t}};function _s(t,n){cs+=t,fs+=n,++ss}function bs(){ys.point=ms}function ms(t,n){ys.point=xs,_s(as=t,us=n)}function xs(t,n){var e=t-as,r=n-us,i=bu(e*e+r*r);ls+=i*(as+t)/2,hs+=i*(us+n)/2,ds+=i,_s(as=t,us=n)}function ws(){ys.point=_s}function Ms(){ys.point=Ts}function Ns(){As(is,os)}function Ts(t,n){ys.point=As,_s(is=as=t,os=us=n)}function As(t,n){var e=t-as,r=n-us,i=bu(e*e+r*r);ls+=i*(as+t)/2,hs+=i*(us+n)/2,ds+=i,ps+=(i=us*t-as*n)*(as+t),vs+=i*(us+n),gs+=3*i,_s(as=t,us=n)}function Ss(t){this._context=t}Ss.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,au)}},result:Nu};var ks,Es,Cs,Ps,zs,Rs=Qa(),Ds={point:Nu,lineStart:function(){Ds.point=qs},lineEnd:function(){ks&&Ls(Es,Cs),Ds.point=Nu},polygonStart:function(){ks=!0},polygonEnd:function(){ks=null},result:function(){var t=+Rs;return Rs.reset(),t}};function qs(t,n){Ds.point=Ls,Es=Ps=t,Cs=zs=n}function Ls(t,n){Ps-=t,zs-=n,Rs.add(bu(Ps*Ps+zs*zs)),Ps=t,zs=n}function Us(){this._string=[]}function Os(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function Bs(t){return function(n){var e=new Fs;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Fs(){}function Ys(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),Cu(e,t.stream(rs)),n(rs.result()),null!=r&&t.clipExtent(r),t}function Is(t,n,e){return Ys(t,function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),a=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,u=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([a,u])},e)}function Hs(t,n,e){return Is(t,[[0,0],n],e)}function js(t,n,e){return Ys(t,function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,a=-i*e[0][1];t.scale(150*i).translate([o,a])},e)}function Xs(t,n,e){return Ys(t,function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],a=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,a])},e)}Us.prototype={_radius:4.5,_circle:Os(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=Os(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}},Fs.prototype={constructor:Fs,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Vs=16,Gs=hu(30*cu);function $s(t,n){return+n?function(t,n){function e(r,i,o,a,u,c,f,s,l,h,d,p,v,g){var y=f-r,_=s-i,b=y*y+_*_;if(b>4*n&&v--){var m=a+h,x=u+d,w=c+p,M=bu(m*m+x*x+w*w),N=wu(w/=M),T=fu(fu(w)-1)<nu||fu(o-l)<nu?(o+l)/2:lu(x,m),A=t(T,N),S=A[0],k=A[1],E=S-r,C=k-i,P=_*E-y*C;(P*P/b>n||fu((y*E+_*C)/b-.5)>.3||a*h+u*d+c*p<Gs)&&(e(r,i,o,a,u,c,S,k,T,m/=M,x/=M,w,v,g),g.point(S,k),e(S,k,T,m,x,w,f,s,l,h,d,p,v,g))}}return function(n){var r,i,o,a,u,c,f,s,l,h,d,p,v={point:g,lineStart:y,lineEnd:b,polygonStart:function(){n.polygonStart(),v.lineStart=m},polygonEnd:function(){n.polygonEnd(),v.lineStart=y}};function g(e,r){e=t(e,r),n.point(e[0],e[1])}function y(){s=NaN,v.point=_,n.lineStart()}function _(r,i){var o=ju([r,i]),a=t(r,i);e(s,l,f,h,d,p,s=a[0],l=a[1],f=r,h=o[0],d=o[1],p=o[2],Vs,n),n.point(s,l)}function b(){v.point=g,n.lineEnd()}function m(){y(),v.point=x,v.lineEnd=w}function x(t,n){_(r=t,n),i=s,o=l,a=h,u=d,c=p,v.point=_}function w(){e(s,l,f,h,d,p,i,o,r,a,u,c,Vs,n),v.lineEnd=b,b()}return v}}(t,n):function(t){return Bs({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}(t)}var Ws=Bs({point:function(t,n){this.stream.point(t*cu,n*cu)}});function Zs(t,n,e,r,i,o){var a=hu(o),u=yu(o),c=a*t,f=u*t,s=a/t,l=u/t,h=(u*e-a*n)/t,d=(u*n+a*e)/t;function p(t,o){return[c*(t*=r)-f*(o*=i)+n,e-f*t-c*o]}return p.invert=function(t,n){return[r*(s*t-l*n+h),i*(d-l*t-s*n)]},p}function Qs(t){return Ks(function(){return t})()}function Ks(t){var n,e,r,i,o,a,u,c,f,s,l=150,h=480,d=250,p=0,v=0,g=0,y=0,_=0,b=0,m=1,x=1,w=null,M=df,N=null,T=Yf,A=.5;function S(t){return c(t[0]*cu,t[1]*cu)}function k(t){return(t=c.invert(t[0],t[1]))&&[t[0]*uu,t[1]*uu]}function E(){var t=Zs(l,0,0,m,x,b).apply(null,n(p,v)),r=(b?Zs:function(t,n,e,r,i){function o(o,a){return[n+t*(o*=r),e-t*(a*=i)]}return o.invert=function(o,a){return[(o-n)/t*r,(e-a)/t*i]},o})(l,h-t[0],d-t[1],m,x,b);return e=$c(g,y,_),u=Vc(n,r),c=Vc(e,u),a=$s(u,A),C()}function C(){return f=s=null,S}return S.stream=function(t){return f&&s===t?f:f=Ws(function(t){return Bs({point:function(n,e){var r=t(n,e);return this.stream.point(r[0],r[1])}})}(e)(M(a(T(s=t)))))},S.preclip=function(t){return arguments.length?(M=t,w=void 0,C()):M},S.postclip=function(t){return arguments.length?(T=t,N=r=i=o=null,C()):T},S.clipAngle=function(t){return arguments.length?(M=+t?pf(w=t*cu):(w=null,df),C()):w*uu},S.clipExtent=function(t){return arguments.length?(T=null==t?(N=r=i=o=null,Yf):yf(N=+t[0][0],r=+t[0][1],i=+t[1][0],o=+t[1][1]),C()):null==N?null:[[N,r],[i,o]]},S.scale=function(t){return arguments.length?(l=+t,E()):l},S.translate=function(t){return arguments.length?(h=+t[0],d=+t[1],E()):[h,d]},S.center=function(t){return arguments.length?(p=t[0]%360*cu,v=t[1]%360*cu,E()):[p*uu,v*uu]},S.rotate=function(t){return arguments.length?(g=t[0]%360*cu,y=t[1]%360*cu,_=t.length>2?t[2]%360*cu:0,E()):[g*uu,y*uu,_*uu]},S.angle=function(t){return arguments.length?(b=t%360*cu,E()):b*uu},S.reflectX=function(t){return arguments.length?(m=t?-1:1,E()):m<0},S.reflectY=function(t){return arguments.length?(x=t?-1:1,E()):x<0},S.precision=function(t){return arguments.length?(a=$s(u,A=t*t),C()):bu(A)},S.fitExtent=function(t,n){return Is(S,t,n)},S.fitSize=function(t,n){return Hs(S,t,n)},S.fitWidth=function(t,n){return js(S,t,n)},S.fitHeight=function(t,n){return Xs(S,t,n)},function(){return n=t.apply(this,arguments),S.invert=n.invert&&k,E()}}function Js(t){var n=0,e=ru/3,r=Ks(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*cu,e=t[1]*cu):[n*uu,e*uu]},i}function tl(t,n){var e=yu(t),r=(e+yu(n))/2;if(fu(r)<nu)return function(t){var n=hu(t);function e(t,e){return[t*n,yu(e)/n]}return e.invert=function(t,e){return[t/n,wu(e*n)]},e}(t);var i=1+e*(2*r-e),o=bu(i)/r;function a(t,n){var e=bu(i-2*r*yu(n))/r;return[e*yu(t*=r),o-e*hu(t)]}return a.invert=function(t,n){var e=o-n,a=lu(t,fu(e))*_u(e);return e*r<0&&(a-=ru*_u(t)*_u(e)),[a/r,wu((i-(t*t+e*e)*r*r)/(2*r))]},a}function nl(){return Js(tl).scale(155.424).center([0,33.6442])}function el(){return nl().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])}function rl(t){return function(n,e){var r=hu(n),i=hu(e),o=t(r*i);return[o*i*yu(n),o*yu(e)]}}function il(t){return function(n,e){var r=bu(n*n+e*e),i=t(r),o=yu(i),a=hu(i);return[lu(n*o,r*a),wu(r&&e*o/r)]}}var ol=rl(function(t){return bu(2/(1+t))});ol.invert=il(function(t){return 2*wu(t/2)});var al=rl(function(t){return(t=xu(t))&&t/yu(t)});function ul(t,n){return[t,vu(mu((iu+n)/2))]}function cl(t){var n,e,r,i=Qs(t),o=i.center,a=i.scale,u=i.translate,c=i.clipExtent,f=null;function s(){var o=ru*a(),u=i(Kc(i.rotate()).invert([0,0]));return c(null==f?[[u[0]-o,u[1]-o],[u[0]+o,u[1]+o]]:t===ul?[[Math.max(u[0]-o,f),n],[Math.min(u[0]+o,e),r]]:[[f,Math.max(u[1]-o,n)],[e,Math.min(u[1]+o,r)]])}return i.scale=function(t){return arguments.length?(a(t),s()):a()},i.translate=function(t){return arguments.length?(u(t),s()):u()},i.center=function(t){return arguments.length?(o(t),s()):o()},i.clipExtent=function(t){return arguments.length?(null==t?f=n=e=r=null:(f=+t[0][0],n=+t[0][1],e=+t[1][0],r=+t[1][1]),s()):null==f?null:[[f,n],[e,r]]},s()}function fl(t){return mu((iu+t)/2)}function sl(t,n){var e=hu(t),r=t===n?yu(t):vu(e/hu(n))/vu(fl(n)/fl(t)),i=e*gu(fl(t),r)/r;if(!r)return ul;function o(t,n){i>0?n<-iu+nu&&(n=-iu+nu):n>iu-nu&&(n=iu-nu);var e=i/gu(fl(n),r);return[e*yu(r*t),i-e*hu(r*t)]}return o.invert=function(t,n){var e=i-n,o=_u(r)*bu(t*t+e*e),a=lu(t,fu(e))*_u(e);return e*r<0&&(a-=ru*_u(t)*_u(e)),[a/r,2*su(gu(i/o,1/r))-iu]},o}function ll(t,n){return[t,n]}function hl(t,n){var e=hu(t),r=t===n?yu(t):(e-hu(n))/(n-t),i=e/r+t;if(fu(r)<nu)return ll;function o(t,n){var e=i-n,o=r*t;return[e*yu(o),i-e*hu(o)]}return o.invert=function(t,n){var e=i-n,o=lu(t,fu(e))*_u(e);return e*r<0&&(o-=ru*_u(t)*_u(e)),[o/r,i-_u(r)*bu(t*t+e*e)]},o}al.invert=il(function(t){return t}),ul.invert=function(t,n){return[t,2*su(pu(n))-iu]},ll.invert=ll;var dl=1.340264,pl=-.081106,vl=893e-6,gl=.003796,yl=bu(3)/2;function _l(t,n){var e=wu(yl*yu(n)),r=e*e,i=r*r*r;return[t*hu(e)/(yl*(dl+3*pl*r+i*(7*vl+9*gl*r))),e*(dl+pl*r+i*(vl+gl*r))]}function bl(t,n){var e=hu(n),r=hu(t)*e;return[e*yu(t)/r,yu(n)/r]}function ml(t,n){var e=n*n,r=e*e;return[t*(.8707-.131979*e+r*(r*(.003971*e-.001529*r)-.013791)),n*(1.007226+e*(.015085+r*(.028874*e-.044475-.005916*r)))]}function xl(t,n){return[hu(n)*yu(t),yu(n)]}function wl(t,n){var e=hu(n),r=1+hu(t)*e;return[e*yu(t)/r,yu(n)/r]}function Ml(t,n){return[vu(mu((iu+n)/2)),-t]}function Nl(t,n){return t.parent===n.parent?1:2}function Tl(t,n){return t+n.x}function Al(t,n){return Math.max(t,n.y)}function Sl(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function kl(t,n){var e,r,i,o,a,u=new zl(t),c=+t.value&&(u.value=t.value),f=[u];for(null==n&&(n=El);e=f.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(a=i.length))for(e.children=new Array(a),o=a-1;o>=0;--o)f.push(r=e.children[o]=new zl(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(Pl)}function El(t){return t.children}function Cl(t){t.data=t.data.data}function Pl(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function zl(t){this.data=t,this.depth=this.height=0,this.parent=null}_l.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(dl+pl*i+o*(vl+gl*i))-n)/(dl+3*pl*i+o*(7*vl+9*gl*i)))*r)*i*i,!(fu(e)<eu));++a);return[yl*t*(dl+3*pl*i+o*(7*vl+9*gl*i))/hu(r),wu(yu(r)/yl)]},bl.invert=il(su),ml.invert=function(t,n){var e,r=n,i=25;do{var o=r*r,a=o*o;r-=e=(r*(1.007226+o*(.015085+a*(.028874*o-.044475-.005916*a)))-n)/(1.007226+o*(.045255+a*(.259866*o-.311325-.005916*11*a)))}while(fu(e)>nu&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},xl.invert=il(wu),wl.invert=il(function(t){return 2*su(t)}),Ml.invert=function(t,n){return[-n,2*su(pu(t))-iu]},zl.prototype=kl.prototype={constructor:zl,count:function(){return this.eachAfter(Sl)},each:function(t){var n,e,r,i,o=this,a=[o];do{for(n=a.reverse(),a=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)a.push(e[r])}while(a.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],a=[];i=o.pop();)if(a.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=a.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return kl(this).eachBefore(Cl)}};var Rl=Array.prototype.slice;function Dl(t){for(var n,e,r=0,i=(t=function(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}(Rl.call(t))).length,o=[];r<i;)n=t[r],e&&Ul(e,n)?++r:(e=Bl(o=ql(o,n)),r=0);return e}function ql(t,n){var e,r;if(Ol(n,t))return[n];for(e=0;e<t.length;++e)if(Ll(n,t[e])&&Ol(Fl(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(Ll(Fl(t[e],t[r]),n)&&Ll(Fl(t[e],n),t[r])&&Ll(Fl(t[r],n),t[e])&&Ol(Yl(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function Ll(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function Ul(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function Ol(t,n){for(var e=0;e<n.length;++e)if(!Ul(t,n[e]))return!1;return!0}function Bl(t){switch(t.length){case 1:return function(t){return{x:t.x,y:t.y,r:t.r}}(t[0]);case 2:return Fl(t[0],t[1]);case 3:return Yl(t[0],t[1],t[2])}}function Fl(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,a=n.y,u=n.r,c=o-e,f=a-r,s=u-i,l=Math.sqrt(c*c+f*f);return{x:(e+o+c/l*s)/2,y:(r+a+f/l*s)/2,r:(l+i+u)/2}}function Yl(t,n,e){var r=t.x,i=t.y,o=t.r,a=n.x,u=n.y,c=n.r,f=e.x,s=e.y,l=e.r,h=r-a,d=r-f,p=i-u,v=i-s,g=c-o,y=l-o,_=r*r+i*i-o*o,b=_-a*a-u*u+c*c,m=_-f*f-s*s+l*l,x=d*p-h*v,w=(p*m-v*b)/(2*x)-r,M=(v*g-p*y)/x,N=(d*b-h*m)/(2*x)-i,T=(h*y-d*g)/x,A=M*M+T*T-1,S=2*(o+w*M+N*T),k=w*w+N*N-o*o,E=-(A?(S+Math.sqrt(S*S-4*A*k))/(2*A):k/S);return{x:r+w+M*E,y:i+N+T*E,r:E}}function Il(t,n,e){var r,i,o,a,u=t.x-n.x,c=t.y-n.y,f=u*u+c*c;f?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(f+a-i)/(2*f),o=Math.sqrt(Math.max(0,a/f-r*r)),e.x=t.x-r*u-o*c,e.y=t.y-r*c+o*u):(r=(f+i-a)/(2*f),o=Math.sqrt(Math.max(0,i/f-r*r)),e.x=n.x+r*u-o*c,e.y=n.y+r*c+o*u)):(e.x=n.x+e.r,e.y=n.y)}function Hl(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function jl(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function Xl(t){this._=t,this.next=null,this.previous=null}function Vl(t){if(!(i=t.length))return 0;var n,e,r,i,o,a,u,c,f,s,l;if((n=t[0]).x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;Il(e,n,r=t[2]),n=new Xl(n),e=new Xl(e),r=new Xl(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(u=3;u<i;++u){Il(n._,e._,r=t[u]),r=new Xl(r),c=e.next,f=n.previous,s=e._.r,l=n._.r;do{if(s<=l){if(Hl(c._,r._)){e=c,n.next=e,e.previous=n,--u;continue t}s+=c._.r,c=c.next}else{if(Hl(f._,r._)){(n=f).next=e,e.previous=n,--u;continue t}l+=f._.r,f=f.previous}}while(c!==f.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=jl(n);(r=r.next)!==e;)(a=jl(r))<o&&(n=r,o=a);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Dl(n),u=0;u<i;++u)(n=t[u]).x-=r.x,n.y-=r.y;return r.r}function Gl(t){return null==t?null:$l(t)}function $l(t){if("function"!=typeof t)throw new Error;return t}function Wl(){return 0}function Zl(t){return function(){return t}}function Ql(t){return Math.sqrt(t.value)}function Kl(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function Jl(t,n){return function(e){if(r=e.children){var r,i,o,a=r.length,u=t(e)*n||0;if(u)for(i=0;i<a;++i)r[i].r+=u;if(o=Vl(r),u)for(i=0;i<a;++i)r[i].r-=u;e.r=o+u}}}function th(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function nh(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function eh(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(r-n)/t.value;++u<c;)(o=a[u]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*f}var rh="$",ih={depth:-1},oh={};function ah(t){return t.id}function uh(t){return t.parentId}function ch(t,n){return t.parent===n.parent?1:2}function fh(t){var n=t.children;return n?n[0]:t.t}function sh(t){var n=t.children;return n?n[n.length-1]:t.t}function lh(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function hh(t,n,e){return t.a.parent===n.parent?t.a:e}function dh(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function ph(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(i-e)/t.value;++u<c;)(o=a[u]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*f}dh.prototype=Object.create(zl.prototype);var vh=(1+Math.sqrt(5))/2;function gh(t,n,e,r,i,o){for(var a,u,c,f,s,l,h,d,p,v,g,y=[],_=n.children,b=0,m=0,x=_.length,w=n.value;b<x;){c=i-e,f=o-r;do{s=_[m++].value}while(!s&&m<x);for(l=h=s,g=s*s*(v=Math.max(f/c,c/f)/(w*t)),p=Math.max(h/g,g/l);m<x;++m){if(s+=u=_[m].value,u<l&&(l=u),u>h&&(h=u),g=s*s*v,(d=Math.max(h/g,g/l))>p){s-=u;break}p=d}y.push(a={value:s,dice:c<f,children:_.slice(b,m)}),a.dice?eh(a,e,r,i,w?r+=f*s/w:o):ph(a,e,r,w?e+=c*s/w:i,o),w-=s,b=m}return y}var yh=function t(n){function e(t,e,r,i,o){gh(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(vh);var _h=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,c,f,s,l=-1,h=a.length,d=t.value;++l<h;){for(c=(u=a[l]).children,f=u.value=0,s=c.length;f<s;++f)u.value+=c[f].value;u.dice?eh(u,e,r,i,r+=(o-r)*u.value/d):ph(u,e,r,e+=(i-e)*u.value/d,o),d-=u.value}else t._squarify=a=gh(n,t,e,r,i,o),a.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(vh);function bh(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function mh(t,n){return t[0]-n[0]||t[1]-n[1]}function xh(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&bh(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function wh(){return Math.random()}var Mh=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(wh),Nh=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(wh),Th=function t(n){function e(){var t=Nh.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(wh),Ah=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(wh),Sh=function t(n){function e(t){var e=Ah.source(n)(t);return function(){return e()/t}}return e.source=t,e}(wh),kh=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(wh);function Eh(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function Ch(t,n){switch(arguments.length){case 0:break;case 1:this.interpolator(t);break;default:this.interpolator(n).domain(t)}return this}var Ph=Array.prototype,zh=Ph.map,Rh=Ph.slice,Dh={name:"implicit"};function qh(){var t=co(),n=[],e=[],r=Dh;function i(i){var o=i+"",a=t.get(o);if(!a){if(r!==Dh)return r;t.set(o,a=n.push(i))}return e[(a-1)%e.length]}return i.domain=function(e){if(!arguments.length)return n.slice();n=[],t=co();for(var r,o,a=-1,u=e.length;++a<u;)t.has(o=(r=e[a])+"")||t.set(o,n.push(r));return i},i.range=function(t){return arguments.length?(e=Rh.call(t),i):e.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return qh(n,e).unknown(r)},Eh.apply(i,arguments),i}function Lh(){var t,n,e=qh().unknown(void 0),r=e.domain,i=e.range,o=[0,1],a=!1,u=0,c=0,f=.5;function s(){var e=r().length,s=o[1]<o[0],l=o[s-0],h=o[1-s];t=(h-l)/Math.max(1,e-u+2*c),a&&(t=Math.floor(t)),l+=(h-l-t*(e-u))*f,n=t*(1-u),a&&(l=Math.round(l),n=Math.round(n));var d=g(e).map(function(n){return l+t*n});return i(s?d.reverse():d)}return delete e.unknown,e.domain=function(t){return arguments.length?(r(t),s()):r()},e.range=function(t){return arguments.length?(o=[+t[0],+t[1]],s()):o.slice()},e.rangeRound=function(t){return o=[+t[0],+t[1]],a=!0,s()},e.bandwidth=function(){return n},e.step=function(){return t},e.round=function(t){return arguments.length?(a=!!t,s()):a},e.padding=function(t){return arguments.length?(u=Math.min(1,c=+t),s()):u},e.paddingInner=function(t){return arguments.length?(u=Math.min(1,t),s()):u},e.paddingOuter=function(t){return arguments.length?(c=+t,s()):c},e.align=function(t){return arguments.length?(f=Math.max(0,Math.min(1,t)),s()):f},e.copy=function(){return Lh(r(),o).round(a).paddingInner(u).paddingOuter(c).align(f)},Eh.apply(s(),arguments)}function Uh(t){return+t}var Oh=[0,1];function Bh(t){return t}function Fh(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:function(t){return function(){return t}}(isNaN(n)?NaN:.5)}function Yh(t){var n,e=t[0],r=t[t.length-1];return e>r&&(n=e,e=r,r=n),function(t){return Math.max(e,Math.min(r,t))}}function Ih(t,n,e){var r=t[0],i=t[1],o=n[0],a=n[1];return i<r?(r=Fh(i,r),o=e(a,o)):(r=Fh(r,i),o=e(o,a)),function(t){return o(r(t))}}function Hh(t,n,e){var r=Math.min(t.length,n.length)-1,o=new Array(r),a=new Array(r),u=-1;for(t[r]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++u<r;)o[u]=Fh(t[u],t[u+1]),a[u]=e(n[u],n[u+1]);return function(n){var e=i(t,n,1,r)-1;return a[e](o[e](n))}}function jh(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp()).unknown(t.unknown())}function Xh(){var t,n,e,r,i,o,a=Oh,u=Oh,c=Te,f=Bh;function s(){return r=Math.min(a.length,u.length)>2?Hh:Ih,i=o=null,l}function l(n){return isNaN(n=+n)?e:(i||(i=r(a.map(t),u,c)))(t(f(n)))}return l.invert=function(e){return f(n((o||(o=r(u,a.map(t),me)))(e)))},l.domain=function(t){return arguments.length?(a=zh.call(t,Uh),f===Bh||(f=Yh(a)),s()):a.slice()},l.range=function(t){return arguments.length?(u=Rh.call(t),s()):u.slice()},l.rangeRound=function(t){return u=Rh.call(t),c=Ae,s()},l.clamp=function(t){return arguments.length?(f=t?Yh(a):Bh,l):f!==Bh},l.interpolate=function(t){return arguments.length?(c=t,s()):c},l.unknown=function(t){return arguments.length?(e=t,l):e},function(e,r){return t=e,n=r,s()}}function Vh(t,n){return Xh()(t,n)}function Gh(n,e,r,i){var o,a=w(n,e,r);switch((i=Oa(null==i?",f":i)).type){case"s":var u=Math.max(Math.abs(n),Math.abs(e));return null!=i.precision||isNaN(o=Wa(a,u))||(i.precision=o),t.formatPrefix(i,u);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=Za(a,Math.max(Math.abs(n),Math.abs(e))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=$a(a))||(i.precision=o-2*("%"===i.type))}return t.format(i)}function $h(t){var n=t.domain;return t.ticks=function(t){var e=n();return m(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){var r=n();return Gh(r[0],r[r.length-1],null==t?10:t,e)},t.nice=function(e){null==e&&(e=10);var r,i=n(),o=0,a=i.length-1,u=i[o],c=i[a];return c<u&&(r=u,u=c,c=r,r=o,o=a,a=r),(r=x(u,c,e))>0?r=x(u=Math.floor(u/r)*r,c=Math.ceil(c/r)*r,e):r<0&&(r=x(u=Math.ceil(u*r)/r,c=Math.floor(c*r)/r,e)),r>0?(i[o]=Math.floor(u/r)*r,i[a]=Math.ceil(c/r)*r,n(i)):r<0&&(i[o]=Math.ceil(u*r)/r,i[a]=Math.floor(c*r)/r,n(i)),t},t}function Wh(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a<o&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function Zh(t){return Math.log(t)}function Qh(t){return Math.exp(t)}function Kh(t){return-Math.log(-t)}function Jh(t){return-Math.exp(-t)}function td(t){return isFinite(t)?+("1e"+t):t<0?0:t}function nd(t){return function(n){return-t(-n)}}function ed(n){var e,r,i=n(Zh,Qh),o=i.domain,a=10;function u(){return e=function(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}(a),r=function(t){return 10===t?td:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}(a),o()[0]<0?(e=nd(e),r=nd(r),n(Kh,Jh)):n(Zh,Qh),i}return i.base=function(t){return arguments.length?(a=+t,u()):a},i.domain=function(t){return arguments.length?(o(t),u()):o()},i.ticks=function(t){var n,i=o(),u=i[0],c=i[i.length-1];(n=c<u)&&(h=u,u=c,c=h);var f,s,l,h=e(u),d=e(c),p=null==t?10:+t,v=[];if(!(a%1)&&d-h<p){if(h=Math.round(h)-1,d=Math.round(d)+1,u>0){for(;h<d;++h)for(s=1,f=r(h);s<a;++s)if(!((l=f*s)<u)){if(l>c)break;v.push(l)}}else for(;h<d;++h)for(s=a-1,f=r(h);s>=1;--s)if(!((l=f*s)<u)){if(l>c)break;v.push(l)}}else v=m(h,d,Math.min(d-h,p)).map(r);return n?v.reverse():v},i.tickFormat=function(n,o){if(null==o&&(o=10===a?".0e":","),"function"!=typeof o&&(o=t.format(o)),n===1/0)return o;null==n&&(n=10);var u=Math.max(1,a*n/i.ticks().length);return function(t){var n=t/r(Math.round(e(t)));return n*a<a-.5&&(n*=a),n<=u?o(t):""}},i.nice=function(){return o(Wh(o(),{floor:function(t){return r(Math.floor(e(t)))},ceil:function(t){return r(Math.ceil(e(t)))}}))},i}function rd(t){return function(n){return Math.sign(n)*Math.log1p(Math.abs(n/t))}}function id(t){return function(n){return Math.sign(n)*Math.expm1(Math.abs(n))*t}}function od(t){var n=1,e=t(rd(n),id(n));return e.constant=function(e){return arguments.length?t(rd(n=+e),id(n)):n},$h(e)}function ad(t){return function(n){return n<0?-Math.pow(-n,t):Math.pow(n,t)}}function ud(t){return t<0?-Math.sqrt(-t):Math.sqrt(t)}function cd(t){return t<0?-t*t:t*t}function fd(t){var n=t(Bh,Bh),e=1;function r(){return 1===e?t(Bh,Bh):.5===e?t(ud,cd):t(ad(e),ad(1/e))}return n.exponent=function(t){return arguments.length?(e=+t,r()):e},$h(n)}function sd(){var t=fd(Xh());return t.copy=function(){return jh(t,sd()).exponent(t.exponent())},Eh.apply(t,arguments),t}var ld=new Date,hd=new Date;function dd(t,n,e,r){function i(n){return t(n=0===arguments.length?new Date:new Date(+n)),n}return i.floor=function(n){return t(n=new Date(+n)),n},i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var a,u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(a=new Date(+e)),n(e,o),t(e)}while(a<e&&e<r);return u},i.filter=function(e){return dd(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return ld.setTime(+n),hd.setTime(+r),t(ld),t(hd),Math.floor(e(ld,hd))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var pd=dd(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});pd.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?dd(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):pd:null};var vd=pd.range,gd=6e4,yd=6048e5,_d=dd(function(t){t.setTime(t-t.getMilliseconds())},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),bd=_d.range,md=dd(function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds())},function(t,n){t.setTime(+t+n*gd)},function(t,n){return(n-t)/gd},function(t){return t.getMinutes()}),xd=md.range,wd=dd(function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds()-t.getMinutes()*gd)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),Md=wd.range,Nd=dd(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*gd)/864e5},function(t){return t.getDate()-1}),Td=Nd.range;function Ad(t){return dd(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*gd)/yd})}var Sd=Ad(0),kd=Ad(1),Ed=Ad(2),Cd=Ad(3),Pd=Ad(4),zd=Ad(5),Rd=Ad(6),Dd=Sd.range,qd=kd.range,Ld=Ed.range,Ud=Cd.range,Od=Pd.range,Bd=zd.range,Fd=Rd.range,Yd=dd(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),Id=Yd.range,Hd=dd(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});Hd.every=function(t){return isFinite(t=Math.floor(t))&&t>0?dd(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var jd=Hd.range,Xd=dd(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*gd)},function(t,n){return(n-t)/gd},function(t){return t.getUTCMinutes()}),Vd=Xd.range,Gd=dd(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),$d=Gd.range,Wd=dd(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),Zd=Wd.range;function Qd(t){return dd(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/yd})}var Kd=Qd(0),Jd=Qd(1),tp=Qd(2),np=Qd(3),ep=Qd(4),rp=Qd(5),ip=Qd(6),op=Kd.range,ap=Jd.range,up=tp.range,cp=np.range,fp=ep.range,sp=rp.range,lp=ip.range,hp=dd(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),dp=hp.range,pp=dd(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});pp.every=function(t){return isFinite(t=Math.floor(t))&&t>0?dd(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var vp=pp.range;function gp(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function yp(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function _p(t,n,e){return{y:t,m:n,d:e,H:0,M:0,S:0,L:0}}function bp(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,a=t.shortDays,u=t.months,c=t.shortMonths,f=Sp(i),s=kp(i),l=Sp(o),h=kp(o),d=Sp(a),p=kp(a),v=Sp(u),g=kp(u),y=Sp(c),_=kp(c),b={a:function(t){return a[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return u[t.getMonth()]},c:null,d:Wp,e:Wp,f:tv,H:Zp,I:Qp,j:Kp,L:Jp,m:nv,M:ev,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:Cv,s:Pv,S:rv,u:iv,U:ov,V:av,w:uv,W:cv,x:null,X:null,y:fv,Y:sv,Z:lv,"%":Ev},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:hv,e:hv,f:yv,H:dv,I:pv,j:vv,L:gv,m:_v,M:bv,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:Cv,s:Pv,S:mv,u:xv,U:wv,V:Mv,w:Nv,W:Tv,x:null,X:null,y:Av,Y:Sv,Z:kv,"%":Ev},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=y.exec(n.slice(e));return r?(t.m=_[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=g[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,e,r){return N(t,n,e,r)},d:Bp,e:Bp,f:Xp,H:Yp,I:Yp,j:Fp,L:jp,m:Op,M:Ip,p:function(t,n,e){var r=f.exec(n.slice(e));return r?(t.p=s[r[0].toLowerCase()],e+r[0].length):-1},q:Up,Q:Gp,s:$p,S:Hp,u:Cp,U:Pp,V:zp,w:Ep,W:Rp,x:function(t,n,r){return N(t,e,n,r)},X:function(t,n,e){return N(t,r,n,e)},y:qp,Y:Dp,Z:Lp,"%":Vp};function w(t,n){return function(e){var r,i,o,a=[],u=-1,c=0,f=t.length;for(e instanceof Date||(e=new Date(+e));++u<f;)37===t.charCodeAt(u)&&(a.push(t.slice(c,u)),null!=(i=xp[r=t.charAt(++u)])?r=t.charAt(++u):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),a.push(r),c=u+1);return a.push(t.slice(c,u)),a.join("")}}function M(t,n){return function(e){var r,i,o=_p(1900,void 0,1);if(N(o,t,e+="",0)!=e.length)return null;if("Q"in o)return new Date(o.Q);if("s"in o)return new Date(1e3*o.s+("L"in o?o.L:0));if(!n||"Z"in o||(o.Z=0),"p"in o&&(o.H=o.H%12+12*o.p),void 0===o.m&&(o.m="q"in o?o.q:0),"V"in o){if(o.V<1||o.V>53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=yp(_p(o.y,0,1))).getUTCDay(),r=i>4||0===i?Jd.ceil(r):Jd(r),r=Wd.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=gp(_p(o.y,0,1))).getDay(),r=i>4||0===i?kd.ceil(r):kd(r),r=Nd.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?yp(_p(o.y,0,1)).getUTCDay():gp(_p(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,yp(o)):gp(o)}}function N(t,n,e,r){for(var i,o,a=0,u=n.length,c=e.length;a<u;){if(r>=c)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in xp?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",!1);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t+="",!0);return n.toString=function(){return t},n}}}var mp,xp={"-":"",_:" ",0:"0"},wp=/^\s*\d+/,Mp=/^%/,Np=/[\\^$*+?|[\]().{}]/g;function Tp(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function Ap(t){return t.replace(Np,"\\$&")}function Sp(t){return new RegExp("^(?:"+t.map(Ap).join("|")+")","i")}function kp(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Ep(t,n,e){var r=wp.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Cp(t,n,e){var r=wp.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Pp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function zp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function Rp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function Dp(t,n,e){var r=wp.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function qp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function Lp(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Up(t,n,e){var r=wp.exec(n.slice(e,e+1));return r?(t.q=3*r[0]-3,e+r[0].length):-1}function Op(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function Bp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function Fp(t,n,e){var r=wp.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function Yp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Ip(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Hp(t,n,e){var r=wp.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function jp(t,n,e){var r=wp.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Xp(t,n,e){var r=wp.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function Vp(t,n,e){var r=Mp.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Gp(t,n,e){var r=wp.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function $p(t,n,e){var r=wp.exec(n.slice(e));return r?(t.s=+r[0],e+r[0].length):-1}function Wp(t,n){return Tp(t.getDate(),n,2)}function Zp(t,n){return Tp(t.getHours(),n,2)}function Qp(t,n){return Tp(t.getHours()%12||12,n,2)}function Kp(t,n){return Tp(1+Nd.count(Hd(t),t),n,3)}function Jp(t,n){return Tp(t.getMilliseconds(),n,3)}function tv(t,n){return Jp(t,n)+"000"}function nv(t,n){return Tp(t.getMonth()+1,n,2)}function ev(t,n){return Tp(t.getMinutes(),n,2)}function rv(t,n){return Tp(t.getSeconds(),n,2)}function iv(t){var n=t.getDay();return 0===n?7:n}function ov(t,n){return Tp(Sd.count(Hd(t)-1,t),n,2)}function av(t,n){var e=t.getDay();return t=e>=4||0===e?Pd(t):Pd.ceil(t),Tp(Pd.count(Hd(t),t)+(4===Hd(t).getDay()),n,2)}function uv(t){return t.getDay()}function cv(t,n){return Tp(kd.count(Hd(t)-1,t),n,2)}function fv(t,n){return Tp(t.getFullYear()%100,n,2)}function sv(t,n){return Tp(t.getFullYear()%1e4,n,4)}function lv(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Tp(n/60|0,"0",2)+Tp(n%60,"0",2)}function hv(t,n){return Tp(t.getUTCDate(),n,2)}function dv(t,n){return Tp(t.getUTCHours(),n,2)}function pv(t,n){return Tp(t.getUTCHours()%12||12,n,2)}function vv(t,n){return Tp(1+Wd.count(pp(t),t),n,3)}function gv(t,n){return Tp(t.getUTCMilliseconds(),n,3)}function yv(t,n){return gv(t,n)+"000"}function _v(t,n){return Tp(t.getUTCMonth()+1,n,2)}function bv(t,n){return Tp(t.getUTCMinutes(),n,2)}function mv(t,n){return Tp(t.getUTCSeconds(),n,2)}function xv(t){var n=t.getUTCDay();return 0===n?7:n}function wv(t,n){return Tp(Kd.count(pp(t)-1,t),n,2)}function Mv(t,n){var e=t.getUTCDay();return t=e>=4||0===e?ep(t):ep.ceil(t),Tp(ep.count(pp(t),t)+(4===pp(t).getUTCDay()),n,2)}function Nv(t){return t.getUTCDay()}function Tv(t,n){return Tp(Jd.count(pp(t)-1,t),n,2)}function Av(t,n){return Tp(t.getUTCFullYear()%100,n,2)}function Sv(t,n){return Tp(t.getUTCFullYear()%1e4,n,4)}function kv(){return"+0000"}function Ev(){return"%"}function Cv(t){return+t}function Pv(t){return Math.floor(+t/1e3)}function zv(n){return mp=bp(n),t.timeFormat=mp.format,t.timeParse=mp.parse,t.utcFormat=mp.utcFormat,t.utcParse=mp.utcParse,mp}zv({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Rv=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ");var Dv=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),qv=1e3,Lv=60*qv,Uv=60*Lv,Ov=24*Uv,Bv=7*Ov,Fv=30*Ov,Yv=365*Ov;function Iv(t){return new Date(t)}function Hv(t){return t instanceof Date?+t:+new Date(+t)}function jv(t,n,r,i,o,a,u,c,f){var s=Vh(Bh,Bh),l=s.invert,h=s.domain,d=f(".%L"),p=f(":%S"),v=f("%I:%M"),g=f("%I %p"),y=f("%a %d"),_=f("%b %d"),b=f("%B"),m=f("%Y"),x=[[u,1,qv],[u,5,5*qv],[u,15,15*qv],[u,30,30*qv],[a,1,Lv],[a,5,5*Lv],[a,15,15*Lv],[a,30,30*Lv],[o,1,Uv],[o,3,3*Uv],[o,6,6*Uv],[o,12,12*Uv],[i,1,Ov],[i,2,2*Ov],[r,1,Bv],[n,1,Fv],[n,3,3*Fv],[t,1,Yv]];function M(e){return(u(e)<e?d:a(e)<e?p:o(e)<e?v:i(e)<e?g:n(e)<e?r(e)<e?y:_:t(e)<e?b:m)(e)}function N(n,r,i,o){if(null==n&&(n=10),"number"==typeof n){var a=Math.abs(i-r)/n,u=e(function(t){return t[2]}).right(x,a);u===x.length?(o=w(r/Yv,i/Yv,n),n=t):u?(o=(u=x[a/x[u-1][2]<x[u][2]/a?u-1:u])[1],n=u[0]):(o=Math.max(w(r,i,n),1),n=c)}return null==o?n:n.every(o)}return s.invert=function(t){return new Date(l(t))},s.domain=function(t){return arguments.length?h(zh.call(t,Hv)):h().map(Iv)},s.ticks=function(t,n){var e,r=h(),i=r[0],o=r[r.length-1],a=o<i;return a&&(e=i,i=o,o=e),e=(e=N(t,i,o,n))?e.range(i,o+1):[],a?e.reverse():e},s.tickFormat=function(t,n){return null==n?M:f(n)},s.nice=function(t,n){var e=h();return(t=N(t,e[0],e[e.length-1],n))?h(Wh(e,t)):s},s.copy=function(){return jh(s,jv(t,n,r,i,o,a,u,c,f))},s}function Xv(){var t,n,e,r,i,o=0,a=1,u=Bh,c=!1;function f(n){return isNaN(n=+n)?i:u(0===e?.5:(n=(r(n)-t)*e,c?Math.max(0,Math.min(1,n)):n))}return f.domain=function(i){return arguments.length?(t=r(o=+i[0]),n=r(a=+i[1]),e=t===n?0:1/(n-t),f):[o,a]},f.clamp=function(t){return arguments.length?(c=!!t,f):c},f.interpolator=function(t){return arguments.length?(u=t,f):u},f.unknown=function(t){return arguments.length?(i=t,f):i},function(i){return r=i,t=i(o),n=i(a),e=t===n?0:1/(n-t),f}}function Vv(t,n){return n.domain(t.domain()).interpolator(t.interpolator()).clamp(t.clamp()).unknown(t.unknown())}function Gv(){var t=fd(Xv());return t.copy=function(){return Vv(t,Gv()).exponent(t.exponent())},Ch.apply(t,arguments)}function $v(){var t,n,e,r,i,o,a,u=0,c=.5,f=1,s=Bh,l=!1;function h(t){return isNaN(t=+t)?a:(t=.5+((t=+o(t))-n)*(t<n?r:i),s(l?Math.max(0,Math.min(1,t)):t))}return h.domain=function(a){return arguments.length?(t=o(u=+a[0]),n=o(c=+a[1]),e=o(f=+a[2]),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),h):[u,c,f]},h.clamp=function(t){return arguments.length?(l=!!t,h):l},h.interpolator=function(t){return arguments.length?(s=t,h):s},h.unknown=function(t){return arguments.length?(a=t,h):a},function(a){return o=a,t=a(u),n=a(c),e=a(f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),h}}function Wv(){var t=fd($v());return t.copy=function(){return Vv(t,Wv()).exponent(t.exponent())},Ch.apply(t,arguments)}function Zv(t){for(var n=t.length/6|0,e=new Array(n),r=0;r<n;)e[r]="#"+t.slice(6*r,6*++r);return e}var Qv=Zv("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Kv=Zv("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"),Jv=Zv("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"),tg=Zv("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"),ng=Zv("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"),eg=Zv("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"),rg=Zv("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"),ig=Zv("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"),og=Zv("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"),ag=Zv("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab");function ug(t){return pe(t[t.length-1])}var cg=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(Zv),fg=ug(cg),sg=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(Zv),lg=ug(sg),hg=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(Zv),dg=ug(hg),pg=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(Zv),vg=ug(pg),gg=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(Zv),yg=ug(gg),_g=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(Zv),bg=ug(_g),mg=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(Zv),xg=ug(mg),wg=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(Zv),Mg=ug(wg),Ng=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(Zv),Tg=ug(Ng),Ag=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(Zv),Sg=ug(Ag),kg=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(Zv),Eg=ug(kg),Cg=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(Zv),Pg=ug(Cg),zg=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(Zv),Rg=ug(zg),Dg=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(Zv),qg=ug(Dg),Lg=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(Zv),Ug=ug(Lg),Og=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(Zv),Bg=ug(Og),Fg=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(Zv),Yg=ug(Fg),Ig=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(Zv),Hg=ug(Ig),jg=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(Zv),Xg=ug(jg),Vg=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(Zv),Gg=ug(Vg),$g=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(Zv),Wg=ug($g),Zg=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(Zv),Qg=ug(Zg),Kg=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(Zv),Jg=ug(Kg),ty=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(Zv),ny=ug(ty),ey=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(Zv),ry=ug(ey),iy=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(Zv),oy=ug(iy),ay=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(Zv),uy=ug(ay);var cy=Qe(ee(300,.5,0),ee(-240,.5,1)),fy=Qe(ee(-100,.75,.35),ee(80,1.5,.8)),sy=Qe(ee(260,.75,.35),ee(80,1.5,.8)),ly=ee();var hy=_n(),dy=Math.PI/3,py=2*Math.PI/3;function vy(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var gy=vy(Zv("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),yy=vy(Zv("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),_y=vy(Zv("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),by=vy(Zv("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function my(t){return function(){return t}}var xy=Math.abs,wy=Math.atan2,My=Math.cos,Ny=Math.max,Ty=Math.min,Ay=Math.sin,Sy=Math.sqrt,ky=1e-12,Ey=Math.PI,Cy=Ey/2,Py=2*Ey;function zy(t){return t>=1?Cy:t<=-1?-Cy:Math.asin(t)}function Ry(t){return t.innerRadius}function Dy(t){return t.outerRadius}function qy(t){return t.startAngle}function Ly(t){return t.endAngle}function Uy(t){return t&&t.padAngle}function Oy(t,n,e,r,i,o,a){var u=t-e,c=n-r,f=(a?o:-o)/Sy(u*u+c*c),s=f*c,l=-f*u,h=t+s,d=n+l,p=e+s,v=r+l,g=(h+p)/2,y=(d+v)/2,_=p-h,b=v-d,m=_*_+b*b,x=i-o,w=h*v-p*d,M=(b<0?-1:1)*Sy(Ny(0,x*x*m-w*w)),N=(w*b-_*M)/m,T=(-w*_-b*M)/m,A=(w*b+_*M)/m,S=(-w*_+b*M)/m,k=N-g,E=T-y,C=A-g,P=S-y;return k*k+E*E>C*C+P*P&&(N=A,T=S),{cx:N,cy:T,x01:-s,y01:-l,x11:N*(i/x-1),y11:T*(i/x-1)}}function By(t){this._context=t}function Fy(t){return new By(t)}function Yy(t){return t[0]}function Iy(t){return t[1]}function Hy(){var t=Yy,n=Iy,e=my(!0),r=null,i=Fy,o=null;function a(a){var u,c,f,s=a.length,l=!1;for(null==r&&(o=i(f=no())),u=0;u<=s;++u)!(u<s&&e(c=a[u],u,a))===l&&((l=!l)?o.lineStart():o.lineEnd()),l&&o.point(+t(c,u,a),+n(c,u,a));if(f)return o=null,f+""||null}return a.x=function(n){return arguments.length?(t="function"==typeof n?n:my(+n),a):t},a.y=function(t){return arguments.length?(n="function"==typeof t?t:my(+t),a):n},a.defined=function(t){return arguments.length?(e="function"==typeof t?t:my(!!t),a):e},a.curve=function(t){return arguments.length?(i=t,null!=r&&(o=i(r)),a):i},a.context=function(t){return arguments.length?(null==t?r=o=null:o=i(r=t),a):r},a}function jy(){var t=Yy,n=null,e=my(0),r=Iy,i=my(!0),o=null,a=Fy,u=null;function c(c){var f,s,l,h,d,p=c.length,v=!1,g=new Array(p),y=new Array(p);for(null==o&&(u=a(d=no())),f=0;f<=p;++f){if(!(f<p&&i(h=c[f],f,c))===v)if(v=!v)s=f,u.areaStart(),u.lineStart();else{for(u.lineEnd(),u.lineStart(),l=f-1;l>=s;--l)u.point(g[l],y[l]);u.lineEnd(),u.areaEnd()}v&&(g[f]=+t(h,f,c),y[f]=+e(h,f,c),u.point(n?+n(h,f,c):g[f],r?+r(h,f,c):y[f]))}if(d)return u=null,d+""||null}function f(){return Hy().defined(i).curve(a).context(o)}return c.x=function(e){return arguments.length?(t="function"==typeof e?e:my(+e),n=null,c):t},c.x0=function(n){return arguments.length?(t="function"==typeof n?n:my(+n),c):t},c.x1=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:my(+t),c):n},c.y=function(t){return arguments.length?(e="function"==typeof t?t:my(+t),r=null,c):e},c.y0=function(t){return arguments.length?(e="function"==typeof t?t:my(+t),c):e},c.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:my(+t),c):r},c.lineX0=c.lineY0=function(){return f().x(t).y(e)},c.lineY1=function(){return f().x(t).y(r)},c.lineX1=function(){return f().x(n).y(e)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:my(!!t),c):i},c.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),c):a},c.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),c):o},c}function Xy(t,n){return n<t?-1:n>t?1:n>=t?0:NaN}function Vy(t){return t}By.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Gy=Wy(Fy);function $y(t){this._curve=t}function Wy(t){function n(n){return new $y(t(n))}return n._curve=t,n}function Zy(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Wy(t)):n()._curve},t}function Qy(){return Zy(Hy().curve(Gy))}function Ky(){var t=jy().curve(Gy),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Zy(e())},delete t.lineX0,t.lineEndAngle=function(){return Zy(r())},delete t.lineX1,t.lineInnerRadius=function(){return Zy(i())},delete t.lineY0,t.lineOuterRadius=function(){return Zy(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Wy(t)):n()._curve},t}function Jy(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}$y.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var t_=Array.prototype.slice;function n_(t){return t.source}function e_(t){return t.target}function r_(t){var n=n_,e=e_,r=Yy,i=Iy,o=null;function a(){var a,u=t_.call(arguments),c=n.apply(this,u),f=e.apply(this,u);if(o||(o=a=no()),t(o,+r.apply(this,(u[0]=c,u)),+i.apply(this,u),+r.apply(this,(u[0]=f,u)),+i.apply(this,u)),a)return o=null,a+""||null}return a.source=function(t){return arguments.length?(n=t,a):n},a.target=function(t){return arguments.length?(e=t,a):e},a.x=function(t){return arguments.length?(r="function"==typeof t?t:my(+t),a):r},a.y=function(t){return arguments.length?(i="function"==typeof t?t:my(+t),a):i},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a}function i_(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function o_(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function a_(t,n,e,r,i){var o=Jy(n,e),a=Jy(n,e=(e+i)/2),u=Jy(r,e),c=Jy(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(a[0],a[1],u[0],u[1],c[0],c[1])}var u_={draw:function(t,n){var e=Math.sqrt(n/Ey);t.moveTo(e,0),t.arc(0,0,e,0,Py)}},c_={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},f_=Math.sqrt(1/3),s_=2*f_,l_={draw:function(t,n){var e=Math.sqrt(n/s_),r=e*f_;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},h_=Math.sin(Ey/10)/Math.sin(7*Ey/10),d_=Math.sin(Py/10)*h_,p_=-Math.cos(Py/10)*h_,v_={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=d_*e,i=p_*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var a=Py*o/5,u=Math.cos(a),c=Math.sin(a);t.lineTo(c*e,-u*e),t.lineTo(u*r-c*i,c*r+u*i)}t.closePath()}},g_={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},y_=Math.sqrt(3),__={draw:function(t,n){var e=-Math.sqrt(n/(3*y_));t.moveTo(0,2*e),t.lineTo(-y_*e,-e),t.lineTo(y_*e,-e),t.closePath()}},b_=Math.sqrt(3)/2,m_=1/Math.sqrt(12),x_=3*(m_/2+1),w_={draw:function(t,n){var e=Math.sqrt(n/x_),r=e/2,i=e*m_,o=r,a=e*m_+e,u=-o,c=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,c),t.lineTo(-.5*r-b_*i,b_*r+-.5*i),t.lineTo(-.5*o-b_*a,b_*o+-.5*a),t.lineTo(-.5*u-b_*c,b_*u+-.5*c),t.lineTo(-.5*r+b_*i,-.5*i-b_*r),t.lineTo(-.5*o+b_*a,-.5*a-b_*o),t.lineTo(-.5*u+b_*c,-.5*c-b_*u),t.closePath()}},M_=[u_,c_,l_,g_,v_,__,w_];function N_(){}function T_(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function A_(t){this._context=t}function S_(t){this._context=t}function k_(t){this._context=t}function E_(t,n){this._basis=new A_(t),this._beta=n}A_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:T_(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:T_(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},S_.prototype={areaStart:N_,areaEnd:N_,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:T_(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},k_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:T_(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},E_.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*a),this._beta*n[c]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var C_=function t(n){function e(t){return 1===n?new A_(t):new E_(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function P_(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function z_(t,n){this._context=t,this._k=(1-n)/6}z_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:P_(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:P_(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var R_=function t(n){function e(t){return new z_(t,n)}return e.tension=function(n){return t(+n)},e}(0);function D_(t,n){this._context=t,this._k=(1-n)/6}D_.prototype={areaStart:N_,areaEnd:N_,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:P_(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var q_=function t(n){function e(t){return new D_(t,n)}return e.tension=function(n){return t(+n)},e}(0);function L_(t,n){this._context=t,this._k=(1-n)/6}L_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:P_(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var U_=function t(n){function e(t){return new L_(t,n)}return e.tension=function(n){return t(+n)},e}(0);function O_(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>ky){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>ky){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*f+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function B_(t,n){this._context=t,this._alpha=n}B_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:O_(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var F_=function t(n){function e(t){return n?new B_(t,n):new z_(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function Y_(t,n){this._context=t,this._alpha=n}Y_.prototype={areaStart:N_,areaEnd:N_,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:O_(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var I_=function t(n){function e(t){return n?new Y_(t,n):new D_(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function H_(t,n){this._context=t,this._alpha=n}H_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:O_(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var j_=function t(n){function e(t){return n?new H_(t,n):new L_(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function X_(t){this._context=t}function V_(t){return t<0?-1:1}function G_(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(V_(o)+V_(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function $_(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function W_(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function Z_(t){this._context=t}function Q_(t){this._context=new K_(t)}function K_(t){this._context=t}function J_(t){this._context=t}function tb(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,a[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,a[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,a[n]-=e*a[n-1];for(i[r-1]=a[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function nb(t,n){this._context=t,this._t=n}function eb(t,n){if((i=t.length)>1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o<i;++o)for(r=a,a=t[n[o]],e=0;e<u;++e)a[e][1]+=a[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]}function rb(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e}function ib(t,n){return t[n]}function ob(t){var n=t.map(ab);return rb(t).sort(function(t,e){return n[t]-n[e]})}function ab(t){for(var n,e=-1,r=0,i=t.length,o=-1/0;++e<i;)(n=+t[e][1])>o&&(o=n,r=e);return r}function ub(t){var n=t.map(cb);return rb(t).sort(function(t,e){return n[t]-n[e]})}function cb(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function fb(t){return function(){return t}}function sb(t){return t[0]}function lb(t){return t[1]}function hb(){this._=null}function db(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function pb(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function vb(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function gb(t){for(;t.L;)t=t.L;return t}function yb(t,n,e,r){var i=[null,null],o=Yb.push(i)-1;return i.left=t,i.right=n,e&&bb(i,t,n,e),r&&bb(i,n,t,r),Bb[t.index].halfedges.push(o),Bb[n.index].halfedges.push(o),i}function _b(t,n,e){var r=[n,e];return r.left=t,r}function bb(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function mb(t,n,e,r,i){var o,a=t[0],u=t[1],c=a[0],f=a[1],s=0,l=1,h=u[0]-c,d=u[1]-f;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o<s)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>s&&(s=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>s&&(s=o)}else if(h>0){if(o<s)return;o<l&&(l=o)}if(o=e-f,d||!(o>0)){if(o/=d,d<0){if(o<s)return;o<l&&(l=o)}else if(d>0){if(o>l)return;o>s&&(s=o)}if(o=i-f,d||!(o<0)){if(o/=d,d<0){if(o>l)return;o>s&&(s=o)}else if(d>0){if(o<s)return;o<l&&(l=o)}return!(s>0||l<1)||(s>0&&(t[0]=[c+s*h,f+s*d]),l<1&&(t[1]=[c+l*h,f+l*d]),!0)}}}}}function xb(t,n,e,r,i){var o=t[1];if(o)return!0;var a,u,c=t[0],f=t.left,s=t.right,l=f[0],h=f[1],d=s[0],p=s[1],v=(l+d)/2,g=(h+p)/2;if(p===h){if(v<n||v>=r)return;if(l>d){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=g-(a=(l-d)/(p-h))*v,a<-1||a>1)if(l>d){if(c){if(c[1]>=i)return}else c=[(e-u)/a,e];o=[(i-u)/a,i]}else{if(c){if(c[1]<e)return}else c=[(i-u)/a,i];o=[(e-u)/a,e]}else if(h<p){if(c){if(c[0]>=r)return}else c=[n,a*n+u];o=[r,a*r+u]}else{if(c){if(c[0]<n)return}else c=[r,a*r+u];o=[n,a*n+u]}return t[0]=c,t[1]=o,!0}function wb(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function Mb(t,n){return n[+(n.left!==t.site)]}function Nb(t,n){return n[+(n.left===t.site)]}X_.prototype={areaStart:N_,areaEnd:N_,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}},Z_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:W_(this,this._t0,$_(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(n=+n,(t=+t)!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,W_(this,$_(this,e=G_(this,t,n)),e);break;default:W_(this,this._t0,e=G_(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(Q_.prototype=Object.create(Z_.prototype)).point=function(t,n){Z_.prototype.point.call(this,n,t)},K_.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},J_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=tb(t),i=tb(n),o=0,a=1;a<e;++o,++a)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[a],n[a]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}},nb.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}},hb.prototype={constructor:hb,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=gb(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(pb(this,e),e=(t=e).U),e.C=!1,r.C=!0,vb(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(vb(this,e),e=(t=e).U),e.C=!1,r.C=!0,pb(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,a=t.R;if(e=o?a?gb(a):o:a,i?i.L===t?i.L=e:i.R=e:this._=e,o&&a?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==a?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=a,a.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,pb(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,vb(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,pb(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,vb(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,pb(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,vb(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var Tb,Ab=[];function Sb(){db(this),this.x=this.y=this.arc=this.site=this.cy=null}function kb(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var a=i[0],u=i[1],c=r[0]-a,f=r[1]-u,s=o[0]-a,l=o[1]-u,h=2*(c*l-f*s);if(!(h>=-Hb)){var d=c*c+f*f,p=s*s+l*l,v=(l*d-f*p)/h,g=(c*p-s*d)/h,y=Ab.pop()||new Sb;y.arc=t,y.site=i,y.x=v+a,y.y=(y.cy=g+u)+Math.sqrt(v*v+g*g),t.circle=y;for(var _=null,b=Fb._;b;)if(y.y<b.y||y.y===b.y&&y.x<=b.x){if(!b.L){_=b.P;break}b=b.L}else{if(!b.R){_=b;break}b=b.R}Fb.insert(_,y),_||(Tb=y)}}}}function Eb(t){var n=t.circle;n&&(n.P||(Tb=n.N),Fb.remove(n),Ab.push(n),db(n),t.circle=null)}var Cb=[];function Pb(){db(this),this.edge=this.site=this.circle=null}function zb(t){var n=Cb.pop()||new Pb;return n.site=t,n}function Rb(t){Eb(t),Ob.remove(t),Cb.push(t),db(t)}function Db(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,a=t.N,u=[t];Rb(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<Ib&&Math.abs(r-c.circle.cy)<Ib;)o=c.P,u.unshift(c),Rb(c),c=o;u.unshift(c),Eb(c);for(var f=a;f.circle&&Math.abs(e-f.circle.x)<Ib&&Math.abs(r-f.circle.cy)<Ib;)a=f.N,u.push(f),Rb(f),f=a;u.push(f),Eb(f);var s,l=u.length;for(s=1;s<l;++s)f=u[s],c=u[s-1],bb(f.edge,c.site,f.site,i);c=u[0],(f=u[l-1]).edge=yb(c.site,f.site,null,i),kb(c),kb(f)}function qb(t){for(var n,e,r,i,o=t[0],a=t[1],u=Ob._;u;)if((r=Lb(u,a)-o)>Ib)u=u.L;else{if(!((i=o-Ub(u,a))>Ib)){r>-Ib?(n=u.P,e=u):i>-Ib?(n=u,e=u.N):n=e=u;break}if(!u.R){n=u;break}u=u.R}!function(t){Bb[t.index]={site:t,halfedges:[]}}(t);var c=zb(t);if(Ob.insert(n,c),n||e){if(n===e)return Eb(n),e=zb(n.site),Ob.insert(c,e),c.edge=e.edge=yb(n.site,c.site),kb(n),void kb(e);if(e){Eb(n),Eb(e);var f=n.site,s=f[0],l=f[1],h=t[0]-s,d=t[1]-l,p=e.site,v=p[0]-s,g=p[1]-l,y=2*(h*g-d*v),_=h*h+d*d,b=v*v+g*g,m=[(g*_-d*b)/y+s,(h*b-v*_)/y+l];bb(e.edge,f,p,m),c.edge=yb(f,t,null,m),e.edge=yb(t,p,null,m),kb(n),kb(e)}else c.edge=yb(n.site,c.site)}}function Lb(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var a=t.P;if(!a)return-1/0;var u=(e=a.site)[0],c=e[1],f=c-n;if(!f)return u;var s=u-r,l=1/o-1/f,h=s/f;return l?(-h+Math.sqrt(h*h-2*l*(s*s/(-2*f)-c+f/2+i-o/2)))/l+r:(r+u)/2}function Ub(t,n){var e=t.N;if(e)return Lb(e,n);var r=t.site;return r[1]===n?r[0]:1/0}var Ob,Bb,Fb,Yb,Ib=1e-6,Hb=1e-12;function jb(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function Xb(t,n){return n[1]-t[1]||n[0]-t[0]}function Vb(t,n){var e,r,i,o=t.sort(Xb).pop();for(Yb=[],Bb=new Array(t.length),Ob=new hb,Fb=new hb;;)if(i=Tb,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(qb(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;Db(i.arc)}if(function(){for(var t,n,e,r,i=0,o=Bb.length;i<o;++i)if((t=Bb[i])&&(r=(n=t.halfedges).length)){var a=new Array(r),u=new Array(r);for(e=0;e<r;++e)a[e]=e,u[e]=wb(t,Yb[n[e]]);for(a.sort(function(t,n){return u[n]-u[t]}),e=0;e<r;++e)u[e]=n[a[e]];for(e=0;e<r;++e)n[e]=u[e]}}(),n){var a=+n[0][0],u=+n[0][1],c=+n[1][0],f=+n[1][1];!function(t,n,e,r){for(var i,o=Yb.length;o--;)xb(i=Yb[o],t,n,e,r)&&mb(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>Ib||Math.abs(i[0][1]-i[1][1])>Ib)||delete Yb[o]}(a,u,c,f),function(t,n,e,r){var i,o,a,u,c,f,s,l,h,d,p,v,g=Bb.length,y=!0;for(i=0;i<g;++i)if(o=Bb[i]){for(a=o.site,u=(c=o.halfedges).length;u--;)Yb[c[u]]||c.splice(u,1);for(u=0,f=c.length;u<f;)p=(d=Nb(o,Yb[c[u]]))[0],v=d[1],l=(s=Mb(o,Yb[c[++u%f]]))[0],h=s[1],(Math.abs(p-l)>Ib||Math.abs(v-h)>Ib)&&(c.splice(u,0,Yb.push(_b(a,d,Math.abs(p-t)<Ib&&r-v>Ib?[t,Math.abs(l-t)<Ib?h:r]:Math.abs(v-r)<Ib&&e-p>Ib?[Math.abs(h-r)<Ib?l:e,r]:Math.abs(p-e)<Ib&&v-n>Ib?[e,Math.abs(l-e)<Ib?h:n]:Math.abs(v-n)<Ib&&p-t>Ib?[Math.abs(h-n)<Ib?l:t,n]:null))-1),++f);f&&(y=!1)}if(y){var _,b,m,x=1/0;for(i=0,y=null;i<g;++i)(o=Bb[i])&&(m=(_=(a=o.site)[0]-t)*_+(b=a[1]-n)*b)<x&&(x=m,y=o);if(y){var w=[t,n],M=[t,r],N=[e,r],T=[e,n];y.halfedges.push(Yb.push(_b(a=y.site,w,M))-1,Yb.push(_b(a,M,N))-1,Yb.push(_b(a,N,T))-1,Yb.push(_b(a,T,w))-1)}}for(i=0;i<g;++i)(o=Bb[i])&&(o.halfedges.length||delete Bb[i])}(a,u,c,f)}this.edges=Yb,this.cells=Bb,Ob=Fb=Yb=Bb=null}function Gb(t){return function(){return t}}function $b(t,n,e){this.target=t,this.type=n,this.transform=e}function Wb(t,n,e){this.k=t,this.x=n,this.y=e}Vb.prototype={constructor:Vb,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return Mb(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,a,u=e.site,c=-1,f=n[i[o-1]],s=f.left===u?f.right:f.left;++c<o;)a=s,s=(f=n[i[c]]).left===u?f.right:f.left,a&&s&&r<a.index&&r<s.index&&jb(u,a,s)<0&&t.push([u.data,a.data,s.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,a=o._found||0,u=o.cells.length;!(i=o.cells[a]);)if(++a>=u)return null;var c=t-i.site[0],f=n-i.site[1],s=c*c+f*f;do{i=o.cells[r=a],a=null,i.halfedges.forEach(function(e){var r=o.edges[e],u=r.left;if(u!==i.site&&u||(u=r.right)){var c=t-u[0],f=n-u[1],l=c*c+f*f;l<s&&(s=l,a=u.index)}})}while(null!==a);return o._found=r,null==e||s<=e*e?i.site:null}},Wb.prototype={constructor:Wb,scale:function(t){return 1===t?this:new Wb(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new Wb(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Zb=new Wb(1,0,0);function Qb(t){for(;!t.__zoom;)if(!(t=t.parentNode))return Zb;return t.__zoom}function Kb(){t.event.stopImmediatePropagation()}function Jb(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function tm(){return!t.event.ctrlKey&&!t.event.button}function nm(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function em(){return this.__zoom||Zb}function rm(){return-t.event.deltaY*(1===t.event.deltaMode?.05:t.event.deltaMode?1:.002)}function im(){return navigator.maxTouchPoints||"ontouchstart"in this}function om(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}Qb.prototype=Wb.prototype,t.FormatSpecifier=Ba,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>xr&&e.name===n)return new Ur([[t]],yi,n,+r);return null},t.arc=function(){var t=Ry,n=Dy,e=my(0),r=null,i=qy,o=Ly,a=Uy,u=null;function c(){var c,f,s=+t.apply(this,arguments),l=+n.apply(this,arguments),h=i.apply(this,arguments)-Cy,d=o.apply(this,arguments)-Cy,p=xy(d-h),v=d>h;if(u||(u=c=no()),l<s&&(f=l,l=s,s=f),l>ky)if(p>Py-ky)u.moveTo(l*My(h),l*Ay(h)),u.arc(0,0,l,h,d,!v),s>ky&&(u.moveTo(s*My(d),s*Ay(d)),u.arc(0,0,s,d,h,v));else{var g,y,_=h,b=d,m=h,x=d,w=p,M=p,N=a.apply(this,arguments)/2,T=N>ky&&(r?+r.apply(this,arguments):Sy(s*s+l*l)),A=Ty(xy(l-s)/2,+e.apply(this,arguments)),S=A,k=A;if(T>ky){var E=zy(T/s*Ay(N)),C=zy(T/l*Ay(N));(w-=2*E)>ky?(m+=E*=v?1:-1,x-=E):(w=0,m=x=(h+d)/2),(M-=2*C)>ky?(_+=C*=v?1:-1,b-=C):(M=0,_=b=(h+d)/2)}var P=l*My(_),z=l*Ay(_),R=s*My(x),D=s*Ay(x);if(A>ky){var q,L=l*My(b),U=l*Ay(b),O=s*My(m),B=s*Ay(m);if(p<Ey&&(q=function(t,n,e,r,i,o,a,u){var c=e-t,f=r-n,s=a-i,l=u-o,h=l*c-s*f;if(!(h*h<ky))return[t+(h=(s*(n-o)-l*(t-i))/h)*c,n+h*f]}(P,z,O,B,L,U,R,D))){var F=P-q[0],Y=z-q[1],I=L-q[0],H=U-q[1],j=1/Ay(function(t){return t>1?0:t<-1?Ey:Math.acos(t)}((F*I+Y*H)/(Sy(F*F+Y*Y)*Sy(I*I+H*H)))/2),X=Sy(q[0]*q[0]+q[1]*q[1]);S=Ty(A,(s-X)/(j-1)),k=Ty(A,(l-X)/(j+1))}}M>ky?k>ky?(g=Oy(O,B,P,z,l,k,v),y=Oy(L,U,R,D,l,k,v),u.moveTo(g.cx+g.x01,g.cy+g.y01),k<A?u.arc(g.cx,g.cy,k,wy(g.y01,g.x01),wy(y.y01,y.x01),!v):(u.arc(g.cx,g.cy,k,wy(g.y01,g.x01),wy(g.y11,g.x11),!v),u.arc(0,0,l,wy(g.cy+g.y11,g.cx+g.x11),wy(y.cy+y.y11,y.cx+y.x11),!v),u.arc(y.cx,y.cy,k,wy(y.y11,y.x11),wy(y.y01,y.x01),!v))):(u.moveTo(P,z),u.arc(0,0,l,_,b,!v)):u.moveTo(P,z),s>ky&&w>ky?S>ky?(g=Oy(R,D,L,U,s,-S,v),y=Oy(P,z,O,B,s,-S,v),u.lineTo(g.cx+g.x01,g.cy+g.y01),S<A?u.arc(g.cx,g.cy,S,wy(g.y01,g.x01),wy(y.y01,y.x01),!v):(u.arc(g.cx,g.cy,S,wy(g.y01,g.x01),wy(g.y11,g.x11),!v),u.arc(0,0,s,wy(g.cy+g.y11,g.cx+g.x11),wy(y.cy+y.y11,y.cx+y.x11),v),u.arc(y.cx,y.cy,S,wy(y.y11,y.x11),wy(y.y01,y.x01),!v))):u.arc(0,0,s,x,m,v):u.lineTo(R,D)}else u.moveTo(0,0);if(u.closePath(),c)return u=null,c+""||null}return c.centroid=function(){var e=(+t.apply(this,arguments)+ +n.apply(this,arguments))/2,r=(+i.apply(this,arguments)+ +o.apply(this,arguments))/2-Ey/2;return[My(r)*e,Ay(r)*e]},c.innerRadius=function(n){return arguments.length?(t="function"==typeof n?n:my(+n),c):t},c.outerRadius=function(t){return arguments.length?(n="function"==typeof t?t:my(+t),c):n},c.cornerRadius=function(t){return arguments.length?(e="function"==typeof t?t:my(+t),c):e},c.padRadius=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:my(+t),c):r},c.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:my(+t),c):i},c.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:my(+t),c):o},c.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:my(+t),c):a},c.context=function(t){return arguments.length?(u=null==t?null:t,c):u},c},t.area=jy,t.areaRadial=Ky,t.ascending=n,t.autoType=function(t){for(var n in t){var e,r,i=t[n].trim();if(i)if("true"===i)i=!0;else if("false"===i)i=!1;else if("NaN"===i)i=NaN;else if(isNaN(e=+i)){if(!(r=i.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;ra&&r[4]&&!r[7]&&(i=i.replace(/-/g,"/").replace(/T/," ")),i=new Date(i)}else i=e;else i=null;t[n]=i}return t},t.axisBottom=function(t){return F(D,t)},t.axisLeft=function(t){return F(q,t)},t.axisRight=function(t){return F(R,t)},t.axisTop=function(t){return F(z,t)},t.bisect=i,t.bisectLeft=o,t.bisectRight=i,t.bisector=e,t.blob=function(t,n){return fetch(t,n).then(ia)},t.brush=function(){return Yi(Ci)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.brushX=function(){return Yi(ki)},t.brushY=function(){return Yi(Ei)},t.buffer=function(t,n){return fetch(t,n).then(oa)},t.chord=function(){var t=0,n=null,e=null,r=null;function i(i){var o,a,u,c,f,s,l=i.length,h=[],d=g(l),p=[],v=[],y=v.groups=new Array(l),_=new Array(l*l);for(o=0,f=-1;++f<l;){for(a=0,s=-1;++s<l;)a+=i[f][s];h.push(a),p.push(g(l)),o+=a}for(n&&d.sort(function(t,e){return n(h[t],h[e])}),e&&p.forEach(function(t,n){t.sort(function(t,r){return e(i[n][t],i[n][r])})}),c=(o=Gi(0,Vi-t*l)/o)?t:Vi/l,a=0,f=-1;++f<l;){for(u=a,s=-1;++s<l;){var b=d[f],m=p[b][s],x=i[b][m],w=a,M=a+=x*o;_[m*l+b]={index:b,subindex:m,startAngle:w,endAngle:M,value:x}}y[b]={index:b,startAngle:u,endAngle:a,value:h[b]},a+=c}for(f=-1;++f<l;)for(s=f-1;++s<l;){var N=_[s*l+f],T=_[f*l+s];(N.value||T.value)&&v.push(N.value<T.value?{source:T,target:N}:{source:N,target:T})}return r?v.sort(r):v}return i.padAngle=function(n){return arguments.length?(t=Gi(0,n),i):t},i.sortGroups=function(t){return arguments.length?(n=t,i):n},i.sortSubgroups=function(t){return arguments.length?(e=t,i):e},i.sortChords=function(t){return arguments.length?(null==t?r=null:(r=$i(t))._=t,i):r&&r._},i},t.clientPoint=Ot,t.cluster=function(){var t=Nl,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter(function(n){var e=n.children;e?(n.x=function(t){return t.reduce(Tl,0)/t.length}(e),n.y=function(t){return 1+t.reduce(Al,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)});var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),f=u.x-t(u,c)/2,s=c.x+t(c,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-f)/(s-f)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.color=pn,t.contourDensity=function(){var t=ko,n=Eo,e=Co,r=960,i=500,o=20,a=2,u=3*o,c=r+2*u>>a,f=i+2*u>>a,s=bo(20);function l(r){var i=new Float32Array(c*f),l=new Float32Array(c*f);r.forEach(function(r,o,s){var l=+t(r,o,s)+u>>a,h=+n(r,o,s)+u>>a,d=+e(r,o,s);l>=0&&l<c&&h>=0&&h<f&&(i[l+h*c]+=d)}),Ao({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),So({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a),Ao({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),So({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a),Ao({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),So({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a);var d=s(i);if(!Array.isArray(d)){var p=T(i);d=w(0,p,d),(d=g(0,Math.floor(p/d)*d,d)).shift()}return To().thresholds(d).size([c,f])(i).map(h)}function h(t){return t.value*=Math.pow(2,-2*a),t.coordinates.forEach(d),t}function d(t){t.forEach(p)}function p(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function y(){return c=r+2*(u=3*o)>>a,f=i+2*u>>a,l}return l.x=function(n){return arguments.length?(t="function"==typeof n?n:bo(+n),l):t},l.y=function(t){return arguments.length?(n="function"==typeof t?t:bo(+t),l):n},l.weight=function(t){return arguments.length?(e="function"==typeof t?t:bo(+t),l):e},l.size=function(t){if(!arguments.length)return[r,i];var n=Math.ceil(t[0]),e=Math.ceil(t[1]);if(!(n>=0||n>=0))throw new Error("invalid size");return r=n,i=e,y()},l.cellSize=function(t){if(!arguments.length)return 1<<a;if(!((t=+t)>=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),y()},l.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?bo(yo.call(t)):bo(t),l):s},l.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=Math.round((Math.sqrt(4*t*t+1)-1)/2),y()},l},t.contours=To,t.create=function(t){return Rt(Z(t).call(document.documentElement))},t.creator=Z,t.cross=function(t,n,e){var r,i,o,u,c=t.length,f=n.length,s=new Array(c*f);for(null==e&&(e=a),r=o=0;r<c;++r)for(u=t[r],i=0;i<f;++i,++o)s[o]=e(u,n[i]);return s},t.csv=fa,t.csvFormat=jo,t.csvFormatBody=Xo,t.csvFormatRow=Go,t.csvFormatRows=Vo,t.csvFormatValue=$o,t.csvParse=Io,t.csvParseRows=Ho,t.cubehelix=ee,t.curveBasis=function(t){return new A_(t)},t.curveBasisClosed=function(t){return new S_(t)},t.curveBasisOpen=function(t){return new k_(t)},t.curveBundle=C_,t.curveCardinal=R_,t.curveCardinalClosed=q_,t.curveCardinalOpen=U_,t.curveCatmullRom=F_,t.curveCatmullRomClosed=I_,t.curveCatmullRomOpen=j_,t.curveLinear=Fy,t.curveLinearClosed=function(t){return new X_(t)},t.curveMonotoneX=function(t){return new Z_(t)},t.curveMonotoneY=function(t){return new Q_(t)},t.curveNatural=function(t){return new J_(t)},t.curveStep=function(t){return new nb(t,.5)},t.curveStepAfter=function(t){return new nb(t,1)},t.curveStepBefore=function(t){return new nb(t,0)},t.customEvent=kt,t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=f,t.dispatch=I,t.drag=function(){var n,e,r,i,o=Gt,a=$t,u=Wt,c=Zt,f={},s=I("start","drag","end"),l=0,h=0;function d(t){t.on("mousedown.drag",p).filter(c).on("touchstart.drag",y).on("touchmove.drag",_).on("touchend.drag touchcancel.drag",b).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function p(){if(!i&&o.apply(this,arguments)){var u=m("mouse",a.apply(this,arguments),Bt,this,arguments);u&&(Rt(t.event.view).on("mousemove.drag",v,!0).on("mouseup.drag",g,!0),Ht(t.event.view),Yt(),r=!1,n=t.event.clientX,e=t.event.clientY,u("start"))}}function v(){if(It(),!r){var i=t.event.clientX-n,o=t.event.clientY-e;r=i*i+o*o>h}f.mouse("drag")}function g(){Rt(t.event.view).on("mousemove.drag mouseup.drag",null),jt(t.event.view,r),It(),f.mouse("end")}function y(){if(o.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=a.apply(this,arguments),u=r.length;for(n=0;n<u;++n)(e=m(r[n].identifier,i,Ft,this,arguments))&&(Yt(),e("start"))}}function _(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=f[r[n].identifier])&&(It(),e("drag"))}function b(){var n,e,r=t.event.changedTouches,o=r.length;for(i&&clearTimeout(i),i=setTimeout(function(){i=null},500),n=0;n<o;++n)(e=f[r[n].identifier])&&(Yt(),e("end"))}function m(n,e,r,i,o){var a,c,h,p=r(e,n),v=s.copy();if(kt(new Vt(d,"beforestart",a,n,l,p[0],p[1],0,0,v),function(){return null!=(t.event.subject=a=u.apply(i,o))&&(c=a.x-p[0]||0,h=a.y-p[1]||0,!0)}))return function t(u){var s,g=p;switch(u){case"start":f[n]=t,s=l++;break;case"end":delete f[n],--l;case"drag":p=r(e,n),s=l}kt(new Vt(d,u,a,n,s,p[0]+c,p[1]+h,p[0]-g[0],p[1]-g[1],v),v.apply,v,[u,i,o])}}return d.filter=function(t){return arguments.length?(o="function"==typeof t?t:Xt(!!t),d):o},d.container=function(t){return arguments.length?(a="function"==typeof t?t:Xt(t),d):a},d.subject=function(t){return arguments.length?(u="function"==typeof t?t:Xt(t),d):u},d.touchable=function(t){return arguments.length?(c="function"==typeof t?t:Xt(!!t),d):c},d.on=function(){var t=s.on.apply(s,arguments);return t===s?d:t},d.clickDistance=function(t){return arguments.length?(h=(t=+t)*t,d):Math.sqrt(h)},d},t.dragDisable=Ht,t.dragEnable=jt,t.dsv=function(t,n,e,r){3===arguments.length&&"function"==typeof e&&(r=e,e=void 0);var i=Fo(t);return ua(n,e).then(function(t){return i.parse(t,r)})},t.dsvFormat=Fo,t.easeBack=si,t.easeBackIn=ci,t.easeBackInOut=si,t.easeBackOut=fi,t.easeBounce=ui,t.easeBounceIn=function(t){return 1-ui(1-t)},t.easeBounceInOut=function(t){return((t*=2)<=1?1-ui(1-t):ui(t-1)+1)/2},t.easeBounceOut=ui,t.easeCircle=Zr,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleInOut=Zr,t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCubic=Ir,t.easeCubicIn=function(t){return t*t*t},t.easeCubicInOut=Ir,t.easeCubicOut=function(t){return--t*t*t+1},t.easeElastic=di,t.easeElasticIn=hi,t.easeElasticInOut=pi,t.easeElasticOut=di,t.easeExp=Wr,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpInOut=Wr,t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeLinear=function(t){return+t},t.easePoly=Xr,t.easePolyIn=Hr,t.easePolyInOut=Xr,t.easePolyOut=jr,t.easeQuad=Yr,t.easeQuadIn=function(t){return t*t},t.easeQuadInOut=Yr,t.easeQuadOut=function(t){return t*(2-t)},t.easeSin=$r,t.easeSinIn=function(t){return 1-Math.cos(t*Gr)},t.easeSinInOut=$r,t.easeSinOut=function(t){return Math.sin(t*Gr)},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.extent=s,t.forceCenter=function(t,n){var e;function r(){var r,i,o=e.length,a=0,u=0;for(r=0;r<o;++r)a+=(i=e[r]).x,u+=i.y;for(a=a/o-t,u=u/o-n,r=0;r<o;++r)(i=e[r]).x-=a,i.y-=u}return null==t&&(t=0),null==n&&(n=0),r.initialize=function(t){e=t},r.x=function(n){return arguments.length?(t=+n,r):t},r.y=function(t){return arguments.length?(n=+t,r):n},r},t.forceCollide=function(t){var n,e,r=1,i=1;function o(){for(var t,o,u,c,f,s,l,h=n.length,d=0;d<i;++d)for(o=wa(n,Aa,Sa).visitAfter(a),t=0;t<h;++t)u=n[t],s=e[u.index],l=s*s,c=u.x+u.vx,f=u.y+u.vy,o.visit(p);function p(t,n,e,i,o){var a=t.data,h=t.r,d=s+h;if(!a)return n>c+d||i<c-d||e>f+d||o<f-d;if(a.index>u.index){var p=c-a.x-a.vx,v=f-a.y-a.vy,g=p*p+v*v;g<d*d&&(0===p&&(g+=(p=ya())*p),0===v&&(g+=(v=ya())*v),g=(d-(g=Math.sqrt(g)))/g*r,u.vx+=(p*=g)*(d=(h*=h)/(l+h)),u.vy+=(v*=g)*d,a.vx-=p*(d=1-d),a.vy-=v*d)}}}function a(t){if(t.data)return t.r=e[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function u(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r<o;++r)i=n[r],e[i.index]=+t(i,r,n)}}return"function"!=typeof t&&(t=ga(null==t?1:+t)),o.initialize=function(t){n=t,u()},o.iterations=function(t){return arguments.length?(i=+t,o):i},o.strength=function(t){return arguments.length?(r=+t,o):r},o.radius=function(n){return arguments.length?(t="function"==typeof n?n:ga(+n),u(),o):t},o},t.forceLink=function(t){var n,e,r,i,o,a=ka,u=function(t){return 1/Math.min(i[t.source.index],i[t.target.index])},c=ga(30),f=1;function s(r){for(var i=0,a=t.length;i<f;++i)for(var u,c,s,l,h,d,p,v=0;v<a;++v)c=(u=t[v]).source,l=(s=u.target).x+s.vx-c.x-c.vx||ya(),h=s.y+s.vy-c.y-c.vy||ya(),l*=d=((d=Math.sqrt(l*l+h*h))-e[v])/d*r*n[v],h*=d,s.vx-=l*(p=o[v]),s.vy-=h*p,c.vx+=l*(p=1-p),c.vy+=h*p}function l(){if(r){var u,c,f=r.length,s=t.length,l=co(r,a);for(u=0,i=new Array(f);u<s;++u)(c=t[u]).index=u,"object"!=typeof c.source&&(c.source=Ea(l,c.source)),"object"!=typeof c.target&&(c.target=Ea(l,c.target)),i[c.source.index]=(i[c.source.index]||0)+1,i[c.target.index]=(i[c.target.index]||0)+1;for(u=0,o=new Array(s);u<s;++u)c=t[u],o[u]=i[c.source.index]/(i[c.source.index]+i[c.target.index]);n=new Array(s),h(),e=new Array(s),d()}}function h(){if(r)for(var e=0,i=t.length;e<i;++e)n[e]=+u(t[e],e,t)}function d(){if(r)for(var n=0,i=t.length;n<i;++n)e[n]=+c(t[n],n,t)}return null==t&&(t=[]),s.initialize=function(t){r=t,l()},s.links=function(n){return arguments.length?(t=n,l(),s):t},s.id=function(t){return arguments.length?(a=t,s):a},s.iterations=function(t){return arguments.length?(f=+t,s):f},s.strength=function(t){return arguments.length?(u="function"==typeof t?t:ga(+t),h(),s):u},s.distance=function(t){return arguments.length?(c="function"==typeof t?t:ga(+t),d(),s):c},s},t.forceManyBody=function(){var t,n,e,r,i=ga(-30),o=1,a=1/0,u=.81;function c(r){var i,o=t.length,a=wa(t,Ca,Pa).visitAfter(s);for(e=r,i=0;i<o;++i)n=t[i],a.visit(l)}function f(){if(t){var n,e,o=t.length;for(r=new Array(o),n=0;n<o;++n)e=t[n],r[e.index]=+i(e,n,t)}}function s(t){var n,e,i,o,a,u=0,c=0;if(t.length){for(i=o=a=0;a<4;++a)(n=t[a])&&(e=Math.abs(n.value))&&(u+=n.value,c+=e,i+=e*n.x,o+=e*n.y);t.x=i/c,t.y=o/c}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=r[n.data.index]}while(n=n.next)}t.value=u}function l(t,i,c,f){if(!t.value)return!0;var s=t.x-n.x,l=t.y-n.y,h=f-i,d=s*s+l*l;if(h*h/u<d)return d<a&&(0===s&&(d+=(s=ya())*s),0===l&&(d+=(l=ya())*l),d<o&&(d=Math.sqrt(o*d)),n.vx+=s*t.value*e/d,n.vy+=l*t.value*e/d),!0;if(!(t.length||d>=a)){(t.data!==n||t.next)&&(0===s&&(d+=(s=ya())*s),0===l&&(d+=(l=ya())*l),d<o&&(d=Math.sqrt(o*d)));do{t.data!==n&&(h=r[t.data.index]*e/d,n.vx+=s*h,n.vy+=l*h)}while(t=t.next)}}return c.initialize=function(n){t=n,f()},c.strength=function(t){return arguments.length?(i="function"==typeof t?t:ga(+t),f(),c):i},c.distanceMin=function(t){return arguments.length?(o=t*t,c):Math.sqrt(o)},c.distanceMax=function(t){return arguments.length?(a=t*t,c):Math.sqrt(a)},c.theta=function(t){return arguments.length?(u=t*t,c):Math.sqrt(u)},c},t.forceRadial=function(t,n,e){var r,i,o,a=ga(.1);function u(t){for(var a=0,u=r.length;a<u;++a){var c=r[a],f=c.x-n||1e-6,s=c.y-e||1e-6,l=Math.sqrt(f*f+s*s),h=(o[a]-l)*i[a]*t/l;c.vx+=f*h,c.vy+=s*h}}function c(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)o[n]=+t(r[n],n,r),i[n]=isNaN(o[n])?0:+a(r[n],n,r)}}return"function"!=typeof t&&(t=ga(+t)),null==n&&(n=0),null==e&&(e=0),u.initialize=function(t){r=t,c()},u.strength=function(t){return arguments.length?(a="function"==typeof t?t:ga(+t),c(),u):a},u.radius=function(n){return arguments.length?(t="function"==typeof n?n:ga(+n),c(),u):t},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(t){return arguments.length?(e=+t,u):e},u},t.forceSimulation=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,u=co(),c=hr(s),f=I("tick","end");function s(){l(),f.call("tick",n),e<r&&(c.stop(),f.call("end",n))}function l(r){var c,f,s=t.length;void 0===r&&(r=1);for(var l=0;l<r;++l)for(e+=(o-e)*i,u.each(function(t){t(e)}),c=0;c<s;++c)null==(f=t[c]).fx?f.x+=f.vx*=a:(f.x=f.fx,f.vx=0),null==f.fy?f.y+=f.vy*=a:(f.y=f.fy,f.vy=0);return n}function h(){for(var n,e=0,r=t.length;e<r;++e){if((n=t[e]).index=e,null!=n.fx&&(n.x=n.fx),null!=n.fy&&(n.y=n.fy),isNaN(n.x)||isNaN(n.y)){var i=za*Math.sqrt(e),o=e*Ra;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function d(n){return n.initialize&&n.initialize(t),n}return null==t&&(t=[]),h(),n={tick:l,restart:function(){return c.restart(s),n},stop:function(){return c.stop(),n},nodes:function(e){return arguments.length?(t=e,h(),u.each(d),n):t},alpha:function(t){return arguments.length?(e=+t,n):e},alphaMin:function(t){return arguments.length?(r=+t,n):r},alphaDecay:function(t){return arguments.length?(i=+t,n):+i},alphaTarget:function(t){return arguments.length?(o=+t,n):o},velocityDecay:function(t){return arguments.length?(a=1-t,n):1-a},force:function(t,e){return arguments.length>1?(null==e?u.remove(t):u.set(t,d(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,c,f=0,s=t.length;for(null==r?r=1/0:r*=r,f=0;f<s;++f)(a=(i=n-(u=t[f]).x)*i+(o=e-u.y)*o)<r&&(c=u,r=a);return c},on:function(t,e){return arguments.length>1?(f.on(t,e),n):f.on(t)}}},t.forceX=function(t){var n,e,r,i=ga(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vx+=(r[o]-i.x)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=ga(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:ga(+t),a(),o):i},o.x=function(n){return arguments.length?(t="function"==typeof n?n:ga(+n),a(),o):t},o},t.forceY=function(t){var n,e,r,i=ga(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vy+=(r[o]-i.y)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=ga(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:ga(+t),a(),o):i},o.y=function(n){return arguments.length?(t="function"==typeof n?n:ga(+n),a(),o):t},o},t.formatDefaultLocale=Ga,t.formatLocale=Va,t.formatSpecifier=Oa,t.geoAlbers=el,t.geoAlbersUsa=function(){var t,n,e,r,i,o,a=el(),u=nl().rotate([154,0]).center([-2,58.5]).parallels([55,65]),c=nl().rotate([157,0]).center([-3,19.9]).parallels([8,18]),f={point:function(t,n){o=[t,n]}};function s(t){var n=t[0],a=t[1];return o=null,e.point(n,a),o||(r.point(n,a),o)||(i.point(n,a),o)}function l(){return t=n=null,s}return s.invert=function(t){var n=a.scale(),e=a.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),c.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++e<i;)r[e].point(t,n)},sphere:function(){for(var t=-1;++t<i;)r[t].sphere()},lineStart:function(){for(var t=-1;++t<i;)r[t].lineStart()},lineEnd:function(){for(var t=-1;++t<i;)r[t].lineEnd()},polygonStart:function(){for(var t=-1;++t<i;)r[t].polygonStart()},polygonEnd:function(){for(var t=-1;++t<i;)r[t].polygonEnd()}});var r,i},s.precision=function(t){return arguments.length?(a.precision(t),u.precision(t),c.precision(t),l()):a.precision()},s.scale=function(t){return arguments.length?(a.scale(t),u.scale(.35*t),c.scale(t),s.translate(a.translate())):a.scale()},s.translate=function(t){if(!arguments.length)return a.translate();var n=a.scale(),o=+t[0],s=+t[1];return e=a.translate(t).clipExtent([[o-.455*n,s-.238*n],[o+.455*n,s+.238*n]]).stream(f),r=u.translate([o-.307*n,s+.201*n]).clipExtent([[o-.425*n+nu,s+.12*n+nu],[o-.214*n-nu,s+.234*n-nu]]).stream(f),i=c.translate([o-.205*n,s+.212*n]).clipExtent([[o-.214*n+nu,s+.166*n+nu],[o-.115*n-nu,s+.234*n-nu]]).stream(f),l()},s.fitExtent=function(t,n){return Is(s,t,n)},s.fitSize=function(t,n){return Hs(s,t,n)},s.fitWidth=function(t,n){return js(s,t,n)},s.fitHeight=function(t,n){return Xs(s,t,n)},s.scale(1070)},t.geoArea=function(t){return Uu.reset(),Cu(t,Ou),2*Uu},t.geoAzimuthalEqualArea=function(){return Qs(ol).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=ol,t.geoAzimuthalEquidistant=function(){return Qs(al).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=al,t.geoBounds=function(t){var n,e,r,i,o,a,u;if(Ju=Ku=-(Zu=Qu=1/0),ic=[],Cu(t,Mc),e=ic.length){for(ic.sort(zc),n=1,o=[r=ic[0]];n<e;++n)Rc(r,(i=ic[n])[0])||Rc(r,i[1])?(Pc(r[0],i[1])>Pc(r[0],r[1])&&(r[1]=i[1]),Pc(i[0],r[1])>Pc(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=Pc(r[1],i[0]))>a&&(a=u,Zu=i[0],Ku=r[1])}return ic=oc=null,Zu===1/0||Qu===1/0?[[NaN,NaN],[NaN,NaN]]:[[Zu,Qu],[Ku,Ju]]},t.geoCentroid=function(t){ac=uc=cc=fc=sc=lc=hc=dc=pc=vc=gc=0,Cu(t,Dc);var n=pc,e=vc,r=gc,i=n*n+e*e+r*r;return i<eu&&(n=lc,e=hc,r=dc,uc<nu&&(n=cc,e=fc,r=sc),(i=n*n+e*e+r*r)<eu)?[NaN,NaN]:[lu(e,n)*uu,wu(r/bu(i))*uu]},t.geoCircle=function(){var t,n,e=Xc([0,0]),r=Xc(90),i=Xc(6),o={point:function(e,r){t.push(e=n(e,r)),e[0]*=uu,e[1]*=uu}};function a(){var a=e.apply(this,arguments),u=r.apply(this,arguments)*cu,c=i.apply(this,arguments)*cu;return t=[],n=$c(-a[0]*cu,-a[1]*cu,0).invert,Jc(o,u,c,1),a={type:"Polygon",coordinates:[t]},t=n=null,a}return a.center=function(t){return arguments.length?(e="function"==typeof t?t:Xc([+t[0],+t[1]]),a):e},a.radius=function(t){return arguments.length?(r="function"==typeof t?t:Xc(+t),a):r},a.precision=function(t){return arguments.length?(i="function"==typeof t?t:Xc(+t),a):i},a},t.geoClipAntimeridian=df,t.geoClipCircle=pf,t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,a=500;return e={stream:function(e){return t&&n===e?t:t=yf(r,i,o,a)(n=e)},extent:function(u){return arguments.length?(r=+u[0][0],i=+u[0][1],o=+u[1][0],a=+u[1][1],t=n=null,e):[[r,i],[o,a]]}}},t.geoClipRectangle=yf,t.geoConicConformal=function(){return Js(sl).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=sl,t.geoConicEqualArea=nl,t.geoConicEqualAreaRaw=tl,t.geoConicEquidistant=function(){return Js(hl).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=hl,t.geoContains=function(t,n){return(t&&Cf.hasOwnProperty(t.type)?Cf[t.type]:zf)(t,n)},t.geoDistance=Ef,t.geoEqualEarth=function(){return Qs(_l).scale(177.158)},t.geoEqualEarthRaw=_l,t.geoEquirectangular=function(){return Qs(ll).scale(152.63)},t.geoEquirectangularRaw=ll,t.geoGnomonic=function(){return Qs(bl).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=bl,t.geoGraticule=Ff,t.geoGraticule10=function(){return Ff()()},t.geoIdentity=function(){var t,n,e,r,i,o,a,u=1,c=0,f=0,s=1,l=1,h=0,d=null,p=1,v=1,g=Bs({point:function(t,n){var e=b([t,n]);this.stream.point(e[0],e[1])}}),y=Yf;function _(){return p=u*s,v=u*l,o=a=null,b}function b(e){var r=e[0]*p,i=e[1]*v;if(h){var o=i*t-r*n;r=r*t+i*n,i=o}return[r+c,i+f]}return b.invert=function(e){var r=e[0]-c,i=e[1]-f;if(h){var o=i*t+r*n;r=r*t-i*n,i=o}return[r/p,i/v]},b.stream=function(t){return o&&a===t?o:o=g(y(a=t))},b.postclip=function(t){return arguments.length?(y=t,d=e=r=i=null,_()):y},b.clipExtent=function(t){return arguments.length?(y=null==t?(d=e=r=i=null,Yf):yf(d=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),_()):null==d?null:[[d,e],[r,i]]},b.scale=function(t){return arguments.length?(u=+t,_()):u},b.translate=function(t){return arguments.length?(c=+t[0],f=+t[1],_()):[c,f]},b.angle=function(e){return arguments.length?(n=yu(h=e%360*cu),t=hu(h),_()):h*uu},b.reflectX=function(t){return arguments.length?(s=t?-1:1,_()):s<0},b.reflectY=function(t){return arguments.length?(l=t?-1:1,_()):l<0},b.fitExtent=function(t,n){return Is(b,t,n)},b.fitSize=function(t,n){return Hs(b,t,n)},b.fitWidth=function(t,n){return js(b,t,n)},b.fitHeight=function(t,n){return Xs(b,t,n)},b},t.geoInterpolate=function(t,n){var e=t[0]*cu,r=t[1]*cu,i=n[0]*cu,o=n[1]*cu,a=hu(r),u=yu(r),c=hu(o),f=yu(o),s=a*hu(e),l=a*yu(e),h=c*hu(i),d=c*yu(i),p=2*wu(bu(Mu(o-r)+a*c*Mu(i-e))),v=yu(p),g=p?function(t){var n=yu(t*=p)/v,e=yu(p-t)/v,r=e*s+n*h,i=e*l+n*d,o=e*u+n*f;return[lu(i,r)*uu,lu(o,bu(r*r+i*i))*uu]}:function(){return[e*uu,r*uu]};return g.distance=p,g},t.geoLength=Af,t.geoMercator=function(){return cl(ul).scale(961/au)},t.geoMercatorRaw=ul,t.geoNaturalEarth1=function(){return Qs(ml).scale(175.295)},t.geoNaturalEarth1Raw=ml,t.geoOrthographic=function(){return Qs(xl).scale(249.5).clipAngle(90+nu)},t.geoOrthographicRaw=xl,t.geoPath=function(t,n){var e,r,i=4.5;function o(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),Cu(t,e(r))),r.result()}return o.area=function(t){return Cu(t,e($f)),$f.result()},o.measure=function(t){return Cu(t,e(Ds)),Ds.result()},o.bounds=function(t){return Cu(t,e(rs)),rs.result()},o.centroid=function(t){return Cu(t,e(ys)),ys.result()},o.projection=function(n){return arguments.length?(e=null==n?(t=null,Yf):(t=n).stream,o):t},o.context=function(t){return arguments.length?(r=null==t?(n=null,new Us):new Ss(n=t),"function"!=typeof i&&r.pointRadius(i),o):n},o.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),o):i},o.projection(t).context(n)},t.geoProjection=Qs,t.geoProjectionMutator=Ks,t.geoRotation=Kc,t.geoStereographic=function(){return Qs(wl).scale(250).clipAngle(142)},t.geoStereographicRaw=wl,t.geoStream=Cu,t.geoTransform=function(t){return{stream:Bs(t)}},t.geoTransverseMercator=function(){var t=cl(Ml),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=Ml,t.gray=function(t,n){return new Bn(t,0,0,null==n?1:n)},t.hcl=Xn,t.hierarchy=kl,t.histogram=function(){var t=v,n=s,e=M;function r(r){var o,a,u=r.length,c=new Array(u);for(o=0;o<u;++o)c[o]=t(r[o],o,r);var f=n(c),s=f[0],l=f[1],h=e(c,s,l);Array.isArray(h)||(h=w(s,l,h),h=g(Math.ceil(s/h)*h,l,h));for(var d=h.length;h[0]<=s;)h.shift(),--d;for(;h[d-1]>l;)h.pop(),--d;var p,v=new Array(d+1);for(o=0;o<=d;++o)(p=v[o]=[]).x0=o>0?h[o-1]:s,p.x1=o<d?h[o]:l;for(o=0;o<u;++o)s<=(a=c[o])&&a<=l&&v[i(h,a,0,d)].push(r[o]);return v}return r.value=function(n){return arguments.length?(t="function"==typeof n?n:p(n),r):t},r.domain=function(t){return arguments.length?(n="function"==typeof t?t:p([t[0],t[1]]),r):n},r.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?p(h.call(t)):p(t),r):e},r},t.hsl=Tn,t.html=pa,t.image=function(t,n){return new Promise(function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t})},t.interpolate=Te,t.interpolateArray=function(t,n){return(ye(n)?ge:_e)(t,n)},t.interpolateBasis=oe,t.interpolateBasisClosed=ae,t.interpolateBlues=Qg,t.interpolateBrBG=fg,t.interpolateBuGn=Sg,t.interpolateBuPu=Eg,t.interpolateCividis=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(-4.54-t*(35.34-t*(2381.73-t*(6402.7-t*(7024.72-2710.57*t)))))))+", "+Math.max(0,Math.min(255,Math.round(32.49+t*(170.73+t*(52.82-t*(131.46-t*(176.58-67.37*t)))))))+", "+Math.max(0,Math.min(255,Math.round(81.24+t*(442.36-t*(2482.43-t*(6167.24-t*(6614.94-2475.67*t)))))))+")"},t.interpolateCool=sy,t.interpolateCubehelix=Ze,t.interpolateCubehelixDefault=cy,t.interpolateCubehelixLong=Qe,t.interpolateDate=be,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateGnBu=Pg,t.interpolateGreens=Jg,t.interpolateGreys=ny,t.interpolateHcl=Ge,t.interpolateHclLong=$e,t.interpolateHsl=je,t.interpolateHslLong=Xe,t.interpolateHue=function(t,n){var e=fe(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateInferno=_y,t.interpolateLab=function(t,n){var e=le((t=On(t)).l,(n=On(n)).l),r=le(t.a,n.a),i=le(t.b,n.b),o=le(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateMagma=yy,t.interpolateNumber=me,t.interpolateNumberArray=ge,t.interpolateObject=xe,t.interpolateOrRd=Rg,t.interpolateOranges=uy,t.interpolatePRGn=lg,t.interpolatePiYG=dg,t.interpolatePlasma=by,t.interpolatePuBu=Ug,t.interpolatePuBuGn=qg,t.interpolatePuOr=vg,t.interpolatePuRd=Bg,t.interpolatePurples=ry,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return ly.h=360*t-100,ly.s=1.5-1.5*n,ly.l=.8-.9*n,ly+""},t.interpolateRdBu=yg,t.interpolateRdGy=bg,t.interpolateRdPu=Yg,t.interpolateRdYlBu=xg,t.interpolateRdYlGn=Mg,t.interpolateReds=oy,t.interpolateRgb=he,t.interpolateRgbBasis=pe,t.interpolateRgbBasisClosed=ve,t.interpolateRound=Ae,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,hy.r=255*(n=Math.sin(t))*n,hy.g=255*(n=Math.sin(t+dy))*n,hy.b=255*(n=Math.sin(t+py))*n,hy+""},t.interpolateSpectral=Tg,t.interpolateString=Ne,t.interpolateTransformCss=qe,t.interpolateTransformSvg=Le,t.interpolateTurbo=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"},t.interpolateViridis=gy,t.interpolateWarm=fy,t.interpolateYlGn=Xg,t.interpolateYlGnBu=Hg,t.interpolateYlOrBr=Gg,t.interpolateYlOrRd=Wg,t.interpolateZoom=Ie,t.interrupt=Pr,t.interval=function(t,n,e){var r=new lr,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?fr():+e,r.restart(function o(a){a+=i,r.restart(o,i+=n,e),t(a)},n,e),r)},t.isoFormat=Rv,t.isoParse=Dv,t.json=function(t,n){return fetch(t,n).then(la)},t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.lab=On,t.lch=function(t,n,e,r){return 1===arguments.length?jn(t):new Vn(e,n,t,null==r?1:r)},t.line=Hy,t.lineRadial=Qy,t.linkHorizontal=function(){return r_(i_)},t.linkRadial=function(){var t=r_(a_);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.linkVertical=function(){return r_(o_)},t.local=qt,t.map=co,t.matcher=nt,t.max=T,t.mean=function(t,n){var e,r=t.length,i=r,o=-1,a=0;if(null==n)for(;++o<r;)isNaN(e=u(t[o]))?--i:a+=e;else for(;++o<r;)isNaN(e=u(n(t[o],o,t)))?--i:a+=e;if(i)return a/i},t.median=function(t,e){var r,i=t.length,o=-1,a=[];if(null==e)for(;++o<i;)isNaN(r=u(t[o]))||a.push(r);else for(;++o<i;)isNaN(r=u(e(t[o],o,t)))||a.push(r);return N(a.sort(n),.5)},t.merge=A,t.min=S,t.mouse=Bt,t.namespace=W,t.namespaces=$,t.nest=function(){var t,n,e,r=[],i=[];function o(e,i,a,u){if(i>=r.length)return null!=t&&e.sort(t),null!=n?n(e):e;for(var c,f,s,l=-1,h=e.length,d=r[i++],p=co(),v=a();++l<h;)(s=p.get(c=d(f=e[l])+""))?s.push(f):p.set(c,[f]);return p.each(function(t,n){u(v,n,o(t,i,a,u))}),v}return e={object:function(t){return o(t,0,fo,so)},map:function(t){return o(t,0,lo,ho)},entries:function(t){return function t(e,o){if(++o>r.length)return e;var a,u=i[o-1];return null!=n&&o>=r.length?a=e.entries():(a=[],e.each(function(n,e){a.push({key:e,values:t(n,o)})})),null!=u?a.sort(function(t,n){return u(t.key,n.key)}):a}(o(t,0,lo,ho),0)},key:function(t){return r.push(t),e},sortKeys:function(t){return i[r.length-1]=t,e},sortValues:function(n){return t=n,e},rollup:function(t){return n=t,e}}},t.now=fr,t.pack=function(){var t=null,n=1,e=1,r=Wl;function i(i){return i.x=n/2,i.y=e/2,t?i.eachBefore(Kl(t)).eachAfter(Jl(r,.5)).eachBefore(th(1)):i.eachBefore(Kl(Ql)).eachAfter(Jl(Wl,1)).eachAfter(Jl(r,i.r/Math.min(n,e))).eachBefore(th(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=Gl(n),i):t},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:Zl(+t),i):r},i},t.packEnclose=Dl,t.packSiblings=function(t){return Vl(t),t},t.pairs=function(t,n){null==n&&(n=a);for(var e=0,r=t.length-1,i=t[0],o=new Array(r<0?0:r);e<r;)o[e]=n(i,i=t[++e]);return o},t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&eh(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a<i&&(i=a=(i+a)/2),u<o&&(o=u=(o+u)/2),r.x0=i,r.y0=o,r.x1=a,r.y1=u}}(n,o)),r&&i.eachBefore(nh),i}return i.round=function(t){return arguments.length?(r=!!t,i):r},i.size=function(e){return arguments.length?(t=+e[0],n=+e[1],i):[t,n]},i.padding=function(t){return arguments.length?(e=+t,i):e},i},t.path=no,t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.pie=function(){var t=Vy,n=Xy,e=null,r=my(0),i=my(Py),o=my(0);function a(a){var u,c,f,s,l,h=a.length,d=0,p=new Array(h),v=new Array(h),g=+r.apply(this,arguments),y=Math.min(Py,Math.max(-Py,i.apply(this,arguments)-g)),_=Math.min(Math.abs(y)/h,o.apply(this,arguments)),b=_*(y<0?-1:1);for(u=0;u<h;++u)(l=v[p[u]=u]=+t(a[u],u,a))>0&&(d+=l);for(null!=n?p.sort(function(t,e){return n(v[t],v[e])}):null!=e&&p.sort(function(t,n){return e(a[t],a[n])}),u=0,f=d?(y-h*b)/d:0;u<h;++u,g=s)c=p[u],s=g+((l=v[c])>0?l*f:0)+b,v[c]={data:a[c],index:u,value:l,startAngle:g,endAngle:s,padAngle:_};return v}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:my(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:my(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:my(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:my(+t),a):o},a},t.piecewise=function(t,n){for(var e=0,r=n.length-1,i=n[0],o=new Array(r<0?0:r);e<r;)o[e]=t(i,i=n[++e]);return function(t){var n=Math.max(0,Math.min(r-1,Math.floor(t*=r)));return o[n](t-n)}},t.pointRadial=Jy,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,a=0,u=t[i-1],c=0;++r<i;)n=u,u=t[r],c+=e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o/(c*=3),a/c]},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],a=n[0],u=n[1],c=o[0],f=o[1],s=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>u!=f>u&&a<(c-e)*(u-r)/(f-r)+e&&(s=!s),c=e,f=r;return s},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(mh),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=xh(r),a=xh(i),u=a[0]===o[0],c=a[a.length-1]===o[o.length-1],f=[];for(n=o.length-1;n>=0;--n)f.push(t[r[o[n]][2]]);for(n=+u;n<a.length-c;++n)f.push(t[r[a[n]][2]]);return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],a=o[0],u=o[1],c=0;++r<i;)n=a,e=u,n-=a=(o=t[r])[0],e-=u=o[1],c+=Math.sqrt(n*n+e*e);return c},t.precisionFixed=$a,t.precisionPrefix=Wa,t.precisionRound=Za,t.quadtree=wa,t.quantile=N,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.radialArea=Ky,t.radialLine=Qy,t.randomBates=Sh,t.randomExponential=kh,t.randomIrwinHall=Ah,t.randomLogNormal=Th,t.randomNormal=Nh,t.randomUniform=Mh,t.range=g,t.rgb=_n,t.ribbon=function(){var t=eo,n=ro,e=io,r=oo,i=ao,o=null;function a(){var a,u=Wi.call(arguments),c=t.apply(this,u),f=n.apply(this,u),s=+e.apply(this,(u[0]=c,u)),l=r.apply(this,u)-Xi,h=i.apply(this,u)-Xi,d=s*Ii(l),p=s*Hi(l),v=+e.apply(this,(u[0]=f,u)),g=r.apply(this,u)-Xi,y=i.apply(this,u)-Xi;if(o||(o=a=no()),o.moveTo(d,p),o.arc(0,0,s,l,h),l===g&&h===y||(o.quadraticCurveTo(0,0,v*Ii(g),v*Hi(g)),o.arc(0,0,v,g,y)),o.quadraticCurveTo(0,0,d,p),o.closePath(),a)return o=null,a+""||null}return a.radius=function(t){return arguments.length?(e="function"==typeof t?t:Zi(+t),a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Zi(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Zi(+t),a):i},a.source=function(n){return arguments.length?(t=n,a):t},a.target=function(t){return arguments.length?(n=t,a):n},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a},t.scaleBand=Lh,t.scaleDiverging=function t(){var n=$h($v()(Bh));return n.copy=function(){return Vv(n,t())},Ch.apply(n,arguments)},t.scaleDivergingLog=function t(){var n=ed($v()).domain([.1,1,10]);return n.copy=function(){return Vv(n,t()).base(n.base())},Ch.apply(n,arguments)},t.scaleDivergingPow=Wv,t.scaleDivergingSqrt=function(){return Wv.apply(null,arguments).exponent(.5)},t.scaleDivergingSymlog=function t(){var n=od($v());return n.copy=function(){return Vv(n,t()).constant(n.constant())},Ch.apply(n,arguments)},t.scaleIdentity=function t(n){var e;function r(t){return isNaN(t=+t)?e:t}return r.invert=r,r.domain=r.range=function(t){return arguments.length?(n=zh.call(t,Uh),r):n.slice()},r.unknown=function(t){return arguments.length?(e=t,r):e},r.copy=function(){return t(n).unknown(e)},n=arguments.length?zh.call(n,Uh):[0,1],$h(r)},t.scaleImplicit=Dh,t.scaleLinear=function t(){var n=Vh(Bh,Bh);return n.copy=function(){return jh(n,t())},Eh.apply(n,arguments),$h(n)},t.scaleLog=function t(){var n=ed(Xh()).domain([1,10]);return n.copy=function(){return jh(n,t()).base(n.base())},Eh.apply(n,arguments),n},t.scaleOrdinal=qh,t.scalePoint=function(){return function t(n){var e=n.copy;return n.padding=n.paddingOuter,delete n.paddingInner,delete n.paddingOuter,n.copy=function(){return t(e())},n}(Lh.apply(null,arguments).paddingInner(1))},t.scalePow=sd,t.scaleQuantile=function t(){var e,r=[],o=[],a=[];function u(){var t=0,n=Math.max(1,o.length);for(a=new Array(n-1);++t<n;)a[t-1]=N(r,t/n);return c}function c(t){return isNaN(t=+t)?e:o[i(a,t)]}return c.invertExtent=function(t){var n=o.indexOf(t);return n<0?[NaN,NaN]:[n>0?a[n-1]:r[0],n<a.length?a[n]:r[r.length-1]]},c.domain=function(t){if(!arguments.length)return r.slice();r=[];for(var e,i=0,o=t.length;i<o;++i)null==(e=t[i])||isNaN(e=+e)||r.push(e);return r.sort(n),u()},c.range=function(t){return arguments.length?(o=Rh.call(t),u()):o.slice()},c.unknown=function(t){return arguments.length?(e=t,c):e},c.quantiles=function(){return a.slice()},c.copy=function(){return t().domain(r).range(o).unknown(e)},Eh.apply(c,arguments)},t.scaleQuantize=function t(){var n,e=0,r=1,o=1,a=[.5],u=[0,1];function c(t){return t<=t?u[i(a,t,0,o)]:n}function f(){var t=-1;for(a=new Array(o);++t<o;)a[t]=((t+1)*r-(t-o)*e)/(o+1);return c}return c.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],f()):[e,r]},c.range=function(t){return arguments.length?(o=(u=Rh.call(t)).length-1,f()):u.slice()},c.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,a[0]]:n>=o?[a[o-1],r]:[a[n-1],a[n]]},c.unknown=function(t){return arguments.length?(n=t,c):c},c.thresholds=function(){return a.slice()},c.copy=function(){return t().domain([e,r]).range(u).unknown(n)},Eh.apply($h(c),arguments)},t.scaleSequential=function t(){var n=$h(Xv()(Bh));return n.copy=function(){return Vv(n,t())},Ch.apply(n,arguments)},t.scaleSequentialLog=function t(){var n=ed(Xv()).domain([1,10]);return n.copy=function(){return Vv(n,t()).base(n.base())},Ch.apply(n,arguments)},t.scaleSequentialPow=Gv,t.scaleSequentialQuantile=function t(){var e=[],r=Bh;function o(t){if(!isNaN(t=+t))return r((i(e,t)-1)/(e.length-1))}return o.domain=function(t){if(!arguments.length)return e.slice();e=[];for(var r,i=0,a=t.length;i<a;++i)null==(r=t[i])||isNaN(r=+r)||e.push(r);return e.sort(n),o},o.interpolator=function(t){return arguments.length?(r=t,o):r},o.copy=function(){return t(r).domain(e)},Ch.apply(o,arguments)},t.scaleSequentialSqrt=function(){return Gv.apply(null,arguments).exponent(.5)},t.scaleSequentialSymlog=function t(){var n=od(Xv());return n.copy=function(){return Vv(n,t()).constant(n.constant())},Ch.apply(n,arguments)},t.scaleSqrt=function(){return sd.apply(null,arguments).exponent(.5)},t.scaleSymlog=function t(){var n=od(Xh());return n.copy=function(){return jh(n,t()).constant(n.constant())},Eh.apply(n,arguments)},t.scaleThreshold=function t(){var n,e=[.5],r=[0,1],o=1;function a(t){return t<=t?r[i(e,t,0,o)]:n}return a.domain=function(t){return arguments.length?(e=Rh.call(t),o=Math.min(e.length,r.length-1),a):e.slice()},a.range=function(t){return arguments.length?(r=Rh.call(t),o=Math.min(e.length,r.length-1),a):r.slice()},a.invertExtent=function(t){var n=r.indexOf(t);return[e[n-1],e[n]]},a.unknown=function(t){return arguments.length?(n=t,a):n},a.copy=function(){return t().domain(e).range(r).unknown(n)},Eh.apply(a,arguments)},t.scaleTime=function(){return Eh.apply(jv(Hd,Yd,Sd,Nd,wd,md,_d,pd,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)},t.scaleUtc=function(){return Eh.apply(jv(pp,hp,Kd,Wd,Gd,Xd,_d,pd,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)]),arguments)},t.scan=function(t,e){if(r=t.length){var r,i,o=0,a=0,u=t[a];for(null==e&&(e=n);++o<r;)(e(i=t[o],u)<0||0!==e(u,u))&&(u=i,a=o);return 0===e(u,u)?a:void 0}},t.schemeAccent=Kv,t.schemeBlues=Zg,t.schemeBrBG=cg,t.schemeBuGn=Ag,t.schemeBuPu=kg,t.schemeCategory10=Qv,t.schemeDark2=Jv,t.schemeGnBu=Cg,t.schemeGreens=Kg,t.schemeGreys=ty,t.schemeOrRd=zg,t.schemeOranges=ay,t.schemePRGn=sg,t.schemePaired=tg,t.schemePastel1=ng,t.schemePastel2=eg,t.schemePiYG=hg,t.schemePuBu=Lg,t.schemePuBuGn=Dg,t.schemePuOr=pg,t.schemePuRd=Og,t.schemePurples=ey,t.schemeRdBu=gg,t.schemeRdGy=_g,t.schemeRdPu=Fg,t.schemeRdYlBu=mg,t.schemeRdYlGn=wg,t.schemeReds=iy,t.schemeSet1=rg,t.schemeSet2=ig,t.schemeSet3=og,t.schemeSpectral=Ng,t.schemeTableau10=ag,t.schemeYlGn=jg,t.schemeYlGnBu=Ig,t.schemeYlOrBr=Vg,t.schemeYlOrRd=$g,t.select=Rt,t.selectAll=function(t){return"string"==typeof t?new Pt([document.querySelectorAll(t)],[document.documentElement]):new Pt([null==t?[]:t],Ct)},t.selection=zt,t.selector=K,t.selectorAll=tt,t.set=go,t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.stack=function(){var t=my([]),n=rb,e=eb,r=ib;function i(i){var o,a,u=t.apply(this,arguments),c=i.length,f=u.length,s=new Array(f);for(o=0;o<f;++o){for(var l,h=u[o],d=s[o]=new Array(c),p=0;p<c;++p)d[p]=l=[0,+r(i[p],h,p,i)],l.data=i[p];d.key=h}for(o=0,a=n(s);o<f;++o)s[a[o]].index=o;return e(s,a),s}return i.keys=function(n){return arguments.length?(t="function"==typeof n?n:my(t_.call(n)),i):t},i.value=function(t){return arguments.length?(r="function"==typeof t?t:my(+t),i):r},i.order=function(t){return arguments.length?(n=null==t?rb:"function"==typeof t?t:my(t_.call(t)),i):n},i.offset=function(t){return arguments.length?(e=null==t?eb:t,i):e},i},t.stackOffsetDiverging=function(t,n){if((u=t.length)>0)for(var e,r,i,o,a,u,c=0,f=t[n[0]].length;c<f;++c)for(o=a=0,e=0;e<u;++e)(i=(r=t[n[e]][c])[1]-r[0])>0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):(r[0]=0,r[1]=i)},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o<a;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}eb(t,n)}},t.stackOffsetNone=eb,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var a=0,u=0;a<e;++a)u+=t[a][r][1]||0;i[r][1]+=i[r][0]=-u/2}eb(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;a<r;++a){for(var u=0,c=0,f=0;u<i;++u){for(var s=t[n[u]],l=s[a][1]||0,h=(l-(s[a-1][1]||0))/2,d=0;d<u;++d){var p=t[n[d]];h+=(p[a][1]||0)-(p[a-1][1]||0)}c+=l,f+=h*l}e[a-1][1]+=e[a-1][0]=o,c&&(o-=f/c)}e[a-1][1]+=e[a-1][0]=o,eb(t,n)}},t.stackOrderAppearance=ob,t.stackOrderAscending=ub,t.stackOrderDescending=function(t){return ub(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(cb),o=ob(t),a=0,u=0,c=[],f=[];for(n=0;n<r;++n)e=o[n],a<u?(a+=i[e],c.push(e)):(u+=i[e],f.push(e));return f.reverse().concat(c)},t.stackOrderNone=rb,t.stackOrderReverse=function(t){return rb(t).reverse()},t.stratify=function(){var t=ah,n=uh;function e(e){var r,i,o,a,u,c,f,s=e.length,l=new Array(s),h={};for(i=0;i<s;++i)r=e[i],u=l[i]=new zl(r),null!=(c=t(r,i,e))&&(c+="")&&(h[f=rh+(u.id=c)]=f in h?oh:u);for(i=0;i<s;++i)if(u=l[i],null!=(c=n(e[i],i,e))&&(c+="")){if(!(a=h[rh+c]))throw new Error("missing: "+c);if(a===oh)throw new Error("ambiguous: "+c);a.children?a.children.push(u):a.children=[u],u.parent=a}else{if(o)throw new Error("multiple roots");o=u}if(!o)throw new Error("no root");if(o.parent=ih,o.eachBefore(function(t){t.depth=t.parent.depth+1,--s}).eachBefore(Pl),o.parent=null,s>0)throw new Error("cycle");return o}return e.id=function(n){return arguments.length?(t=$l(n),e):t},e.parentId=function(t){return arguments.length?(n=$l(t),e):n},e},t.style=ft,t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.svg=va,t.symbol=function(){var t=my(u_),n=my(64),e=null;function r(){var r;if(e||(e=r=no()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),r)return e=null,r+""||null}return r.type=function(n){return arguments.length?(t="function"==typeof n?n:my(n),r):t},r.size=function(t){return arguments.length?(n="function"==typeof t?t:my(+t),r):n},r.context=function(t){return arguments.length?(e=null==t?null:t,r):e},r},t.symbolCircle=u_,t.symbolCross=c_,t.symbolDiamond=l_,t.symbolSquare=g_,t.symbolStar=v_,t.symbolTriangle=__,t.symbolWye=w_,t.symbols=M_,t.text=ua,t.thresholdFreedmanDiaconis=function(t,e,r){return t=d.call(t,u).sort(n),Math.ceil((r-e)/(2*(N(t,.75)-N(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*f(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=M,t.tickFormat=Gh,t.tickIncrement=x,t.tickStep=w,t.ticks=m,t.timeDay=Nd,t.timeDays=Td,t.timeFormatDefaultLocale=zv,t.timeFormatLocale=bp,t.timeFriday=zd,t.timeFridays=Bd,t.timeHour=wd,t.timeHours=Md,t.timeInterval=dd,t.timeMillisecond=pd,t.timeMilliseconds=vd,t.timeMinute=md,t.timeMinutes=xd,t.timeMonday=kd,t.timeMondays=qd,t.timeMonth=Yd,t.timeMonths=Id,t.timeSaturday=Rd,t.timeSaturdays=Fd,t.timeSecond=_d,t.timeSeconds=bd,t.timeSunday=Sd,t.timeSundays=Dd,t.timeThursday=Pd,t.timeThursdays=Od,t.timeTuesday=Ed,t.timeTuesdays=Ld,t.timeWednesday=Cd,t.timeWednesdays=Ud,t.timeWeek=Sd,t.timeWeeks=Dd,t.timeYear=Hd,t.timeYears=jd,t.timeout=yr,t.timer=hr,t.timerFlush=dr,t.touch=Ft,t.touches=function(t,n){null==n&&(n=Ut().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Ot(t,n[e]);return i},t.transition=Or,t.transpose=k,t.tree=function(){var t=ch,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,a=new dh(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new dh(r[i],i)),e.parent=n;return(a.parent=new dh(null,0)).children=[a],a}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(a),r)i.eachBefore(u);else{var f=i,s=i,l=i;i.eachBefore(function(t){t.x<f.x&&(f=t),t.x>s.x&&(s=t),t.depth>l.depth&&(l=t)});var h=f===s?1:t(f,s)/2,d=h-f.x,p=n/(s.x+h+d),v=e/(l.depth||1);i.eachBefore(function(t){t.x=(t.x+d)*p,t.y=t.depth*v})}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,c=o.parent.children[0],f=o.m,s=a.m,l=u.m,h=c.m;u=sh(u),o=fh(o),u&&o;)c=fh(c),(a=sh(a)).a=n,(i=u.z+l-o.z-f+t(u._,o._))>0&&(lh(hh(u,n,r),n,i),f+=i,s+=i),l+=u.m,f+=o.m,h+=c.m,s+=a.m;u&&!sh(a)&&(a.t=u,a.m+=l-s),o&&!fh(c)&&(c.t=o,c.m+=f-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=yh,n=!1,e=1,r=1,i=[0],o=Wl,a=Wl,u=Wl,c=Wl,f=Wl;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(nh),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l<r&&(r=l=(r+l)/2),h<s&&(s=h=(s+h)/2),n.x0=r,n.y0=s,n.x1=l,n.y1=h,n.children&&(e=i[n.depth+1]=o(n)/2,r+=f(n)-e,s+=a(n)-e,(l-=u(n)-e)<r&&(r=l=(r+l)/2),(h-=c(n)-e)<s&&(s=h=(s+h)/2),t(n,r,s,l,h))}return s.round=function(t){return arguments.length?(n=!!t,s):n},s.size=function(t){return arguments.length?(e=+t[0],r=+t[1],s):[e,r]},s.tile=function(n){return arguments.length?(t=$l(n),s):t},s.padding=function(t){return arguments.length?s.paddingInner(t).paddingOuter(t):s.paddingInner()},s.paddingInner=function(t){return arguments.length?(o="function"==typeof t?t:Zl(+t),s):o},s.paddingOuter=function(t){return arguments.length?s.paddingTop(t).paddingRight(t).paddingBottom(t).paddingLeft(t):s.paddingTop()},s.paddingTop=function(t){return arguments.length?(a="function"==typeof t?t:Zl(+t),s):a},s.paddingRight=function(t){return arguments.length?(u="function"==typeof t?t:Zl(+t),s):u},s.paddingBottom=function(t){return arguments.length?(c="function"==typeof t?t:Zl(+t),s):c},s.paddingLeft=function(t){return arguments.length?(f="function"==typeof t?t:Zl(+t),s):f},s},t.treemapBinary=function(t,n,e,r,i){var o,a,u=t.children,c=u.length,f=new Array(c+1);for(f[0]=a=o=0;o<c;++o)f[o+1]=a+=u[o].value;!function t(n,e,r,i,o,a,c){if(n>=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=c)}for(var l=f[n],h=r/2+l,d=n+1,p=e-1;d<p;){var v=d+p>>>1;f[v]<h?d=v+1:p=v}h-f[d-1]<f[d]-h&&n+1<d&&--d;var g=f[d]-l,y=r-g;if(a-i>c-o){var _=(i*y+a*g)/r;t(n,d,g,i,o,_,c),t(d,e,y,_,o,a,c)}else{var b=(o*y+c*g)/r;t(n,d,g,i,o,a,b),t(d,e,y,i,b,a,c)}}(0,c,t.value,n,e,r,i)},t.treemapDice=eh,t.treemapResquarify=_h,t.treemapSlice=ph,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?ph:eh)(t,n,e,r,i)},t.treemapSquarify=yh,t.tsv=sa,t.tsvFormat=Ko,t.tsvFormatBody=Jo,t.tsvFormatRow=na,t.tsvFormatRows=ta,t.tsvFormatValue=ea,t.tsvParse=Zo,t.tsvParseRows=Qo,t.utcDay=Wd,t.utcDays=Zd,t.utcFriday=rp,t.utcFridays=sp,t.utcHour=Gd,t.utcHours=$d,t.utcMillisecond=pd,t.utcMilliseconds=vd,t.utcMinute=Xd,t.utcMinutes=Vd,t.utcMonday=Jd,t.utcMondays=ap,t.utcMonth=hp,t.utcMonths=dp,t.utcSaturday=ip,t.utcSaturdays=lp,t.utcSecond=_d,t.utcSeconds=bd,t.utcSunday=Kd,t.utcSundays=op,t.utcThursday=ep,t.utcThursdays=fp,t.utcTuesday=tp,t.utcTuesdays=up,t.utcWednesday=np,t.utcWednesdays=cp,t.utcWeek=Kd,t.utcWeeks=op,t.utcYear=pp,t.utcYears=vp,t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.variance=c,t.version="5.16.0",t.voronoi=function(){var t=sb,n=lb,e=null;function r(r){return new Vb(r.map(function(e,i){var o=[Math.round(t(e,i,r)/Ib)*Ib,Math.round(n(e,i,r)/Ib)*Ib];return o.index=i,o.data=e,o}),e)}return r.polygons=function(t){return r(t).polygons()},r.links=function(t){return r(t).links()},r.triangles=function(t){return r(t).triangles()},r.x=function(n){return arguments.length?(t="function"==typeof n?n:fb(+n),r):t},r.y=function(t){return arguments.length?(n="function"==typeof t?t:fb(+t),r):n},r.extent=function(t){return arguments.length?(e=null==t?null:[[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]],r):e&&[[e[0][0],e[0][1]],[e[1][0],e[1][1]]]},r.size=function(t){return arguments.length?(e=null==t?null:[[0,0],[+t[0],+t[1]]],r):e&&[e[1][0]-e[0][0],e[1][1]-e[0][1]]},r},t.window=ct,t.xml=da,t.zip=function(){return k(arguments)},t.zoom=function(){var n,e,r=tm,i=nm,o=om,a=rm,u=im,c=[0,1/0],f=[[-1/0,-1/0],[1/0,1/0]],s=250,l=Ie,h=I("start","zoom","end"),d=500,p=150,v=0;function g(t){t.property("__zoom",em).on("wheel.zoom",M).on("mousedown.zoom",N).on("dblclick.zoom",T).filter(u).on("touchstart.zoom",A).on("touchmove.zoom",S).on("touchend.zoom touchcancel.zoom",k).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function y(t,n){return(n=Math.max(c[0],Math.min(c[1],n)))===t.k?t:new Wb(n,t.x,t.y)}function _(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new Wb(t.k,r,i)}function b(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function m(t,n,e){t.on("start.zoom",function(){x(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){x(this,arguments).end()}).tween("zoom",function(){var t=this,r=arguments,o=x(t,r),a=i.apply(t,r),u=null==e?b(a):"function"==typeof e?e.apply(t,r):e,c=Math.max(a[1][0]-a[0][0],a[1][1]-a[0][1]),f=t.__zoom,s="function"==typeof n?n.apply(t,r):n,h=l(f.invert(u).concat(c/f.k),s.invert(u).concat(c/s.k));return function(t){if(1===t)t=s;else{var n=h(t),e=c/n[2];t=new Wb(e,u[0]-n[0]*e,u[1]-n[1]*e)}o.zoom(null,t)}})}function x(t,n,e){return!e&&t.__zooming||new w(t,n)}function w(t,n){this.that=t,this.args=n,this.active=0,this.extent=i.apply(t,n),this.taps=0}function M(){if(r.apply(this,arguments)){var t=x(this,arguments),n=this.__zoom,e=Math.max(c[0],Math.min(c[1],n.k*Math.pow(2,a.apply(this,arguments)))),i=Bt(this);if(t.wheel)t.mouse[0][0]===i[0]&&t.mouse[0][1]===i[1]||(t.mouse[1]=n.invert(t.mouse[0]=i)),clearTimeout(t.wheel);else{if(n.k===e)return;t.mouse=[i,n.invert(i)],Pr(this),t.start()}Jb(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},p),t.zoom("mouse",o(_(y(n,e),t.mouse[0],t.mouse[1]),t.extent,f))}}function N(){if(!e&&r.apply(this,arguments)){var n=x(this,arguments,!0),i=Rt(t.event.view).on("mousemove.zoom",function(){if(Jb(),!n.moved){var e=t.event.clientX-u,r=t.event.clientY-c;n.moved=e*e+r*r>v}n.zoom("mouse",o(_(n.that.__zoom,n.mouse[0]=Bt(n.that),n.mouse[1]),n.extent,f))},!0).on("mouseup.zoom",function(){i.on("mousemove.zoom mouseup.zoom",null),jt(t.event.view,n.moved),Jb(),n.end()},!0),a=Bt(this),u=t.event.clientX,c=t.event.clientY;Ht(t.event.view),Kb(),n.mouse=[a,this.__zoom.invert(a)],Pr(this),n.start()}}function T(){if(r.apply(this,arguments)){var n=this.__zoom,e=Bt(this),a=n.invert(e),u=n.k*(t.event.shiftKey?.5:2),c=o(_(y(n,u),e,a),i.apply(this,arguments),f);Jb(),s>0?Rt(this).transition().duration(s).call(m,c,e):Rt(this).call(g.transform,c)}}function A(){if(r.apply(this,arguments)){var e,i,o,a,u=t.event.touches,c=u.length,f=x(this,arguments,t.event.changedTouches.length===c);for(Kb(),i=0;i<c;++i)a=[a=Ft(this,u,(o=u[i]).identifier),this.__zoom.invert(a),o.identifier],f.touch0?f.touch1||f.touch0[2]===a[2]||(f.touch1=a,f.taps=0):(f.touch0=a,e=!0,f.taps=1+!!n);n&&(n=clearTimeout(n)),e&&(f.taps<2&&(n=setTimeout(function(){n=null},d)),Pr(this),f.start())}}function S(){if(this.__zooming){var e,r,i,a,u=x(this,arguments),c=t.event.changedTouches,s=c.length;for(Jb(),n&&(n=clearTimeout(n)),u.taps=0,e=0;e<s;++e)i=Ft(this,c,(r=c[e]).identifier),u.touch0&&u.touch0[2]===r.identifier?u.touch0[0]=i:u.touch1&&u.touch1[2]===r.identifier&&(u.touch1[0]=i);if(r=u.that.__zoom,u.touch1){var l=u.touch0[0],h=u.touch0[1],d=u.touch1[0],p=u.touch1[1],v=(v=d[0]-l[0])*v+(v=d[1]-l[1])*v,g=(g=p[0]-h[0])*g+(g=p[1]-h[1])*g;r=y(r,Math.sqrt(v/g)),i=[(l[0]+d[0])/2,(l[1]+d[1])/2],a=[(h[0]+p[0])/2,(h[1]+p[1])/2]}else{if(!u.touch0)return;i=u.touch0[0],a=u.touch0[1]}u.zoom("touch",o(_(r,i,a),u.extent,f))}}function k(){if(this.__zooming){var n,r,i=x(this,arguments),o=t.event.changedTouches,a=o.length;for(Kb(),e&&clearTimeout(e),e=setTimeout(function(){e=null},d),n=0;n<a;++n)r=o[n],i.touch0&&i.touch0[2]===r.identifier?delete i.touch0:i.touch1&&i.touch1[2]===r.identifier&&delete i.touch1;if(i.touch1&&!i.touch0&&(i.touch0=i.touch1,delete i.touch1),i.touch0)i.touch0[1]=this.__zoom.invert(i.touch0[0]);else if(i.end(),2===i.taps){var u=Rt(this).on("dblclick.zoom");u&&u.apply(this,arguments)}}}return g.transform=function(t,n,e){var r=t.selection?t.selection():t;r.property("__zoom",em),t!==r?m(t,n,e):r.interrupt().each(function(){x(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},g.scaleBy=function(t,n,e){g.scaleTo(t,function(){var t=this.__zoom.k,e="function"==typeof n?n.apply(this,arguments):n;return t*e},e)},g.scaleTo=function(t,n,e){g.transform(t,function(){var t=i.apply(this,arguments),r=this.__zoom,a=null==e?b(t):"function"==typeof e?e.apply(this,arguments):e,u=r.invert(a),c="function"==typeof n?n.apply(this,arguments):n;return o(_(y(r,c),a,u),t,f)},e)},g.translateBy=function(t,n,e){g.transform(t,function(){return o(this.__zoom.translate("function"==typeof n?n.apply(this,arguments):n,"function"==typeof e?e.apply(this,arguments):e),i.apply(this,arguments),f)})},g.translateTo=function(t,n,e,r){g.transform(t,function(){var t=i.apply(this,arguments),a=this.__zoom,u=null==r?b(t):"function"==typeof r?r.apply(this,arguments):r;return o(Zb.translate(u[0],u[1]).scale(a.k).translate("function"==typeof n?-n.apply(this,arguments):-n,"function"==typeof e?-e.apply(this,arguments):-e),t,f)},r)},w.prototype={start:function(){return 1==++this.active&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(delete this.that.__zooming,this.emit("end")),this},emit:function(t){kt(new $b(g,t,this.that.__zoom),h.apply,h,[t,this.that,this.args])}},g.wheelDelta=function(t){return arguments.length?(a="function"==typeof t?t:Gb(+t),g):a},g.filter=function(t){return arguments.length?(r="function"==typeof t?t:Gb(!!t),g):r},g.touchable=function(t){return arguments.length?(u="function"==typeof t?t:Gb(!!t),g):u},g.extent=function(t){return arguments.length?(i="function"==typeof t?t:Gb([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),g):i},g.scaleExtent=function(t){return arguments.length?(c[0]=+t[0],c[1]=+t[1],g):[c[0],c[1]]},g.translateExtent=function(t){return arguments.length?(f[0][0]=+t[0][0],f[1][0]=+t[1][0],f[0][1]=+t[0][1],f[1][1]=+t[1][1],g):[[f[0][0],f[0][1]],[f[1][0],f[1][1]]]},g.constrain=function(t){return arguments.length?(o=t,g):o},g.duration=function(t){return arguments.length?(s=+t,g):s},g.interpolate=function(t){return arguments.length?(l=t,g):l},g.on=function(){var t=h.on.apply(h,arguments);return t===h?g:t},g.clickDistance=function(t){return arguments.length?(v=(t=+t)*t,g):Math.sqrt(v)},g},t.zoomIdentity=Zb,t.zoomTransform=Qb,Object.defineProperty(t,"__esModule",{value:!0})});
diff --git a/tools/determinism/deterministic_build_ignorelist.pyl b/tools/determinism/deterministic_build_ignorelist.pyl index 9470da1..cebd7451 100644 --- a/tools/determinism/deterministic_build_ignorelist.pyl +++ b/tools/determinism/deterministic_build_ignorelist.pyl
@@ -27,6 +27,10 @@ 'nacl_test_data/glibc/pm_exit_status_test_libs/lib64/libppapi_cpp_lib.so', 'nacl_test_data/glibc/simple_libs/lib64/libppapi_cpp_lib.so', 'nacl_test_data/glibc/sysconf_nprocessors_onln_test_libs/lib64/libppapi_cpp_lib.so', + 'nacl_test_data/nonsfi/irt_exception_test_pnacl_newlib_x32_nonsfi.nexe', + 'nacl_test_data/nonsfi/irt_manifest_file_pnacl_newlib_x32_nonsfi.nexe', + 'ppapi_nacl_tests_pnacl_newlib_x64.nexe', + 'test_data/ppapi/tests/extensions/packaged_app/nonsfi/ppapi_tests_extensions_packaged_app_pnacl_newlib_x32_nonsfi.nexe', # https://crbug.com/1040247 'nacl_irt_x86_64.nexe',
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec index 8c4f7b4..4a7298d7 100644 --- a/tools/gritsettings/resource_ids.spec +++ b/tools/gritsettings/resource_ids.spec
@@ -106,12 +106,9 @@ "includes": [1220], "structures": [1240], }, - "chrome/browser/resources/bookmarks/bookmarks_resources.grd": { + "<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/bookmarks/bookmarks_resources.grd": { + "META": {"sizes": {"includes": [50],}}, "includes": [1260], - "structures": [1280], - }, - "chrome/browser/resources/bookmarks/bookmarks_resources_vulcanized.grd": { - "includes": [1300], }, "chrome/browser/resources/chromeos/cellular_setup/cellular_setup_resources.grd": { "structures": [1360],
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 0c28c705..66b7c87 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -22028,13 +22028,11 @@ <int value="580" label="PasswordLeakDetectionEnabled"/> <int value="581" label="LockScreenMediaPlaybackEnabled"/> <int value="582" label="DnsOverHttpsMode"/> - <int value="583" label="SendFilesForMalwareCheck"/> <int value="584" label="PolicyAtomicGroupsEnabled"/> <int value="585" label="UnsafeEventsReportingEnabled"/> <int value="586" label="BlockLargeFileTransfer"/> <int value="587" label="DelayDeliveryUntilVerdict"/> <int value="588" label="AllowPasswordProtectedFiles"/> - <int value="589" label="CheckContentCompliance"/> <int value="590" label="URLsToCheckComplianceOfDownloadedContent"/> <int value="591" label="URLsToNotCheckComplianceOfUploadedContent"/> <int value="592" label="DictationEnabled"/> @@ -29751,7 +29749,8 @@ <int value="3541" label="V8WheelEvent_DeltaMode_AttributeGetter"/> <int value="3542" label="V8Touch_Force_AttributeGetter"/> <int value="3543" label="WebGLRenderingContextMakeXRCompatible"/> - <int value="3544" label="IdentifiabilityStudyReserved3544"/> + <int value="3544" + label="V8WebGLCompressedTextureASTC_GetSupportedProfiles_Method"/> <int value="3545" label="IdentifiabilityStudyReserved3545"/> <int value="3546" label="V8BeforeInstallPromptEvent_Platforms_AttributeGetter"/> @@ -29776,10 +29775,10 @@ <int value="3565" label="IdentifiabilityStudyReserved3565"/> <int value="3566" label="V8BaseAudioContext_SampleRate_AttributeGetter"/> <int value="3567" label="WindowScreenId"/> - <int value="3568" label="IdentifiabilityStudyReserved3568"/> - <int value="3569" label="IdentifiabilityStudyReserved3569"/> - <int value="3570" label="IdentifiabilityStudyReserved3570"/> - <int value="3571" label="IdentifiabilityStudyReserved3571"/> + <int value="3568" label="WebGLRenderingContextGetParameter"/> + <int value="3569" label="WebGLRenderingContextGetRenderbufferParameter"/> + <int value="3570" label="WebGLRenderingContextGetShaderPrecisionFormat"/> + <int value="3571" label="WebGL2RenderingContextGetInternalFormatParameter"/> <int value="3572" label="IdentifiabilityStudyReserved3572"/> <int value="3573" label="IdentifiabilityStudyReserved3573"/> <int value="3574" label="IdentifiabilityStudyReserved3574"/> @@ -44065,6 +44064,7 @@ <int value="517429103" label="AutofillImportDynamicForms:enabled"/> <int value="517568645" label="AnimatedAppMenuIcon:disabled"/> <int value="518419320" label="RemoteCopyProgressNotification:disabled"/> + <int value="519140642" label="SendWebUIJavaScriptErrorReports:enabled"/> <int value="520982116" label="BuiltInModuleAll:enabled"/> <int value="529235584" label="PhoneHub:enabled"/> <int value="530828403" label="AllowStartingServiceManagerOnly:disabled"/> @@ -44539,7 +44539,6 @@ <int value="1015012662" label="ChromeOSDirectVideoDecoder:enabled"/> <int value="1015895665" label="drop-sync-credential:enabled"/> <int value="1017364362" label="VrIconInDaydreamHome:enabled"/> - <int value="1018165268" label="InterestFeedFeedback:enabled"/> <int value="1018797564" label="EnableAppListSearchAutocomplete:disabled"/> <int value="1018998019" label="memlog"/> <int value="1019623058" label="ash-enable-shelf-model-synchronization"/> @@ -45212,7 +45211,6 @@ <int value="1688075820" label="OmniboxExperimentalKeywordMode:disabled"/> <int value="1689123607" label="enable-app-link"/> <int value="1689183477" label="enable-merge-key-char-events"/> - <int value="1689275095" label="InterestFeedFeedback:disabled"/> <int value="1690248203" label="HelpAppV2:enabled"/> <int value="1690837904" label="save-previous-document-resources"/> <int value="1691568199" label="AndroidSpellCheckerNonLowEnd:disabled"/> @@ -45379,6 +45377,7 @@ <int value="1854226565" label="AutofillNoLocalSaveOnUnmaskSuccess:enabled"/> <int value="1854646491" label="DetailedLanguageSettings:disabled"/> <int value="1855524566" label="allow-insecure-websocket-from-https-origin"/> + <int value="1857000695" label="SendWebUIJavaScriptErrorReports:disabled"/> <int value="1858385315" label="ChromeHomeBottomNavLabels:enabled"/> <int value="1858919054" label="SplitSettingsSync:disabled"/> <int value="1860597983" label="AndroidSpellChecker:disabled"/> @@ -47127,6 +47126,7 @@ <int value="675" label="line-gap-override"/> <int value="676" label="math-shift"/> <int value="677" label="math-depth"/> + <int value="678" label="advance-proportional-override"/> </enum> <enum name="MappedEditingCommands">
diff --git a/tools/metrics/histograms/histograms_index.txt b/tools/metrics/histograms/histograms_index.txt index 42d988b..b7148793 100644 --- a/tools/metrics/histograms/histograms_index.txt +++ b/tools/metrics/histograms/histograms_index.txt
@@ -111,4 +111,5 @@ tools/metrics/histograms/histograms_xml/web_audio/histograms.xml tools/metrics/histograms/histograms_xml/web_core/histograms.xml tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml +tools/metrics/histograms/histograms_xml/weblayer/histograms.xml tools/metrics/histograms/histograms_xml/windows/histograms.xml \ No newline at end of file
diff --git a/tools/metrics/histograms/histograms_xml/apps/histograms.xml b/tools/metrics/histograms/histograms_xml/apps/histograms.xml index c62e1b0d..fde63fc 100644 --- a/tools/metrics/histograms/histograms_xml/apps/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/apps/histograms.xml
@@ -187,7 +187,7 @@ </histogram> <histogram name="Apps.AppList.DriveQuickAccessProvider.CacheEmpty" - enum="BooleanEmpty" expires_after="2021-02-07"> + enum="BooleanEmpty" expires_after="2021-04-11"> <owner>tby@chromium.org</owner> <owner>wrong@chromium.org</owner> <owner>jiameng@chromium.org</owner> @@ -210,7 +210,7 @@ </histogram> <histogram name="Apps.AppList.DriveQuickAccessProvider.DriveFSMounted" - enum="Boolean" expires_after="2021-02-07"> + enum="Boolean" expires_after="2021-04-11"> <owner>tby@chromium.org</owner> <owner>wrong@chromium.org</owner> <owner>jiameng@chromium.org</owner> @@ -221,7 +221,7 @@ </histogram> <histogram name="Apps.AppList.DriveQuickAccessProvider.FileError" - enum="DriveFileError" expires_after="2021-02-07"> + enum="DriveFileError" expires_after="2021-04-11"> <owner>tby@chromium.org</owner> <owner>wrong@chromium.org</owner> <owner>jiameng@chromium.org</owner> @@ -369,7 +369,7 @@ </histogram> <histogram name="Apps.AppList.OsSettingsProvider.QueryTime" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>jiameng@chromium.org</owner> <owner>tby@chromium.org</owner> <summary> @@ -522,7 +522,7 @@ </histogram> <histogram name="Apps.AppList.ZeroStateFileProvider.Latency" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>wrong@chromium.org</owner> <owner>tby@chromium.org</owner> <owner>jiameng@chromium.org</owner> @@ -543,7 +543,7 @@ </histogram> <histogram name="Apps.AppList.ZeroStateResults.LaunchedItemType" - enum="ZeroStateResultType" expires_after="2021-02-07"> + enum="ZeroStateResultType" expires_after="2021-04-11"> <owner>wrong@chromium.org</owner> <owner>tby@chromium.org</owner> <owner>jiameng@chromium.org</owner> @@ -565,7 +565,7 @@ </histogram> <histogram name="Apps.AppList.ZeroStateResults.ReceivedScore.OmniboxSearch" - units="score" expires_after="2021-02-07"> + units="score" expires_after="2021-04-11"> <owner>wrong@chromium.org</owner> <owner>tby@chromium.org</owner> <owner>jiameng@chromium.org</owner> @@ -589,7 +589,7 @@ </histogram> <histogram name="Apps.AppList.ZeroStateResultsList.Clicked" - enum="BooleanClicked" expires_after="2021-02-07"> + enum="BooleanClicked" expires_after="2021-04-11"> <owner>wrong@chromium.org</owner> <owner>tby@chromium.org</owner> <owner>jiameng@chromium.org</owner> @@ -674,7 +674,7 @@ </histogram> <histogram name="Apps.AppListAppLaunchedV2" enum="AppListLaunchedFrom" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <!-- Name completed by histogram_suffixes name="AppListState" --> <owner>mmourgos@chromium.org</owner> @@ -1098,7 +1098,7 @@ </histogram> <histogram name="Apps.AppListSuggestedChipOpenType" enum="AppListSearchResult" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <!-- Name completed by histogram_suffixes name="TabletOrClamshellMode" --> <owner>newcomer@chromium.org</owner> @@ -1634,7 +1634,7 @@ <histogram base="true" name="Apps.PaginationTransition.DragScroll.PresentationTime.MaxLatency" - units="ms" expires_after="2020-12-27"> + units="ms" expires_after="2021-04-11"> <!-- Name completed by histogram_suffixes name="TabletOrClamshellMode" -->
diff --git a/tools/metrics/histograms/histograms_xml/arc/histograms.xml b/tools/metrics/histograms/histograms_xml/arc/histograms.xml index c248dc6..5306846 100644 --- a/tools/metrics/histograms/histograms_xml/arc/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/arc/histograms.xml
@@ -74,13 +74,13 @@ </summary> </histogram> -<histogram name="Arc.AndroidBootTime" units="ms" expires_after="2021-02-07"> +<histogram name="Arc.AndroidBootTime" units="ms" expires_after="2021-04-11"> <owner>elijahtaylor@google.com</owner> <owner>shihuis@google.com</owner> <summary>The time elapsed for booting up the ARC instance.</summary> </histogram> -<histogram name="Arc.AppCount" units="units" expires_after="2021-02-07"> +<histogram name="Arc.AppCount" units="units" expires_after="2021-04-11"> <owner>elijahtaylor@google.com</owner> <owner>shihuis@google.com</owner> <summary> @@ -319,7 +319,7 @@ </histogram> <histogram name="Arc.ContainerRestartAfterCrashCount" units="units" - expires_after="2020-12-27"> + expires_after="2021-04-11"> <owner>elijahtaylor@google.com</owner> <owner>yusukes@google.com</owner> <summary> @@ -395,7 +395,7 @@ </histogram> <histogram name="Arc.EngagementTime.ArcTotal" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>maajid@google.com</owner> <owner>shaochuan@google.com</owner> <owner>shihuis@google.com</owner> @@ -432,7 +432,7 @@ </histogram> <histogram name="Arc.EngagementTime.Total" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>maajid@google.com</owner> <owner>shaochuan@google.com</owner> <owner>shihuis@google.com</owner> @@ -549,7 +549,7 @@ </summary> </histogram> -<histogram name="Arc.ImeCount" units="units" expires_after="2021-02-07"> +<histogram name="Arc.ImeCount" units="units" expires_after="2021-04-11"> <owner>yhanada@chromium.org</owner> <owner>tetsui@chromium.org</owner> <summary> @@ -952,7 +952,7 @@ </histogram> <histogram name="Arc.Session.StopReason" enum="ArcStopReason" - expires_after="2020-12-05"> + expires_after="2021-04-11"> <!-- Name completed by histogram_suffixes name="ArcUserTypes" --> <owner>shaochuan@google.com</owner> @@ -1086,7 +1086,7 @@ </histogram> <histogram name="Arc.UserInteraction" enum="ArcUserInteraction" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>jhorwich@chromium.org</owner> <owner>elijahtaylor@chromium.org</owner> <owner>shihuis@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/ash/histograms.xml b/tools/metrics/histograms/histograms_xml/ash/histograms.xml index f769eaf..ce33b5aa 100644 --- a/tools/metrics/histograms/histograms_xml/ash/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ash/histograms.xml
@@ -345,7 +345,7 @@ </histogram> <histogram name="Ash.Desks.DesksSwitch" enum="DesksSwitchSource" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>afakhry@chromium.org</owner> <owner>tclaiborne@chromium.org</owner> <summary> @@ -367,7 +367,7 @@ </histogram> <histogram name="Ash.Desks.NewDesk2" enum="DesksCreationRemovalSource" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>afakhry@chromium.org</owner> <owner>tclaiborne@chromium.org</owner> <summary> @@ -378,7 +378,7 @@ </histogram> <histogram name="Ash.Desks.NumberOfWindowsOnDesk_1" units="units" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>afakhry@chromium.org</owner> <owner>tclaiborne@chromium.org</owner> <summary> @@ -388,7 +388,7 @@ </histogram> <histogram name="Ash.Desks.NumberOfWindowsOnDesk_2" units="units" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>afakhry@chromium.org</owner> <owner>tclaiborne@chromium.org</owner> <summary> @@ -398,7 +398,7 @@ </histogram> <histogram name="Ash.Desks.NumberOfWindowsOnDesk_3" units="units" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>afakhry@chromium.org</owner> <owner>tclaiborne@chromium.org</owner> <summary> @@ -408,7 +408,7 @@ </histogram> <histogram name="Ash.Desks.NumberOfWindowsOnDesk_4" units="units" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>afakhry@chromium.org</owner> <owner>tclaiborne@chromium.org</owner> <summary> @@ -671,7 +671,7 @@ </histogram> <histogram name="Ash.HotseatTransition.Drag.PresentationTime" units="ms" - expires_after="2021-01-31"> + expires_after="2021-04-11"> <owner>anasalazar@chromium.org</owner> <owner>newcomer@chromium.org</owner> <summary> @@ -888,7 +888,7 @@ </histogram> <histogram name="Ash.NightLight.ScheduleType" enum="AshNightLightScheduleType" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>afakhry@chromium.org</owner> <summary> The selected Night Light schedule type. Emitted when the user changes the @@ -1162,7 +1162,7 @@ </histogram> <histogram name="Ash.Shelf.NumberOfPinnedItems" units="Icons" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>anasalazar@google.com</owner> <owner>mmourgos@google.com</owner> <summary> @@ -1606,7 +1606,7 @@ </histogram> <histogram name="Ash.TouchView.TouchViewActive" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>girard@chromium.org</owner> <summary> The length of time that TouchView is active, for each activation.
diff --git a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml index 59f8b04..e11a284 100644 --- a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml
@@ -31,7 +31,7 @@ </histogram> <histogram name="Assistant.BetterOnboarding.Shown" - enum="AssistantBetterOnboardingMode" expires_after="2021-02-07"> + enum="AssistantBetterOnboardingMode" expires_after="2021-04-11"> <owner>xiaohuic@chromium.org</owner> <owner>croissant-eng@chromium.org</owner> <summary> @@ -41,7 +41,7 @@ </histogram> <histogram name="Assistant.ButtonClickCount" enum="AssistantButtonId" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>xiaohuic@chromium.org</owner> <owner>meilinw@chromium.org</owner> <summary> @@ -72,7 +72,7 @@ </histogram> <histogram name="Assistant.EntryPoint" enum="AssistantEntryPoint" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>xiaohuic@chromium.org</owner> <owner>meilinw@chromium.org</owner> <summary> @@ -147,7 +147,7 @@ </histogram> <histogram name="Assistant.QueryResponseType" enum="AssistantQueryResponseType" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>xiaohuic@chromium.org</owner> <owner>meilinw@chromium.org</owner> <summary>The Assistant query response type.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/back_forward_cache/histograms.xml b/tools/metrics/histograms/histograms_xml/back_forward_cache/histograms.xml index eaee707..5855b98 100644 --- a/tools/metrics/histograms/histograms_xml/back_forward_cache/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/back_forward_cache/histograms.xml
@@ -69,7 +69,7 @@ <histogram name="BackForwardCache.AllSites.HistoryNavigationOutcome.BrowsingInstanceNotSwappedReason" enum="BackForwardCacheBrowsingInstanceNotSwappedReason" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>hajimehoshi@chromium.org</owner> <owner>bfcache-dev@chromium.org</owner> <summary> @@ -107,7 +107,7 @@ <histogram name="BackForwardCache.AllSites.HistoryNavigationOutcome.NotRestoredReason" - enum="BackForwardCacheNotRestoredReason" expires_after="2021-02-07"> + enum="BackForwardCacheNotRestoredReason" expires_after="2021-04-11"> <owner>hajimehoshi@chromium.org</owner> <owner>bfcache-dev@chromium.org</owner> <summary> @@ -123,7 +123,7 @@ <histogram name="BackForwardCache.EvictedAfterDocumentRestoredReason" enum="BackForwardCacheEvictedAfterDocumentRestoredReason" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>hajimehoshi@chromium.org</owner> <owner>bfcache-dev@chromium.org</owner> <summary> @@ -197,7 +197,7 @@ </histogram> <histogram name="BackForwardCache.HistoryNavigationOutcome.BlocklistedFeature" - enum="WebSchedulerTrackedFeature" expires_after="2021-02-07"> + enum="WebSchedulerTrackedFeature" expires_after="2021-04-11"> <owner>hajimehoshi@chromium.org</owner> <owner>bfcache-dev@chromium.org</owner> <summary> @@ -215,7 +215,7 @@ <histogram name="BackForwardCache.HistoryNavigationOutcome.BrowsingInstanceNotSwappedReason" enum="BackForwardCacheBrowsingInstanceNotSwappedReason" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>hajimehoshi@chromium.org</owner> <owner>bfcache-dev@chromium.org</owner> <summary> @@ -232,7 +232,7 @@ <histogram name="BackForwardCache.HistoryNavigationOutcome.DisabledForRenderFrameHostReason" enum="BackForwardCacheDisabledForRenderFrameHostReason" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>carlscab@chromium.org</owner> <owner>hajimehoshi@chromium.org</owner> <owner>bfcache-dev@chromium.org</owner> @@ -254,7 +254,7 @@ </histogram> <histogram name="BackForwardCache.HistoryNavigationOutcome.NotRestoredReason" - enum="BackForwardCacheNotRestoredReason" expires_after="2021-02-07"> + enum="BackForwardCacheNotRestoredReason" expires_after="2021-04-11"> <owner>hajimehoshi@chromium.org</owner> <owner>bfcache-dev@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/blink/histograms.xml b/tools/metrics/histograms/histograms_xml/blink/histograms.xml index 8731400..bedc2fe2 100644 --- a/tools/metrics/histograms/histograms_xml/blink/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/blink/histograms.xml
@@ -568,7 +568,7 @@ </histogram> <histogram name="Blink.DecodedImageType" enum="DecodedImageType" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>urvang@chromium.org</owner> <summary>Image codec inferred during decode.</summary> </histogram> @@ -994,7 +994,7 @@ </histogram> <histogram base="true" name="Blink.ImageDecoders.InitiallyFullyDecodedByteSize" - units="bytes" expires_after="2021-02-07"> + units="bytes" expires_after="2021-04-11"> <owner>mbarowsky@chromium.org</owner> <owner>andrescj@chromium.org</owner> <summary> @@ -1025,7 +1025,7 @@ </histogram> <histogram name="Blink.ImageDecoders.Jpeg.ColorSpace" enum="JpegColorSpace" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>andrescj@chromium.org</owner> <owner>mcasas@chromium.org</owner> <summary> @@ -1316,7 +1316,11 @@ </histogram> <histogram base="true" name="Blink.MainFrame.ScrollingCoordinatorRatio" - units="%" expires_after="2020-11-08"> + units="%" expires_after="M88"> + <obsolete> + Merged into Blink.MainFrame.CompositingCommitRatio in + http://crrev.com/815947 in M88. + </obsolete> <owner>schenney@chromium.org</owner> <owner>paint-dev@chromium.org</owner> <!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" --> @@ -1426,7 +1430,7 @@ </histogram> <histogram name="Blink.OffscreenCanvas.ContextType" enum="CanvasContextType" - expires_after="2021-01-31"> + expires_after="2021-04-11"> <owner>aaronhk@chromium.org</owner> <owner>fserb@chromium.org</owner> <summary> @@ -1638,7 +1642,11 @@ </histogram> <histogram name="Blink.ScrollingCoordinator.UpdateTime" units="microseconds" - expires_after="2021-03-21"> + expires_after="M88"> + <obsolete> + Merged into Blink.CompositingCommit.UpdateTime in http://crrev.com/815947 in + M88. + </obsolete> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePreFCPSuffixes" --> <!-- Name completed by histogram_suffixes name="BlinkUpdateTimePostFCPSuffixes" -->
diff --git a/tools/metrics/histograms/histograms_xml/browser/histograms.xml b/tools/metrics/histograms/histograms_xml/browser/histograms.xml index d67f09b..4486008e 100644 --- a/tools/metrics/histograms/histograms_xml/browser/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/browser/histograms.xml
@@ -378,7 +378,7 @@ </histogram> <histogram name="Browser.Tabs.SelectionToVisibilityRequestTime" - units="microseconds" expires_after="2021-02-07"> + units="microseconds" expires_after="2021-04-11"> <owner>sadrul@chromium.org</owner> <owner>sky@chromium.org</owner> <summary> @@ -533,7 +533,7 @@ </histogram> <histogram name="BrowserRenderProcessHost.FramePrioritiesSeen" - enum="FramePrioritiesSeen" expires_after="2021-02-07"> + enum="FramePrioritiesSeen" expires_after="2021-04-11"> <owner>ericrobinson@chromium.org</owner> <owner>csharrison@chromium.org</owner> <summary> @@ -777,7 +777,7 @@ </histogram> <histogram name="BrowserSwitcher.LaunchTime" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>nicolaso@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml index f78e64c..d18eec5 100644 --- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -57,7 +57,7 @@ </histogram> <histogram name="ChromeOS.Apps.IntentPickerAction" - enum="ArcIntentHandlerAction" expires_after="2021-02-07"> + enum="ArcIntentHandlerAction" expires_after="2021-04-11"> <owner>elijahtaylor@google.com</owner> <owner>dominickn@chromium.org</owner> <owner>shihuis@google.com</owner> @@ -401,7 +401,7 @@ </histogram> <histogram name="ChromeOS.MemoryPressureLevel" enum="MemoryPressureLevel" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>xdai@chromium.org</owner> <summary> The memory pressure level in Chrome OS, which is recorded periodically (once @@ -492,7 +492,7 @@ </histogram> <histogram name="ChromeOS.SAML.Provider" enum="ChromeOSSamlProvider" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>mslus@chromium.org</owner> <owner>mohammedabdon@chromium.org</owner> <summary>Records SAML provider when SAML login flow is used.</summary> @@ -548,6 +548,17 @@ </summary> </histogram> +<histogram name="ChromeOS.Settings.Device.KeyboardFunctionKeys" + enum="BooleanToggled" expires_after="2021-09-30"> + <owner>khorimoto@chromium.org</owner> + <owner>hsuregan@chromium.org</owner> + <owner>cros-customization@google.com</owner> + <summary> + Records when a user changes the kKeyboardFunctionKeys setting on the Device + page. + </summary> +</histogram> + <histogram name="ChromeOS.Settings.Languages.Browser.Interaction" enum="SettingsLanguagesPageBrowserInteraction" expires_after="2021-03-31"> <owner>myy@chromium.org</owner> @@ -903,7 +914,7 @@ </histogram> <histogram name="ChromeOS.SystemTray.FeaturePodCountOnOpen" units="count" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>tengs@chromium.org</owner> <owner>amehfooz@chromium.org</owner> <summary> @@ -1034,7 +1045,7 @@ </histogram> <histogram base="true" name="ChromeOS.USB.DeviceAttached" - enum="ChromeOSUsbEventTiming" expires_after="2021-02-07"> + enum="ChromeOSUsbEventTiming" expires_after="2021-04-11"> <owner>allenwebb@chromium.org</owner> <owner>jorgelo@chromium.org</owner> <owner>mnissler@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml index 3fa42df..7176dd4 100644 --- a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml
@@ -123,7 +123,7 @@ </histogram> <histogram name="Compositing.DirectRenderer.GL.DrawFrameUs" - units="microseconds" expires_after="2021-02-07"> + units="microseconds" expires_after="2021-04-11"> <owner>weiliangc@chromium.org</owner> <summary> Time spent drawing of composited layers by GLRenderer, in microseconds. This @@ -138,7 +138,7 @@ </histogram> <histogram name="Compositing.DirectRenderer.PartialSwap.ExtraDamage" units="%" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>vasilyt@chromium.org</owner> <owner>backer@chromium.org</owner> <summary> @@ -153,7 +153,7 @@ </histogram> <histogram name="Compositing.DirectRenderer.PartialSwap.FrameBufferDamage" - units="%" expires_after="2021-02-07"> + units="%" expires_after="2021-04-11"> <owner>vasilyt@chromium.org</owner> <owner>backer@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/content/histograms.xml b/tools/metrics/histograms/histograms_xml/content/histograms.xml index 9174cba..0a37d5a 100644 --- a/tools/metrics/histograms/histograms_xml/content/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/content/histograms.xml
@@ -526,7 +526,7 @@ </histogram> <histogram name="ContentSettings.Popups.StrongBlockerActions" - enum="StrongPopupBlockerAction" expires_after="2021-02-07"> + enum="StrongPopupBlockerAction" expires_after="2021-04-11"> <owner>csharrison@chromium.org</owner> <summary> Counts of various events related to the strong popup blocker (aka abusive
diff --git a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml index 1e577fa..fa4ac4b 100644 --- a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml
@@ -31,7 +31,7 @@ </histogram> <histogram name="Cookie.CommitProblem" enum="CookieCommitProblem" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>morlovich@chromium.org</owner> <summary> Recorded when a problem occurs trying to commit changes to the cookie store @@ -173,7 +173,7 @@ </histogram> <histogram name="Cookie.LoadProblem" enum="CookieLoadProblem" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>morlovich@chromium.org</owner> <summary> Recorded when a problem is recorded when loading the persistent cookie @@ -405,7 +405,7 @@ </summary> </histogram> -<histogram name="Cookie.Type" enum="CookieType" expires_after="2021-02-07"> +<histogram name="Cookie.Type" enum="CookieType" expires_after="2021-04-11"> <owner>mkwst@chromium.org</owner> <summary>For each cookie added to the store, record it's type(s).</summary> </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/cras/histograms.xml b/tools/metrics/histograms/histograms_xml/cras/histograms.xml index af9cf0d..0bf37744 100644 --- a/tools/metrics/histograms/histograms_xml/cras/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/cras/histograms.xml
@@ -80,7 +80,7 @@ </histogram> <histogram name="Cras.HfpBatteryIndicatorSupported" - enum="CrasHfpBatteryIndicator" expires_after="2021-02-07"> + enum="CrasHfpBatteryIndicator" expires_after="2021-04-11"> <owner>enshuo@chromium.org</owner> <owner>chromeos-audio@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/crostini/histograms.xml b/tools/metrics/histograms/histograms_xml/crostini/histograms.xml index ca75aa3f..b39ba3b 100644 --- a/tools/metrics/histograms/histograms_xml/crostini/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/crostini/histograms.xml
@@ -172,7 +172,7 @@ </histogram> <histogram name="Crostini.Crosvm.RssPercentage" units="%" - expires_after="2021-01-31"> + expires_after="2021-04-11"> <owner>clumptini@google.com</owner> <owner>tbuckley@chromium.org</owner> <summary> @@ -218,7 +218,7 @@ </histogram> <histogram name="Crostini.FilesystemCorruption" enum="CorruptionStates" - expires_after="2021-01-31"> + expires_after="2021-04-11"> <owner>clumptini@google.com</owner> <owner>tbuckley@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml index c9a7dbaa..8fef683e 100644 --- a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
@@ -258,7 +258,7 @@ </histogram> <histogram name="Cryptohome.HomedirEncryptionType" enum="HomedirEncryptionType" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>dspaid@chromium.org</owner> <summary> The encryption type used for a user's cryptohome directory. This is logged @@ -406,7 +406,7 @@ </histogram> <histogram name="Cryptohome.TimeSessionUnlock" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>kerrnel@chromium.org</owner> <owner>mnissler@chromium.org</owner> <summary> @@ -533,7 +533,7 @@ </histogram> <histogram name="Cryptohome.TpmResults" enum="CryptohomeTpmResults" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>afakhry@chromium.org</owner> <summary> The errors resulting from interacting with the Trusted Platform Module (TPM)
diff --git a/tools/metrics/histograms/histograms_xml/download/histograms.xml b/tools/metrics/histograms/histograms_xml/download/histograms.xml index 8b183f1..e8af4d0 100644 --- a/tools/metrics/histograms/histograms_xml/download/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/download/histograms.xml
@@ -37,7 +37,7 @@ </histogram> <histogram name="Download.BandwidthOverallBytesPerSecond" units="units" - expires_after="2020-12-27"> + expires_after="2021-04-11"> <owner>dtrainor@chromium.org</owner> <summary> Overall bandwidth seen for the download. Note that this is measured at the @@ -323,7 +323,7 @@ </histogram> <histogram name="Download.IOSDownloadFileUI" enum="DownloadFileUI" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>ewannpv@chromium.org</owner> <owner>eugenebut@chromium.org</owner> <summary> @@ -344,7 +344,7 @@ </histogram> <histogram name="Download.IOSDownloadMimeType" enum="DownloadMimeTypeResult" - expires_after="2020-12-20"> + expires_after="2021-04-11"> <owner>eugenebut@chromium.org</owner> <summary> MIME type of a download response. Logged when the download UI was offered by
diff --git a/tools/metrics/histograms/histograms_xml/event/histograms.xml b/tools/metrics/histograms/histograms_xml/event/histograms.xml index b0e6941..ade4fc5 100644 --- a/tools/metrics/histograms/histograms_xml/event/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/event/histograms.xml
@@ -76,7 +76,7 @@ </histogram> <histogram name="Event.BrowserVerifiedUserActivation" enum="BooleanSuccess" - expires_after="2020-12-31"> + expires_after="2021-04-11"> <owner>liviutinta@chromium.org</owner> <owner>mustaq@chromium.org</owner> <owner>input-dev@chromium.org</owner> @@ -444,7 +444,7 @@ <histogram name="Event.Latency.ScrollBegin.Scrollbar.BrowserNotifiedToBeforeGpuSwap2" - units="microseconds" expires_after="2020-12-01"> + units="microseconds" expires_after="2021-04-11"> <owner>nzolghadr@chromium.org</owner> <owner>dlibby@microsoft.com</owner> <owner>input-dev@chromium.org</owner> @@ -1256,7 +1256,7 @@ </histogram> <histogram name="Event.Latency.ScrollUpdate.Touch.TimeToHandled2" - units="microseconds" expires_after="2021-02-07"> + units="microseconds" expires_after="2021-04-11"> <owner>tdresser@chromium.org</owner> <summary> Time between initial creation of a touch event and the generated
diff --git a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml index d783bcf..51225f7 100644 --- a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
@@ -1729,7 +1729,7 @@ </histogram> <histogram name="Extensions.Functions.ExtensionServiceWorkerCalls" - enum="ExtensionFunctions" expires_after="2021-01-31"> + enum="ExtensionFunctions" expires_after="2021-04-11"> <owner>lazyboy@chromium.org</owner> <owner>dbertoni@chromium.org</owner> <owner>rdevlin.cronin@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/fingerprint/histograms.xml b/tools/metrics/histograms/histograms_xml/fingerprint/histograms.xml index 4fd7cbe..b301fb60 100644 --- a/tools/metrics/histograms/histograms_xml/fingerprint/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/fingerprint/histograms.xml
@@ -43,7 +43,7 @@ </histogram> <histogram name="Fingerprint.Unlock.AttemptsCountBeforeSuccess" units="count" - expires_after="2021-01-03"> + expires_after="2021-04-11"> <owner>rsorokin@chromium.org</owner> <owner>jessejames@chromium.org</owner> <owner>cros-oac@google.com</owner> @@ -72,7 +72,7 @@ </histogram> <histogram name="Fingerprint.Unlock.Match.Duration.Capture" units="ms" - expires_after="2021-01-03"> + expires_after="2021-04-11"> <owner>rsorokin@chromium.org</owner> <owner>jessejames@chromium.org</owner> <owner>cros-oac@google.com</owner> @@ -83,7 +83,7 @@ </histogram> <histogram name="Fingerprint.Unlock.Match.Duration.Matcher" units="ms" - expires_after="2021-01-03"> + expires_after="2021-04-11"> <owner>rsorokin@chromium.org</owner> <owner>jessejames@chromium.org</owner> <owner>cros-oac@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/gcm/histograms.xml b/tools/metrics/histograms/histograms_xml/gcm/histograms.xml index 470e2fe..4cb83b41 100644 --- a/tools/metrics/histograms/histograms_xml/gcm/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/gcm/histograms.xml
@@ -293,7 +293,7 @@ </histogram> <histogram name="GCM.RegistrationRequest.NetErrorCode" enum="NetErrorCodes" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>peter@chromium.org</owner> <owner>platform-capabilities@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml index 3fd9b46..5daea60 100644 --- a/tools/metrics/histograms/histograms_xml/gpu/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/gpu/histograms.xml
@@ -750,7 +750,7 @@ </histogram> <histogram name="GPU.IOSurface.CreateTime" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>ccameron@chromium.org</owner> <summary> The time that it took for a call to IOSurfaceCreate to complete. @@ -783,7 +783,7 @@ </histogram> <histogram name="GPU.OopRaster.GlyphCacheMiss" - enum="OopRasterGlyphCacheMissType" expires_after="2021-02-07"> + enum="OopRasterGlyphCacheMissType" expires_after="2021-04-11"> <owner>khushalsagar@chromium.org</owner> <summary> During OutOfProcess(Oop) raster, the renderer generates and sends the
diff --git a/tools/metrics/histograms/histograms_xml/input/histograms.xml b/tools/metrics/histograms/histograms_xml/input/histograms.xml index 6abac05..68cae5f 100644 --- a/tools/metrics/histograms/histograms_xml/input/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/input/histograms.xml
@@ -518,7 +518,7 @@ </histogram> <histogram name="InputMethod.VirtualKeyboard.DecoderEvent" - enum="InputMethodDecoderEvent" expires_after="2021-02-01"> + enum="InputMethodDecoderEvent" expires_after="2021-04-11"> <owner>shend@chromium.org</owner> <owner>essential-inputs-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/ios/histograms.xml b/tools/metrics/histograms/histograms_xml/ios/histograms.xml index c91388ce..6f83a1c 100644 --- a/tools/metrics/histograms/histograms_xml/ios/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ios/histograms.xml
@@ -546,7 +546,7 @@ </histogram> <histogram name="IOS.PageLoadCount.Counts" - enum="IOSPageLoadCountNavigationType" expires_after="2021-02-07"> + enum="IOSPageLoadCountNavigationType" expires_after="2021-04-11"> <owner>danyao@chromium.org</owner> <summary>The number of navigation started events by navigation type.</summary> </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/login/histograms.xml b/tools/metrics/histograms/histograms_xml/login/histograms.xml index 929e9aa..94d8305 100644 --- a/tools/metrics/histograms/histograms_xml/login/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/login/histograms.xml
@@ -66,7 +66,7 @@ </histogram> <histogram name="Login.FailureReason" enum="LoginFailureReason" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>achuith@chromium.org</owner> <summary>Chrome OS login failure reason.</summary> </histogram> @@ -106,7 +106,7 @@ </histogram> <histogram name="Login.OfflineFailure.IsKnownUser" enum="LoginIsKnownUser" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>glevin@chromium.org</owner> <summary> On offline login failure, records whether it is for an existing user. @@ -264,7 +264,7 @@ </histogram> <histogram name="Login.UserType" enum="LoginUserType" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>cmasone@chromium.org</owner> <summary> Chrome OS histogram that keeps track of the way a user logs in and whether
diff --git a/tools/metrics/histograms/histograms_xml/memory/histograms.xml b/tools/metrics/histograms/histograms_xml/memory/histograms.xml index d23420ca..3968b8b 100644 --- a/tools/metrics/histograms/histograms_xml/memory/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/memory/histograms.xml
@@ -1631,6 +1631,65 @@ </summary> </histogram> +<histogram name="Memory.PaintPreviewCompositor.PrivateMemoryFootprint" + units="MB" expires_after="2021-04-10"> + <owner>ckitagawa@chromium.org</owner> + <owner>fredmello@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <summary> + A rough estimate of the private memory footprint of the paint preview + compositor process. + + Recorded at Poisson sampled time intervals with a mean of 5 minutes on + Android and 30 minutes on other platforms. + </summary> +</histogram> + +<histogram name="Memory.PaintPreviewCompositor.PrivateSwapFootprint" units="MB" + expires_after="2021-04-10"> + <owner>ckitagawa@chromium.org</owner> + <owner>fredmello@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <summary> + An amount of private memory of the paint preview compositor process placed + in swap (VmSwap). + + Recorded at Poisson sampled time intervals with a mean of 5 minutes on + Android and 30 minutes on other platforms. + </summary> +</histogram> + +<histogram name="Memory.PaintPreviewCompositor.ResidentSet" units="MiB" + expires_after="2021-04-10"> + <owner>ckitagawa@chromium.org</owner> + <owner>fredmello@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <summary> + The size of the resident memory in a paint preview compositor process. This + is influenced by factors we control (e.g. memory that is not accessed can be + swapped) and factors we don't control (e.g. an unrelated process using a lot + of memory can force memory in our process to be swapped). Recorded once on + Windows/Linux/ChromeOS/Android. + + Recorded at Poisson sampled time intervals with a mean of 5 minutes on + Android and 30 minutes on other platforms. + </summary> +</histogram> + +<histogram name="Memory.PaintPreviewCompositor.SharedMemoryFootprint" + units="MB" expires_after="2021-04-10"> + <owner>ckitagawa@chromium.org</owner> + <owner>fredmello@chromium.org</owner> + <owner>mahmoudi@chromium.org</owner> + <summary> + A rough estimate of the shared memory footprint of the paint preview + compositor process. + + Recorded at Poisson sampled time intervals with a mean of 5 minutes on + Android and 30 minutes on other platforms. + </summary> +</histogram> + <histogram name="Memory.ParkableString.CompressedSizeKb" units="KB" expires_after="M87"> <owner>lizeb@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/mobile/histograms.xml b/tools/metrics/histograms/histograms_xml/mobile/histograms.xml index 866abd0..2e2f6afb 100644 --- a/tools/metrics/histograms/histograms_xml/mobile/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/mobile/histograms.xml
@@ -810,7 +810,7 @@ </histogram> <histogram name="MobileIntent.FirstPartyToInternalScheme" enum="Boolean" - expires_after="2021-01-01"> + expires_after="2021-04-11"> <owner>peconn@chromium.org</owner> <owner>peter@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml index b0f7ee4..5f71d84 100644 --- a/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/omnibox/histograms.xml
@@ -602,7 +602,7 @@ </summary> </histogram> -<histogram name="Omnibox.PasteAndGo" units="count" expires_after="2021-02-07"> +<histogram name="Omnibox.PasteAndGo" units="count" expires_after="2021-04-11"> <owner>mpearson@chromium.org</owner> <owner>jdonnelly@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/oobe/histograms.xml b/tools/metrics/histograms/histograms_xml/oobe/histograms.xml index c794ee9..b5a5440 100644 --- a/tools/metrics/histograms/histograms_xml/oobe/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/oobe/histograms.xml
@@ -254,7 +254,7 @@ </histogram> <histogram name="OOBE.StepCompletionTimeByExitReason" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>raleksandrov@google.com</owner> <owner>cros-oac@google.com</owner> <summary>Time spent on specific OOBE screen grouped by exit reason.</summary> @@ -273,7 +273,7 @@ </histogram> <histogram name="OOBE.SyncConsentScreen.ReviewFollowingSetup" - enum="BooleanChecked" expires_after="2021-02-07"> + enum="BooleanChecked" expires_after="2021-04-11"> <owner>raleksandrov@google.com</owner> <owner>cros-oac@google.com</owner> <summary> @@ -364,7 +364,7 @@ </histogram> <histogram name="OOBE.WelcomeScreen.A11yUserActions" - enum="WelcomeScreenA11yUserAction" expires_after="2021-01-31"> + enum="WelcomeScreenA11yUserAction" expires_after="2021-04-11"> <owner>dkuzmin@google.com</owner> <owner>cros-oac@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml index d257207..2e6e04a 100644 --- a/tools/metrics/histograms/histograms_xml/others/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -304,7 +304,7 @@ </histogram> <histogram name="Ads.Media.LoadType" enum="MediaLoadType" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>johnidel@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary> @@ -1285,7 +1285,7 @@ </histogram> <histogram name="BlueZ.ResultOfPairing" enum="BlueZResultOfPairing" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>mcchou@chromium.org</owner> <summary> This is specific to Chrome OS. Records the outcomes of pairing with remote @@ -1580,7 +1580,7 @@ </histogram> <histogram name="BrotliFilter.CompressionPercent" units="%" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>eustas@chromium.org</owner> <summary>Compressed/Decompressed size ratio.</summary> </histogram> @@ -1910,7 +1910,7 @@ </histogram> <histogram name="ChildProcess.Crashed.UtilityProcessHash" - enum="UtilityProcessNameHash" expires_after="2021-02-07"> + enum="UtilityProcessNameHash" expires_after="2021-04-11"> <owner>wfh@chromium.org</owner> <owner>chrome-stability-core@google.com</owner> <summary> @@ -5556,7 +5556,7 @@ </histogram> <histogram name="Graphics.Smoothness.FrameSequenceLength" units="count" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>sadrul@chromium.org</owner> <owner>graphics-dev@chromium.org</owner> <summary> @@ -6134,7 +6134,7 @@ </histogram> <histogram name="HttpCache.Pattern" enum="HttpCachePattern" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>morlovich@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary>For each http cache transaction, the recorded pattern.</summary> @@ -7109,7 +7109,7 @@ </histogram> <histogram name="Keyboard.ShortcutViewer.StartupTime" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>jamescook@chromium.org</owner> <owner>msw@chromium.org</owner> <owner>wutao@chromium.org</owner> @@ -7663,7 +7663,7 @@ </histogram> <histogram name="Linux.GlibcVersion" enum="LinuxGlibcVersion" - expires_after="2020-12-20"> + expires_after="2021-04-11"> <owner>thestig@chromium.org</owner> <owner>thomasanderson@chromium.org</owner> <summary> @@ -7811,7 +7811,7 @@ </histogram> <histogram name="LoadingPredictor.PreconnectCount" units="origins" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>alexilin@chromium.org</owner> <summary> The number of origins that were preconnected for a page load. It includes @@ -7821,7 +7821,7 @@ </histogram> <histogram name="LoadingPredictor.PreconnectHitsPercentage" units="%" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>alexilin@chromium.org</owner> <summary> The percentage of origins that were preconnected and requested by a page @@ -7832,7 +7832,7 @@ </histogram> <histogram base="true" name="LoadingPredictor.PreconnectLearningCount" - units="origins" expires_after="2021-02-07"> + units="origins" expires_after="2021-04-11"> <owner>alexilin@chromium.org</owner> <owner>tbansal@chromium.org</owner> <summary> @@ -7842,7 +7842,7 @@ </histogram> <histogram base="true" name="LoadingPredictor.PreconnectLearningPrecision" - units="%" expires_after="2021-02-07"> + units="%" expires_after="2021-04-11"> <owner>alexilin@chromium.org</owner> <owner>tbansal@chromium.org</owner> <summary> @@ -7877,7 +7877,7 @@ </histogram> <histogram name="LoadingPredictor.PreresolveCount" units="hosts" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>alexilin@chromium.org</owner> <summary> The number of hosts that were preresolved for a page load. It includes only @@ -8544,7 +8544,7 @@ </histogram> <histogram name="MPArch.ChildProcessLaunchSubsequent" units="units" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>ppi@chromium.org</owner> <summary> The time it takes to spawn child sub processes not counting the first one. @@ -9032,7 +9032,7 @@ </histogram> <histogram name="NQE.EffectiveConnectionType.OnECTComputation" - enum="NQEEffectiveConnectionType" expires_after="2021-02-07"> + enum="NQEEffectiveConnectionType" expires_after="2021-04-11"> <owner>tbansal@chromium.org</owner> <owner>src/net/nqe/OWNERS</owner> <summary> @@ -9102,7 +9102,7 @@ </histogram> <histogram name="NQE.RTT.ObservationSource" enum="NQEObservationSource" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>tbansal@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -9698,7 +9698,7 @@ </summary> </histogram> -<histogram name="PDF.HasAttachment" enum="Boolean" expires_after="2021-02-07"> +<histogram name="PDF.HasAttachment" enum="Boolean" expires_after="2021-04-11"> <owner>hnakashima@chromium.org</owner> <owner>thestig@chromium.org</owner> <summary> @@ -10693,7 +10693,7 @@ </histogram> <histogram name="ProtoDB.InitStatus" enum="LevelDBStatus" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>nyquist@chromium.org</owner> <owner>ssid@chromium.org</owner> <summary>The LevelDB Status from a ProtoDatabase Init call.</summary> @@ -10753,7 +10753,7 @@ </histogram> <histogram name="ProximityAuth.BleWeaveConnectionResult" - enum="ProximityAuth_BleWeaveConnectionResult" expires_after="2021-02-07"> + enum="ProximityAuth_BleWeaveConnectionResult" expires_after="2021-04-11"> <owner>hansberry@chromium.org</owner> <summary> Provides a breakdown of how often each BLE weave connection result occurs. @@ -10762,7 +10762,7 @@ <histogram name="ProximityAuth.BluetoothGattConnectionResult" enum="ProximityAuth_BluetoothGattConnectionResult" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>hansberry@chromium.org</owner> <summary> Provides a breakdown of how many times each possible Bluetooth GATT @@ -10851,7 +10851,7 @@ </histogram> <histogram name="PushMessaging.DeliveryStatus" enum="PushEventStatus" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>peter@chromium.org</owner> <summary> When a Service Worker receives a push message, this records whether the @@ -13587,7 +13587,7 @@ </histogram> <histogram name="SpellCheck.SpellingService.RequestHttpResponseCode" - enum="HttpResponseCode" expires_after="2021-01-31"> + enum="HttpResponseCode" expires_after="2021-04-11"> <owner>yyushkina@google.com</owner> <owner>gujen@google.com</owner> <owner>chrome-language@google.com</owner> @@ -15250,7 +15250,7 @@ </histogram> <histogram name="Tracing.Background.ScenarioState" - enum="BackgroundTracingState" expires_after="2021-02-07"> + enum="BackgroundTracingState" expires_after="2021-04-11"> <owner>oysteine@chromium.org</owner> <summary> Records state of the Background Tracing system, from when scenarios are @@ -16545,7 +16545,7 @@ </histogram> <histogram name="WebFont.BlankTextShownTime" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>kenjibaheux@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <summary> @@ -16580,7 +16580,7 @@ </histogram> <histogram name="WebFont.DownloadTime.0.Under10KB" units="ms" - expires_after="2021-01-20"> + expires_after="2021-04-11"> <owner>kenjibaheux@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <summary> @@ -16590,7 +16590,7 @@ </histogram> <histogram name="WebFont.DownloadTime.1.10KBTo50KB" units="ms" - expires_after="2021-01-20"> + expires_after="2021-04-11"> <owner>kenjibaheux@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <summary> @@ -16600,7 +16600,7 @@ </histogram> <histogram name="WebFont.DownloadTime.2.50KBTo100KB" units="ms" - expires_after="2021-01-20"> + expires_after="2021-04-11"> <owner>kenjibaheux@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <summary> @@ -16610,7 +16610,7 @@ </histogram> <histogram name="WebFont.DownloadTime.3.100KBTo1MB" units="ms" - expires_after="2021-01-20"> + expires_after="2021-04-11"> <owner>kenjibaheux@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <summary> @@ -16620,7 +16620,7 @@ </histogram> <histogram name="WebFont.DownloadTime.4.Over1MB" units="ms" - expires_after="2021-01-20"> + expires_after="2021-04-11"> <owner>kenjibaheux@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> <summary> @@ -16939,7 +16939,7 @@ </histogram> <histogram name="WebUI.CreatedForUrl" enum="WebUIUrlHashes" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>dbeam@chromium.org</owner> <summary>URLs for which Chrome creates WebUIControllers.</summary> </histogram> @@ -17203,7 +17203,7 @@ </histogram> <histogram name="WrenchMenu.MenuAction" enum="WrenchMenuAction" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>ainslie@chromium.org</owner> <owner>edwardjung@chromium.org</owner> <summary>Number of times that each menu item is clicked.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/password/histograms.xml b/tools/metrics/histograms/histograms_xml/password/histograms.xml index 69dd4a36..1486f21 100644 --- a/tools/metrics/histograms/histograms_xml/password/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/password/histograms.xml
@@ -1238,7 +1238,7 @@ <histogram name="PasswordManager.IsSyncPasswordHashSavedForAdvancedProtectionUser" - enum="IsSyncPasswordHashSaved" expires_after="2021-02-04"> + enum="IsSyncPasswordHashSaved" expires_after="2021-04-11"> <owner>bdea@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -2306,7 +2306,7 @@ </histogram> <histogram name="PasswordProtection.ModalWarningDialogAction" - enum="PasswordProtectionWarningAction" expires_after="2021-02-07"> + enum="PasswordProtectionWarningAction" expires_after="2021-04-11"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -2328,7 +2328,7 @@ </histogram> <histogram name="PasswordProtection.PageInfoAction" - enum="PasswordProtectionWarningAction" expires_after="2021-01-30"> + enum="PasswordProtectionWarningAction" expires_after="2021-04-11"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/power/histograms.xml b/tools/metrics/histograms/histograms_xml/power/histograms.xml index 6fa9d0ff..2f1c528 100644 --- a/tools/metrics/histograms/histograms_xml/power/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/power/histograms.xml
@@ -136,7 +136,7 @@ </histogram> <histogram name="Power.BatteryRemainingAtStartOfSessionOnAC" units="%" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>tbroch@chromium.org</owner> <summary> Chrome OS remaining battery charge as percent of the maximum battery charge, @@ -637,7 +637,7 @@ </summary> </histogram> -<histogram name="Power.IdleTimeOnBattery" units="ms" expires_after="2021-02-07"> +<histogram name="Power.IdleTimeOnBattery" units="ms" expires_after="2021-04-11"> <owner>tbroch@chromium.org</owner> <owner>jiameng@chromium.org</owner> <summary> @@ -647,7 +647,7 @@ </histogram> <histogram name="Power.KernelResumeTimeOnAC" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>tbroch@chromium.org</owner> <summary> The time that the kernel took to resume the Chrome OS device from @@ -692,7 +692,7 @@ </histogram> <histogram name="Power.LengthOfSession" units="seconds" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>tbroch@chromium.org</owner> <summary> The length of time, in seconds, that a user spent in a single session. @@ -885,7 +885,7 @@ </histogram> <histogram name="Power.PowerSupplyType" enum="PowerSupplyType" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>bleung@chromium.org</owner> <owner>tbroch@chromium.org</owner> <summary> @@ -1094,7 +1094,7 @@ </histogram> <histogram name="PowerML.SmartDimModel.Result" - enum="PowerMLSmartDimModelResult" expires_after="2021-02-07"> + enum="PowerMLSmartDimModelResult" expires_after="2021-04-11"> <owner>jiameng@chromium.org</owner> <summary> This is the status code returned by the model when calculating a user
diff --git a/tools/metrics/histograms/histograms_xml/profile/histograms.xml b/tools/metrics/histograms/histograms_xml/profile/histograms.xml index 3d3b2b9..852d789 100644 --- a/tools/metrics/histograms/histograms_xml/profile/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/profile/histograms.xml
@@ -409,7 +409,7 @@ </histogram> <histogram name="Profile.SessionDuration.PerProfile" enum="Profile" - expires_after="2021-01-03"> + expires_after="2021-04-11"> <owner>msarda@chromium.org</owner> <owner>tangltom@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/quota/histograms.xml b/tools/metrics/histograms/histograms_xml/quota/histograms.xml index 00a48e6..9021d99 100644 --- a/tools/metrics/histograms/histograms_xml/quota/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/quota/histograms.xml
@@ -50,7 +50,7 @@ </histogram> <histogram name="Quota.AvailableDiskSpace2" units="MB" - expires_after="2021-02-10"> + expires_after="2021-04-11"> <owner>jarrydg@chromium.org</owner> <owner>chrome-owp-storage@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml index 5e9551e..4dd16c2 100644 --- a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
@@ -774,7 +774,7 @@ </histogram> <histogram name="SafeBrowsing.RT.Backoff.State" enum="BooleanEnabled" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml index ea064b05..1ee63893 100644 --- a/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/sb_client/histograms.xml
@@ -22,7 +22,7 @@ <histograms> <histogram name="SBClientDownload.CheckDownloadStats" - enum="SBClientDownloadCheckDownloadStats" expires_after="2021-02-07"> + enum="SBClientDownloadCheckDownloadStats" expires_after="2021-04-11"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <owner>mattm@chromium.org</owner> @@ -262,7 +262,7 @@ <histogram name="SBClientPhishing.CancelClassificationReason" enum="SBClientPhishingCancelClassificationReason" - expires_after="2021-01-27"> + expires_after="2021-04-11"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -425,7 +425,7 @@ </histogram> <histogram name="SBClientPhishing.PhishingDetectionDuration" units="ms" - expires_after="2021-02-06"> + expires_after="2021-04-11"> <owner>bdea@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -513,7 +513,7 @@ </histogram> <histogram name="SBClientPhishing.TermFeatureChunkTime" units="ms" - expires_after="2021-01-27"> + expires_after="2021-04-11"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -531,7 +531,7 @@ </histogram> <histogram name="SBClientPhishing.TermFeatureTimeout" units="units" - expires_after="2021-01-27"> + expires_after="2021-04-11"> <owner>drubery@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/security/histograms.xml b/tools/metrics/histograms/histograms_xml/security/histograms.xml index 84cbcb1..1dd0cafc 100644 --- a/tools/metrics/histograms/histograms_xml/security/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/security/histograms.xml
@@ -571,7 +571,7 @@ </histogram> <histogram base="true" name="Security.SiteEngagement" units="units" - expires_after="2021-02-01"> + expires_after="2021-04-11"> <owner>cthomp@chromium.org</owner> <owner>security-enamel@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/smart/histograms.xml b/tools/metrics/histograms/histograms_xml/smart/histograms.xml index bc3a58c..14f1b2f 100644 --- a/tools/metrics/histograms/histograms_xml/smart/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/smart/histograms.xml
@@ -46,7 +46,7 @@ </histogram> <histogram name="SmartLock.AuthMethodChoice.Unlock.PasswordState" - enum="SmartLockAuthEventPasswordState" expires_after="2021-02-02"> + enum="SmartLockAuthEventPasswordState" expires_after="2021-04-11"> <owner>hansberry@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -118,7 +118,7 @@ </histogram> <histogram name="SmartLock.EnabledDevicesCount" units="devices" - expires_after="2021-02-02"> + expires_after="2021-04-11"> <owner>hansberry@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -162,7 +162,7 @@ </histogram> <histogram name="SmartLock.GetRemoteStatus.SignIn" enum="BooleanSuccess" - expires_after="2021-02-02"> + expires_after="2021-04-11"> <owner>hansberry@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary> @@ -194,7 +194,7 @@ <histogram name="SmartLock.GetRemoteStatus.Unlock.Failure" enum="SmartLockGetRemoteStatusResultFailureReason" - expires_after="2021-02-02"> + expires_after="2021-04-11"> <owner>hansberry@chromium.org</owner> <owner>better-together-dev@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/stability/histograms.xml b/tools/metrics/histograms/histograms_xml/stability/histograms.xml index 2930560..8e7611c 100644 --- a/tools/metrics/histograms/histograms_xml/stability/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/stability/histograms.xml
@@ -424,7 +424,7 @@ </histogram> <histogram name="Stability.iOS.UTE.TimeBetweenUTEAndNextLaunch" units="ms" - expires_after="2020-12-01"> + expires_after="2021-04-11"> <owner>michaeldo@chromium.org</owner> <owner>olivierrobin@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/sync/histograms.xml b/tools/metrics/histograms/histograms_xml/sync/histograms.xml index d2a8c23..fd130e5 100644 --- a/tools/metrics/histograms/histograms_xml/sync/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/sync/histograms.xml
@@ -305,7 +305,7 @@ </histogram> <histogram name="Sync.DataTypeRunFailures2" enum="SyncModelTypes" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>jkrcal@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -316,7 +316,7 @@ </histogram> <histogram name="Sync.DataTypeStartFailures2" enum="SyncModelTypes" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>jkrcal@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -500,7 +500,7 @@ </histogram> <histogram base="true" name="Sync.ModelTypeCount4" units="entries" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>jkrcal@chromium.org</owner> <owner>mastiz@chromium.org</owner> <summary> @@ -513,7 +513,7 @@ </histogram> <histogram base="true" name="Sync.ModelTypeEntityChange3" - enum="SyncEntityChange" expires_after="2021-02-07"> + enum="SyncEntityChange" expires_after="2021-04-11"> <owner>jkrcal@chromium.org</owner> <summary> Recorded once for every sync entity change (whenever it is commited to the @@ -584,7 +584,7 @@ </histogram> <histogram name="Sync.NonReflectionUpdateFreshnessPossiblySkewed2" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>mastiz@chromium.org</owner> <owner>melandory@chromium.org</owner> <summary> @@ -797,7 +797,7 @@ </histogram> <histogram name="Sync.Startup.DeferredInitTrigger" - enum="SyncDeferredInitTrigger" expires_after="2021-01-31"> + enum="SyncDeferredInitTrigger" expires_after="2021-04-11"> <owner>mastiz@chromium.org</owner> <owner>treib@chromium.org</owner> <summary>The type of event that triggered sync initialization.</summary> @@ -813,7 +813,7 @@ </histogram> <histogram name="Sync.Startup.TypeTriggeringInit" enum="SyncModelTypes" - expires_after="2021-01-31"> + expires_after="2021-04-11"> <owner>mastiz@chromium.org</owner> <owner>treib@chromium.org</owner> <summary>Data type that first requests sync initialization.</summary>
diff --git a/tools/metrics/histograms/histograms_xml/tab/histograms.xml b/tools/metrics/histograms/histograms_xml/tab/histograms.xml index 04a9ddd5..defbce2 100644 --- a/tools/metrics/histograms/histograms_xml/tab/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/tab/histograms.xml
@@ -1218,6 +1218,20 @@ </summary> </histogram> +<histogram name="Tabs.NTPCountAtResume" units="tabs" expires_after="M95"> + <owner>gogerald@chromium.org</owner> + <owner>nasims@google.com</owner> + <summary> + [iOS] The number of NTP tabs open when the app comes out of the background. + </summary> +</histogram> + +<histogram name="Tabs.NTPCountAtStartup" units="tabs" expires_after="M95"> + <owner>gogerald@chromium.org</owner> + <owner>nasims@google.com</owner> + <summary>[iOS] The number of NTP tabs open at cold launch.</summary> +</histogram> + <histogram name="Tabs.NumberOfTabsOnResume" units="tabs" expires_after="never"> <!-- expires-never: https://crbug.com/966137 -->
diff --git a/tools/metrics/histograms/histograms_xml/ukm/histograms.xml b/tools/metrics/histograms/histograms_xml/ukm/histograms.xml index 925785c..39ffa16 100644 --- a/tools/metrics/histograms/histograms_xml/ukm/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/ukm/histograms.xml
@@ -70,7 +70,7 @@ </histogram> <histogram name="UKM.Entries.Dropped" enum="UkmDataDroppedReason" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>rkaplow@chromium.org</owner> <owner>ukm-team@google.com</owner> <summary> @@ -104,7 +104,7 @@ </histogram> <histogram name="UKM.Entries.SerializedCount2" units="entries" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>rkaplow@chromium.org</owner> <owner>ukm-team@google.com</owner> <summary>Number of serialized UKM entries when storing a UKM log.</summary> @@ -134,7 +134,7 @@ </summary> </histogram> -<histogram name="UKM.LogSize.OnSuccess" units="KB" expires_after="2021-02-07"> +<histogram name="UKM.LogSize.OnSuccess" units="KB" expires_after="2021-04-11"> <owner>rkaplow@chromium.org</owner> <owner>ukm-team@google.com</owner> <summary> @@ -207,7 +207,7 @@ </histogram> <histogram name="UKM.Sources.Dropped" enum="UkmDataDroppedReason" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>rkaplow@chromium.org</owner> <owner>ukm-team@google.com</owner> <summary> @@ -217,7 +217,7 @@ </histogram> <histogram name="UKM.Sources.KeptSourcesCount" units="sources" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>rkaplow@chromium.org</owner> <owner>ukm-team@google.com</owner> <summary> @@ -244,7 +244,7 @@ </histogram> <histogram name="UKM.Sources.UnsentSourcesCount" units="sources" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>rkaplow@chromium.org</owner> <owner>ukm-team@google.com</owner> <summary> @@ -264,7 +264,7 @@ </histogram> <histogram name="UKM.UnsentLogs.NumDropped" units="units" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>rkaplow@chromium.org</owner> <owner>ukm-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/uma/histograms.xml b/tools/metrics/histograms/histograms_xml/uma/histograms.xml index be051eb6..a5cc51e 100644 --- a/tools/metrics/histograms/histograms_xml/uma/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/uma/histograms.xml
@@ -315,7 +315,7 @@ </histogram> <histogram name="UMA.MetricsService.Initialize" enum="Boolean" - expires_after="2020-12-01"> + expires_after="2021-04-11"> <owner>rkaplow@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary> @@ -522,7 +522,7 @@ </histogram> <histogram name="UMA.TruncatedEvents.UserAction" units="events" - expires_after="2021-04-04"> + expires_after="2021-04-11"> <owner>rkaplow@chromium.org</owner> <owner>src/base/metrics/OWNERS</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/v8/histograms.xml b/tools/metrics/histograms/histograms_xml/v8/histograms.xml index b164b72..8bafc3f 100644 --- a/tools/metrics/histograms/histograms_xml/v8/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/v8/histograms.xml
@@ -108,7 +108,7 @@ </histogram> <histogram name="V8.CompileLazyMicroSeconds" units="microseconds" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>hablich@chromium.org</owner> <summary> Aggregated time spent compiling functions lazily during a single script
diff --git a/tools/metrics/histograms/histograms_xml/video_tutorials/histograms.xml b/tools/metrics/histograms/histograms_xml/video_tutorials/histograms.xml index 6e844d7b..0af0520 100644 --- a/tools/metrics/histograms/histograms_xml/video_tutorials/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/video_tutorials/histograms.xml
@@ -22,9 +22,12 @@ <histograms> <variants name="VideoTutorialFeatureTopic"> + <variant name="ChromeIntro"/> <variant name="Download"/> <variant name="Search"/> + <variant name="Summary"/> <variant name="Unknown"/> + <variant name="VoiceSearch"/> </variants> <histogram name="VideoTutorials.Player.LoadTimeLatency" units="ms"
diff --git a/tools/metrics/histograms/histograms_xml/web_apk/histograms.xml b/tools/metrics/histograms/histograms_xml/web_apk/histograms.xml index 09afb50..52089418f 100644 --- a/tools/metrics/histograms/histograms_xml/web_apk/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/web_apk/histograms.xml
@@ -89,7 +89,7 @@ </histogram> <histogram name="WebApk.Install.InstallEvent" enum="WebApkInstallEvent" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>hartmanng@chromium.org</owner> <owner> src/chrome/android/java/src/org/chromium/chrome/browser/webapps/OWNERS @@ -225,7 +225,7 @@ </histogram> <histogram name="WebApk.Startup.Cold.ShellLaunchToSplashscreenVisible" - units="ms" expires_after="2021-02-07"> + units="ms" expires_after="2021-04-11"> <owner>mheikal@chromium.org</owner> <owner>yfriedman@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/web_core/histograms.xml b/tools/metrics/histograms/histograms_xml/web_core/histograms.xml index 9becda6..dd651a0 100644 --- a/tools/metrics/histograms/histograms_xml/web_core/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/web_core/histograms.xml
@@ -80,7 +80,7 @@ </histogram> <histogram name="WebCore.FindInPage.TaskDuration" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>rakina@chromium.org</owner> <owner>altimin@chromium.org</owner> <summary> @@ -326,7 +326,7 @@ </histogram> <histogram name="WebCore.IndexedDB.LevelDB.OpenTime" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>cmumford@chromium.org</owner> <summary> The time that it takes to open IndexedDB's LevelDB backing store. @@ -828,7 +828,7 @@ </histogram> <histogram name="WebCore.WebSocket.SendType" enum="WebSocketSendType" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>yhirano@chromium.org</owner> <owner>ricea@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml index 359902b..19c918d 100644 --- a/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml +++ b/tools/metrics/histograms/histograms_xml/web_rtc/histograms.xml
@@ -193,7 +193,7 @@ </histogram> <histogram name="WebRTC.Audio.ApmCaptureOutputLevelAverageRms" - units="dBFS (negated)" expires_after="2021-02-07"> + units="dBFS (negated)" expires_after="2021-04-11"> <owner>peah@chromium.org</owner> <summary> This histogram reports the average RMS of the signal in the output of @@ -308,7 +308,7 @@ </histogram> <histogram name="WebRTC.Audio.AverageExcessBufferDelayMs" units="ms" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>hlundin@chromium.org</owner> <summary> Measures the average waiting time in the buffer for each packet. The waiting @@ -740,14 +740,14 @@ </histogram> <histogram name="WebRTC.BWE.InitiallyLostPackets" units="packets" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>holmer@chromium.org</owner> <summary> The number of video packets lost durig the first 2 seconds in a WebRTC call. </summary> </histogram> -<histogram name="WebRTC.BWE.InitialRtt" units="ms" expires_after="2021-02-07"> +<histogram name="WebRTC.BWE.InitialRtt" units="ms" expires_after="2021-04-11"> <owner>holmer@chromium.org</owner> <summary> The round-trip time as measured 2 seconds into a WebRTC call. @@ -900,7 +900,7 @@ </histogram> <histogram name="WebRTC.Call.EstimatedSendBitrateInKbps" units="kbps" - expires_after="2021-02-07"> + expires_after="2021-04-11"> <owner>holmer@chromium.org</owner> <summary> Average estimated send bitrate during a call, counted from first packet sent
diff --git a/tools/metrics/histograms/histograms_xml/weblayer/histograms.xml b/tools/metrics/histograms/histograms_xml/weblayer/histograms.xml new file mode 100644 index 0000000..42bb929 --- /dev/null +++ b/tools/metrics/histograms/histograms_xml/weblayer/histograms.xml
@@ -0,0 +1,56 @@ +<!-- +Copyright 2020 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<!-- +This file is used to generate a comprehensive list of WebLayer histograms +along with a detailed description for each histogram. + +For best practices on writing histogram descriptions, see +https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md + +Please send CLs to chromium-metrics-reviews@google.com rather than to specific +individuals. These CLs will be automatically reassigned to a reviewer within +about 5 minutes. This approach helps the metrics team to load-balance incoming +reviews. Googlers can read more about this at go/gwsq-gerrit. +--> + +<histogram-configuration> + +<histograms> + +<histogram name="WebLayer.Startup.ClassLoaderCreationTime" units="ms" + expires_after="M98"> + <owner>cduvall@chromium.org</owner> + <owner>src/weblayer/OWNERS</owner> + <summary> + The time it takes for the WebLayer class loader to be created. Recorded at + WebLayer startup. + </summary> +</histogram> + +<histogram name="WebLayer.Startup.ContextCreationTime" units="ms" + expires_after="M98"> + <owner>cduvall@chromium.org</owner> + <owner>src/weblayer/OWNERS</owner> + <summary> + The time it takes for the WebLayer context to be created. Recorded at + WebLayer startup. + </summary> +</histogram> + +<histogram name="WebLayer.Startup.WebLayerLoaderCreationTime" units="ms" + expires_after="M98"> + <owner>cduvall@chromium.org</owner> + <owner>src/weblayer/OWNERS</owner> + <summary> + The time it takes for the WebLayer loader to be created. Recorded at + WebLayer startup. + </summary> +</histogram> + +</histograms> + +</histogram-configuration>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index f85faa03..4030f41b 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -2027,6 +2027,9 @@ </summary> </metric> <metric name="ScrollingCoordinator"> + <obsolete> + Merged into CompositingCommit in http://crrev.com/815947 in M88. + </obsolete> <summary> The time spent in ScrollingCoordinator, between navigation and First Contentful Paint, in microseconds. @@ -2062,6 +2065,21 @@ </metric> </event> +<event name="Blink.PaintTiming" singular="True"> + <owner>npm@chromium.org</owner> + <owner>sullivan@chromium.org</owner> + <summary> + Paint timing metrics recorded in Blink, usually used as debugging metrics + for PaintTiming metrics in the PageLoad event. + </summary> + <metric name="LCPDebugging.HasViewportImage" enum="Boolean"> + <summary> + Records whether a page has an image whose size equals the full viewport. + Recorded when the LCP algorithm has stopped. + </summary> + </metric> +</event> + <event name="Blink.Script.AsyncScripts" singular="True"> <owner>dom@chromium.org</owner> <owner>chrome-loading@google.com</owner> @@ -2804,6 +2822,9 @@ </summary> </metric> <metric name="ScrollingCoordinator"> + <obsolete> + Merged into CompositingCommit in http://crrev.com/815947 in M88. + </obsolete> <summary> The time taken for scrolling coordinator for the main frame in microseconds during the sampled frame. @@ -2864,6 +2885,9 @@ </summary> </metric> <metric name="ScrollingCoordinatorPercentage"> + <obsolete> + Merged into CompositingCommitPercentage in http://crrev.com/815947 in M88. + </obsolete> <summary> The percentage of the main frame time used in scrolling coordinator. An int in the range [0,100].
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index f809a81a..69851f9 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -151,7 +151,7 @@ <item id="history_ui_favicon_request_handler_get_favicon" added_in_milestone="77" hash_code="17562717" type="0" content_hash_code="64054629" os_list="linux,windows" file_path="components/favicon/core/history_ui_favicon_request_handler_impl.cc"/> <item id="http_server_error_response" added_in_milestone="66" hash_code="32197336" type="0" content_hash_code="61082230" os_list="linux,windows" file_path="net/server/http_server.cc"/> <item id="https_server_previews_navigation" added_in_milestone="74" hash_code="35725390" type="0" deprecated="2020-04-23" content_hash_code="84423109" file_path="chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc"/> - <item id="ice_config_fetcher" added_in_milestone="81" hash_code="137093034" type="0" content_hash_code="60051202" os_list="linux,windows" file_path="chrome/browser/sharing/webrtc/ice_config_fetcher.cc"/> + <item id="ice_config_fetcher" added_in_milestone="81" hash_code="137093034" type="0" deprecated="2020-10-13" content_hash_code="60051202" file_path="chrome/browser/sharing/webrtc/ice_config_fetcher.cc"/> <item id="icon_cacher" added_in_milestone="62" hash_code="103133150" type="0" content_hash_code="116368348" os_list="linux,windows" file_path="components/ntp_tiles/icon_cacher_impl.cc"/> <item id="icon_catcher_get_large_icon" added_in_milestone="62" hash_code="44494884" type="0" content_hash_code="98262037" os_list="linux,windows" file_path="components/ntp_tiles/icon_cacher_impl.cc"/> <item id="image_annotation" added_in_milestone="73" hash_code="107881858" type="0" content_hash_code="76229990" os_list="linux,windows" file_path="services/image_annotation/annotator.cc"/>
diff --git a/ui/android/java/res/values-night/colors.xml b/ui/android/java/res/values-night/colors.xml index 3c21387..0ab787c 100644 --- a/ui/android/java/res/values-night/colors.xml +++ b/ui/android/java/res/values-night/colors.xml
@@ -75,4 +75,5 @@ <color name="omnibox_bg_color">@color/omnibox_bg_color_dark</color> <color name="image_loading_color">@color/image_loading_color_light</color> <color name="promo_illustration_bg_color">@color/promo_illustration_bg_color_dark</color> + <color name="preference_highlighted_bg_color">@color/preference_highlighted_bg_color_light</color> </resources>
diff --git a/ui/android/java/res/values/semantic_colors_adaptive.xml b/ui/android/java/res/values/semantic_colors_adaptive.xml index 1b1810e..873c3f1 100644 --- a/ui/android/java/res/values/semantic_colors_adaptive.xml +++ b/ui/android/java/res/values/semantic_colors_adaptive.xml
@@ -111,4 +111,5 @@ <color name="omnibox_bg_color" tools:ignore="UnusedResources">@color/omnibox_bg_color_light</color> <color name="image_loading_color" tools:ignore="UnusedResources">@color/image_loading_color_dark</color> <color name="promo_illustration_bg_color" tools:ignore="UnusedResources">@color/promo_illustration_bg_color_light</color> + <color name="preference_highlighted_bg_color">@color/preference_highlighted_bg_color_dark</color> </resources>
diff --git a/ui/android/java/res/values/semantic_colors_non_adaptive.xml b/ui/android/java/res/values/semantic_colors_non_adaptive.xml index 72f3937..fe3f8bd 100644 --- a/ui/android/java/res/values/semantic_colors_non_adaptive.xml +++ b/ui/android/java/res/values/semantic_colors_non_adaptive.xml
@@ -120,4 +120,8 @@ <color name="omnibox_bg_color_light">@color/modern_grey_100</color> <color name="omnibox_bg_color_dark">@color/modern_grey_800</color> <color name="omnibox_bg_color_incognito" tools:ignore="UnusedResources">@color/black_alpha_38</color> + + <!-- Settings --> + <color name="preference_highlighted_bg_color_dark">@color/modern_blue_600_alpha_12</color> + <color name="preference_highlighted_bg_color_light">@color/white_alpha_24</color> </resources>
diff --git a/ui/base/ime/chromeos/BUILD.gn b/ui/base/ime/chromeos/BUILD.gn index ed2a8b8..0d4ff07 100644 --- a/ui/base/ime/chromeos/BUILD.gn +++ b/ui/base/ime/chromeos/BUILD.gn
@@ -14,6 +14,7 @@ sources = [ "component_extension_ime_manager.cc", "component_extension_ime_manager.h", + "component_extension_ime_manager_delegate.h", "extension_ime_util.cc", "extension_ime_util.h", "fake_ime_keyboard.cc",
diff --git a/ui/base/ime/chromeos/component_extension_ime_manager.cc b/ui/base/ime/chromeos/component_extension_ime_manager.cc index a2ae037..4c6132b 100644 --- a/ui/base/ime/chromeos/component_extension_ime_manager.cc +++ b/ui/base/ime/chromeos/component_extension_ime_manager.cc
@@ -55,12 +55,6 @@ ComponentExtensionIME::~ComponentExtensionIME() = default; -ComponentExtensionIMEManagerDelegate::ComponentExtensionIMEManagerDelegate() = - default; - -ComponentExtensionIMEManagerDelegate::~ComponentExtensionIMEManagerDelegate() = - default; - ComponentExtensionIMEManager::ComponentExtensionIMEManager() { for (const auto& input_method : input_method::kInputMethods) { if (input_method.is_login_keyboard)
diff --git a/ui/base/ime/chromeos/component_extension_ime_manager.h b/ui/base/ime/chromeos/component_extension_ime_manager.h index 18239878..268e4222 100644 --- a/ui/base/ime/chromeos/component_extension_ime_manager.h +++ b/ui/base/ime/chromeos/component_extension_ime_manager.h
@@ -13,6 +13,7 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/observer_list.h" +#include "ui/base/ime/chromeos/component_extension_ime_manager_delegate.h" #include "ui/base/ime/chromeos/input_method_descriptor.h" class Profile; @@ -47,24 +48,6 @@ std::vector<ComponentExtensionEngine> engines; }; -// Provides an interface to list/load/unload for component extension IME. -class COMPONENT_EXPORT(UI_BASE_IME_CHROMEOS) - ComponentExtensionIMEManagerDelegate { - public: - ComponentExtensionIMEManagerDelegate(); - virtual ~ComponentExtensionIMEManagerDelegate(); - - // Lists installed component extension IMEs. - virtual std::vector<ComponentExtensionIME> ListIME() = 0; - - // Loads component extension IME associated with |extension_id|. - // Returns false if it fails, otherwise returns true. - virtual void Load(Profile* profile, - const std::string& extension_id, - const std::string& manifest, - const base::FilePath& path) = 0; -}; - // This class manages component extension input method. class COMPONENT_EXPORT(UI_BASE_IME_CHROMEOS) ComponentExtensionIMEManager { public:
diff --git a/ui/base/ime/chromeos/component_extension_ime_manager_delegate.h b/ui/base/ime/chromeos/component_extension_ime_manager_delegate.h new file mode 100644 index 0000000..0fcef4a --- /dev/null +++ b/ui/base/ime/chromeos/component_extension_ime_manager_delegate.h
@@ -0,0 +1,37 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_IME_CHROMEOS_COMPONENT_EXTENSION_IME_MANAGER_DELEGATE_H_ +#define UI_BASE_IME_CHROMEOS_COMPONENT_EXTENSION_IME_MANAGER_DELEGATE_H_ + +#include "base/component_export.h" +#include "base/files/file_path.h" +#include "base/macros.h" + +class Profile; + +namespace chromeos { + +struct ComponentExtensionIME; + +// Provides an interface to list/load/unload for component extension IME. +class COMPONENT_EXPORT(UI_BASE_IME_CHROMEOS) + ComponentExtensionIMEManagerDelegate { + public: + virtual ~ComponentExtensionIMEManagerDelegate() {} + + // Lists installed component extension IMEs. + virtual std::vector<ComponentExtensionIME> ListIME() = 0; + + // Loads component extension IME associated with |extension_id|. + // Returns false if it fails, otherwise returns true. + virtual void Load(Profile* profile, + const std::string& extension_id, + const std::string& manifest, + const base::FilePath& path) = 0; +}; + +} // namespace chromeos + +#endif // UI_BASE_IME_CHROMEOS_COMPONENT_EXTENSION_IME_MANAGER_DELEGATE_H_
diff --git a/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.cc b/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.cc index b8ca2e0..99647f9 100644 --- a/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.cc +++ b/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h" +#include "ui/base/ime/chromeos/component_extension_ime_manager.h" namespace chromeos { namespace input_method {
diff --git a/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h b/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h index 677fd53..280e021 100644 --- a/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h +++ b/ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h
@@ -7,7 +7,7 @@ #include "base/component_export.h" #include "base/macros.h" -#include "ui/base/ime/chromeos/component_extension_ime_manager.h" +#include "ui/base/ime/chromeos/component_extension_ime_manager_delegate.h" namespace chromeos { namespace input_method {
diff --git a/ui/base/models/dialog_model.h b/ui/base/models/dialog_model.h index 26e8293..4a5be0d6 100644 --- a/ui/base/models/dialog_model.h +++ b/ui/base/models/dialog_model.h
@@ -14,6 +14,7 @@ #include "base/util/type_safety/pass_key.h" #include "ui/base/models/dialog_model_field.h" #include "ui/base/models/dialog_model_host.h" +#include "ui/base/models/image_model.h" #include "ui/base/ui_base_types.h" namespace ui { @@ -126,6 +127,11 @@ return *this; } + Builder& SetIcon(ImageModel icon) { + model_->icon_ = std::move(icon); + return *this; + } + // Make screen readers announce the contents of the dialog as it appears. // See |ax::mojom::Role::kAlertDialog|. Builder& SetIsAlertDialog() { @@ -281,6 +287,8 @@ return title_; } + const ImageModel& icon(util::PassKey<DialogModelHost>) const { return icon_; } + base::Optional<int> initially_focused_field( util::PassKey<DialogModelHost>) const { return initially_focused_field_; @@ -327,8 +335,8 @@ base::Optional<bool> override_show_close_button_; bool close_on_deactivate_ = true; base::string16 title_; + ImageModel icon_; - static constexpr int kExtraButtonId = DIALOG_BUTTON_LAST + 1; std::vector<std::unique_ptr<DialogModelField>> fields_; base::Optional<int> initially_focused_field_; bool is_alert_dialog_ = false;
diff --git a/ui/base/models/dialog_model_field.cc b/ui/base/models/dialog_model_field.cc index 0781fdb..3432b97 100644 --- a/ui/base/models/dialog_model_field.cc +++ b/ui/base/models/dialog_model_field.cc
@@ -3,7 +3,9 @@ // found in the LICENSE file. #include "ui/base/models/dialog_model_field.h" + #include "base/bind.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/models/dialog_model.h" namespace ui { @@ -18,9 +20,23 @@ DialogModelLabel::Link::Link(const Link&) = default; DialogModelLabel::Link::~Link() = default; -DialogModelLabel::DialogModelLabel(int message_id) : message_id_(message_id) {} +DialogModelLabel::DialogModelLabel(int message_id) + : message_id_(message_id), + string_(l10n_util::GetStringUTF16(message_id_)) {} DialogModelLabel::DialogModelLabel(int message_id, std::vector<Link> links) - : message_id_(message_id), links_(std::move(links)) {} + : message_id_(message_id), links_(std::move(links)) { + // Note that this constructor does not set |string_| which is invalid for + // labels with links. +} + +DialogModelLabel::DialogModelLabel(base::string16 fixed_string) + : message_id_(-1), string_(std::move(fixed_string)) {} + +const base::string16& DialogModelLabel::GetString( + util::PassKey<DialogModelHost>) const { + DCHECK(links_.empty()); + return string_; +} DialogModelLabel::DialogModelLabel(const DialogModelLabel&) = default;
diff --git a/ui/base/models/dialog_model_field.h b/ui/base/models/dialog_model_field.h index 35a622d..1e2c2c8 100644 --- a/ui/base/models/dialog_model_field.h +++ b/ui/base/models/dialog_model_field.h
@@ -45,6 +45,7 @@ }; explicit DialogModelLabel(int message_id); + explicit DialogModelLabel(base::string16 fixed_string); DialogModelLabel(const DialogModelLabel&); DialogModelLabel& operator=(const DialogModelLabel&) = delete; ~DialogModelLabel(); @@ -54,11 +55,22 @@ static DialogModelLabel CreateWithLinks(int message_id, std::vector<Link> links); + // Gets the string. Not for use with links, in which case the caller must use + // links() and message_id() to construct the final label. This is required to + // style the final label appropriately and support link callbacks. The caller + // is responsible for checking links().empty() before calling this. + const base::string16& GetString(util::PassKey<DialogModelHost>) const; + DialogModelLabel& set_is_secondary() { is_secondary_ = true; return *this; } + DialogModelLabel& set_allow_character_break() { + allow_character_break_ = true; + return *this; + } + int message_id(util::PassKey<DialogModelHost>) const { return message_id_; } const std::vector<Link> links(util::PassKey<DialogModelHost>) const { return links_; @@ -66,13 +78,18 @@ bool is_secondary(util::PassKey<DialogModelHost>) const { return is_secondary_; } + bool allow_character_break(util::PassKey<DialogModelHost>) const { + return allow_character_break_; + } private: explicit DialogModelLabel(int message_id, std::vector<Link> links); const int message_id_; + const base::string16 string_; const std::vector<Link> links_; bool is_secondary_ = false; + bool allow_character_break_ = false; }; // These "field" classes represent entries in a DialogModel. They are owned
diff --git a/ui/compositor/animation_throughput_reporter.h b/ui/compositor/animation_throughput_reporter.h index 7fb9b665..334a9ed 100644 --- a/ui/compositor/animation_throughput_reporter.h +++ b/ui/compositor/animation_throughput_reporter.h
@@ -35,8 +35,8 @@ // and none of the layer animation sequences is aborted. class COMPOSITOR_EXPORT AnimationThroughputReporter { public: - using ReportCallback = - base::RepeatingCallback<void(cc::FrameSequenceMetrics::ThroughputData)>; + using ReportCallback = base::RepeatingCallback<void( + const cc::FrameSequenceMetrics::CustomReportData&)>; AnimationThroughputReporter(LayerAnimator* animator, ReportCallback report_callback); AnimationThroughputReporter(const AnimationThroughputReporter&) = delete;
diff --git a/ui/compositor/animation_throughput_reporter_unittest.cc b/ui/compositor/animation_throughput_reporter_unittest.cc index 446a57db..20cfae3d 100644 --- a/ui/compositor/animation_throughput_reporter_unittest.cc +++ b/ui/compositor/animation_throughput_reporter_unittest.cc
@@ -85,7 +85,7 @@ LayerAnimator* animator = layer.GetAnimator(); AnimationThroughputReporter reporter( animator, base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData) { + [&](const cc::FrameSequenceMetrics::CustomReportData&) { run_loop.Quit(); })); @@ -107,7 +107,7 @@ LayerAnimator* animator = layer.GetAnimator(); AnimationThroughputReporter reporter( animator, base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData) { + [&](const cc::FrameSequenceMetrics::CustomReportData&) { run_loop.Quit(); })); @@ -134,7 +134,7 @@ LayerAnimator* animator = layer.GetAnimator(); AnimationThroughputReporter reporter( animator, base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData) { + [&](const cc::FrameSequenceMetrics::CustomReportData&) { run_loop.Quit(); })); @@ -159,9 +159,10 @@ std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>(); // |reporter| keeps reporting as long as it is alive. AnimationThroughputReporter reporter( - animator, - base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData) { run_loop->Quit(); })); + animator, base::BindLambdaForTesting( + [&](const cc::FrameSequenceMetrics::CustomReportData&) { + run_loop->Quit(); + })); // Report data for animation of opacity goes to 1. layer->SetOpacity(1.0f); @@ -183,7 +184,7 @@ LayerAnimator* animator = layer->GetAnimator(); AnimationThroughputReporter reporter( animator, base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData) { + [&](const cc::FrameSequenceMetrics::CustomReportData&) { ADD_FAILURE() << "No report for aborted animations."; })); @@ -213,7 +214,7 @@ LayerAnimator* animator = layer->GetAnimator(); AnimationThroughputReporter reporter( animator, base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData) { + [&](const cc::FrameSequenceMetrics::CustomReportData&) { ADD_FAILURE() << "No report for aborted animations."; })); @@ -246,7 +247,7 @@ { AnimationThroughputReporter reporter( animator, base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData) { + [&](const cc::FrameSequenceMetrics::CustomReportData&) { ADD_FAILURE() << "No report for aborted animations."; })); @@ -282,7 +283,7 @@ { AnimationThroughputReporter reporter( animator, base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData) { + [&](const cc::FrameSequenceMetrics::CustomReportData&) { ADD_FAILURE() << "No report for aborted animations."; })); @@ -297,7 +298,7 @@ { AnimationThroughputReporter reporter( animator, base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData) { + [&](const cc::FrameSequenceMetrics::CustomReportData&) { run_loop.Quit(); }));
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 975f772..e309355 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -674,7 +674,7 @@ void Compositor::NotifyThroughputTrackerResults( cc::CustomTrackerResults results) { for (auto& pair : results) - ReportThroughputForTracker(pair.first, std::move(pair.second)); + ReportMetricsForTracker(pair.first, std::move(pair.second)); } void Compositor::DidReceiveCompositorFrameAck() { @@ -757,14 +757,14 @@ host_->RequestPresentationTimeForNextFrame(std::move(callback)); } -void Compositor::ReportThroughputForTracker( +void Compositor::ReportMetricsForTracker( int tracker_id, - cc::FrameSequenceMetrics::ThroughputData throughput) { + const cc::FrameSequenceMetrics::CustomReportData& data) { auto it = throughput_tracker_map_.find(tracker_id); if (it == throughput_tracker_map_.end()) return; - std::move(it->second).Run(std::move(throughput)); + std::move(it->second).Run(data); throughput_tracker_map_.erase(it); }
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 32cdffd..dc011fe 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -406,10 +406,10 @@ private: friend class base::RefCounted<Compositor>; - // Called when throughput data for the tracker of |tracker_id| is ready. - void ReportThroughputForTracker( + // Called when collected metrics for the tracker of |tracker_id| is ready. + void ReportMetricsForTracker( int tracker_id, - cc::FrameSequenceMetrics::ThroughputData throughput); + const cc::FrameSequenceMetrics::CustomReportData& data); gfx::Size size_;
diff --git a/ui/compositor/compositor_unittest.cc b/ui/compositor/compositor_unittest.cc index 469faab2a..2f99374 100644 --- a/ui/compositor/compositor_unittest.cc +++ b/ui/compositor/compositor_unittest.cc
@@ -177,7 +177,7 @@ { auto tracker = compositor()->RequestNewThroughputTracker(); tracker.Start(base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData throughput) { + [&](const cc::FrameSequenceMetrics::CustomReportData& data) { // This should not be called since the tracking is auto canceled. ADD_FAILURE(); })); @@ -188,7 +188,7 @@ { auto tracker = compositor()->RequestNewThroughputTracker(); tracker.Start(base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData throughput) { + [&](const cc::FrameSequenceMetrics::CustomReportData& data) { // May be called since Stop() is called. })); auto moved_tracker = std::move(tracker); @@ -199,7 +199,7 @@ { auto tracker = compositor()->RequestNewThroughputTracker(); tracker.Start(base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData throughput) { + [&](const cc::FrameSequenceMetrics::CustomReportData& data) { // This should not be called since Cancel() is called. ADD_FAILURE(); })); @@ -211,7 +211,7 @@ { auto tracker = compositor()->RequestNewThroughputTracker(); tracker.Start(base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData throughput) { + [&](const cc::FrameSequenceMetrics::CustomReportData& data) { // May be called since Stop() is called. })); tracker.Stop(); @@ -222,7 +222,7 @@ { auto tracker = compositor()->RequestNewThroughputTracker(); tracker.Start(base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData throughput) { + [&](const cc::FrameSequenceMetrics::CustomReportData& data) { // This should not be called since Cancel() is called. ADD_FAILURE(); })); @@ -245,9 +245,9 @@ base::RunLoop run_loop; tracker.Start(base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData throughput) { - EXPECT_GT(throughput.frames_expected, 0u); - EXPECT_GT(throughput.frames_produced, 0u); + [&](const cc::FrameSequenceMetrics::CustomReportData& data) { + EXPECT_GT(data.frames_expected, 0u); + EXPECT_GT(data.frames_produced, 0u); run_loop.Quit(); })); @@ -273,7 +273,7 @@ TEST_F(CompositorTestWithMessageLoop, ThroughputTrackerOutliveCompositor) { auto tracker = compositor()->RequestNewThroughputTracker(); tracker.Start(base::BindLambdaForTesting( - [&](cc::FrameSequenceMetrics::ThroughputData throughput) { + [&](const cc::FrameSequenceMetrics::CustomReportData& data) { ADD_FAILURE() << "No report should happen"; }));
diff --git a/ui/compositor/throughput_tracker_host.h b/ui/compositor/throughput_tracker_host.h index 9082d00..d763516 100644 --- a/ui/compositor/throughput_tracker_host.h +++ b/ui/compositor/throughput_tracker_host.h
@@ -19,9 +19,9 @@ virtual ~ThroughputTrackerHost() = default; // Starts the tracking for the given tracker id. |callback| is invoked after - // the tracker is stopped and the throughput data is collected. + // the tracker is stopped and the metrics data is collected. using ReportCallback = base::OnceCallback<void( - const cc::FrameSequenceMetrics::ThroughputData throughput)>; + const cc::FrameSequenceMetrics::CustomReportData& data)>; virtual void StartThroughputTracker(TrackerId tracker_id, ReportCallback callback) = 0;
diff --git a/ui/events/event_unittest.cc b/ui/events/event_unittest.cc index 7bde1cb..79ac1dd 100644 --- a/ui/events/event_unittest.cc +++ b/ui/events/event_unittest.cc
@@ -24,14 +24,6 @@ #include "ui/events/test/test_event_target.h" #include "ui/gfx/transform.h" -#if defined(USE_X11) -#include "ui/events/test/events_test_utils_x11.h" -#include "ui/events/x/x11_event_translation.h" // nogncheck -#include "ui/gfx/x/event.h" // nogncheck -#include "ui/gfx/x/x11.h" // nogncheck -#include "ui/gfx/x/x11_types.h" // nogncheck -#endif - namespace ui { TEST(EventTest, NoNativeEvent) { @@ -45,14 +37,6 @@ KeyEvent keyev(native_event); EXPECT_TRUE(keyev.HasNativeEvent()); #endif -#if defined(USE_X11) - if (!features::IsUsingOzonePlatform()) { - ScopedXI2Event event; - event.InitKeyEvent(ET_KEY_RELEASED, VKEY_A, EF_NONE); - auto keyev = ui::BuildKeyEventFromXEvent(*event); - EXPECT_FALSE(keyev->HasNativeEvent()); - } -#endif } TEST(EventTest, GetCharacter) { @@ -65,20 +49,6 @@ KeyEvent keyev2(ET_KEY_PRESSED, VKEY_RETURN, EF_NONE); EXPECT_EQ(13, keyev2.GetCharacter()); -#if defined(USE_X11) - if (!features::IsUsingOzonePlatform()) { - // For X11, test the functions with native_event() as well. crbug.com/107837 - ScopedXI2Event event; - event.InitKeyEvent(ET_KEY_PRESSED, VKEY_RETURN, EF_CONTROL_DOWN); - auto keyev3 = ui::BuildKeyEventFromXEvent(*event); - EXPECT_EQ(10, keyev3->GetCharacter()); - - event.InitKeyEvent(ET_KEY_PRESSED, VKEY_RETURN, EF_NONE); - auto keyev4 = ui::BuildKeyEventFromXEvent(*event); - EXPECT_EQ(13, keyev4->GetCharacter()); - } -#endif - // Check if expected Unicode character was returned for a key combination // contains Control. // e.g. Control+Shift+2 produces U+200C on "Persian" keyboard. @@ -319,43 +289,6 @@ } TEST(EventTest, NormalizeKeyEventFlags) { -#if defined(USE_X11) - if (!features::IsUsingOzonePlatform()) { - // Normalize flags when KeyEvent is created from XEvent. - ScopedXI2Event event; - { - event.InitKeyEvent(ET_KEY_PRESSED, VKEY_SHIFT, EF_SHIFT_DOWN); - auto keyev = ui::BuildKeyEventFromXEvent(*event); - EXPECT_EQ(EF_SHIFT_DOWN, keyev->flags()); - } - { - event.InitKeyEvent(ET_KEY_RELEASED, VKEY_SHIFT, EF_SHIFT_DOWN); - auto keyev = ui::BuildKeyEventFromXEvent(*event); - EXPECT_EQ(EF_NONE, keyev->flags()); - } - { - event.InitKeyEvent(ET_KEY_PRESSED, VKEY_CONTROL, EF_CONTROL_DOWN); - auto keyev = ui::BuildKeyEventFromXEvent(*event); - EXPECT_EQ(EF_CONTROL_DOWN, keyev->flags()); - } - { - event.InitKeyEvent(ET_KEY_RELEASED, VKEY_CONTROL, EF_CONTROL_DOWN); - auto keyev = ui::BuildKeyEventFromXEvent(*event); - EXPECT_EQ(EF_NONE, keyev->flags()); - } - { - event.InitKeyEvent(ET_KEY_PRESSED, VKEY_MENU, EF_ALT_DOWN); - auto keyev = ui::BuildKeyEventFromXEvent(*event); - EXPECT_EQ(EF_ALT_DOWN, keyev->flags()); - } - { - event.InitKeyEvent(ET_KEY_RELEASED, VKEY_MENU, EF_ALT_DOWN); - auto keyev = ui::BuildKeyEventFromXEvent(*event); - EXPECT_EQ(EF_NONE, keyev->flags()); - } - } -#endif - // Do not normalize flags for synthesized events without // KeyEvent::NormalizeFlags called explicitly. { @@ -424,15 +357,6 @@ KeyEvent key(ET_KEY_PRESSED, VKEY_SPACE, EF_NONE); EXPECT_EQ(kCodeForSpace, key.GetCodeString()); } -#if defined(USE_X11) - if (!features::IsUsingOzonePlatform()) { - // KeyEvent converts from the native keycode (XKB) to the code. - ScopedXI2Event xevent; - xevent.InitKeyEvent(ET_KEY_PRESSED, VKEY_SPACE, kNativeCodeSpace); - auto keyev = ui::BuildKeyEventFromXEvent(*xevent); - EXPECT_EQ(kCodeForSpace, keyev->GetCodeString()); - } -#endif // USE_X11 #if defined(OS_WIN) { // Test a non extended key. @@ -462,135 +386,6 @@ #endif // OS_WIN } -#if defined(USE_X11) -namespace { - -void SetKeyEventTimestamp(x11::Event* event, int64_t time64) { - uint32_t time = time64 & UINT32_MAX; - event->As<x11::KeyEvent>()->time = static_cast<x11::Time>(time); -} - -void AdvanceKeyEventTimestamp(x11::Event* event) { - auto time = static_cast<uint32_t>(event->As<x11::KeyEvent>()->time) + 1; - event->As<x11::KeyEvent>()->time = static_cast<x11::Time>(time); -} - -} // namespace - -TEST(EventTest, AutoRepeat) { - if (features::IsUsingOzonePlatform()) - return; - const uint16_t kNativeCodeA = - ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_A); - const uint16_t kNativeCodeB = - ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_B); - - ScopedXI2Event native_event_a_pressed; - native_event_a_pressed.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, kNativeCodeA); - ScopedXI2Event native_event_a_pressed_1500; - native_event_a_pressed_1500.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, - kNativeCodeA); - ScopedXI2Event native_event_a_pressed_3000; - native_event_a_pressed_3000.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, - kNativeCodeA); - - ScopedXI2Event native_event_a_released; - native_event_a_released.InitKeyEvent(ET_KEY_RELEASED, VKEY_A, kNativeCodeA); - ScopedXI2Event native_event_b_pressed; - native_event_b_pressed.InitKeyEvent(ET_KEY_PRESSED, VKEY_B, kNativeCodeB); - ScopedXI2Event native_event_a_pressed_nonstandard_state; - native_event_a_pressed_nonstandard_state.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, - kNativeCodeA); - // IBUS-GTK uses the mask (1 << 25) to detect reposted event. - { - x11::Event& event = *native_event_a_pressed_nonstandard_state; - int mask = static_cast<int>(event.As<x11::KeyEvent>()->state) | 1 << 25; - event.As<x11::KeyEvent>()->state = static_cast<x11::KeyButMask>(mask); - } - - int64_t ticks_base = - (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds() - 5000; - SetKeyEventTimestamp(native_event_a_pressed, ticks_base); - SetKeyEventTimestamp(native_event_a_pressed_1500, ticks_base + 1500); - SetKeyEventTimestamp(native_event_a_pressed_3000, ticks_base + 3000); - - { - auto key_a1 = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_FALSE(key_a1->is_repeat()); - - auto key_a1_released = BuildKeyEventFromXEvent(*native_event_a_released); - EXPECT_FALSE(key_a1_released->is_repeat()); - - auto key_a2 = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_FALSE(key_a2->is_repeat()); - - AdvanceKeyEventTimestamp(native_event_a_pressed); - auto key_a2_repeated = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_TRUE(key_a2_repeated->is_repeat()); - - auto key_a2_released = BuildKeyEventFromXEvent(*native_event_a_released); - EXPECT_FALSE(key_a2_released->is_repeat()); - } - - // Interleaved with different key press. - { - auto key_a3 = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_FALSE(key_a3->is_repeat()); - - auto key_b = BuildKeyEventFromXEvent(*native_event_b_pressed); - EXPECT_FALSE(key_b->is_repeat()); - - AdvanceKeyEventTimestamp(native_event_a_pressed); - auto key_a3_again = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_FALSE(key_a3_again->is_repeat()); - - AdvanceKeyEventTimestamp(native_event_a_pressed); - auto key_a3_repeated = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_TRUE(key_a3_repeated->is_repeat()); - - AdvanceKeyEventTimestamp(native_event_a_pressed); - auto key_a3_repeated2 = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_TRUE(key_a3_repeated2->is_repeat()); - - auto key_a3_released = BuildKeyEventFromXEvent(*native_event_a_released); - EXPECT_FALSE(key_a3_released->is_repeat()); - } - - // Hold the key longer than max auto repeat timeout. - { - auto key_a4_0 = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_FALSE(key_a4_0->is_repeat()); - - auto key_a4_1500 = BuildKeyEventFromXEvent(*native_event_a_pressed_1500); - EXPECT_TRUE(key_a4_1500->is_repeat()); - - auto key_a4_3000 = BuildKeyEventFromXEvent(*native_event_a_pressed_3000); - EXPECT_TRUE(key_a4_3000->is_repeat()); - - auto key_a4_released = BuildKeyEventFromXEvent(*native_event_a_released); - EXPECT_FALSE(key_a4_released->is_repeat()); - } - - { - auto key_a4_pressed = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_FALSE(key_a4_pressed->is_repeat()); - - auto key_a4_pressed_nonstandard_state = - BuildKeyEventFromXEvent(*native_event_a_pressed_nonstandard_state); - EXPECT_FALSE(key_a4_pressed_nonstandard_state->is_repeat()); - } - - { - auto key_a1 = BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_FALSE(key_a1->is_repeat()); - - auto key_a1_with_same_event = - BuildKeyEventFromXEvent(*native_event_a_pressed); - EXPECT_FALSE(key_a1_with_same_event->is_repeat()); - } -} -#endif // USE_X11 - TEST(EventTest, TouchEventRadiusDefaultsToOtherAxis) { const base::TimeTicks time = base::TimeTicks::Now(); const float non_zero_length1 = 30; @@ -852,37 +647,6 @@ EXPECT_FALSE(mouseev3.flags() & EF_UNADJUSTED_MOUSE); } -// Checks that Event.Latency.OS.TOUCH_PRESSED, TOUCH_MOVED, -// and TOUCH_RELEASED histograms are computed properly. -#if defined(USE_X11) -TEST(EventTest, EventLatencyOSTouchHistograms) { - if (features::IsUsingOzonePlatform()) - return; - base::HistogramTester histogram_tester; - ScopedXI2Event scoped_xevent; - - // SetUp for test - DeviceDataManagerX11::CreateInstance(); - std::vector<int> devices; - devices.push_back(0); - ui::SetUpTouchDevicesForTest(devices); - - // Init touch begin, update, and end events with tracking id 5, touch id 0. - scoped_xevent.InitTouchEvent(0, x11::Input::DeviceEvent::TouchBegin, 5, - gfx::Point(10, 10), {}); - auto touch_begin = ui::BuildTouchEventFromXEvent(*scoped_xevent); - histogram_tester.ExpectTotalCount("Event.Latency.OS.TOUCH_PRESSED", 1); - scoped_xevent.InitTouchEvent(0, x11::Input::DeviceEvent::TouchUpdate, 5, - gfx::Point(20, 20), {}); - auto touch_update = ui::BuildTouchEventFromXEvent(*scoped_xevent); - histogram_tester.ExpectTotalCount("Event.Latency.OS.TOUCH_MOVED", 1); - scoped_xevent.InitTouchEvent(0, x11::Input::DeviceEvent::TouchEnd, 5, - gfx::Point(30, 30), {}); - auto touch_end = ui::BuildTouchEventFromXEvent(*scoped_xevent); - histogram_tester.ExpectTotalCount("Event.Latency.OS.TOUCH_RELEASED", 1); -} -#endif - // Checks that Event.Latency.OS.MOUSE_WHEEL histogram is computed properly. TEST(EventTest, EventLatencyOSMouseWheelHistogram) { #if defined(OS_WIN) @@ -891,22 +655,6 @@ MouseWheelEvent mouseWheelEvent(event); histogram_tester.ExpectTotalCount("Event.Latency.OS.MOUSE_WHEEL", 1); #endif -#if defined(USE_X11) - if (features::IsUsingOzonePlatform()) - return; - base::HistogramTester histogram_tester; - DeviceDataManagerX11::CreateInstance(); - - // Initializes a native event and uses it to generate a MouseWheel event. - xcb_generic_event_t ge; - memset(&ge, 0, sizeof(ge)); - auto* button = reinterpret_cast<xcb_button_press_event_t*>(&ge); - button->response_type = x11::ButtonEvent::Press; - button->detail = 4; // A valid wheel button number between min and max. - x11::Event native_event(&ge, x11::Connection::Get()); - auto mouse_ev = ui::BuildMouseWheelEventFromXEvent(native_event); - histogram_tester.ExpectTotalCount("Event.Latency.OS.MOUSE_WHEEL", 1); -#endif } TEST(EventTest, UpdateForRootTransformation) {
diff --git a/ui/gl/gl_fence_egl.cc b/ui/gl/gl_fence_egl.cc index 27bd780..eb32bf1 100644 --- a/ui/gl/gl_fence_egl.cc +++ b/ui/gl/gl_fence_egl.cc
@@ -10,17 +10,6 @@ namespace gl { -namespace { - -bool g_ignore_egl_sync_failures = false; - -} // namespace - -// static -void GLFenceEGL::SetIgnoreFailures() { - g_ignore_egl_sync_failures = true; -} - GLFenceEGL::GLFenceEGL() = default; // static @@ -66,7 +55,7 @@ void GLFenceEGL::ClientWait() { EGLint result = ClientWaitWithTimeoutNanos(EGL_FOREVER_KHR); - DCHECK(g_ignore_egl_sync_failures || EGL_TIMEOUT_EXPIRED_KHR != result); + DCHECK_NE(EGL_TIMEOUT_EXPIRED_KHR, result); } EGLint GLFenceEGL::ClientWaitWithTimeoutNanos(EGLTimeKHR timeout) { @@ -75,7 +64,7 @@ if (result == EGL_FALSE) { LOG(ERROR) << "Failed to wait for EGLSync. error:" << ui::GetLastEGLErrorString(); - CHECK(g_ignore_egl_sync_failures); + CHECK(false); } return result; } @@ -89,7 +78,7 @@ if (eglWaitSyncKHR(display_, sync_, flags) == EGL_FALSE) { LOG(ERROR) << "Failed to wait for EGLSync. error:" << ui::GetLastEGLErrorString(); - CHECK(g_ignore_egl_sync_failures); + CHECK(false); } }
diff --git a/ui/gl/gl_fence_egl.h b/ui/gl/gl_fence_egl.h index 946469ae..b9a429d 100644 --- a/ui/gl/gl_fence_egl.h +++ b/ui/gl/gl_fence_egl.h
@@ -14,8 +14,6 @@ class GL_EXPORT GLFenceEGL : public GLFence { public: - static void SetIgnoreFailures(); - ~GLFenceEGL() override; // Factory method using default initialization.
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc index 045fdc9..2a8f16f5 100644 --- a/ui/message_center/views/notification_view_md.cc +++ b/ui/message_center/views/notification_view_md.cc
@@ -600,6 +600,7 @@ header_row_ = new NotificationHeaderView(this); header_row_->SetPreferredSize(header_row_->GetPreferredSize() - gfx::Size(GetInsets().width(), 0)); + header_row_->SetID(kHeaderRow); control_buttons_view_ = header_row_->AddChildView( std::make_unique<NotificationControlButtonsView>(this)); AddChildView(header_row_);
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h index 7848548..aa9bd8c 100644 --- a/ui/message_center/views/notification_view_md.h +++ b/ui/message_center/views/notification_view_md.h
@@ -168,6 +168,13 @@ public NotificationInputDelegate, public views::ButtonListener { public: + // This defines an enumeration of IDs that can uniquely identify a view within + // the scope of NotificationViewMD. + enum ViewId { + // We start from 1 because 0 is the default view ID. + kHeaderRow = 1, + }; + explicit NotificationViewMD(const Notification& notification); ~NotificationViewMD() override;
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.cc b/ui/ozone/platform/drm/gpu/screen_manager.cc index d916bba3..9d36d67a 100644 --- a/ui/ozone/platform/drm/gpu/screen_manager.cc +++ b/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -93,6 +93,13 @@ return nullptr; } +std::vector<uint64_t> GetModifiersForPrimaryFormat( + HardwareDisplayController* controller) { + gfx::BufferFormat format = display::DisplaySnapshot::PrimaryFormat(); + uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(format); + return controller->GetFormatModifiersForModesetting(fourcc_format); +} + } // namespace ScreenManager::ScreenManager() = default; @@ -425,32 +432,13 @@ DrmOverlayPlane ScreenManager::GetModesetBuffer( HardwareDisplayController* controller, - const gfx::Rect& bounds) { - DrmWindow* window = FindWindowAt(bounds); - - gfx::BufferFormat format = display::DisplaySnapshot::PrimaryFormat(); - uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer(format); - const auto& modifiers = - controller->GetFormatModifiersForModesetting(fourcc_format); - if (window) { - const DrmOverlayPlane* primary = window->GetLastModesetBuffer(); - const DrmDevice* drm = controller->GetDrmDevice().get(); - if (primary && primary->buffer->size() == bounds.size() && - primary->buffer->drm_device() == drm) { - // If the controller doesn't advertise modifiers, wont have a - // modifier either and we can reuse the buffer. Otherwise, check - // to see if the controller supports the buffers format - // modifier. - if (modifiers.empty()) - return primary->Clone(); - for (const uint64_t modifier : modifiers) { - if (modifier == primary->buffer->format_modifier()) - return primary->Clone(); - } - } - } - + const gfx::Rect& bounds, + const std::vector<uint64_t>& modifiers) { scoped_refptr<DrmDevice> drm = controller->GetDrmDevice(); + uint32_t fourcc_format = ui::GetFourCCFormatForOpaqueFramebuffer( + display::DisplaySnapshot::PrimaryFormat()); + // Get the buffer that best reflects what the next Page Flip will look like, + // which is using the preferred modifiers from the controllers. std::unique_ptr<GbmBuffer> buffer = drm->gbm_device()->CreateBufferWithModifiers( fourcc_format, bounds.size(), GBM_BO_USE_SCANOUT, modifiers); @@ -459,6 +447,19 @@ return DrmOverlayPlane::Error(); } + // If the current primary plane matches what we need for the next page flip, + // we can clone it. + DrmWindow* window = FindWindowAt(bounds); + if (window) { + const DrmOverlayPlane* primary = window->GetLastModesetBuffer(); + const DrmDevice* drm = controller->GetDrmDevice().get(); + if (primary && primary->buffer->size() == bounds.size() && + primary->buffer->drm_device() == drm) { + if (primary->buffer->format_modifier() == buffer->GetFormatModifier()) + return primary->Clone(); + } + } + scoped_refptr<DrmFramebuffer> framebuffer = DrmFramebuffer::AddFramebuffer( drm, buffer.get(), buffer->GetSize(), modifiers); if (!framebuffer) { @@ -481,7 +482,9 @@ bool ScreenManager::EnableController(HardwareDisplayController* controller) { DCHECK(!controller->crtc_controllers().empty()); gfx::Rect rect(controller->origin(), controller->GetModeSize()); - DrmOverlayPlane plane = GetModesetBuffer(controller, rect); + + auto modifiers = GetModifiersForPrimaryFormat(controller); + DrmOverlayPlane plane = GetModesetBuffer(controller, rect, modifiers); if (!plane.buffer || !controller->Enable(plane)) { LOG(ERROR) << "Failed to enable controller"; return false; @@ -497,7 +500,8 @@ gfx::Rect rect(origin, gfx::Size(mode.hdisplay, mode.vdisplay)); controller->set_origin(origin); - DrmOverlayPlane plane = GetModesetBuffer(controller, rect); + auto modifiers = GetModifiersForPrimaryFormat(controller); + DrmOverlayPlane plane = GetModesetBuffer(controller, rect, modifiers); if (!plane.buffer || !controller->Modeset(plane, mode)) { LOG(ERROR) << "Failed to modeset controller"; return false;
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.h b/ui/ozone/platform/drm/gpu/screen_manager.h index 88d425f..2491291 100644 --- a/ui/ozone/platform/drm/gpu/screen_manager.h +++ b/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -138,7 +138,8 @@ const drmModeModeInfo& mode); DrmOverlayPlane GetModesetBuffer(HardwareDisplayController* controller, - const gfx::Rect& bounds); + const gfx::Rect& bounds, + const std::vector<uint64_t>& modifiers); bool EnableController(HardwareDisplayController* controller);
diff --git a/ui/platform_window/x11/test/events_x_unittest.cc b/ui/platform_window/x11/test/events_x_unittest.cc index 3ce0b2d..cd58435 100644 --- a/ui/platform_window/x11/test/events_x_unittest.cc +++ b/ui/platform_window/x11/test/events_x_unittest.cc
@@ -12,6 +12,7 @@ #include <utility> #include "base/stl_util.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/simple_test_tick_clock.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" @@ -20,8 +21,11 @@ #include "ui/events/event.h" #include "ui/events/event_constants.h" #include "ui/events/event_utils.h" +#include "ui/events/keycodes/dom/dom_code.h" +#include "ui/events/keycodes/dom/keycode_converter.h" #include "ui/events/test/events_test_utils.h" #include "ui/events/test/events_test_utils_x11.h" +#include "ui/events/test/keyboard_layout.h" #include "ui/events/test/scoped_event_test_tick_clock.h" #include "ui/events/types/event_type.h" #include "ui/events/x/events_x_utils.h" @@ -577,4 +581,247 @@ EXPECT_EQ(TimeTicksFromMillis(0xFFFFFFFF), ui::EventTimeFromXEvent(event)); } +// Moved from event_unittest.cc + +TEST_F(EventsXTest, NativeEvent) { + ScopedXI2Event event; + event.InitKeyEvent(ET_KEY_RELEASED, VKEY_A, EF_NONE); + auto keyev = ui::BuildKeyEventFromXEvent(*event); + EXPECT_FALSE(keyev->HasNativeEvent()); +} + +TEST_F(EventsXTest, GetCharacter) { + ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US); + + // For X11, test the functions with native_event() as well. crbug.com/107837 + ScopedXI2Event event; + event.InitKeyEvent(ET_KEY_PRESSED, VKEY_RETURN, EF_CONTROL_DOWN); + auto keyev3 = ui::BuildKeyEventFromXEvent(*event); + EXPECT_EQ(10, keyev3->GetCharacter()); + + event.InitKeyEvent(ET_KEY_PRESSED, VKEY_RETURN, EF_NONE); + auto keyev4 = ui::BuildKeyEventFromXEvent(*event); + EXPECT_EQ(13, keyev4->GetCharacter()); +} + +TEST_F(EventsXTest, NormalizeKeyEventFlags) { + // Normalize flags when KeyEvent is created from XEvent. + ScopedXI2Event event; + { + event.InitKeyEvent(ET_KEY_PRESSED, VKEY_SHIFT, EF_SHIFT_DOWN); + auto keyev = ui::BuildKeyEventFromXEvent(*event); + EXPECT_EQ(EF_SHIFT_DOWN, keyev->flags()); + } + { + event.InitKeyEvent(ET_KEY_RELEASED, VKEY_SHIFT, EF_SHIFT_DOWN); + auto keyev = ui::BuildKeyEventFromXEvent(*event); + EXPECT_EQ(EF_NONE, keyev->flags()); + } + { + event.InitKeyEvent(ET_KEY_PRESSED, VKEY_CONTROL, EF_CONTROL_DOWN); + auto keyev = ui::BuildKeyEventFromXEvent(*event); + EXPECT_EQ(EF_CONTROL_DOWN, keyev->flags()); + } + { + event.InitKeyEvent(ET_KEY_RELEASED, VKEY_CONTROL, EF_CONTROL_DOWN); + auto keyev = ui::BuildKeyEventFromXEvent(*event); + EXPECT_EQ(EF_NONE, keyev->flags()); + } + { + event.InitKeyEvent(ET_KEY_PRESSED, VKEY_MENU, EF_ALT_DOWN); + auto keyev = ui::BuildKeyEventFromXEvent(*event); + EXPECT_EQ(EF_ALT_DOWN, keyev->flags()); + } + { + event.InitKeyEvent(ET_KEY_RELEASED, VKEY_MENU, EF_ALT_DOWN); + auto keyev = ui::BuildKeyEventFromXEvent(*event); + EXPECT_EQ(EF_NONE, keyev->flags()); + } +} + +TEST_F(EventsXTest, KeyEventCode) { + const DomCode kDomCodeForSpace = DomCode::SPACE; + const char kCodeForSpace[] = "Space"; + ASSERT_EQ(kDomCodeForSpace, + ui::KeycodeConverter::CodeStringToDomCode(kCodeForSpace)); + const uint16_t kNativeCodeSpace = + ui::KeycodeConverter::DomCodeToNativeKeycode(kDomCodeForSpace); + ASSERT_NE(ui::KeycodeConverter::InvalidNativeKeycode(), kNativeCodeSpace); + ASSERT_EQ(kNativeCodeSpace, + ui::KeycodeConverter::DomCodeToNativeKeycode(kDomCodeForSpace)); + + // KeyEvent converts from the native keycode (XKB) to the code. + ScopedXI2Event xevent; + xevent.InitKeyEvent(ET_KEY_PRESSED, VKEY_SPACE, kNativeCodeSpace); + auto keyev = ui::BuildKeyEventFromXEvent(*xevent); + EXPECT_EQ(kCodeForSpace, keyev->GetCodeString()); +} + +namespace { + +void SetKeyEventTimestamp(x11::Event* event, int64_t time64) { + uint32_t time = time64 & UINT32_MAX; + event->As<x11::KeyEvent>()->time = static_cast<x11::Time>(time); +} + +void AdvanceKeyEventTimestamp(x11::Event* event) { + auto time = static_cast<uint32_t>(event->As<x11::KeyEvent>()->time) + 1; + event->As<x11::KeyEvent>()->time = static_cast<x11::Time>(time); +} + +} // namespace + +TEST_F(EventsXTest, AutoRepeat) { + const uint16_t kNativeCodeA = + ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_A); + const uint16_t kNativeCodeB = + ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_B); + + ScopedXI2Event native_event_a_pressed; + native_event_a_pressed.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, kNativeCodeA); + ScopedXI2Event native_event_a_pressed_1500; + native_event_a_pressed_1500.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, + kNativeCodeA); + ScopedXI2Event native_event_a_pressed_3000; + native_event_a_pressed_3000.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, + kNativeCodeA); + + ScopedXI2Event native_event_a_released; + native_event_a_released.InitKeyEvent(ET_KEY_RELEASED, VKEY_A, kNativeCodeA); + ScopedXI2Event native_event_b_pressed; + native_event_b_pressed.InitKeyEvent(ET_KEY_PRESSED, VKEY_B, kNativeCodeB); + ScopedXI2Event native_event_a_pressed_nonstandard_state; + native_event_a_pressed_nonstandard_state.InitKeyEvent(ET_KEY_PRESSED, VKEY_A, + kNativeCodeA); + // IBUS-GTK uses the mask (1 << 25) to detect reposted event. + { + x11::Event& event = *native_event_a_pressed_nonstandard_state; + int mask = static_cast<int>(event.As<x11::KeyEvent>()->state) | 1 << 25; + event.As<x11::KeyEvent>()->state = static_cast<x11::KeyButMask>(mask); + } + + int64_t ticks_base = + (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds() - 5000; + SetKeyEventTimestamp(native_event_a_pressed, ticks_base); + SetKeyEventTimestamp(native_event_a_pressed_1500, ticks_base + 1500); + SetKeyEventTimestamp(native_event_a_pressed_3000, ticks_base + 3000); + + { + auto key_a1 = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_FALSE(key_a1->is_repeat()); + + auto key_a1_released = BuildKeyEventFromXEvent(*native_event_a_released); + EXPECT_FALSE(key_a1_released->is_repeat()); + + auto key_a2 = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_FALSE(key_a2->is_repeat()); + + AdvanceKeyEventTimestamp(native_event_a_pressed); + auto key_a2_repeated = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_TRUE(key_a2_repeated->is_repeat()); + + auto key_a2_released = BuildKeyEventFromXEvent(*native_event_a_released); + EXPECT_FALSE(key_a2_released->is_repeat()); + } + + // Interleaved with different key press. + { + auto key_a3 = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_FALSE(key_a3->is_repeat()); + + auto key_b = BuildKeyEventFromXEvent(*native_event_b_pressed); + EXPECT_FALSE(key_b->is_repeat()); + + AdvanceKeyEventTimestamp(native_event_a_pressed); + auto key_a3_again = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_FALSE(key_a3_again->is_repeat()); + + AdvanceKeyEventTimestamp(native_event_a_pressed); + auto key_a3_repeated = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_TRUE(key_a3_repeated->is_repeat()); + + AdvanceKeyEventTimestamp(native_event_a_pressed); + auto key_a3_repeated2 = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_TRUE(key_a3_repeated2->is_repeat()); + + auto key_a3_released = BuildKeyEventFromXEvent(*native_event_a_released); + EXPECT_FALSE(key_a3_released->is_repeat()); + } + + // Hold the key longer than max auto repeat timeout. + { + auto key_a4_0 = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_FALSE(key_a4_0->is_repeat()); + + auto key_a4_1500 = BuildKeyEventFromXEvent(*native_event_a_pressed_1500); + EXPECT_TRUE(key_a4_1500->is_repeat()); + + auto key_a4_3000 = BuildKeyEventFromXEvent(*native_event_a_pressed_3000); + EXPECT_TRUE(key_a4_3000->is_repeat()); + + auto key_a4_released = BuildKeyEventFromXEvent(*native_event_a_released); + EXPECT_FALSE(key_a4_released->is_repeat()); + } + + { + auto key_a4_pressed = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_FALSE(key_a4_pressed->is_repeat()); + + auto key_a4_pressed_nonstandard_state = + BuildKeyEventFromXEvent(*native_event_a_pressed_nonstandard_state); + EXPECT_FALSE(key_a4_pressed_nonstandard_state->is_repeat()); + } + + { + auto key_a1 = BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_FALSE(key_a1->is_repeat()); + + auto key_a1_with_same_event = + BuildKeyEventFromXEvent(*native_event_a_pressed); + EXPECT_FALSE(key_a1_with_same_event->is_repeat()); + } +} + +// Checks that Event.Latency.OS.TOUCH_PRESSED, TOUCH_MOVED, +// and TOUCH_RELEASED histograms are computed properly. +TEST_F(EventsXTest, EventLatencyOSTouchHistograms) { + base::HistogramTester histogram_tester; + ScopedXI2Event scoped_xevent; + + // SetUp for test + DeviceDataManagerX11::CreateInstance(); + std::vector<int> devices; + devices.push_back(0); + ui::SetUpTouchDevicesForTest(devices); + + // Init touch begin, update, and end events with tracking id 5, touch id 0. + scoped_xevent.InitTouchEvent(0, x11::Input::DeviceEvent::TouchBegin, 5, + gfx::Point(10, 10), {}); + auto touch_begin = ui::BuildTouchEventFromXEvent(*scoped_xevent); + histogram_tester.ExpectTotalCount("Event.Latency.OS.TOUCH_PRESSED", 1); + scoped_xevent.InitTouchEvent(0, x11::Input::DeviceEvent::TouchUpdate, 5, + gfx::Point(20, 20), {}); + auto touch_update = ui::BuildTouchEventFromXEvent(*scoped_xevent); + histogram_tester.ExpectTotalCount("Event.Latency.OS.TOUCH_MOVED", 1); + scoped_xevent.InitTouchEvent(0, x11::Input::DeviceEvent::TouchEnd, 5, + gfx::Point(30, 30), {}); + auto touch_end = ui::BuildTouchEventFromXEvent(*scoped_xevent); + histogram_tester.ExpectTotalCount("Event.Latency.OS.TOUCH_RELEASED", 1); +} + +TEST_F(EventsXTest, EventLatencyOSMouseWheelHistogram) { + base::HistogramTester histogram_tester; + DeviceDataManagerX11::CreateInstance(); + + // Initializes a native event and uses it to generate a MouseWheel event. + xcb_generic_event_t ge; + memset(&ge, 0, sizeof(ge)); + auto* button = reinterpret_cast<xcb_button_press_event_t*>(&ge); + button->response_type = x11::ButtonEvent::Press; + button->detail = 4; // A valid wheel button number between min and max. + x11::Event native_event(&ge, x11::Connection::Get()); + auto mouse_ev = ui::BuildMouseWheelEventFromXEvent(native_event); + histogram_tester.ExpectTotalCount("Event.Latency.OS.MOUSE_WHEEL", 1); +} + } // namespace ui
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc index 89b31d4..b251773 100644 --- a/ui/views/bubble/bubble_dialog_model_host.cc +++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -134,11 +134,19 @@ SetButtons(button_mask); SetTitle(model_->title(GetPassKey())); + if (model_->override_show_close_button(GetPassKey())) { SetShowCloseButton(*model_->override_show_close_button(GetPassKey())); } else { SetShowCloseButton(!IsModalDialog()); } + + if (!model_->icon(GetPassKey()).IsEmpty()) { + // TODO(pbos): Consider adding ImageModel support to SetIcon(). + SetIcon(model_->icon(GetPassKey()).GetImage().AsImageSkia()); + SetShowIcon(true); + } + if (model_->is_alert_dialog(GetPassKey())) SetAccessibleRole(ax::mojom::Role::kAlertDialog); @@ -290,8 +298,20 @@ first_row = false; } - set_margins(LayoutProvider::Get()->GetDialogInsetsForContentType( - first_field_content_type, last_field_content_type)); + gfx::Insets margins = LayoutProvider::Get()->GetDialogInsetsForContentType( + first_field_content_type, last_field_content_type); + if (!model_->icon(GetPassKey()).IsEmpty()) { + // If we have a window icon, inset margins additionally to align with + // title label. + // TODO(pbos): Reconsider this. Aligning with title gives a massive gap on + // the left side of the dialog. This style is from + // ExtensionUninstallDialogView as part of refactoring it to use + // DialogModel. + margins.set_left( + margins.left() + model_->icon(GetPassKey()).Size().width() + + LayoutProvider::Get()->GetInsetsMetric(INSETS_DIALOG_TITLE).left()); + } + set_margins(margins); } void BubbleDialogModelHost::OnWindowClosing() { @@ -479,8 +499,7 @@ } auto text_label = std::make_unique<Label>( - l10n_util::GetStringUTF16(dialog_label.message_id(GetPassKey())), - style::CONTEXT_DIALOG_BODY_TEXT, + dialog_label.GetString(GetPassKey()), style::CONTEXT_DIALOG_BODY_TEXT, dialog_label.is_secondary(GetPassKey()) ? style::STYLE_SECONDARY : style::STYLE_PRIMARY); text_label->SetMultiLine(true);
diff --git a/ui/views/controls/button/button.h b/ui/views/controls/button/button.h index d5f45758..39826085 100644 --- a/ui/views/controls/button/button.h +++ b/ui/views/controls/button/button.h
@@ -381,6 +381,7 @@ }; BEGIN_VIEW_BUILDER(VIEWS_EXPORT, Button, InkDropHostView) +VIEW_BUILDER_PROPERTY(base::string16, AccessibleName) VIEW_BUILDER_PROPERTY(base::TimeDelta, AnimationDuration) VIEW_BUILDER_PROPERTY(bool, AnimateOnStateChange) VIEW_BUILDER_PROPERTY(bool, HasInkDropActionOnClick)
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h index 52da416..87bbdb17 100644 --- a/ui/views/controls/textfield/textfield.h +++ b/ui/views/controls/textfield/textfield.h
@@ -739,20 +739,22 @@ }; BEGIN_VIEW_BUILDER(VIEWS_EXPORT, Textfield, View) -VIEW_BUILDER_PROPERTY(bool, ReadOnly) -VIEW_BUILDER_PROPERTY(base::string16, Text) -VIEW_BUILDER_PROPERTY(ui::TextInputType, TextInputType) -VIEW_BUILDER_PROPERTY(int, TextInputFlags) -VIEW_BUILDER_PROPERTY(SkColor, TextColor) -VIEW_BUILDER_PROPERTY(SkColor, SelectionTextColor) -VIEW_BUILDER_PROPERTY(SkColor, BackgroundColor) -VIEW_BUILDER_PROPERTY(SkColor, SelectionBackgroundColor) -VIEW_BUILDER_PROPERTY(bool, CursorEnabled) -VIEW_BUILDER_PROPERTY(base::string16, PlaceholderText) -VIEW_BUILDER_PROPERTY(bool, Invalid) -VIEW_BUILDER_PROPERTY(gfx::HorizontalAlignment, HorizontalAlignment) -VIEW_BUILDER_PROPERTY(gfx::Range, SelectedRange) VIEW_BUILDER_PROPERTY(base::string16, AccessibleName) +VIEW_BUILDER_PROPERTY(SkColor, BackgroundColor) +VIEW_BUILDER_PROPERTY(bool, CursorEnabled) +VIEW_BUILDER_PROPERTY(int, DefaultWidthInChars) +VIEW_BUILDER_PROPERTY(gfx::HorizontalAlignment, HorizontalAlignment) +VIEW_BUILDER_PROPERTY(bool, Invalid) +VIEW_BUILDER_PROPERTY(int, MinimumWidthInChars) +VIEW_BUILDER_PROPERTY(base::string16, PlaceholderText) +VIEW_BUILDER_PROPERTY(bool, ReadOnly) +VIEW_BUILDER_PROPERTY(gfx::Range, SelectedRange) +VIEW_BUILDER_PROPERTY(SkColor, SelectionBackgroundColor) +VIEW_BUILDER_PROPERTY(SkColor, SelectionTextColor) +VIEW_BUILDER_PROPERTY(base::string16, Text) +VIEW_BUILDER_PROPERTY(SkColor, TextColor) +VIEW_BUILDER_PROPERTY(int, TextInputFlags) +VIEW_BUILDER_PROPERTY(ui::TextInputType, TextInputType) END_VIEW_BUILDER(VIEWS_EXPORT, Textfield) } // namespace views
diff --git a/ui/webui/resources/cr_elements/cr_icons_css.html b/ui/webui/resources/cr_elements/cr_icons_css.html index fd1e81e..ab876e9 100644 --- a/ui/webui/resources/cr_elements/cr_icons_css.html +++ b/ui/webui/resources/cr_elements/cr_icons_css.html
@@ -28,6 +28,10 @@ --cr-icon-image: url(../images/icon_delete_gray.svg); } + .icon-edit { + --cr-icon-image: url(../images/icon_edit.svg); + } + .icon-picture-delete { --cr-icon-image: url(../images/icon_picture_delete.svg); }
diff --git a/ui/webui/resources/cr_elements_images.grdp b/ui/webui/resources/cr_elements_images.grdp index 4e2836b..61a8eab 100644 --- a/ui/webui/resources/cr_elements_images.grdp +++ b/ui/webui/resources/cr_elements_images.grdp
@@ -25,6 +25,8 @@ file="images/icon_clear.svg" type="BINDATA" /> <include name="IDR_WEBUI_IMAGES_ICON_DELETE_GRAY_SVG" file="images/icon_delete_gray.svg" type="BINDATA" /> + <include name="IDR_WEBUI_IMAGES_ICON_EDIT_SVG" + file="images/icon_edit.svg" type="BINDATA" /> <include name="IDR_WEBUI_IMAGES_ICON_EXPAND_LESS_SVG" file="images/icon_expand_less.svg" type="BINDATA" /> <include name="IDR_WEBUI_IMAGES_ICON_EXPAND_MORE_SVG"
diff --git a/ui/webui/resources/images/icon_edit.svg b/ui/webui/resources/images/icon_edit.svg new file mode 100644 index 0000000..2acc71a --- /dev/null +++ b/ui/webui/resources/images/icon_edit.svg
@@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20.41 4.94l-1.35-1.35c-.78-.78-2.05-.78-2.83 0L13.4 6.41 3 16.82V21h4.18l10.46-10.46 2.77-2.77c.79-.78.79-2.05 0-2.83zm-14 14.12L5 19v-1.36l9.82-9.82 1.41 1.41-9.82 9.83z"/></svg> \ No newline at end of file
diff --git a/ui/webui/resources/tools/generate_grd.gni b/ui/webui/resources/tools/generate_grd.gni index 1caec6f..d44c8b2d 100644 --- a/ui/webui/resources/tools/generate_grd.gni +++ b/ui/webui/resources/tools/generate_grd.gni
@@ -11,10 +11,6 @@ } inputs = invoker.manifest_files - if (defined(invoker.input_files)) { - inputs += invoker.input_files - } - outputs = [ invoker.out_grd ] args = [
diff --git a/ui/wm/core/window_animations.cc b/ui/wm/core/window_animations.cc index 282c0fb..f2685187 100644 --- a/ui/wm/core/window_animations.cc +++ b/ui/wm/core/window_animations.cc
@@ -146,9 +146,9 @@ SmoothnessCallback callback) { return base::BindRepeating( [](SmoothnessCallback callback, - cc::FrameSequenceMetrics::ThroughputData throughput) { - const int smoothness = std::floor(100.0f * throughput.frames_produced / - throughput.frames_expected); + const cc::FrameSequenceMetrics::CustomReportData& data) { + const int smoothness = + std::floor(100.0f * data.frames_produced / data.frames_expected); callback.Run(smoothness); }, std::move(callback));
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java index 7bd95d6..61967b68 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/WebLayerImpl.java
@@ -45,6 +45,7 @@ import org.chromium.base.compat.ApiHelperForO; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.library_loader.LibraryProcessType; +import org.chromium.base.metrics.RecordHistogram; import org.chromium.components.browser_ui.contacts_picker.ContactsPickerDialog; import org.chromium.components.browser_ui.photo_picker.DecoderServiceHost; import org.chromium.components.browser_ui.photo_picker.ImageDecoder; @@ -432,6 +433,19 @@ public void setClient(IWebLayerClient client) { StrictModeWorkaround.apply(); sClient = client; + + if (WebLayerFactoryImpl.getClientMajorVersion() >= 88) { + try { + RecordHistogram.recordTimesHistogram("WebLayer.Startup.ClassLoaderCreationTime", + sClient.getClassLoaderCreationTime()); + RecordHistogram.recordTimesHistogram( + "WebLayer.Startup.ContextCreationTime", sClient.getContextCreationTime()); + RecordHistogram.recordTimesHistogram("WebLayer.Startup.WebLayerLoaderCreationTime", + sClient.getWebLayerLoaderCreationTime()); + } catch (RemoteException e) { + throw new APICallException(e); + } + } } @Override
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayerClient.aidl b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayerClient.aidl index a26f56d..cc6781a 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayerClient.aidl +++ b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/IWebLayerClient.aidl
@@ -13,4 +13,9 @@ // Since Version 86. Intent createImageDecoderServiceIntent() = 3; + + // Since Version 88. + long getClassLoaderCreationTime() = 4; + long getContextCreationTime() = 5; + long getWebLayerLoaderCreationTime() = 6; }
diff --git a/weblayer/public/java/org/chromium/weblayer/WebLayer.java b/weblayer/public/java/org/chromium/weblayer/WebLayer.java index 1f043a0..7dca1ca 100644 --- a/weblayer/public/java/org/chromium/weblayer/WebLayer.java +++ b/weblayer/public/java/org/chromium/weblayer/WebLayer.java
@@ -14,6 +14,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.StrictMode; +import android.os.SystemClock; import android.util.AndroidRuntimeException; import android.util.Log; import android.webkit.ValueCallback; @@ -71,6 +72,11 @@ @NonNull private final IWebLayer mImpl; + // Times used for logging UMA histograms. + private static long sClassLoaderCreationTime; + private static long sContextCreationTime; + private static long sWebLayerLoaderCreationTime; + /** The result of calling {@link #initializeWebViewCompatibilityMode}. */ public enum WebViewCompatibilityResult { /** Compatibility mode has been successfully set up. */ @@ -274,13 +280,16 @@ mContext = mContext.createAttributionContext(context.getAttributionTag()); } try { - Class factoryClass = getOrCreateRemoteClassLoader(mContext).loadClass( - "org.chromium.weblayer_private.WebLayerFactoryImpl"); + ClassLoader classLoader = getOrCreateRemoteClassLoader(mContext); + long start = SystemClock.elapsedRealtime(); + Class factoryClass = + classLoader.loadClass("org.chromium.weblayer_private.WebLayerFactoryImpl"); mFactory = IWebLayerFactory.Stub.asInterface( (IBinder) factoryClass .getMethod("create", String.class, int.class, int.class) .invoke(null, WebLayerClientVersionConstants.PRODUCT_VERSION, WebLayerClientVersionConstants.PRODUCT_MAJOR_VERSION, -1)); + sWebLayerLoaderCreationTime = SystemClock.elapsedRealtime() - start; available = mFactory.isClientSupported(); majorVersion = mFactory.getImplementationMajorVersion(); version = mFactory.getImplementationVersion(); @@ -598,6 +607,7 @@ return sRemoteClassLoader; } + long start = SystemClock.elapsedRealtime(); // Child processes do not need WebView compatibility since there is no chance // WebView will run in the same process. if (sDisableWebViewCompatibilityMode) { @@ -617,6 +627,7 @@ } else { sRemoteClassLoader = WebViewCompatibilityHelper.initialize(appContext); } + sClassLoaderCreationTime = SystemClock.elapsedRealtime() - start; return sRemoteClassLoader; } @@ -628,6 +639,7 @@ if (sRemoteContext != null) { return sRemoteContext; } + long start = SystemClock.elapsedRealtime(); Class<?> webViewFactoryClass = Class.forName("android.webkit.WebViewFactory"); String implPackageName = getImplPackageName(appContext); sAppContext = appContext; @@ -643,6 +655,7 @@ (String) webViewFactoryClass.getMethod("getWebViewPackageName").invoke(null); sRemoteContext = createRemoteContextFromPackageName(appContext, implPackageName); } + sContextCreationTime = SystemClock.elapsedRealtime() - start; return sRemoteContext; } @@ -721,6 +734,21 @@ // The id is part of the public library to avoid conflicts. return R.id.weblayer_media_session_notification; } + + @Override + public long getClassLoaderCreationTime() { + return sClassLoaderCreationTime; + } + + @Override + public long getContextCreationTime() { + return sContextCreationTime; + } + + @Override + public long getWebLayerLoaderCreationTime() { + return sWebLayerLoaderCreationTime; + } } @VerifiesOnO