diff --git a/DEPS b/DEPS index b7a3654b..4d5ccc1a 100644 --- a/DEPS +++ b/DEPS
@@ -129,7 +129,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'c8098329300b4c6421c541d16442ba13dad57c33', + 'skia_revision': 'fde841de44a63701b0a4396da35893f348559ce9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -141,11 +141,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '7d64c4863dd9063d68439b7dda945b3c2db4810f', + 'angle_revision': 'e0da9cefcd5adebee2de8857c577bb86a882922a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '7288151c792f157af1360cb67784420fbc7df748', + 'swiftshader_revision': '84c3a94e14502b0b54a644dc0e661071b7347224', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -252,7 +252,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. - 'spv_tools_revision': '3335c61147d76b9282aaee1a499bb40ca71905ac', + 'spv_tools_revision': '3aad3e9228b36562252a7f6ac17c50de868c67bb', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -805,7 +805,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '00d82c6be096d29280151b3fc40b1ded336f00e2', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '4375b4659b71ed479fb98f9f63d1a3093e0f10ea', 'condition': 'checkout_linux', }, @@ -830,7 +830,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4b79c3870c5135c39c75822919eb76ac2d5633f4', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '7e7523be4e21b0841ae815ef37521a5476f68549', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1183,7 +1183,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '82e3e617c15c89f34513fa76bc99cff93f3321d0', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '1e504391033b86e26e63412f1773137a2a8a7bb7', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', @@ -1354,7 +1354,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '3f6583d3fee4ab71866ade794504a20eb6f63f88', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '7eb4248b02ecfa4f3b9f2acb7932aff2a5b08911', + Var('webrtc_git') + '/src.git' + '@' + '5111c338ca5704459bb2962a8d32c30ec4831913', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1395,7 +1395,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c4a9d8a46b85fbe97141415c6b0cee0506d65c34', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3ba785c802b9c256e7ffc0d9b4f2de6b90dc71c0', 'condition': 'checkout_src_internal', },
diff --git a/WATCHLISTS b/WATCHLISTS index dce208c..f7fc05b 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1833,6 +1833,7 @@ 'dougt+watch@chromium.org', 'dtseng+watch@chromium.org', 'je_julie.kim@chromium.org', + 'kbabbitt@microsoft.com', 'nektar+watch@chromium.org', 'yuzo+watch@chromium.org'], 'add_to_homescreen': ['dominickn+watch-a2hs@chromium.org', @@ -1931,6 +1932,7 @@ 'dmazzoni@chromium.org', 'dougt+watch@chromium.org', 'je_julie.kim@chromium.org', + 'kbabbitt@microsoft.com', 'nektar@chromium.org'], 'blink_animation': ['alexis.menard@intel.com', 'blink-reviews-animation@chromium.org',
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc index 74d56657..d694f10 100644 --- a/ash/app_list/views/app_list_folder_view.cc +++ b/ash/app_list/views/app_list_folder_view.cc
@@ -797,11 +797,19 @@ } void AppListFolderView::CloseFolderPage() { - GiveBackFocusToSearchBox(); if (items_grid_view()->dragging()) items_grid_view()->EndDrag(true); + // When a folder is closed focus |activated_folder_item_view_| but only show + // the selection highlight if there is already one showing. + const bool should_show_focus_ring_on_hide = + items_grid_view()->has_selected_view(); items_grid_view()->ClearAnySelectedView(); container_view_->ShowApps(folder_item_); + if (should_show_focus_ring_on_hide) { + GetActivatedFolderItemView()->RequestFocus(); + } else { + GetActivatedFolderItemView()->SilentlyRequestFocus(); + } } bool AppListFolderView::IsOEMFolder() const {
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc index 885baa9d..80d9005 100644 --- a/ash/app_list/views/app_list_item_view.cc +++ b/ash/app_list/views/app_list_item_view.cc
@@ -14,6 +14,7 @@ #include "ash/app_list/views/apps_grid_view.h" #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/app_list/app_list_switches.h" +#include "base/auto_reset.h" #include "base/bind.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" @@ -396,6 +397,12 @@ SetUIState(UI_STATE_NORMAL); } +void AppListItemView::SilentlyRequestFocus() { + DCHECK(!focus_silently_); + base::AutoReset<bool> auto_reset(&focus_silently_, true); + RequestFocus(); +} + void AppListItemView::SetItemName(const base::string16& display_name, const base::string16& full_name) { const base::string16 folder_name_placeholder = @@ -641,6 +648,8 @@ } void AppListItemView::OnFocus() { + if (focus_silently_) + return; apps_grid_view_->SetSelectedView(this); }
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h index ef9b7df..7ae0281 100644 --- a/ash/app_list/views/app_list_item_view.h +++ b/ash/app_list/views/app_list_item_view.h
@@ -66,6 +66,9 @@ void SetAsAttemptedFolderTarget(bool is_target_folder); + // Sets focus without a11y announcements or focus ring. + void SilentlyRequestFocus(); + AppListItem* item() const { return item_weak_; } views::Label* title() { return title_; } @@ -237,6 +240,10 @@ // True if the drag host proxy is crated for mouse dragging. bool mouse_drag_proxy_created_ = false; + // Whether AppsGridView should not be notified of a focus event, triggering + // A11y alerts and a focus ring. + bool focus_silently_ = false; + // The animation that runs when dragged view enters or exits this view. std::unique_ptr<gfx::SlideAnimation> dragged_view_hover_animation_;
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc index 05d2da1..24d9588 100644 --- a/ash/app_list/views/app_list_view.cc +++ b/ash/app_list/views/app_list_view.cc
@@ -192,10 +192,13 @@ ~StateAnimationMetricsReporter() override = default; - void Start(bool is_in_tablet_mode) { - DCHECK(!started_); - is_in_tablet_mode_ = is_in_tablet_mode; + void SetTargetState(ash::mojom::AppListViewState target_state) { + target_state_ = target_state; + } + + void Start() { #if defined(DCHECK) + DCHECK(!started_); started_ = ui::ScopedAnimationDurationScaleMode::duration_scale_mode() != ui::ScopedAnimationDurationScaleMode::ZERO_DURATION; #endif @@ -203,13 +206,36 @@ void Report(int value) override { UMA_HISTOGRAM_PERCENTAGE("Apps.StateTransition.AnimationSmoothness", value); - if (is_in_tablet_mode_) { - UMA_HISTOGRAM_PERCENTAGE( - "Apps.StateTransition.AnimationSmoothness.TabletMode", value); - } else { - UMA_HISTOGRAM_PERCENTAGE( - "Apps.StateTransition.AnimationSmoothness.ClamshellMode", value); + switch (*target_state_) { + case ash::mojom::AppListViewState::kClosed: + UMA_HISTOGRAM_PERCENTAGE( + "Apps.StateTransition.AnimationSmoothness.Close.ClamshellMode", + value); + break; + case ash::mojom::AppListViewState::kPeeking: + UMA_HISTOGRAM_PERCENTAGE( + "Apps.StateTransition.AnimationSmoothness.Peeking.ClamshellMode", + value); + break; + case ash::mojom::AppListViewState::kHalf: + UMA_HISTOGRAM_PERCENTAGE( + "Apps.StateTransition.AnimationSmoothness.Half.ClamshellMode", + value); + break; + case ash::mojom::AppListViewState::kFullscreenAllApps: + UMA_HISTOGRAM_PERCENTAGE( + "Apps.StateTransition.AnimationSmoothness.FullscreenAllApps." + "ClamshellMode", + value); + break; + case ash::mojom::AppListViewState::kFullscreenSearch: + UMA_HISTOGRAM_PERCENTAGE( + "Apps.StateTransition.AnimationSmoothness.FullscreenSearch." + "ClamshellMode", + value); + break; } + target_state_.reset(); view_->OnStateTransitionAnimationCompleted(); #if defined(DCHECK) started_ = false; @@ -220,7 +246,7 @@ #if defined(DCHECK) bool started_ = false; #endif - bool is_in_tablet_mode_ = false; + base::Optional<ash::mojom::AppListViewState> target_state_; AppListView* view_; DISALLOW_COPY_AND_ASSIGN(StateAnimationMetricsReporter); @@ -1370,6 +1396,7 @@ settings.SetTweenType(gfx::Tween::EASE_OUT); settings.SetPreemptionStrategy( ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + state_animation_metrics_reporter_->SetTargetState(target_state); settings.SetAnimationMetricsReporter(state_animation_metrics_reporter_.get()); settings.AddObserver(transition_animation_observer_.get()); @@ -1392,6 +1419,8 @@ animation_duration /= 2; } + state_animation_metrics_reporter_->SetTargetState( + ash::mojom::AppListViewState::kClosed); SetState(ash::mojom::AppListViewState::kClosed); app_list_main_view_->contents_view()->FadeOutOnClose(animation_duration); } @@ -1606,7 +1635,7 @@ } ui::AnimationMetricsReporter* AppListView::GetStateTransitionMetricsReporter() { - state_animation_metrics_reporter_->Start(is_tablet_mode_); + state_animation_metrics_reporter_->Start(); return state_animation_metrics_reporter_.get(); }
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc index 7827010..2b8fb64c 100644 --- a/ash/app_list/views/app_list_view_unittest.cc +++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -305,6 +305,8 @@ void Show() { view_->ShowWhenReady(); } + AppsGridViewTestApi* test_api() { return test_api_.get(); } + void SimulateKeyPress(ui::KeyboardCode key_code, bool shift_down, bool ctrl_down = false) { @@ -792,7 +794,6 @@ EXPECT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); std::vector<views::View*> forward_view_list; - forward_view_list.push_back(search_box_view()->search_box()); const views::ViewModelT<AppListItemView>* view_model = app_list_folder_view()->items_grid_view()->view_model(); for (int i = 0; i < view_model->view_size(); ++i) @@ -800,6 +801,7 @@ forward_view_list.push_back( app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest()); forward_view_list.push_back(search_box_view()->search_box()); + forward_view_list.push_back(view_model->view_at(0)); std::vector<views::View*> backward_view_list = forward_view_list; std::reverse(backward_view_list.begin(), backward_view_list.end()); @@ -937,7 +939,6 @@ EXPECT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); std::vector<views::View*> forward_view_list; - forward_view_list.push_back(search_box_view()->search_box()); const views::ViewModelT<AppListItemView>* view_model = app_list_folder_view()->items_grid_view()->view_model(); for (size_t i = 0; i < AppListConfig::instance().max_folder_items_per_page(); @@ -947,11 +948,13 @@ forward_view_list.push_back( app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest()); forward_view_list.push_back(search_box_view()->search_box()); + forward_view_list.push_back(view_model->view_at(0)); // Test traversal triggered by down. TestFocusTraversal(forward_view_list, ui::VKEY_DOWN, false); std::vector<views::View*> backward_view_list; + backward_view_list.push_back(view_model->view_at(0)); backward_view_list.push_back(search_box_view()->search_box()); backward_view_list.push_back( app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest()); @@ -981,7 +984,6 @@ 1, false /* animate */); std::vector<views::View*> forward_view_list; - forward_view_list.push_back(search_box_view()->search_box()); const views::ViewModelT<AppListItemView>* view_model = app_list_folder_view()->items_grid_view()->view_model(); for (int i = AppListConfig::instance().max_folder_items_per_page(); @@ -992,11 +994,15 @@ forward_view_list.push_back( app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest()); forward_view_list.push_back(search_box_view()->search_box()); + forward_view_list.push_back(view_model->view_at( + AppListConfig::instance().max_folder_items_per_page())); // Test traversal triggered by down. TestFocusTraversal(forward_view_list, ui::VKEY_DOWN, false); std::vector<views::View*> backward_view_list; + backward_view_list.push_back(view_model->view_at( + AppListConfig::instance().max_folder_items_per_page())); backward_view_list.push_back(search_box_view()->search_box()); backward_view_list.push_back( app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest()); @@ -1011,7 +1017,8 @@ TestFocusTraversal(backward_view_list, ui::VKEY_UP, false); } -// Tests that the focus is set back onto search box after state transition. +// Tests that the focus is set back onto search box after all state transitions +// besides those going to/from an activated folder. TEST_F(AppListViewFocusTest, FocusResetAfterStateTransition) { Show(); @@ -1021,6 +1028,7 @@ const int kTileResults = 3; const int kListResults = 2; SetUpSearchResults(kTileResults, kListResults, true); + EXPECT_EQ(app_list_view()->app_list_state(), ash::mojom::AppListViewState::kHalf); EXPECT_EQ(search_box_view()->search_box(), focused_view()); @@ -1028,6 +1036,7 @@ // Move focus to the first search result, then transition to PEEKING state. SimulateKeyPress(ui::VKEY_TAB, false); SimulateKeyPress(ui::VKEY_TAB, false); + SetAppListState(ash::mojom::AppListViewState::kPeeking); EXPECT_EQ(app_list_view()->app_list_state(), ash::mojom::AppListViewState::kPeeking); @@ -1041,15 +1050,25 @@ ash::mojom::AppListViewState::kFullscreenAllApps); EXPECT_EQ(search_box_view()->search_box(), focused_view()); - // Move focus to first suggestion app, then open the folder. + // Move focus to the folder and open it. folder_item_view()->RequestFocus(); SimulateKeyPress(ui::VKEY_RETURN, false); - EXPECT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); - EXPECT_EQ(search_box_view()->search_box(), focused_view()); - // Move focus to the first app, then transition to PEEKING state. - SimulateKeyPress(ui::VKEY_TAB, false); + // Test that the first item in the folder is focused. + EXPECT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); + EXPECT_EQ(app_list_folder_view()->items_grid_view()->view_model()->view_at(0), + focused_view()); + + // Close the folder. + SimulateKeyPress(ui::VKEY_ESCAPE, false); + + // Test that focus is on the previously activated folder item + EXPECT_EQ(folder_item_view(), focused_view()); + + // Transition to PEEKING state. SetAppListState(ash::mojom::AppListViewState::kPeeking); + + // Test that the searchbox is focused. EXPECT_EQ(app_list_view()->app_list_state(), ash::mojom::AppListViewState::kPeeking); EXPECT_EQ(search_box_view()->search_box(), focused_view()); @@ -1435,6 +1454,90 @@ EXPECT_FALSE(contents_view()->GetAppsContainerView()->IsInFolderView()); } +// Tests that the selection highlight follows the page change. +TEST_F(AppListViewFocusTest, SelectionHighlightFollowsChangingPage) { + // Move the focus to the first app in the grid. + Show(); + SetAppListState(ash::mojom::AppListViewState::kFullscreenAllApps); + const views::ViewModelT<AppListItemView>* view_model = + apps_grid_view()->view_model(); + AppListItemView* first_item_view = view_model->view_at(0); + first_item_view->RequestFocus(); + ASSERT_EQ(0, apps_grid_view()->pagination_model()->selected_page()); + + // Select the second page. + apps_grid_view()->pagination_model()->SelectPage(1, false); + + // Test that focus followed to the next page. + EXPECT_EQ(view_model->view_at(test_api()->TilesPerPage(0)), + apps_grid_view()->GetSelectedView()); + + // Select the first page. + apps_grid_view()->pagination_model()->SelectPage(0, false); + + // Test that focus followed. + EXPECT_EQ(view_model->view_at(test_api()->TilesPerPage(0) - 1), + apps_grid_view()->GetSelectedView()); +} + +// Tests that the selection highlight only shows up inside a folder if the +// selection highlight existed on the folder before it opened. +TEST_F(AppListViewFocusTest, SelectionDoesNotShowInFolderIfNotSelected) { + // Open a folder without making the view selected. + Show(); + SetAppListState(ash::mojom::AppListViewState::kFullscreenAllApps); + const gfx::Point folder_item_view_bounds = + folder_item_view()->bounds().CenterPoint(); + ui::GestureEvent tap(folder_item_view_bounds.x(), folder_item_view_bounds.y(), + 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + folder_item_view()->OnGestureEvent(&tap); + ASSERT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); + + // Test that there is no selected view in the folders grid view, but the first + // item is focused. + AppsGridView* items_grid_view = app_list_folder_view()->items_grid_view(); + EXPECT_FALSE(items_grid_view->has_selected_view()); + EXPECT_EQ(items_grid_view->view_model()->view_at(0), focused_view()); + + // Hide the folder, expect that the folder is not selected, but is focused. + app_list_view()->AcceleratorPressed( + ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); + EXPECT_FALSE(apps_grid_view()->has_selected_view()); + EXPECT_EQ(folder_item_view(), focused_view()); +} + +// Tests that the selection highlight only shows on the activated folder if it +// existed within the folder. +TEST_F(AppListViewFocusTest, SelectionGoesIntoFolderIfSelected) { + // Open a folder without making the view selected. + Show(); + SetAppListState(ash::mojom::AppListViewState::kFullscreenAllApps); + + folder_item_view()->RequestFocus(); + ASSERT_TRUE(apps_grid_view()->IsSelectedView(folder_item_view())); + + // Show the folder. + const gfx::Point folder_item_view_bounds = + folder_item_view()->bounds().CenterPoint(); + ui::GestureEvent tap(folder_item_view_bounds.x(), folder_item_view_bounds.y(), + 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + folder_item_view()->OnGestureEvent(&tap); + ASSERT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView()); + + // Test that the focused view is also selected. + AppsGridView* items_grid_view = app_list_folder_view()->items_grid_view(); + EXPECT_EQ(items_grid_view->GetSelectedView(), focused_view()); + EXPECT_EQ(items_grid_view->view_model()->view_at(0), focused_view()); + + // Hide the folder, expect that the folder is selected and focused. + app_list_view()->AcceleratorPressed( + ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); + EXPECT_TRUE(apps_grid_view()->IsSelectedView(folder_item_view())); + EXPECT_EQ(folder_item_view(), focused_view()); +} + // Tests that opening the app list opens in peeking mode by default. TEST_F(AppListViewTest, ShowPeekingByDefault) { Initialize(0, false, false);
diff --git a/ash/app_list/views/apps_container_view.cc b/ash/app_list/views/apps_container_view.cc index 6b544f03..a7b97f2 100644 --- a/ash/app_list/views/apps_container_view.cc +++ b/ash/app_list/views/apps_container_view.cc
@@ -103,14 +103,20 @@ SetShowState(SHOW_ACTIVE_FOLDER, false); - // Avoid announcing search box focus since it is overlapped with opening - // folder alert. - auto* search_box = contents_view_->GetSearchBoxView()->search_box(); - search_box->GetViewAccessibility().OverrideIsIgnored(true); - + // If there is no selected view in the root grid when a folder is opened, + // silently focus the first item in the folder to avoid showing the selection + // highlight or announcing to A11y, but still ensuring the arrow keys navigate + // from the first item. + AppListItemView* first_item_view_in_folder_grid = + app_list_folder_view_->items_grid_view()->view_model()->view_at(0); + if (!apps_grid_view()->has_selected_view()) { + first_item_view_in_folder_grid->SilentlyRequestFocus(); + } else { + first_item_view_in_folder_grid->RequestFocus(); + } // Disable all the items behind the folder so that they will not be reached // during focus traversal. - search_box->RequestFocus(); + DisableFocusForShowingActiveFolder(true); }
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc index f945f37..5a32203 100644 --- a/ash/app_list/views/apps_grid_view.cc +++ b/ash/app_list/views/apps_grid_view.cc
@@ -2522,7 +2522,18 @@ Layout(); MaybeStartPageFlipTimer(last_drag_point_); } else { - ClearSelectedView(selected_view_); + // If |selected_view_| is no longer on the page, select the first item in + // the page relative to the page swap in order to keep keyboard focus + // movement predictable. + if (selected_view_ && GetIndexOfView(selected_view_).page != new_selected) { + GetViewAtIndex( + GridIndex(new_selected, (old_selected < new_selected) + ? 0 + : (GetItemsNumOfPage(new_selected) - 1))) + ->RequestFocus(); + } else { + ClearSelectedView(selected_view_); + } Layout(); } }
diff --git a/ash/system/message_center/unified_message_center_view.cc b/ash/system/message_center/unified_message_center_view.cc index a7d7834..72a290a 100644 --- a/ash/system/message_center/unified_message_center_view.cc +++ b/ash/system/message_center/unified_message_center_view.cc
@@ -193,8 +193,12 @@ StackingNotificationCounterView::~StackingNotificationCounterView() = default; -void StackingNotificationCounterView::SetCount(int total_notification_count, +bool StackingNotificationCounterView::SetCount(int total_notification_count, int stacked_notification_count) { + if (total_notification_count == total_notification_count_ && + stacked_notification_count == stacked_notification_count_) + return false; + total_notification_count_ = total_notification_count; stacked_notification_count_ = stacked_notification_count; @@ -213,6 +217,7 @@ } SchedulePaint(); + return true; } void StackingNotificationCounterView::OnPaint(gfx::Canvas* canvas) { @@ -357,10 +362,10 @@ model_->set_notification_target_mode( UnifiedSystemTrayModel::NotificationTargetMode::LAST_POSITION); - const bool was_visible = stacking_counter_->visible(); - stacking_counter_->SetCount(message_list_view_->GetTotalNotificationCount(), - GetStackedNotificationCount()); - if (was_visible != stacking_counter_->visible()) { + bool was_count_updated = stacking_counter_->SetCount( + message_list_view_->GetTotalNotificationCount(), + GetStackedNotificationCount()); + if (was_count_updated) { const int previous_y = scroller_->y(); Layout(); // Adjust scroll position when counter visibility is changed so that
diff --git a/ash/system/message_center/unified_message_center_view.h b/ash/system/message_center/unified_message_center_view.h index 5ebafe01..6de6186 100644 --- a/ash/system/message_center/unified_message_center_view.h +++ b/ash/system/message_center/unified_message_center_view.h
@@ -32,7 +32,9 @@ explicit StackingNotificationCounterView(views::ButtonListener* listener); ~StackingNotificationCounterView() override; - void SetCount(int total_notification_count, int stacked_notification_count); + // Sets the number of total notifications and hidden notifications. Returns + // true if the count was updated from the previous SetCount() call. + bool SetCount(int total_notification_count, int stacked_notification_count); // views::View: void OnPaint(gfx::Canvas* canvas) override;
diff --git a/ash/system/message_center/unified_message_center_view_unittest.cc b/ash/system/message_center/unified_message_center_view_unittest.cc index 9be21ad..fe0d5f97 100644 --- a/ash/system/message_center/unified_message_center_view_unittest.cc +++ b/ash/system/message_center/unified_message_center_view_unittest.cc
@@ -581,6 +581,36 @@ EXPECT_FALSE(GetStackingCounter()->visible()); } +TEST_F(UnifiedMessageCenterViewTest, + RedesignedStackingCounter_LabelRelaidOutOnScroll) { + EnableNotificationStackingBarRedesign(); + + // Open the message center at the top of the notification list so the stacking + // bar is hidden by default. + std::string id = AddNotification(); + for (size_t i = 0; i < 20; ++i) + AddNotification(); + model()->SetTargetNotification(id); + + CreateMessageCenterView(); + EXPECT_FALSE(GetStackingCounterLabel()->visible()); + + // Scroll past one notification to show the stacking bar. + int scroll_amount = GetMessageViewVisibleBounds(0).height() + 1; + GetScroller()->ScrollToPosition(GetScrollBar(), scroll_amount); + message_center_view()->OnMessageCenterScrolled(); + EXPECT_TRUE(GetStackingCounterLabel()->visible()); + int label_width = GetStackingCounterLabel()->bounds().width(); + EXPECT_GT(label_width, 0); + + // Scroll past 10 more notifications so the label width must be expanded to + // contain longer 2-digit label. + scroll_amount = (GetMessageViewVisibleBounds(0).height() * 11) + 1; + GetScroller()->ScrollToPosition(GetScrollBar(), scroll_amount); + message_center_view()->OnMessageCenterScrolled(); + EXPECT_GT(GetStackingCounterLabel()->bounds().width(), label_width); +} + TEST_F(UnifiedMessageCenterViewTest, RectBelowScroll) { for (size_t i = 0; i < 6; ++i) AddNotification();
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc index afcf04d..ae58f82 100644 --- a/base/message_loop/message_loop.cc +++ b/base/message_loop/message_loop.cc
@@ -56,10 +56,20 @@ MessageLoop::~MessageLoop() { // Clean up any unprocessed tasks, but take care: deleting a task could - // result in the addition of more tasks (e.g., via DeleteSoon). This is taken - // care by the queue as it will prevent further tasks from being posted to its - // associated TaskRunner instances. - default_task_queue_->ShutdownTaskQueue(); + // result in the addition of more tasks (e.g., via DeleteSoon). We set a + // limit on the number of times we will allow a deleted task to generate more + // tasks. Normally, we should only pass through this loop once or twice. If + // we end up hitting the loop limit, then it is probably due to one task that + // is being stubborn. Inspect the queues to see who is left. + bool tasks_remain; + for (int i = 0; i < 100; ++i) { + backend_->DeletePendingTasks(); + // If we end up with empty queues, then break out of the loop. + tasks_remain = backend_->HasTasks(); + if (!tasks_remain) + break; + } + DCHECK(!tasks_remain); // If |pump_| is non-null, this message loop has been bound and should be the // current one on this thread. Otherwise, this loop is being destructed before @@ -131,20 +141,24 @@ // implementation detail. http://crbug.com/703346 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); - sequence_manager_->AddTaskObserver(task_observer); + backend_->AddTaskObserver(task_observer); } void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_); - sequence_manager_->RemoveTaskObserver(task_observer); + backend_->RemoveTaskObserver(task_observer); } bool MessageLoop::IsBoundToCurrentThread() const { - return sequence_manager_->IsBoundToCurrentThread(); + return backend_->IsBoundToCurrentThread(); } bool MessageLoop::IsIdleForTesting() { - return sequence_manager_->IsIdleForTesting(); + return backend_->IsIdleForTesting(); +} + +MessageLoopBase* MessageLoop::GetMessageLoopBase() { + return backend_.get(); } //------------------------------------------------------------------------------ @@ -161,9 +175,8 @@ } MessageLoop::MessageLoop(Type type, std::unique_ptr<MessagePump> custom_pump) - : sequence_manager_( - sequence_manager::internal::SequenceManagerImpl::CreateUnbound( - sequence_manager::SequenceManager::Settings{type})), + : backend_(sequence_manager::internal::SequenceManagerImpl::CreateUnbound( + sequence_manager::SequenceManager::Settings{type})), default_task_queue_(CreateDefaultTaskQueue()), type_(type), custom_pump_(std::move(custom_pump)) { @@ -173,9 +186,13 @@ scoped_refptr<sequence_manager::TaskQueue> MessageLoop::CreateDefaultTaskQueue() { - auto default_task_queue = sequence_manager_->CreateTaskQueue( - sequence_manager::TaskQueue::Spec("default_tq")); - sequence_manager_->SetTaskRunner(default_task_queue->task_runner()); + sequence_manager::internal::SequenceManagerImpl* manager = + static_cast<sequence_manager::internal::SequenceManagerImpl*>( + backend_.get()); + scoped_refptr<sequence_manager::TaskQueue> default_task_queue = + manager->CreateTaskQueueWithType<sequence_manager::TaskQueue>( + sequence_manager::TaskQueue::Spec("default_tq")); + manager->SetTaskRunner(default_task_queue->task_runner()); return default_task_queue; } @@ -191,7 +208,7 @@ DCHECK(!MessageLoopCurrent::IsSet()) << "should only have one message loop per thread"; - sequence_manager_->BindToCurrentThread(std::move(pump)); + backend_->BindToCurrentThread(std::move(pump)); } std::unique_ptr<MessagePump> MessageLoop::CreateMessagePump() { @@ -203,21 +220,21 @@ } void MessageLoop::SetTimerSlack(TimerSlack timer_slack) { - sequence_manager_->SetTimerSlack(timer_slack); + backend_->SetTimerSlack(timer_slack); } std::string MessageLoop::GetThreadName() const { - return sequence_manager_->GetThreadName(); + return backend_->GetThreadName(); } scoped_refptr<SingleThreadTaskRunner> MessageLoop::task_runner() const { - return sequence_manager_->GetTaskRunner(); + return backend_->GetTaskRunner(); } void MessageLoop::SetTaskRunner( scoped_refptr<SingleThreadTaskRunner> task_runner) { DCHECK(task_runner); - sequence_manager_->SetTaskRunner(task_runner); + backend_->SetTaskRunner(task_runner); } #if !defined(OS_NACL) @@ -235,7 +252,7 @@ #if defined(OS_IOS) void MessageLoopForUI::Attach() { - sequence_manager_->AttachToMessagePump(); + backend_->AttachToMessagePump(); } #endif // defined(OS_IOS)
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h index ddfed50..46782b4 100644 --- a/base/message_loop/message_loop.h +++ b/base/message_loop/message_loop.h
@@ -34,7 +34,8 @@ class TaskQueue; namespace internal { class SequenceManagerImpl; -} // namespace internal +class ThreadControllerImpl; +} } // namespace sequence_manager // A MessageLoop is used to process events for a particular thread. There is @@ -80,8 +81,11 @@ // Please be SURE your task is reentrant (nestable) and all global variables // are stable and accessible before calling SetNestableTasksAllowed(true). -class BASE_EXPORT MessageLoop { +class BASE_EXPORT MessageLoopBase { public: + MessageLoopBase() = default; + virtual ~MessageLoopBase() = default; + // A MessageLoop has a particular type, which indicates the set of // asynchronous events it may process in addition to tasks and timers. // @@ -105,7 +109,7 @@ // TYPE_CUSTOM // MessagePump was supplied to constructor. // - enum class Type { + enum Type { TYPE_DEFAULT, TYPE_UI, TYPE_CUSTOM, @@ -115,6 +119,106 @@ #endif // defined(OS_ANDROID) }; + // Returns true if this loop is |type|. This allows subclasses (especially + // those in tests) to specialize how they are identified. + virtual bool IsType(Type type) const = 0; + + // Returns the name of the thread this message loop is bound to. This function + // is only valid when this message loop is running, BindToCurrentThread has + // already been called and has an "happens-before" relationship with this call + // (this relationship is obtained implicitly by the MessageLoop's task posting + // system unless calling this very early). + virtual std::string GetThreadName() const = 0; + + using DestructionObserver = MessageLoopCurrent::DestructionObserver; + + // Add a DestructionObserver, which will start receiving notifications + // immediately. + virtual void AddDestructionObserver( + DestructionObserver* destruction_observer) = 0; + + // Remove a DestructionObserver. It is safe to call this method while a + // DestructionObserver is receiving a notification callback. + virtual void RemoveDestructionObserver( + DestructionObserver* destruction_observer) = 0; + + // TODO(altimin,yutak): Replace with base::TaskObserver. + using TaskObserver = MessageLoopCurrent::TaskObserver; + + // These functions can only be called on the same thread that |this| is + // running on. + // These functions must not be called from a TaskObserver callback. + virtual void AddTaskObserver(TaskObserver* task_observer) = 0; + virtual void RemoveTaskObserver(TaskObserver* task_observer) = 0; + + // When this functionality is enabled, the queue time will be recorded for + // posted tasks. + virtual void SetAddQueueTimeToTasks(bool enable) = 0; + + // Returns true if this is the active MessageLoop for the current thread. + virtual bool IsBoundToCurrentThread() const = 0; + + // Returns true if the message loop is idle (ignoring delayed tasks). This is + // the same condition which triggers DoWork() to return false: i.e. + // out of tasks which can be processed at the current run-level -- there might + // be deferred non-nestable tasks remaining if currently in a nested run + // level. + virtual bool IsIdleForTesting() = 0; + + // Returns the MessagePump owned by this MessageLoop if any. + virtual MessagePump* GetMessagePump() const = 0; + + // Sets a new TaskRunner for this message loop. If the message loop was + // already bound, this must be called on the thread to which it is bound. + // TODO(alexclarke): Remove this as part of https://crbug.com/825327. + virtual void SetTaskRunner( + scoped_refptr<SingleThreadTaskRunner> task_runner) = 0; + + // Gets the TaskRunner associated with this message loop. + // TODO(alexclarke): Remove this as part of https://crbug.com/825327. + virtual scoped_refptr<SingleThreadTaskRunner> GetTaskRunner() = 0; + + // Binds the MessageLoop to the current thread using |pump|. + virtual void BindToCurrentThread(std::unique_ptr<MessagePump> pump) = 0; + + // Returns true if the MessageLoop retains any tasks inside it. + virtual bool HasTasks() = 0; + + // Deletes all tasks associated with this MessageLoop. Note that the tasks + // can post other tasks when destructed. + virtual void DeletePendingTasks() = 0; + + protected: + friend class MessageLoop; + friend class MessageLoopForUI; + friend class MessageLoopCurrent; + friend class MessageLoopCurrentForIO; + friend class MessageLoopCurrentForUI; + friend class Thread; + friend class sequence_manager::internal::ThreadControllerImpl; + + // Explicitly allow or disallow task execution. Task execution is disallowed + // implicitly when we enter a nested runloop. + virtual void SetTaskExecutionAllowed(bool allowed) = 0; + + // Whether task execution is allowed at the moment. + virtual bool IsTaskExecutionAllowed() const = 0; + +#if defined(OS_IOS) + virtual void AttachToMessagePump() = 0; +#endif + + virtual Type GetType() const = 0; + + // Set the timer slack for this message loop. + // TODO(alexclarke): Remove this as part of https://crbug.com/891670. + virtual void SetTimerSlack(TimerSlack timer_slack) = 0; +}; + +class BASE_EXPORT MessageLoop { + public: + // For migration convenience we define the Type enum. + using Type = MessageLoopBase::Type; static constexpr Type TYPE_DEFAULT = Type::TYPE_DEFAULT; static constexpr Type TYPE_UI = Type::TYPE_UI; static constexpr Type TYPE_CUSTOM = Type::TYPE_CUSTOM; @@ -125,7 +229,7 @@ // Normally, it is not necessary to instantiate a MessageLoop. Instead, it // is typical to make use of the current thread's MessageLoop instance. - explicit MessageLoop(Type type = Type::TYPE_DEFAULT); + explicit MessageLoop(Type type = TYPE_DEFAULT); // Creates a TYPE_CUSTOM MessageLoop with the supplied MessagePump, which must // be non-NULL. explicit MessageLoop(std::unique_ptr<MessagePump> custom_pump); @@ -186,6 +290,8 @@ // TODO(alexclarke): Make this const when MessageLoopImpl goes away. bool IsIdleForTesting(); + MessageLoopBase* GetMessageLoopBase(); + //---------------------------------------------------------------------------- protected: using MessagePumpFactoryCallback = @@ -202,16 +308,17 @@ // Configure various members and bind this message loop to the current thread. void BindToCurrentThread(); - // A raw pointer to the MessagePump handed-off to |sequence_manager_|. - // Valid for the lifetime of |sequence_manager_|. + // A raw pointer to the MessagePump handed-off to |backend_|. + // Valid for the lifetime of |backend_|. MessagePump* pump_ = nullptr; - // TODO(crbug.com/891670): We shouldn't publicly expose all of - // SequenceManagerImpl. - const std::unique_ptr<sequence_manager::internal::SequenceManagerImpl> - sequence_manager_; - // SequenceManager requires an explicit initialisation of the default task - // queue. + // The SequenceManager-based implementation of the MessageLoop. + // TODO(crbug.com/891670): MessageLoopBase is now always a + // SequenceManagerImpl, this can be simplified but we also shouldn't publicly + // expose all of SequenceManagerImpl either. + const std::unique_ptr<MessageLoopBase> backend_; + // SequenceManager-based backend requires an explicit initialisation of the + // default task queue. const scoped_refptr<sequence_manager::TaskQueue> default_task_queue_; private: @@ -238,11 +345,6 @@ std::unique_ptr<MessagePump> CreateMessagePump(); - sequence_manager::internal::SequenceManagerImpl* GetSequenceManagerImpl() - const { - return sequence_manager_.get(); - } - const Type type_; // If set this will be returned by the next call to CreateMessagePump().
diff --git a/base/message_loop/message_loop_current.cc b/base/message_loop/message_loop_current.cc index 2e2adfa..7dcab95 100644 --- a/base/message_loop/message_loop_current.cc +++ b/base/message_loop/message_loop_current.cc
@@ -19,14 +19,13 @@ // MessageLoopCurrent // static -sequence_manager::internal::SequenceManagerImpl* -MessageLoopCurrent::GetCurrentSequenceManagerImpl() { +MessageLoopBase* MessageLoopCurrent::GetCurrentMessageLoopBase() { return sequence_manager::internal::SequenceManagerImpl::GetCurrent(); } // static MessageLoopCurrent MessageLoopCurrent::Get() { - return MessageLoopCurrent(GetCurrentSequenceManagerImpl()); + return MessageLoopCurrent(GetCurrentMessageLoopBase()); } // static @@ -36,7 +35,7 @@ // static bool MessageLoopCurrent::IsSet() { - return !!GetCurrentSequenceManagerImpl(); + return !!GetCurrentMessageLoopBase(); } void MessageLoopCurrent::AddDestructionObserver( @@ -67,7 +66,7 @@ } bool MessageLoopCurrent::IsBoundToCurrentThread() const { - return current_ == GetCurrentSequenceManagerImpl(); + return current_ == GetCurrentMessageLoopBase(); } bool MessageLoopCurrent::IsIdleForTesting() { @@ -100,13 +99,13 @@ } MessageLoopCurrent::ScopedNestableTaskAllower::ScopedNestableTaskAllower() - : sequence_manager_(GetCurrentSequenceManagerImpl()), - old_state_(sequence_manager_->IsTaskExecutionAllowed()) { - sequence_manager_->SetTaskExecutionAllowed(true); + : loop_(GetCurrentMessageLoopBase()), + old_state_(loop_->IsTaskExecutionAllowed()) { + loop_->SetTaskExecutionAllowed(true); } MessageLoopCurrent::ScopedNestableTaskAllower::~ScopedNestableTaskAllower() { - sequence_manager_->SetTaskExecutionAllowed(old_state_); + loop_->SetTaskExecutionAllowed(old_state_); } bool MessageLoopCurrent::operator==(const MessageLoopCurrent& other) const { @@ -120,27 +119,26 @@ // static MessageLoopCurrentForUI MessageLoopCurrentForUI::Get() { - auto* sequence_manager = GetCurrentSequenceManagerImpl(); - DCHECK(sequence_manager); + MessageLoopBase* loop = GetCurrentMessageLoopBase(); + DCHECK(loop); #if defined(OS_ANDROID) - DCHECK(sequence_manager->IsType(MessageLoop::TYPE_UI) || - sequence_manager->IsType(MessageLoop::TYPE_JAVA)); + DCHECK(loop->IsType(MessageLoop::TYPE_UI) || + loop->IsType(MessageLoop::TYPE_JAVA)); #else // defined(OS_ANDROID) - DCHECK(sequence_manager->IsType(MessageLoop::TYPE_UI)); + DCHECK(loop->IsType(MessageLoop::TYPE_UI)); #endif // defined(OS_ANDROID) - return MessageLoopCurrentForUI(sequence_manager); + return MessageLoopCurrentForUI(loop); } // static bool MessageLoopCurrentForUI::IsSet() { - sequence_manager::internal::SequenceManagerImpl* sequence_manager = - GetCurrentSequenceManagerImpl(); - return sequence_manager && + MessageLoopBase* loop = GetCurrentMessageLoopBase(); + return loop && #if defined(OS_ANDROID) - (sequence_manager->IsType(MessageLoop::TYPE_UI) || - sequence_manager->IsType(MessageLoop::TYPE_JAVA)); + (loop->IsType(MessageLoop::TYPE_UI) || + loop->IsType(MessageLoop::TYPE_JAVA)); #else // defined(OS_ANDROID) - sequence_manager->IsType(MessageLoop::TYPE_UI); + loop->IsType(MessageLoop::TYPE_UI); #endif // defined(OS_ANDROID) } @@ -192,16 +190,16 @@ // static MessageLoopCurrentForIO MessageLoopCurrentForIO::Get() { - auto* sequence_manager = GetCurrentSequenceManagerImpl(); - DCHECK(sequence_manager); - DCHECK(sequence_manager->IsType(MessageLoop::TYPE_IO)); - return MessageLoopCurrentForIO(sequence_manager); + MessageLoopBase* loop = GetCurrentMessageLoopBase(); + DCHECK(loop); + DCHECK(loop->IsType(MessageLoop::TYPE_IO)); + return MessageLoopCurrentForIO(loop); } // static bool MessageLoopCurrentForIO::IsSet() { - auto* sequence_manager = GetCurrentSequenceManagerImpl(); - return sequence_manager && sequence_manager->IsType(MessageLoop::TYPE_IO); + MessageLoopBase* loop = GetCurrentMessageLoopBase(); + return loop && loop->IsType(MessageLoop::TYPE_IO); } MessagePumpForIO* MessageLoopCurrentForIO::GetMessagePumpForIO() const {
diff --git a/base/message_loop/message_loop_current.h b/base/message_loop/message_loop_current.h index 270c6593..1809f87 100644 --- a/base/message_loop/message_loop_current.h +++ b/base/message_loop/message_loop_current.h
@@ -23,6 +23,7 @@ namespace base { +class MessageLoopBase; class MessageLoopImpl; namespace sequence_manager { @@ -171,7 +172,7 @@ ~ScopedNestableTaskAllower(); private: - sequence_manager::internal::SequenceManagerImpl* const sequence_manager_; + MessageLoopBase* const loop_; const bool old_state_; }; @@ -186,12 +187,9 @@ bool IsIdleForTesting(); protected: - explicit MessageLoopCurrent( - sequence_manager::internal::SequenceManagerImpl* sequence_manager) - : current_(sequence_manager) {} + explicit MessageLoopCurrent(MessageLoopBase* current) : current_(current) {} - static sequence_manager::internal::SequenceManagerImpl* - GetCurrentSequenceManagerImpl(); + static MessageLoopBase* GetCurrentMessageLoopBase(); friend class MessageLoopImpl; friend class MessagePumpLibeventTest; @@ -201,7 +199,7 @@ friend class MessageLoopTaskRunnerTest; friend class web::TestWebThreadBundle; - sequence_manager::internal::SequenceManagerImpl* current_; + MessageLoopBase* current_; }; #if !defined(OS_NACL) @@ -252,8 +250,7 @@ #endif private: - explicit MessageLoopCurrentForUI( - sequence_manager::internal::SequenceManagerImpl* current) + explicit MessageLoopCurrentForUI(MessageLoopBase* current) : MessageLoopCurrent(current) {} MessagePumpForUI* GetMessagePumpForUI() const; @@ -309,8 +306,7 @@ #endif // !defined(OS_NACL_SFI) private: - explicit MessageLoopCurrentForIO( - sequence_manager::internal::SequenceManagerImpl* current) + explicit MessageLoopCurrentForIO(MessageLoopBase* current) : MessageLoopCurrent(current) {} MessagePumpForIO* GetMessagePumpForIO() const;
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc index c9605a4..fe65fb73 100644 --- a/base/message_loop/message_loop_unittest.cc +++ b/base/message_loop/message_loop_unittest.cc
@@ -2328,11 +2328,23 @@ } // namespace // Test that MessageLoop destruction handles a task's destructor posting another -// task. -TEST(MessageLoopDestructionTest, DestroysFineWithPostTaskOnDestroy) { +// task by: +// 1) Not getting stuck clearing its task queue. +// 2) DCHECKing when clearing pending tasks many times still doesn't yield an +// empty queue. +TEST(MessageLoopDestructionTest, ExpectDeathWithStubbornPostTaskOnDestroy) { std::unique_ptr<MessageLoop> loop = std::make_unique<MessageLoop>(); - PostTaskOnDestroy::PostTaskWithPostingDestructor(1000); + EXPECT_DCHECK_DEATH({ + PostTaskOnDestroy::PostTaskWithPostingDestructor(1000); + loop.reset(); + }); +} + +TEST(MessageLoopDestructionTest, DestroysFineWithReasonablePostTaskOnDestroy) { + std::unique_ptr<MessageLoop> loop = std::make_unique<MessageLoop>(); + + PostTaskOnDestroy::PostTaskWithPostingDestructor(10); loop.reset(); }
diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc index c3e85f6..b7cfb6e 100644 --- a/base/message_loop/message_pump_perftest.cc +++ b/base/message_loop/message_pump_perftest.cc
@@ -10,13 +10,11 @@ #include "base/format_macros.h" #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" -#include "base/message_loop/message_loop_current.h" #include "base/single_thread_task_runner.h" #include "base/strings/stringprintf.h" #include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" -#include "base/task/sequence_manager/sequence_manager_impl.h" #include "base/threading/thread.h" #include "base/time/time.h" #include "build/build_config.h" @@ -177,12 +175,12 @@ } } - sequence_manager::internal::SequenceManagerImpl* target_message_loop_base() { + MessageLoopBase* target_message_loop_base() { #if defined(OS_ANDROID) if (java_thread_) - return java_thread_->message_loop()->GetSequenceManagerImpl(); + return java_thread_->message_loop()->GetMessageLoopBase(); #endif - return MessageLoopCurrent::Get()->GetCurrentSequenceManagerImpl(); + return message_loop_->GetMessageLoopBase(); } private:
diff --git a/base/message_loop/message_pump_unittest.cc b/base/message_loop/message_pump_unittest.cc index 220a7e0..0dc49be 100644 --- a/base/message_loop/message_pump_unittest.cc +++ b/base/message_loop/message_pump_unittest.cc
@@ -28,9 +28,9 @@ namespace { -bool PumpTypeUsesDoSomeWork(MessageLoop::Type type) { +bool PumpTypeUsesDoSomeWork(MessageLoopBase::Type type) { switch (type) { - case MessageLoop::Type::TYPE_DEFAULT: + case MessageLoopBase::Type::TYPE_DEFAULT: #if defined(OS_IOS) // iOS uses a MessagePumpCFRunLoop instead of MessagePumpDefault for // TYPE_DEFAULT. TODO(gab): migrate MessagePumpCFRunLoop too. @@ -39,7 +39,7 @@ return true; #endif - case MessageLoop::Type::TYPE_UI: + case MessageLoopBase::Type::TYPE_UI: #if defined(OS_IOS) // iOS uses a MessagePumpDefault for UI in unit tests, ref. // test_support_ios.mm::CreateMessagePumpForUIForTests(). @@ -56,7 +56,7 @@ return false; #endif - case MessageLoop::Type::TYPE_IO: + case MessageLoopBase::Type::TYPE_IO: #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) return true; #elif defined(OS_POSIX) && !defined(OS_NACL_SFI) @@ -69,9 +69,9 @@ return false; #endif - case MessageLoop::Type::TYPE_CUSTOM: + case MessageLoopBase::Type::TYPE_CUSTOM: #if defined(OS_ANDROID) - case MessageLoop::Type::TYPE_JAVA: + case MessageLoopBase::Type::TYPE_JAVA: #endif // defined(OS_ANDROID) // Not tested in this file. NOTREACHED(); @@ -96,7 +96,7 @@ DISALLOW_COPY_AND_ASSIGN(MockMessagePumpDelegate); }; -class MessagePumpTest : public ::testing::TestWithParam<MessageLoop::Type> { +class MessagePumpTest : public ::testing::TestWithParam<MessageLoopBase::Type> { public: MessagePumpTest() : message_pump_(MessageLoop::CreateMessagePumpForType(GetParam())) {}
diff --git a/base/task/sequence_manager/sequence_manager_impl.h b/base/task/sequence_manager/sequence_manager_impl.h index 13ddd3ee..42c2207 100644 --- a/base/task/sequence_manager/sequence_manager_impl.h +++ b/base/task/sequence_manager/sequence_manager_impl.h
@@ -54,7 +54,6 @@ class RealTimeDomain; class TaskQueueImpl; -class ThreadControllerImpl; // The task queue manager provides N task queues and a selector interface for // choosing which task queue to service next. Each task queue consists of two @@ -72,7 +71,8 @@ : public SequenceManager, public internal::SequencedTaskSource, public internal::TaskQueueSelector::Observer, - public RunLoop::NestingObserver { + public RunLoop::NestingObserver, + public MessageLoopBase { public: using Observer = SequenceManager::Observer; @@ -97,6 +97,8 @@ scoped_refptr<SingleThreadTaskRunner> task_runner, SequenceManager::Settings settings); + void BindToMessageLoop(MessageLoopBase* message_loop_base); + // SequenceManager implementation: void BindToCurrentThread() override; void BindToMessagePump(std::unique_ptr<MessagePump> message_pump) override; @@ -128,31 +130,33 @@ bool HasPendingHighResolutionTasks() override; bool OnSystemIdle() override; - void AddTaskObserver(MessageLoop::TaskObserver* task_observer); - void RemoveTaskObserver(MessageLoop::TaskObserver* task_observer); + // MessageLoopBase implementation: + void AddTaskObserver(MessageLoop::TaskObserver* task_observer) override; + void RemoveTaskObserver(MessageLoop::TaskObserver* task_observer) override; void AddDestructionObserver( - MessageLoopCurrent::DestructionObserver* destruction_observer); + MessageLoopCurrent::DestructionObserver* destruction_observer) override; void RemoveDestructionObserver( - MessageLoopCurrent::DestructionObserver* destruction_observer); + MessageLoopCurrent::DestructionObserver* destruction_observer) override; // TODO(alexclarke): Remove this as part of https://crbug.com/825327. - void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner); + void SetTaskRunner( + scoped_refptr<SingleThreadTaskRunner> task_runner) override; // TODO(alexclarke): Remove this as part of https://crbug.com/825327. - scoped_refptr<SingleThreadTaskRunner> GetTaskRunner(); - std::string GetThreadName() const; - bool IsBoundToCurrentThread() const; - MessagePump* GetMessagePump() const; - bool IsType(MessageLoop::Type type) const; - void SetAddQueueTimeToTasks(bool enable); - void SetTaskExecutionAllowed(bool allowed); - bool IsTaskExecutionAllowed() const; + scoped_refptr<SingleThreadTaskRunner> GetTaskRunner() override; + std::string GetThreadName() const override; + bool IsBoundToCurrentThread() const override; + MessagePump* GetMessagePump() const override; + bool IsType(MessageLoop::Type type) const override; + void SetAddQueueTimeToTasks(bool enable) override; + void SetTaskExecutionAllowed(bool allowed) override; + bool IsTaskExecutionAllowed() const override; #if defined(OS_IOS) - void AttachToMessagePump(); + void AttachToMessagePump() override; #endif bool IsIdleForTesting() override; - void BindToCurrentThread(std::unique_ptr<MessagePump> pump); - void DeletePendingTasks(); - bool HasTasks(); - MessageLoop::Type GetType() const; + void BindToCurrentThread(std::unique_ptr<MessagePump> pump) override; + void DeletePendingTasks() override; + bool HasTasks() override; + MessageLoop::Type GetType() const override; // Requests that a task to process work is scheduled. void ScheduleWork();
diff --git a/base/test/trace_to_file.cc b/base/test/trace_to_file.cc index db2f46fd..3ad4463 100644 --- a/base/test/trace_to_file.cc +++ b/base/test/trace_to_file.cc
@@ -9,7 +9,9 @@ #include "base/command_line.h" #include "base/files/file_util.h" #include "base/memory/ref_counted_memory.h" +#include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_buffer.h" #include "base/trace_event/trace_log.h" @@ -94,6 +96,11 @@ buffer.SetOutputCallback( Bind(&TraceToFile::TraceOutputCallback, Unretained(this))); + // In tests we might not have a MessageLoop, create one if needed. + std::unique_ptr<MessageLoop> message_loop; + if (!ThreadTaskRunnerHandle::IsSet()) + message_loop = std::make_unique<MessageLoop>(); + RunLoop run_loop; trace_event::TraceLog::GetInstance()->Flush( Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc index 67618d30..9c4f81c 100644 --- a/base/threading/platform_thread_win.cc +++ b/base/threading/platform_thread_win.cc
@@ -214,7 +214,7 @@ ThreadIdNameManager::GetInstance()->SetName(name); // The SetThreadDescription API works even if no debugger is attached. - auto set_thread_description_func = + static auto set_thread_description_func = reinterpret_cast<SetThreadDescription>(::GetProcAddress( ::GetModuleHandle(L"Kernel32.dll"), "SetThreadDescription")); if (set_thread_description_func) {
diff --git a/base/trace_event/heap_profiler.h b/base/trace_event/heap_profiler.h index c8deaf60..575dfef 100644 --- a/base/trace_event/heap_profiler.h +++ b/base/trace_event/heap_profiler.h
@@ -30,6 +30,15 @@ #define TRACE_HEAP_PROFILER_API_SCOPED_WITH_PROGRAM_COUNTER \ trace_event_internal::HeapProfilerScopedStackFrame +// Returns the current task context (c-string) tracked by heap profiler. This is +// useful along with TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION if a async +// system needs to track client's allocation context across post tasks. Use this +// macro to get the current context and use +// TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION in the posted task which +// allocates memory for a client. +#define TRACE_HEAP_PROFILER_API_GET_CURRENT_TASK_CONTEXT \ + trace_event_internal::HeapProfilerCurrentTaskContext + // A scoped ignore event used to tell heap profiler to ignore all the // allocations in the scope. It is useful to exclude allocations made for // tracing from the heap profiler dumps. @@ -92,6 +101,12 @@ const void* const program_counter_; }; +inline const char* HeapProfilerCurrentTaskContext() { + return base::trace_event::AllocationContextTracker:: + GetInstanceForCurrentThread() + ->TaskContext(); +} + class BASE_EXPORT HeapProfilerScopedIgnore { public: inline HeapProfilerScopedIgnore() {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 5c5b2e510..b891b02 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8916021787046451008 \ No newline at end of file +8915992854282451632 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index bf2e941..b622d13 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8916033694640134192 \ No newline at end of file +8916000087704284384 \ No newline at end of file
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index d5200040..fa4412f 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc
@@ -20,6 +20,7 @@ #include "cc/test/pixel_test_utils.h" #include "cc/test/test_in_process_context_provider.h" #include "components/viz/client/client_resource_provider.h" +#include "components/viz/common/display/update_vsync_parameters_callback.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/common/frame_sinks/copy_output_result.h" @@ -62,15 +63,13 @@ // for tests. class PixelTestSkiaOutputSurfaceImpl : public viz::SkiaOutputSurfaceImpl { public: - PixelTestSkiaOutputSurfaceImpl( - viz::GpuServiceImpl* gpu_service, - gpu::SurfaceHandle surface_handle, - viz::SyntheticBeginFrameSource* synthetic_begin_frame_source, - const viz::RendererSettings& renderer_settings, - bool flipped_output_surface) + PixelTestSkiaOutputSurfaceImpl(viz::GpuServiceImpl* gpu_service, + gpu::SurfaceHandle surface_handle, + const viz::RendererSettings& renderer_settings, + bool flipped_output_surface) : SkiaOutputSurfaceImpl(gpu_service, surface_handle, - synthetic_begin_frame_source, + viz::UpdateVSyncParametersCallback(), renderer_settings), flipped_output_surface_(flipped_output_surface) {} @@ -353,8 +352,7 @@ // Set up the skia renderer. output_surface_ = std::make_unique<PixelTestSkiaOutputSurfaceImpl>( - gpu_service_.get(), gpu::kNullSurfaceHandle, - nullptr /* synthetic_begin_frame_source */, renderer_settings_, + gpu_service_.get(), gpu::kNullSurfaceHandle, renderer_settings_, flipped_output_surface); output_surface_->BindToClient(output_surface_client_.get()); resource_provider_ = std::make_unique<viz::DisplayResourceProvider>(
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 22c41dce..a9626a0c 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -1677,6 +1677,7 @@ "java/src/org/chromium/chrome/browser/ui/ImmersiveModeManager.java", "java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java", "java/src/org/chromium/chrome/browser/ui/system/NavigationBarColorController.java", + "java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java", "java/src/org/chromium/chrome/browser/ui/system/SystemUiCoordinator.java", "java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java", "java/src/org/chromium/chrome/browser/util/ChromeContextUtil.java",
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_filled.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_filled.xml index b404524b..686da94a 100644 --- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_filled.xml +++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_filled.xml
@@ -2,7 +2,7 @@ <!-- 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. --> -<org.chromium.ui.widget.ButtonView +<org.chromium.chrome.browser.autofill_assistant.carousel.ButtonView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content"
diff --git a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_hairline.xml b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_hairline.xml index d7f7506..e2a6aca 100644 --- a/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_hairline.xml +++ b/chrome/android/features/autofill_assistant/java/res/layout/autofill_assistant_button_hairline.xml
@@ -2,7 +2,7 @@ <!-- 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. --> -<org.chromium.ui.widget.ButtonView +<org.chromium.chrome.browser.autofill_assistant.carousel.ButtonView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content"
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinderTest.java index 587527ab..89644e5 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinderTest.java
@@ -25,6 +25,7 @@ import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ui.DummyUiActivity; import org.chromium.chrome.test.ui.DummyUiActivityTestCase; +import org.chromium.content_public.browser.test.util.Criteria; import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.modelutil.PropertyModel; @@ -36,6 +37,7 @@ @RunWith(ChromeJUnit4ClassRunner.class) public class TabGridContainerViewBinderTest extends DummyUiActivityTestCase { private static final int CONTAINER_HEIGHT = 56; + private TabGridContainerViewBinder mTabGridContainerViewHolder; private PropertyModel mContainerModel; private PropertyModelChangeProcessor mMCP; private TabListRecyclerView mRecyclerView; @@ -95,7 +97,7 @@ @Test @MediumTest - public void testShowWithAnimation() { + public void testShowWithAnimation() throws Exception { TestThreadUtils.runOnUiThreadBlocking(() -> { mContainerModel.set( TabListContainerProperties.VISIBILITY_LISTENER, mMockVisibilityListener); @@ -112,13 +114,18 @@ } assertThat(mIsAnimating, equalTo(true)); - CriteriaHelper.pollUiThread(() -> mRecyclerView.getAlpha() == 1.0f); + CriteriaHelper.pollUiThread(new Criteria() { + @Override + public boolean isSatisfied() { + return mRecyclerView.getAlpha() == 1.0f; + } + }); } @Test @MediumTest @UiThreadTest - public void testShowWithoutAnimation() { + public void testShowWithoutAnimation() throws Exception { mContainerModel.set( TabListContainerProperties.VISIBILITY_LISTENER, mMockVisibilityListener); @@ -134,7 +141,7 @@ @Test @MediumTest - public void testHidesWithAnimation() { + public void testHidesWithAnimation() throws Exception { TestThreadUtils.runOnUiThreadBlocking(() -> { mContainerModel.set( TabListContainerProperties.VISIBILITY_LISTENER, mMockVisibilityListener); @@ -159,14 +166,19 @@ } assertThat(mIsAnimating, equalTo(true)); - CriteriaHelper.pollUiThread(() -> mRecyclerView.getAlpha() == 0.0f); + CriteriaHelper.pollUiThread(new Criteria() { + @Override + public boolean isSatisfied() { + return mRecyclerView.getAlpha() == 0.0f; + } + }); assertThat(mRecyclerView.getVisibility(), equalTo(View.INVISIBLE)); } @Test @MediumTest @UiThreadTest - public void testHidesWithoutAnimation() { + public void testHidesWithoutAnimation() throws Exception { mContainerModel.set( TabListContainerProperties.VISIBILITY_LISTENER, mMockVisibilityListener); @@ -188,7 +200,7 @@ @Test @MediumTest @UiThreadTest - public void testIsIncognitoSetsBackgroundColor() { + public void testIsIncognitoSetsBackgroundColor() throws Exception { mContainerModel.set(TabListContainerProperties.IS_INCOGNITO, true); assertThat(mRecyclerView.getBackground(), instanceOf(ColorDrawable.class)); assertThat(((ColorDrawable) mRecyclerView.getBackground()).getColor(), @@ -205,7 +217,7 @@ @Test @MediumTest @UiThreadTest - public void testTopContainerHeightSetsTopMargin() { + public void testTopContainerHeightSetsTopMargin() throws Exception { assertThat(mRecyclerView.getLayoutParams(), instanceOf(FrameLayout.LayoutParams.class)); assertThat( ((FrameLayout.LayoutParams) mRecyclerView.getLayoutParams()).topMargin, equalTo(0)); @@ -218,7 +230,7 @@ @Test @MediumTest @UiThreadTest - public void testBottomContainerHeightSetsBottomMargin() { + public void testBottomContainerHeightSetsBottomMargin() throws Exception { assertThat(mRecyclerView.getLayoutParams(), instanceOf(FrameLayout.LayoutParams.class)); assertThat(((FrameLayout.LayoutParams) mRecyclerView.getLayoutParams()).bottomMargin, equalTo(0));
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java index 70bf7db..ad0092fe 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
@@ -113,33 +113,35 @@ @Test @MediumTest @UiThreadTest - public void testSelected() { + public void testSelected() throws Exception { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { mGridModel.set(TabProperties.IS_SELECTED, true); - Assert.assertNotNull(((FrameLayout) (mTabGridViewHolder.itemView)).getForeground()); + Assert.assertTrue( + ((FrameLayout) (mTabGridViewHolder.itemView)).getForeground() != null); mGridModel.set(TabProperties.IS_SELECTED, false); - Assert.assertNull(((FrameLayout) (mTabGridViewHolder.itemView)).getForeground()); + Assert.assertFalse( + ((FrameLayout) (mTabGridViewHolder.itemView)).getForeground() != null); } else { mGridModel.set(TabProperties.IS_SELECTED, true); Drawable selectedDrawable = mTabGridViewHolder.itemView.findViewById(R.id.background_view).getBackground(); - Assert.assertNotNull(selectedDrawable); + Assert.assertTrue(selectedDrawable != null); mGridModel.set(TabProperties.IS_SELECTED, false); Drawable elevationDrawable = mTabGridViewHolder.itemView.findViewById(R.id.background_view).getBackground(); - Assert.assertNotNull(elevationDrawable); + Assert.assertTrue(elevationDrawable != null); Assert.assertNotSame(selectedDrawable, elevationDrawable); } mStripModel.set(TabProperties.IS_SELECTED, true); - Assert.assertNotNull(((FrameLayout) (mTabStripViewHolder.itemView)).getForeground()); + Assert.assertTrue(((FrameLayout) (mTabStripViewHolder.itemView)).getForeground() != null); mStripModel.set(TabProperties.IS_SELECTED, false); - Assert.assertNull(((FrameLayout) (mTabStripViewHolder.itemView)).getForeground()); + Assert.assertFalse(((FrameLayout) (mTabStripViewHolder.itemView)).getForeground() != null); } @Test @MediumTest @UiThreadTest - public void testTitle() { + public void testTitle() throws Exception { final String title = "Surf the cool webz"; mGridModel.set(TabProperties.TITLE, title); Assert.assertEquals(mTabGridViewHolder.title.getText(), title); @@ -148,7 +150,7 @@ @Test @MediumTest @UiThreadTest - public void testThumbnail() { + public void testThumbnail() throws Exception { mGridModel.set(TabProperties.THUMBNAIL_FETCHER, mMockThumbnailProvider); // This should have set the image resource id to 0 and reset it. if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { @@ -166,7 +168,7 @@ @Test @MediumTest @UiThreadTest - public void testClickToSelect() { + public void testClickToSelect() throws Exception { mTabGridViewHolder.itemView.performClick(); Assert.assertTrue(mSelectClicked.get()); mSelectClicked.set(false); @@ -184,7 +186,7 @@ @Test @MediumTest @UiThreadTest - public void testClickToClose() { + public void testClickToClose() throws Exception { mTabGridViewHolder.closeButton.performClick(); Assert.assertTrue(mCloseClicked.get()); mCloseClicked.set(false);
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TestRecyclerViewSimpleViewBinder.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TestRecyclerViewSimpleViewBinder.java index ca739508..dd073d7 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TestRecyclerViewSimpleViewBinder.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TestRecyclerViewSimpleViewBinder.java
@@ -20,8 +20,7 @@ */ public class TestRecyclerViewSimpleViewBinder<VH extends RecyclerView.ViewHolder> implements PropertyModelChangeProcessor.ViewBinder<PropertyModel, VH, PropertyKey> { - private SimpleRecyclerViewMcpBase - .ViewBinder<PropertyModel, VH, PropertyKey> mInternalViewBinder; + SimpleRecyclerViewMcpBase.ViewBinder<PropertyModel, VH, PropertyKey> mInternalViewBinder; /** * Main constructor
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java index 77de04b..97fb1ae7 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java
@@ -69,6 +69,7 @@ private static final String TAB1_TITLE = "Tab1"; private static final String TAB2_TITLE = "Tab2"; private static final String TAB3_TITLE = "Tab3"; + private static final String NEW_TITLE = "New title"; private static final int TAB1_ID = 456; private static final int TAB2_ID = 789; private static final int TAB3_ID = 123; @@ -104,6 +105,8 @@ ArgumentCaptor<TabModelSelectorObserver> mTabModelSelectorObserverCaptor; @Captor ArgumentCaptor<ChromeFullscreenManager.FullscreenListener> mFullscreenListenerCaptor; + @Captor + ArgumentCaptor<Tab> mTabCaptor; private Tab mTab1; private Tab mTab2;
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java index 5789fa1..6bdf32a1 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -40,6 +40,7 @@ import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; +import org.chromium.chrome.browser.favicon.FaviconHelper; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tabmodel.TabLaunchType; @@ -83,6 +84,8 @@ @Captor ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; @Captor + ArgumentCaptor<FaviconHelper.FaviconImageCallback> mFaviconCallbackCaptor; + @Captor ArgumentCaptor<TabObserver> mTabObserverCaptor; @Captor ArgumentCaptor<Callback<Drawable>> mCallbackCaptor;
diff --git a/chrome/android/java/res/layout/edit_url_suggestion_layout.xml b/chrome/android/java/res/layout/edit_url_suggestion_layout.xml index 45d585b8..2a16a58 100644 --- a/chrome/android/java/res/layout/edit_url_suggestion_layout.xml +++ b/chrome/android/java/res/layout/edit_url_suggestion_layout.xml
@@ -50,7 +50,7 @@ android:layout_centerVertical="true" android:layout_toStartOf="@id/edit_url_suggestion_icons" android:orientation="vertical" - android:layout_marginStart="@dimen/omnibox_suggestion_start_offset"> + android:layout_marginStart="@dimen/omnibox_suggestion_start_offset_without_icon"> <TextView android:id="@+id/title_text_view"
diff --git a/chrome/android/java/res/layout/selectable_list_layout.xml b/chrome/android/java/res/layout/selectable_list_layout.xml index e767534..c9307ff8 100644 --- a/chrome/android/java/res/layout/selectable_list_layout.xml +++ b/chrome/android/java/res/layout/selectable_list_layout.xml
@@ -3,7 +3,8 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<merge xmlns:android="http://schemas.android.com/apk/res/android"> +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> <!-- This view provides a background for the toolbar when the page's background is visible through the lateral margins of the search view --> @@ -38,14 +39,15 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone" > - <TextView + <org.chromium.chrome.browser.widget.TextViewWithCompoundDrawables android:id="@+id/empty_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:drawablePadding="3dp" android:visibility="gone" - android:textAppearance="@style/TextAppearance.BlackDisabledText1" /> + android:textAppearance="@style/TextAppearance.BlackDisabledText1" + app:chromeDrawableTint="@color/light_icon_color"/> </FrameLayout> <org.chromium.chrome.browser.widget.LoadingView
diff --git a/chrome/android/java/res/layout/suspended_tab.xml b/chrome/android/java/res/layout/suspended_tab.xml index e613cb3..7876aca 100644 --- a/chrome/android/java/res/layout/suspended_tab.xml +++ b/chrome/android/java/res/layout/suspended_tab.xml
@@ -15,7 +15,7 @@ android:background="@color/modern_primary_color" android:fillViewport="true" android:layout_height="wrap_content" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:paddingStart="24dp" android:paddingEnd="24dp" android:paddingTop="24dp"
diff --git a/chrome/android/java/res/values-sw600dp/dimens.xml b/chrome/android/java/res/values-sw600dp/dimens.xml index 1a78b275..49c5003 100644 --- a/chrome/android/java/res/values-sw600dp/dimens.xml +++ b/chrome/android/java/res/values-sw600dp/dimens.xml
@@ -31,7 +31,9 @@ <dimen name="location_bar_icon_width">40dp</dimen> <dimen name="location_bar_action_icon_width">40dp</dimen> <dimen name="location_bar_url_action_offset">0dp</dimen> - <dimen name="omnibox_suggestion_start_offset">@dimen/location_bar_icon_width</dimen> + <dimen name="omnibox_suggestion_start_offset_without_icon">@dimen/location_bar_icon_width</dimen> + <dimen name="omnibox_suggestion_start_offset_with_icon">@dimen/omnibox_suggestion_start_offset_without_icon</dimen> + <dimen name="omnibox_answer_suggestion_icon_margin_start">0dp</dimen> <!-- NTP dimensions -->
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index ef4a8765..14d06848 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -307,7 +307,11 @@ <!-- omnibox_suggestion_answer_line2_vertical_spacing + 2dp --> <dimen name="omnibox_suggestion_answer_image_vertical_spacing">5dp</dimen> <dimen name="omnibox_suggestion_answer_image_horizontal_spacing">4dp</dimen> - <dimen name="omnibox_suggestion_start_offset">18dp</dimen> + <dimen name="omnibox_suggestion_start_offset_without_icon">18dp</dimen> + <dimen name="omnibox_suggestion_start_offset_with_icon">56dp</dimen> + + <dimen name="omnibox_suggestion_favicon_size">24dp</dimen> + <dimen name="omnibox_suggestion_refine_width">48dp</dimen> <dimen name="omnibox_suggestion_text_vertical_padding">5dp</dimen> <dimen name="omnibox_suggestion_multiline_text_vertical_padding">10dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java index 5cbeabf..50d2783 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ActivityTabTaskDescriptionHelper.java
@@ -225,8 +225,9 @@ public void updateTaskDescription(String label, Bitmap icon) { int color = mDefaultThemeColor; if (mCurrentTab != null) { - TabThemeColorHelper tabTheme = TabThemeColorHelper.get(mCurrentTab); - if (!tabTheme.isDefaultColor()) color = tabTheme.getColor(); + if (!TabThemeColorHelper.isDefaultColorUsed(mCurrentTab)) { + color = TabThemeColorHelper.getColor(mCurrentTab); + } } ApiCompatibilityUtils.setTaskDescription(mActivity, label, icon, color); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index 4a1a45e..c6b9a46b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -14,7 +14,6 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -134,7 +133,6 @@ import org.chromium.chrome.browser.sync.SyncController; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabFullscreenHandler; -import org.chromium.chrome.browser.tab.TabThemeColorHelper; import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager; import org.chromium.chrome.browser.tabmodel.EmptyTabModel; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; @@ -143,7 +141,6 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; import org.chromium.chrome.browser.tabmodel.TabModelUtils; -import org.chromium.chrome.browser.tabmodel.TabSelectionType; import org.chromium.chrome.browser.tabmodel.TabWindowManager; import org.chromium.chrome.browser.tasks.EngagementTimeUtil; import org.chromium.chrome.browser.tasks.JourneyManager; @@ -152,8 +149,8 @@ import org.chromium.chrome.browser.toolbar.top.ToolbarControlContainer; import org.chromium.chrome.browser.translate.TranslateBridge; import org.chromium.chrome.browser.ui.RootUiCoordinator; +import org.chromium.chrome.browser.ui.system.StatusBarColorController; import org.chromium.chrome.browser.util.AccessibilityUtil; -import org.chromium.chrome.browser.util.ColorUtils; import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.MathUtils; import org.chromium.chrome.browser.vr.ArDelegate; @@ -204,7 +201,8 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent> extends AsyncInitializationActivity implements TabCreatorManager, AccessibilityStateChangeListener, PolicyChangeListener, - ContextualSearchTabPromotionDelegate, SnackbarManageable, SceneChangeObserver { + ContextualSearchTabPromotionDelegate, SnackbarManageable, SceneChangeObserver, + StatusBarColorController.StatusBarColorProvider { /** * Factory which creates the AppMenuHandler. */ @@ -255,7 +253,6 @@ private TabModelSelector mTabModelSelector; private TabModelSelectorTabObserver mTabModelSelectorTabObserver; - private ActivityTabProvider.ActivityTabTabObserver mStatusBarColorTabObserver; private TabCreatorManager.TabCreator mRegularTabCreator; private TabCreatorManager.TabCreator mIncognitoTabCreator; private TabContentManager mTabContentManager; @@ -303,9 +300,7 @@ private BottomSheetController mBottomSheetController; private BottomSheet mBottomSheet; private ScrimView mScrimView; - private float mStatusBarScrimFraction; - private int mBaseStatusBarColor; - private int mScrimColor; + private StatusBarColorController mStatusBarColorController; // Timestamp in ms when initial layout inflation begins private long mInflateInitialLayoutBeginMs; @@ -446,10 +441,8 @@ super.performPostInflationStartup(); ViewGroup coordinator = findViewById(R.id.coordinator); - mScrimView = new ScrimView(this, (fraction) -> { - mStatusBarScrimFraction = fraction; - setStatusBarColor(null, mBaseStatusBarColor); - }, coordinator); + mScrimView = new ScrimView( + this, getStatusBarColorController().getStatusBarScrimDelegate(), coordinator); Intent intent = getIntent(); if (intent != null && getSavedInstanceState() == null) { @@ -618,11 +611,8 @@ @Override protected void onInitialLayoutInflationComplete() { mInflateInitialLayoutEndMs = SystemClock.elapsedRealtime(); - // Set the status bar color to white by default. - boolean isTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(this); - setStatusBarColor( - isTablet ? Color.BLACK : ColorUtils.getDefaultThemeColor(getResources(), false), - true); + + getStatusBarColorController().updateStatusBarColor(true); ViewGroup rootView = (ViewGroup) getWindow().getDecorView().getRootView(); mCompositorViewHolder = (CompositorViewHolder) findViewById(R.id.compositor_view_holder); @@ -706,6 +696,7 @@ mActivityTabProvider.setTabModelSelector(mTabModelSelector); mTabThemeColorProvider = new TabThemeColorProvider(this); mTabThemeColorProvider.setActivityTabProvider(mActivityTabProvider); + getStatusBarColorController().setTabModelSelector(mTabModelSelector); if (mTabModelSelector == null) { assert isFinishing(); @@ -740,27 +731,6 @@ } }; - mStatusBarColorTabObserver = - new ActivityTabProvider.ActivityTabTabObserver(getActivityTabProvider()) { - @Override - public void onShown(Tab tab, @TabSelectionType int type) { - setStatusBarColor(tab, TabThemeColorHelper.getColor(tab)); - } - - @Override - public void onDidChangeThemeColor(Tab tab, int color) { - setStatusBarColor(tab, color); - } - - @Override - protected void onObservingDifferentTab(Tab tab) { - // |tab == null| means we're switching tabs - by the tab switcher or by swiping - // on the omnibox. These cases are dealt with differently, elsewhere. - if (tab == null) return; - setStatusBarColor(tab, TabThemeColorHelper.getColor(tab)); - } - }; - if (mAssistStatusHandler != null) { mAssistStatusHandler.setTabModelSelector(mTabModelSelector); } @@ -952,50 +922,26 @@ } /** - * Set device status bar to a given color. - * @param tab The tab that is currently showing, used to determine whether {@code color} is the - * default theme color. - * @param color The color that the status bar should be set to. + * @return The {@link StatusBarColorController} that adjusts the status bar color. */ - protected void setStatusBarColor(@Nullable Tab tab, int color) { - setStatusBarColor(color, tab != null && TabThemeColorHelper.get(tab).isDefaultColor()); - } - - /** - * Set device status bar to a given color. - * @param color The color that the status bar should be set to. - * @param isDefaultThemeColor Whether {@code color} is the default theme color. - */ - // TODO(danielpark): Move status bar & status bar icon color logic into helper class. - // See crbug.com/855079. - protected void setStatusBarColor(int color, boolean isDefaultThemeColor) { - if (UiUtils.isSystemUiThemingDisabled()) return; - - int statusBarColor = color; - boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; - View root = getWindow().getDecorView().getRootView(); - if (supportsDarkStatusIcons) { - mBaseStatusBarColor = color; - - if (mScrimColor == 0) { - mScrimColor = - ApiCompatibilityUtils.getColor(getResources(), R.color.black_alpha_65); - } - // Apply a color overlay if the scrim is showing. - float scrimColorAlpha = (mScrimColor >>> 24) / 255f; - int scrimColorOpaque = mScrimColor & 0xFF000000; - statusBarColor = ColorUtils.getColorWithOverlay( - statusBarColor, scrimColorOpaque, mStatusBarScrimFraction * scrimColorAlpha); - - boolean needsDarkStatusBarIcons = - !ColorUtils.shouldUseLightForegroundOnBackground(statusBarColor); - ApiCompatibilityUtils.setStatusBarIconColor(root, needsDarkStatusBarIcons); - } else { - statusBarColor = isDefaultThemeColor ? Color.BLACK - : ColorUtils.getDarkenedColorForStatusBar(color); + public final StatusBarColorController getStatusBarColorController() { + // TODO(https://crbug.com/943371): Initialize in SystemUiCoordinator. This requires + // SystemUiCoordinator to be created before WebappActivty#onResume(). + if (mStatusBarColorController == null) { + mStatusBarColorController = new StatusBarColorController(this); } - ApiCompatibilityUtils.setStatusBarColor(getWindow(), statusBarColor); + return mStatusBarColorController; + } + + @Override + public int getBaseStatusBarColor() { + return StatusBarColorController.UNDEFINED_STATUS_BAR_COLOR; + } + + @Override + public boolean isStatusBarDefaultThemeColor() { + return false; } private void createContextReporterIfNeeded() { @@ -1356,11 +1302,6 @@ mTabModelSelectorTabObserver = null; } - if (mStatusBarColorTabObserver != null) { - mStatusBarColorTabObserver.destroy(); - mStatusBarColorTabObserver = null; - } - if (mCompositorViewHolder != null) { if (mCompositorViewHolder.getLayoutManager() != null) { mCompositorViewHolder.getLayoutManager().removeSceneChangeObserver(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 0165264..0b7a9cfced 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -15,7 +15,6 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.ShortcutManager; -import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.os.SystemClock; @@ -130,7 +129,6 @@ import org.chromium.chrome.browser.tab.TabDelegateFactory; import org.chromium.chrome.browser.tab.TabRedirectHandler; import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate; -import org.chromium.chrome.browser.tab.TabThemeColorHelper; import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager; import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; @@ -151,7 +149,6 @@ import org.chromium.chrome.browser.toolbar.top.ToolbarControlContainer; import org.chromium.chrome.browser.usage_stats.UsageStatsService; import org.chromium.chrome.browser.util.AccessibilityUtil; -import org.chromium.chrome.browser.util.ColorUtils; import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.vr.VrModuleProvider; @@ -167,7 +164,6 @@ import org.chromium.content_public.browser.WebContentsAccessibility; import org.chromium.content_public.common.ContentSwitches; import org.chromium.content_public.common.Referrer; -import org.chromium.ui.UiUtils; import org.chromium.ui.base.PageTransition; import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.modaldialog.ModalDialogManager; @@ -1614,22 +1610,6 @@ mTabModelSelectorImpl.addObserver(new EmptyTabModelSelectorObserver() { @Override - public void onTabModelSelected(TabModel newModel, TabModel oldModel) { - if (isInOverviewMode()) { - // The passed-in color is ignored when the tab switcher is open. This call - // causes the toolbar color to change (if necessary) based on whether or not - // we're in incognito mode. - setStatusBarColor(null, Color.BLACK); - } else { - // When opening a new Incognito Tab from a normal Tab (or vice versa), the - // status bar color is updated. However, this update is triggered after the - // animation, so we update here for the duration of the new Tab animation. - setStatusBarColor(null, ColorUtils.getDefaultThemeColor( - getResources(), newModel.isIncognito())); - } - } - - @Override public void onTabStateInitialized() { if (!mCreatedTabOnStartup) return; @@ -2356,7 +2336,6 @@ if (getFindToolbarManager() != null) getFindToolbarManager().hideToolbar(); if (getAssistStatusHandler() != null) getAssistStatusHandler().updateAssistState(); if (getAppMenuHandler() != null) getAppMenuHandler().hideAppMenu(); - setStatusBarColor(null, Color.BLACK); } @Override @@ -2370,36 +2349,6 @@ @Override public void onOverviewModeFinishedHiding() { if (getAssistStatusHandler() != null) getAssistStatusHandler().updateAssistState(); - if (getActivityTab() != null) { - setStatusBarColor(getActivityTab(), TabThemeColorHelper.getColor(getActivityTab())); - } - } - - @Override - protected void setStatusBarColor(@Nullable Tab tab, int color) { - if (isTablet() || UiUtils.isSystemUiThemingDisabled()) return; - - if (!isInOverviewMode()) { - super.setStatusBarColor(tab, color); - return; - } - - boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; - if (!supportsDarkStatusIcons) { - super.setStatusBarColor(tab, Color.BLACK); - return; - } - - if (!ChromeFeatureList.isInitialized() - || (!ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID) - && !DeviceClassManager.enableAccessibilityLayout())) { - super.setStatusBarColor(tab, ColorUtils.getDefaultThemeColor(getResources(), false)); - return; - } - - boolean incognito = - mTabModelSelectorImpl != null && mTabModelSelectorImpl.isIncognitoSelected(); - super.setStatusBarColor(tab, ColorUtils.getDefaultThemeColor(getResources(), incognito)); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClientAppBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClientAppBroadcastReceiver.java index 3188d56..a8e73851 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClientAppBroadcastReceiver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClientAppBroadcastReceiver.java
@@ -105,7 +105,8 @@ String packageName = intent.getData().getSchemeSpecificPart(); if (packageName != null && packageName.startsWith(WebApkConstants.WEBAPK_PACKAGE_PREFIX)) { - WebApkUma.recordWebApkUninstalled(); + // Native is likely not loaded. Defer recording UMA till the next browser launch. + WebApkUma.deferRecordWebApkUninstalled(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java index 45c5182..87f7f6d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -27,6 +27,7 @@ import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel; import org.chromium.chrome.browser.contextualsearch.ContextualSearchInternalStateController.InternalState; import org.chromium.chrome.browser.contextualsearch.ContextualSearchSelectionController.SelectionType; +import org.chromium.chrome.browser.contextualsearch.ResolvedSearchTerm.CardTag; import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler; import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler.OverrideUrlLoadingResult; import org.chromium.chrome.browser.externalnav.ExternalNavigationParams; @@ -670,19 +671,22 @@ * to the server along with user action results in a subsequent request. * @param searchUrlFull The URL for the full search to present in the overlay, or empty. * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. + * @param cocaCardTag The primary internal Coca card tag for the response, or {@code 0} if none. */ @CalledByNative public void onSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, final String mid, boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, final String contextLanguage, final String thumbnailUrl, - final String caption, final String quickActionUri, final int quickActionCategory, - final long loggedEventId, final String searchUrlFull, final String searchUrlPreload) { - mNetworkCommunicator.handleSearchTermResolutionResponse( - new ResolvedSearchTerm(isNetworkUnavailable, responseCode, searchTerm, displayText, - alternateTerm, mid, doPreventPreload, selectionStartAdjust, - selectionEndAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri, - quickActionCategory, loggedEventId, searchUrlFull, searchUrlPreload)); + final String caption, final String quickActionUri, + @QuickActionCategory final int quickActionCategory, final long loggedEventId, + final String searchUrlFull, final String searchUrlPreload, + @CardTag final int cocaCardTag) { + mNetworkCommunicator.handleSearchTermResolutionResponse(new ResolvedSearchTerm( + isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, mid, + doPreventPreload, selectionStartAdjust, selectionEndAdjust, contextLanguage, + thumbnailUrl, caption, quickActionUri, quickActionCategory, loggedEventId, + searchUrlFull, searchUrlPreload, cocaCardTag)); } @Override @@ -742,6 +746,7 @@ quickActionShown, resolvedSearchTerm.quickActionCategory()); mSearchPanel.getPanelMetrics().setWasQuickActionShown( quickActionShown, resolvedSearchTerm.quickActionCategory()); + ContextualSearchUma.logCardTag(resolvedSearchTerm.cardTagEnum()); // If there was an error, fall back onto a literal search for the selection. // Since we're showing the panel, there must be a selection.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java index bad960bf..87ab5cf3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -12,6 +12,7 @@ import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason; +import org.chromium.chrome.browser.contextualsearch.ResolvedSearchTerm.CardTag; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.components.sync.AndroidSyncSettings; @@ -1433,6 +1434,16 @@ } /** + * Logs the primary CoCa {@link CardTag} for a recent resolve, including {@codeCardTag.CT_NONE} + * when no card or tag, and {@codeCardTag.CT_OTHER} when it's one we do not recognize. + * @param cardTagEnum The primary CoCa card Tag for the result. + */ + public static void logCardTag(@CardTag int cardTagEnum) { + RecordHistogram.recordEnumeratedHistogram( + "Search.ContextualSearch.CardTag", cardTagEnum, CardTag.NUM_ENTRIES); + } + + /** * Logs results-seen when we have a useful Ranker prediction inference. * @param wasPanelSeen Whether the panel was seen. * @param predictionKind An integer reflecting the Ranker prediction, e.g. that this is a good
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java index a8800902..b6b01e0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ResolvedSearchTerm.java
@@ -4,10 +4,36 @@ package org.chromium.chrome.browser.contextualsearch; +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Encapsulates the results of a server Resolve request into a single immutable object. */ public class ResolvedSearchTerm { + @IntDef({CardTag.CT_NONE, CardTag.CT_OTHER, CardTag.CT_HAS_ENTITY, CardTag.CT_BUSINESS, + CardTag.CT_PRODUCT, CardTag.CT_CONTACT, CardTag.CT_EMAIL, CardTag.CT_LOCATION, + CardTag.CT_URL, CardTag.CT_DEFINITION, CardTag.CT_TRANSLATE, + CardTag.CT_CONTEXTUAL_DEFINITION}) + @Retention(RetentionPolicy.SOURCE) + public @interface CardTag { + int CT_NONE = 0; + int CT_OTHER = 1; + int CT_HAS_ENTITY = 2; + int CT_BUSINESS = 3; + int CT_PRODUCT = 4; + int CT_CONTACT = 5; + int CT_EMAIL = 6; + int CT_LOCATION = 7; + int CT_URL = 8; + int CT_DEFINITION = 9; + int CT_TRANSLATE = 10; + int CT_CONTEXTUAL_DEFINITION = 11; + int NUM_ENTRIES = 12; + } + private final boolean mIsNetworkUnavailable; private final int mResponseCode; private final String mSearchTerm; @@ -26,6 +52,8 @@ private final long mLoggedEventId; private final String mSearchUrlFull; private final String mSearchUrlPreload; + @CardTag + private final int mCardTagEnum; /** * Called in response to the @@ -53,13 +81,15 @@ * to the server along with user action results in a subsequent request. * @param searchUrlFull The URL for the full search to present in the overlay, or empty. * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. + * @param cardTag The primary internal Coca card tag for the resolution, or {@code 0} if none. */ ResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, final String mid, boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, final String contextLanguage, final String thumbnailUrl, final String caption, - final String quickActionUri, final int quickActionCategory, final long loggedEventId, - final String searchUrlFull, final String searchUrlPreload) { + final String quickActionUri, @QuickActionCategory final int quickActionCategory, + final long loggedEventId, final String searchUrlFull, final String searchUrlPreload, + final int cardTag) { mIsNetworkUnavailable = isNetworkUnavailable; mResponseCode = responseCode; mSearchTerm = searchTerm; @@ -77,6 +107,7 @@ mLoggedEventId = loggedEventId; mSearchUrlFull = searchUrlFull; mSearchUrlPreload = searchUrlPreload; + mCardTagEnum = fromCocaCardTag(cardTag); } /** @@ -94,7 +125,7 @@ ResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, boolean doPreventPreload) { this(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, "", - doPreventPreload, 0, 0, "", "", "", "", QuickActionCategory.NONE, 0L, "", ""); + doPreventPreload, 0, 0, "", "", "", "", QuickActionCategory.NONE, 0L, "", "", 0); } public boolean isNetworkUnavailable() { @@ -164,4 +195,37 @@ public String searchUrlPreload() { return mSearchUrlPreload; } + + public @CardTag int cardTagEnum() { + return mCardTagEnum; + } + + public static @CardTag int fromCocaCardTag(int internalCocaCardTag) { + switch (internalCocaCardTag) { + case 0: + return CardTag.CT_NONE; + case 43: + return CardTag.CT_HAS_ENTITY; + case 5: + return CardTag.CT_BUSINESS; + case 26: + return CardTag.CT_PRODUCT; + case 8: + return CardTag.CT_CONTACT; + case 13: + return CardTag.CT_EMAIL; + case 21: + return CardTag.CT_LOCATION; + case 40: + return CardTag.CT_URL; + case 11: + return CardTag.CT_DEFINITION; + case 39: + return CardTag.CT_TRANSLATE; + case 47: + return CardTag.CT_CONTEXTUAL_DEFINITION; + default: + return CardTag.CT_OTHER; + } + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 9d217d9..d7732981 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -268,8 +268,8 @@ getToolbarManager().setShouldUpdateToolbarPrimaryColor(false); } - super.setStatusBarColor(toolbarColor, - ColorUtils.isUsingDefaultToolbarColor(getResources(), false, toolbarColor)); + getStatusBarColorController().updateStatusBarColor(ColorUtils.isUsingDefaultToolbarColor( + getResources(), false, getBaseStatusBarColor())); // Properly attach tab's infobar to the view hierarchy, as the main tab might have been // initialized prior to inflation. @@ -511,16 +511,15 @@ if (tab.isPreview()) { final int defaultColor = ColorUtils.getDefaultThemeColor(getResources(), false); manager.onThemeColorChanged(defaultColor, false); - setStatusBarColor(defaultColor, false); mTriggeredPreviewChange = true; } else if (mOriginalColor != manager.getPrimaryColor() && mTriggeredPreviewChange) { manager.onThemeColorChanged(mOriginalColor, false); - setStatusBarColor(mOriginalColor, false); mTriggeredPreviewChange = false; mOriginalColor = 0; } + getStatusBarColorController().updateStatusBarColor(false); manager.setShouldUpdateToolbarPrimaryColor(shouldUpdateOriginal); } }); @@ -774,10 +773,18 @@ } @Override - protected void setStatusBarColor(Tab tab, int color) { - // Intentionally do nothing as CustomTabActivity explicitly sets status bar color. Except - // for Custom Tabs opened by Chrome. - if (mIntentDataProvider.isOpenedByChrome()) super.setStatusBarColor(tab, color); + public int getBaseStatusBarColor() { + if (mIntentDataProvider.isOpenedByChrome()) return super.getBaseStatusBarColor(); + if (getActivityTab() != null && getActivityTab().isPreview()) { + return ColorUtils.getDefaultThemeColor(getResources(), false); + } + return mIntentDataProvider.getToolbarColor(); + } + + @Override + public boolean isStatusBarDefaultThemeColor() { + if (mIntentDataProvider.isOpenedByChrome()) return super.isStatusBarDefaultThemeColor(); + return false; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogManager.java index f6490574..d16b22c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameDialogManager.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.download.home.rename; import android.content.Context; +import android.support.annotation.IntDef; import android.text.TextUtils; import org.chromium.base.Callback; @@ -11,6 +12,9 @@ import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * A class to manage Rename Dialog and Rename Extension Dialog display sequence. * Decides the state transition of two dialog, and provide controller for action events. @@ -34,32 +38,38 @@ private @RenameResult int mLastRenameAttemptResult; private RenameCallback mRenameCallback; - private RenameDialogState mCurState; + private @RenameDialogState int mCurState; - private enum RenameDialogState { + @IntDef({RenameDialogState.NO_DIALOG, RenameDialogState.RENAME_DIALOG_DEFAULT, + RenameDialogState.RENAME_DIALOG_CANCEL, RenameDialogState.RENAME_DIALOG_COMMIT_ERROR, + RenameDialogState.RENAME_EXTENSION_DIALOG_DEFAULT, + RenameDialogState.RENAME_EXTENSION_DIALOG_CANCEL, + RenameDialogState.RENAME_EXTENSION_DIALOG_COMMIT_ERROR}) + @Retention(RetentionPolicy.SOURCE) + private @interface RenameDialogState { /** Initial State, should not show any dialog. */ - NO_DIALOG, + int NO_DIALOG = 0; /** Should show the rename dialog, asking user to input. */ - RENAME_DIALOG_DEFAULT, + int RENAME_DIALOG_DEFAULT = 1; /** Rename dialog intent is aborted. */ - RENAME_DIALOG_CANCEL, + int RENAME_DIALOG_CANCEL = 2; /** Get error message after rename attempt, should show the rename dialog with error message. */ - RENAME_DIALOG_COMMIT_ERROR, + int RENAME_DIALOG_COMMIT_ERROR = 3; /** Should show the rename extension dialog, asking user to confirm the intent of changing extension. */ - RENAME_EXTENSION_DIALOG_DEFAULT, + int RENAME_EXTENSION_DIALOG_DEFAULT = 4; /** Cancel the intent of changing the extension. */ - RENAME_EXTENSION_DIALOG_CANCEL, + int RENAME_EXTENSION_DIALOG_CANCEL = 5; /** * Get error message after rename attempt after confirming the change of extension, * should show the rename dialog with error message. */ - RENAME_EXTENSION_DIALOG_COMMIT_ERROR + int RENAME_EXTENSION_DIALOG_COMMIT_ERROR = 6; } public RenameDialogManager(Context context, ModalDialogManager modalDialogManager) { @@ -98,34 +108,34 @@ * Decider to telling the right order to dialog coordinators depending on the state transition * update. */ - private void processDialogState(RenameDialogState nextState, int dismissalCause) { + private void processDialogState(@RenameDialogState int nextState, int dismissalCause) { switch (nextState) { - case NO_DIALOG: + case RenameDialogState.NO_DIALOG: if (mCurState == RenameDialogState.RENAME_EXTENSION_DIALOG_DEFAULT) { mRenameExtensionDialogCoordinator.dismissDialog(dismissalCause); } else if (mCurState == RenameDialogState.RENAME_DIALOG_DEFAULT) { mRenameDialogCoordinator.dismissDialog(dismissalCause); } break; - case RENAME_DIALOG_DEFAULT: + case RenameDialogState.RENAME_DIALOG_DEFAULT: mRenameDialogCoordinator.showDialog(mOriginalName); break; - case RENAME_DIALOG_COMMIT_ERROR: + case RenameDialogState.RENAME_DIALOG_COMMIT_ERROR: mRenameDialogCoordinator.showDialogWithErrorMessage( mLastAttemptedName, mLastRenameAttemptResult); break; - case RENAME_DIALOG_CANCEL: + case RenameDialogState.RENAME_DIALOG_CANCEL: mRenameDialogCoordinator.dismissDialog(dismissalCause); break; - case RENAME_EXTENSION_DIALOG_DEFAULT: + case RenameDialogState.RENAME_EXTENSION_DIALOG_DEFAULT: mRenameExtensionDialogCoordinator.showDialog(); mRenameDialogCoordinator.dismissDialog(dismissalCause); break; - case RENAME_EXTENSION_DIALOG_CANCEL: + case RenameDialogState.RENAME_EXTENSION_DIALOG_CANCEL: mRenameExtensionDialogCoordinator.dismissDialog(dismissalCause); mRenameDialogCoordinator.showDialog(mLastAttemptedName); break; - case RENAME_EXTENSION_DIALOG_COMMIT_ERROR: + case RenameDialogState.RENAME_EXTENSION_DIALOG_COMMIT_ERROR: mRenameExtensionDialogCoordinator.dismissDialog(dismissalCause); mRenameDialogCoordinator.showDialogWithErrorMessage( mLastAttemptedName, mLastRenameAttemptResult);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java index 9c9f32b..e53dfa55 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -58,6 +58,7 @@ import org.chromium.chrome.browser.media.MediaViewerUtils; import org.chromium.chrome.browser.metrics.LaunchMetrics; import org.chromium.chrome.browser.metrics.PackageMetrics; +import org.chromium.chrome.browser.metrics.WebApkUma; import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; import org.chromium.chrome.browser.notifications.channels.ChannelsUpdater; import org.chromium.chrome.browser.ntp.NewTabPage; @@ -430,6 +431,7 @@ deferredStartupHandler.addDeferredTask( ChromeApplication.getComponent().resolveTwaClearDataDialogRecorder() ::makeDeferredRecordings); + deferredStartupHandler.addDeferredTask(WebApkUma::recordDeferredUma); deferredStartupHandler.addDeferredTask( () -> IncognitoTabLauncher.updateComponentEnabledState());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java index f78e9cc..2135f16 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
@@ -17,6 +17,7 @@ import org.chromium.base.ContextUtils; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.task.AsyncTask; +import org.chromium.chrome.browser.preferences.ChromePreferenceManager; import org.chromium.chrome.browser.util.ConversionUtils; import org.chromium.chrome.browser.webapps.WebApkInfo; @@ -124,6 +125,25 @@ private static final long WEBAPK_EXTRA_INSTALLATION_SPACE_BYTES = 100 * (long) ConversionUtils.BYTES_PER_MEGABYTE; // 100 MB + /** Makes recordings that were deferred in order to not load native. */ + public static void recordDeferredUma() { + ChromePreferenceManager preferenceManager = ChromePreferenceManager.getInstance(); + int numUninstalls = + preferenceManager.readInt(ChromePreferenceManager.WEBAPK_NUMBER_OF_UNINSTALLS); + if (numUninstalls == 0) return; + + for (int i = 0; i < numUninstalls; ++i) { + RecordHistogram.recordBooleanHistogram("WebApk.Uninstall.Browser", true); + } + preferenceManager.writeInt(ChromePreferenceManager.WEBAPK_NUMBER_OF_UNINSTALLS, 0); + } + + /** Sets WebAPK uninstall to be recorded next time that native is loaded. */ + public static void deferRecordWebApkUninstalled() { + ChromePreferenceManager.getInstance().incrementInt( + ChromePreferenceManager.WEBAPK_NUMBER_OF_UNINSTALLS); + } + /** * Records the time point when a request to update a WebAPK is sent to the WebAPK Server. * @param type representing when the update request is sent to the WebAPK server. @@ -221,10 +241,6 @@ } } - public static void recordWebApkUninstalled() { - RecordHistogram.recordBooleanHistogram("WebApk.Uninstall.Browser", true); - } - /** * Records the requests of Android runtime permissions which haven't been granted to Chrome when * Chrome is running in WebAPK runtime.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java index 3b9f00f..77d63a4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java
@@ -136,6 +136,7 @@ private float mMaxRequiredWidth; private float mMaxMatchContentsWidth; private boolean mUseDarkColors = true; + private boolean mShowSuggestionFavicons; private int mLayoutDirection; private WindowAndroid mWindowAndroid; @@ -307,6 +308,9 @@ mEditUrlProcessor = null; } + mShowSuggestionFavicons = + ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_SHOW_SUGGESTION_FAVICONS); + for (Runnable deferredRunnable : mDeferredNativeRunnables) { mHandler.post(deferredRunnable); } @@ -369,6 +373,7 @@ */ void setAutocompleteProfile(Profile profile) { mAutocomplete.setProfile(profile); + mBasicSuggestionProcessor.setProfile(profile); } /** @@ -754,6 +759,9 @@ PropertyModel model = processor.createModelForSuggestion(suggestion); model.set(SuggestionCommonProperties.LAYOUT_DIRECTION, mLayoutDirection); model.set(SuggestionCommonProperties.USE_DARK_COLORS, mUseDarkColors); + model.set(SuggestionCommonProperties.SHOW_SUGGESTION_ICONS, + mShowSuggestionFavicons + || DeviceFormFactor.isNonMultiDisplayContextOnTablet(mContext)); // Before populating the model, add it to the list of current models. If the suggestion // has an image and the image was already cached, it will be updated synchronously and
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionCommonProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionCommonProperties.java index bd61a0f..980af8f6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionCommonProperties.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/SuggestionCommonProperties.java
@@ -18,6 +18,10 @@ /** The layout direction to be applied to the entire suggestion view. */ public static final WritableIntPropertyKey LAYOUT_DIRECTION = new WritableIntPropertyKey(); + /** Whether suggestion icons should be presented. */ + public static final WritableBooleanPropertyKey SHOW_SUGGESTION_ICONS = + new WritableBooleanPropertyKey(); + public static final PropertyKey[] ALL_KEYS = - new PropertyKey[] {USE_DARK_COLORS, LAYOUT_DIRECTION}; + new PropertyKey[] {USE_DARK_COLORS, LAYOUT_DIRECTION, SHOW_SUGGESTION_ICONS}; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java index c3e1b98..96e81476 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.omnibox.suggestions.basic; import android.content.Context; +import android.graphics.Bitmap; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; @@ -16,6 +17,7 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.favicon.LargeIconBridge; import org.chromium.chrome.browser.omnibox.MatchClassificationStyle; import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType; import org.chromium.chrome.browser.omnibox.UrlBarEditingTextStateProvider; @@ -25,6 +27,7 @@ import org.chromium.chrome.browser.omnibox.suggestions.SuggestionCommonProperties; import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties.SuggestionIcon; import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties.SuggestionTextContainer; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.ui.modelutil.PropertyModel; import java.util.ArrayList; @@ -35,7 +38,10 @@ private final Context mContext; private final SuggestionHost mSuggestionHost; private final UrlBarEditingTextStateProvider mUrlBarEditingTextProvider; + private LargeIconBridge mLargeIconBridge; private boolean mEnableNewAnswerLayout; + private boolean mEnableSuggestionFavicons; + private final int mDesiredFaviconWidthPx; /** * @param context An Android context. @@ -45,6 +51,8 @@ public BasicSuggestionProcessor(Context context, SuggestionHost suggestionHost, UrlBarEditingTextStateProvider editingTextProvider) { mContext = context; + mDesiredFaviconWidthPx = mContext.getResources().getDimensionPixelSize( + R.dimen.omnibox_suggestion_favicon_size); mSuggestionHost = suggestionHost; mUrlBarEditingTextProvider = editingTextProvider; } @@ -66,8 +74,6 @@ @Override public void populateModel(OmniboxSuggestion suggestion, PropertyModel model, int position) { - model.set(SuggestionViewProperties.SUGGESTION_ICON_TYPE, - SuggestionViewProperties.SuggestionIcon.UNDEFINED); model.set(SuggestionViewProperties.DELEGATE, mSuggestionHost.createSuggestionViewDelegate(suggestion, position)); @@ -85,6 +91,18 @@ // Experiment: controls presence of certain answer icon types. mEnableNewAnswerLayout = ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_NEW_ANSWER_LAYOUT); + mEnableSuggestionFavicons = + ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_SHOW_SUGGESTION_FAVICONS); + } + + /** + * Updates the profile used for extracting website favicons. + * @param profile The profile to be used. + */ + public void setProfile(Profile profile) { + if (mEnableSuggestionFavicons) { + mLargeIconBridge = new LargeIconBridge(profile); + } } private void setStateForSuggestion(PropertyModel model, OmniboxSuggestion suggestion) { @@ -173,6 +191,17 @@ .omnibox_suggestion_second_line_text_size))); model.set(SuggestionViewProperties.TEXT_LINE_1_MAX_LINES, 1); model.set(SuggestionViewProperties.TEXT_LINE_2_MAX_LINES, 1); + model.set(SuggestionViewProperties.SUGGESTION_ICON_BITMAP, null); + + // Include site favicon if we are presenting URL and have favicon available. + if (mLargeIconBridge != null && suggestion.getUrl() != null) { + mLargeIconBridge.getLargeIconForUrl(suggestion.getUrl(), mDesiredFaviconWidthPx, + (Bitmap icon, int fallbackColor, boolean isFallbackColorDefault, + int iconType) -> { + if (!mSuggestionHost.isActiveModel(model)) return; + model.set(SuggestionViewProperties.SUGGESTION_ICON_BITMAP, icon); + }); + } boolean sameAsTyped = mUrlBarEditingTextProvider.getTextWithoutAutocomplete().trim().equalsIgnoreCase(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionView.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionView.java index 0ae1809b..6a6a6ee2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionView.java
@@ -10,7 +10,7 @@ import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.annotation.ColorRes; -import android.support.annotation.DrawableRes; +import android.support.annotation.DimenRes; import android.support.annotation.IntDef; import android.support.annotation.VisibleForTesting; import android.support.v4.graphics.drawable.DrawableCompat; @@ -49,6 +49,13 @@ int MULTI_LINE_ANSWER = 2; } + @IntDef({SuggestionIconType.FALLBACK, SuggestionIconType.FAVICON}) + @Retention(RetentionPolicy.SOURCE) + @interface SuggestionIconType { + int FALLBACK = 0; + int FAVICON = 1; + } + private final int mSuggestionHeight; private final int mSuggestionAnswerHeight; @SuggestionLayoutType @@ -63,9 +70,14 @@ private final View mRefineView; private TintedDrawable mRefineIcon; + private boolean mUseDarkIconTint; + // Pre-computed offsets in px. - private final int mSuggestionStartOffsetPx; - private final int mSuggestionIconWidthPx; + private int mSuggestionIconAreaSizePx; + private int mSuggestionFaviconSizePx; + // Current suggestion icon dimensions. + private int mSuggestionIconWidthPx; + private int mSuggestionIconHeightPx; /** * Constructs a new omnibox suggestion view. @@ -140,14 +152,11 @@ mRefineWidth = getResources().getDimensionPixelSize(R.dimen.omnibox_suggestion_refine_width); - mRefineViewOffsetPx = getResources().getDimensionPixelSize( R.dimen.omnibox_suggestion_refine_view_modern_end_padding); - - mSuggestionStartOffsetPx = - getResources().getDimensionPixelOffset(R.dimen.omnibox_suggestion_start_offset); - mSuggestionIconWidthPx = - getResources().getDimensionPixelSize(R.dimen.location_bar_icon_width); + mSuggestionFaviconSizePx = + getResources().getDimensionPixelSize(R.dimen.omnibox_suggestion_favicon_size); + setSuggestionIconAreaWidthRes(R.dimen.omnibox_suggestion_start_offset_without_icon); } @Override @@ -257,6 +266,15 @@ return mContentsView.mAnswerImage; } + /** + * Specify area width for the suggestion icon. + * This call generally controls suggestion icon visibility. + * @param areaWidthRes Dimen resource specifying area width. + */ + void setSuggestionIconAreaWidthRes(@DimenRes int areaWidthRes) { + mSuggestionIconAreaSizePx = getResources().getDimensionPixelOffset(areaWidthRes); + } + void setRefinable(boolean refinable) { if (refinable) { mRefineView.setVisibility(VISIBLE); @@ -303,20 +321,26 @@ /** * Updates the suggestion icon to the specified drawable with the specified tint. - * @param resId resource id (may be bitmap or vector) of icon to display - * @param useDarkTint specifies whether to apply dark or light tint to an icon + * @param icon Drawable instance. + * @param type Type / function of the supplied icon. * @param allowTint specifies whether icon should receive a tint or displayed as is. + * @param useDarkTint specifies whether to apply dark or light tint to an icon */ - void setSuggestionIconDrawable(@DrawableRes int resId, boolean useDarkTint, boolean allowTint) { - mContentsView.mSuggestionIcon = AppCompatResources.getDrawable(getContext(), resId); + void setSuggestionIconDrawable( + Drawable icon, @SuggestionIconType int type, boolean allowTint, boolean useDarkTint) { + if (type == SuggestionIconType.FALLBACK) { + mSuggestionIconWidthPx = icon.getIntrinsicWidth(); + mSuggestionIconHeightPx = icon.getIntrinsicHeight(); + } else { + mSuggestionIconWidthPx = mSuggestionFaviconSizePx; + mSuggestionIconHeightPx = mSuggestionFaviconSizePx; + } + + mContentsView.mSuggestionIcon = icon; mContentsView.mAllowTint = allowTint; - mContentsView.mSuggestionIcon.setBounds(0, 0, - mContentsView.mSuggestionIcon.getIntrinsicWidth(), - mContentsView.mSuggestionIcon.getIntrinsicHeight()); + mUseDarkIconTint = useDarkTint; + icon.setBounds(0, 0, mSuggestionIconWidthPx, mSuggestionIconHeightPx); updateSuggestionIconTint(useDarkTint); - // Note: invalidate() does not immediately invoke onDraw(), but schedules it to be called at - // some point in the future. - // https://developer.android.com/reference/android/view/View.html#invalidate() mContentsView.invalidate(); } @@ -429,12 +453,11 @@ if (mSuggestionIcon != null) { canvas.save(); float suggestionIconLeft = - (mSuggestionIconWidthPx - mSuggestionIcon.getIntrinsicWidth()) / 2f; + (mSuggestionIconAreaSizePx - mSuggestionIconWidthPx) / 2f; if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { - suggestionIconLeft += getMeasuredWidth() - mSuggestionIconWidthPx; + suggestionIconLeft += getMeasuredWidth() - mSuggestionIconAreaSizePx; } - float suggestionIconTop = - (getMeasuredHeight() - mSuggestionIcon.getIntrinsicHeight()) / 2f; + float suggestionIconTop = (getMeasuredHeight() - mSuggestionIconHeightPx) / 2f; canvas.translate(suggestionIconLeft, suggestionIconTop); mSuggestionIcon.draw(canvas); canvas.restore(); @@ -498,10 +521,10 @@ final int answerImageBottom = answerImageTop + mAnswerImage.getMeasuredHeight(); final int line1AdditionalStartPadding = mSuggestionDelegate.getAdditionalTextLine1StartPadding( - mTextLine1, r - l - mSuggestionStartOffsetPx); + mTextLine1, r - l - mSuggestionIconAreaSizePx); if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { - int rightStartPos = r - l - mSuggestionStartOffsetPx; + int rightStartPos = r - l - mSuggestionIconAreaSizePx; mTextLine1.layout( 0, line1Top, rightStartPos - line1AdditionalStartPadding, line1Bottom); mAnswerImage.layout(rightStartPos - imageWidth, answerImageTop, rightStartPos, @@ -509,11 +532,11 @@ mTextLine2.layout( 0, line2Top, rightStartPos - (imageWidth + imageSpacing), line2Bottom); } else { - mTextLine1.layout(mSuggestionStartOffsetPx + line1AdditionalStartPadding, line1Top, + mTextLine1.layout(mSuggestionIconAreaSizePx + line1AdditionalStartPadding, line1Top, r - l, line1Bottom); - mAnswerImage.layout(mSuggestionStartOffsetPx, answerImageTop, - mSuggestionStartOffsetPx + imageWidth, answerImageBottom); - mTextLine2.layout(mSuggestionStartOffsetPx + imageWidth + imageSpacing, line2Top, + mAnswerImage.layout(mSuggestionIconAreaSizePx, answerImageTop, + mSuggestionIconAreaSizePx + imageWidth, answerImageBottom); + mTextLine2.layout(mSuggestionIconAreaSizePx + imageWidth + imageSpacing, line2Top, r - l, line2Bottom); } } @@ -524,7 +547,7 @@ // style spans) measured and if that remains the same along with the // height/width of this view, then we should be able to skip measure // properly. - int maxWidth = MeasureSpec.getSize(widthMeasureSpec) - mSuggestionStartOffsetPx; + int maxWidth = MeasureSpec.getSize(widthMeasureSpec) - mSuggestionIconAreaSizePx; mTextLine1.measure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(mSuggestionHeight, MeasureSpec.AT_MOST)); mTextLine2.measure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewProperties.java index 852a1336..576bbb1f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewProperties.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewProperties.java
@@ -107,6 +107,9 @@ /** The suggestion icon type shown. */ public static final WritableIntPropertyKey SUGGESTION_ICON_TYPE = new WritableIntPropertyKey(); + /** Bitmap (typically site favicon) to be displayed as a suggestion icon. */ + public static final WritableObjectPropertyKey<Bitmap> SUGGESTION_ICON_BITMAP = + new WritableObjectPropertyKey<>(); /** * The sizing information for the first line of text. @@ -152,7 +155,7 @@ HAS_ANSWER_IMAGE, ANSWER_IMAGE, REFINABLE, SUGGESTION_ICON_TYPE, TEXT_LINE_1_SIZING, TEXT_LINE_1_MAX_LINES, TEXT_LINE_1_TEXT_COLOR, TEXT_LINE_1_TEXT_DIRECTION, TEXT_LINE_1_TEXT, TEXT_LINE_2_SIZING, TEXT_LINE_2_MAX_LINES, TEXT_LINE_2_TEXT_COLOR, - TEXT_LINE_2_TEXT_DIRECTION, TEXT_LINE_2_TEXT}; + TEXT_LINE_2_TEXT_DIRECTION, TEXT_LINE_2_TEXT, SUGGESTION_ICON_BITMAP}; public static final PropertyKey[] ALL_KEYS = PropertyModel.concatKeys(ALL_UNIQUE_KEYS, SuggestionCommonProperties.ALL_KEYS);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewViewBinder.java index 78bcf9d..08f5f7c19 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionViewViewBinder.java
@@ -4,7 +4,11 @@ package org.chromium.chrome.browser.omnibox.suggestions.basic; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.support.v4.view.ViewCompat; +import android.support.v7.content.res.AppCompatResources; import android.text.Spannable; import android.text.TextUtils; import android.util.Pair; @@ -14,8 +18,8 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.omnibox.suggestions.SuggestionCommonProperties; +import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionView.SuggestionIconType; import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties.SuggestionIcon; -import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; @@ -55,39 +59,9 @@ if (refinable) { view.initRefineIcon(model.get(SuggestionCommonProperties.USE_DARK_COLORS)); } - } else if (SuggestionViewProperties.SUGGESTION_ICON_TYPE.equals(propertyKey)) { - if (!DeviceFormFactor.isNonMultiDisplayContextOnTablet(view.getContext())) return; - - @SuggestionIcon - int type = model.get(SuggestionViewProperties.SUGGESTION_ICON_TYPE); - - if (type == SuggestionIcon.UNDEFINED) return; - boolean allowTint = true; - - int drawableId = R.drawable.ic_omnibox_page; - switch (type) { - case SuggestionIcon.BOOKMARK: - drawableId = R.drawable.btn_star; - break; - case SuggestionIcon.MAGNIFIER: - drawableId = R.drawable.ic_suggestion_magnifier; - break; - case SuggestionIcon.HISTORY: - drawableId = R.drawable.ic_suggestion_history; - break; - case SuggestionIcon.VOICE: - drawableId = R.drawable.btn_mic; - break; - case SuggestionIcon.CALCULATOR: - allowTint = false; - drawableId = R.drawable.ic_equals_sign_round; - break; - default: - break; - } - - view.setSuggestionIconDrawable( - drawableId, model.get(SuggestionCommonProperties.USE_DARK_COLORS), allowTint); + } else if (SuggestionViewProperties.SUGGESTION_ICON_TYPE.equals(propertyKey) + || SuggestionViewProperties.SUGGESTION_ICON_BITMAP.equals(propertyKey)) { + updateSuggestionIcon(view, model); } else if (SuggestionViewProperties.TEXT_LINE_1_SIZING.equals(propertyKey)) { Pair<Integer, Integer> sizing = model.get(SuggestionViewProperties.TEXT_LINE_1_SIZING); view.getTextLine1().setTextSize(sizing.first, sizing.second); @@ -116,6 +90,11 @@ } else if (SuggestionViewProperties.TEXT_LINE_2_TEXT_DIRECTION.equals(propertyKey)) { view.getTextLine2().setTextDirection( model.get(SuggestionViewProperties.TEXT_LINE_2_TEXT_DIRECTION)); + } else if (SuggestionCommonProperties.SHOW_SUGGESTION_ICONS.equals(propertyKey)) { + boolean showIcons = model.get(SuggestionCommonProperties.SHOW_SUGGESTION_ICONS); + view.setSuggestionIconAreaWidthRes(showIcons + ? R.dimen.omnibox_suggestion_start_offset_with_icon + : R.dimen.omnibox_suggestion_start_offset_without_icon); } else if (SuggestionViewProperties.TEXT_LINE_2_TEXT.equals(propertyKey)) { Spannable line2Text = model.get(SuggestionViewProperties.TEXT_LINE_2_TEXT).text; if (TextUtils.isEmpty(line2Text)) { @@ -156,4 +135,57 @@ : SuggestionView.SuggestionLayoutType.ANSWER); } } + + private static void updateSuggestionIcon(SuggestionView view, PropertyModel model) { + if (!model.get(SuggestionCommonProperties.SHOW_SUGGESTION_ICONS)) return; + + Drawable icon = null; + boolean allowTint = true; + @SuggestionIconType + int iconType = SuggestionIconType.FALLBACK; + + Bitmap iconBitmap = model.get(SuggestionViewProperties.SUGGESTION_ICON_BITMAP); + if (iconBitmap != null) { + icon = new BitmapDrawable(iconBitmap); + allowTint = false; + iconType = SuggestionIconType.FAVICON; + } else { + @SuggestionIcon + int type = model.get(SuggestionViewProperties.SUGGESTION_ICON_TYPE); + + int drawableId = R.drawable.ic_omnibox_page; + switch (type) { + case SuggestionIcon.GLOBE: + drawableId = R.drawable.ic_globe_24dp; + break; + case SuggestionIcon.BOOKMARK: + drawableId = R.drawable.btn_star; + break; + case SuggestionIcon.MAGNIFIER: + drawableId = R.drawable.ic_suggestion_magnifier; + break; + case SuggestionIcon.HISTORY: + drawableId = R.drawable.ic_suggestion_history; + break; + case SuggestionIcon.VOICE: + drawableId = R.drawable.btn_mic; + break; + case SuggestionIcon.CALCULATOR: + drawableId = R.drawable.ic_equals_sign_round; + allowTint = false; + break; + case SuggestionIcon.UNDEFINED: + // Since SuggestionViews may be re-used, there is a risk we would be + // presenting an stale favicon already. + assert false : "Unknown suggestion icon type."; + break; + default: + break; + } + icon = AppCompatResources.getDrawable(view.getContext(), drawableId); + } + + view.setSuggestionIconDrawable( + icon, iconType, allowTint, model.get(SuggestionCommonProperties.USE_DARK_COLORS)); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java index d2bb0fb..10dd1e6a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -290,6 +290,9 @@ public static final String TWA_DIALOG_NUMBER_OF_DIMSISSALS_ON_CLEAR_DATA = "twa_dialog_number_of_dismissals_on_clear_data"; + /** Key for deferred recording of WebAPK uninstalls. */ + public static final String WEBAPK_NUMBER_OF_UNINSTALLS = "webapk_number_of_uninstalls"; + public static final String INTEREST_FEED_CONTENT_SUGGESTIONS_KEY = "interest_feed_content_suggestions";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java index cccc7062..ff0135f4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
@@ -139,13 +139,6 @@ } /** - * @return Whether the theme color for this tab is the default color. - */ - public boolean isDefaultColor() { - return mTab.isNativePage() || mDefaultColor == getColor(); - } - - /** * @return The default theme color for this tab. */ @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index 8d4cdef..4b59128 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -339,6 +339,7 @@ setMenuHandler(menuHandler); mToolbar.initialize(mLocationBarModel, this, mAppMenuButtonHelper); + mToolbar.addUrlExpansionObserver(activity.getStatusBarColorController()); mAppMenuPropertiesDelegate = appMenuPropertiesDelegate; @@ -1171,6 +1172,8 @@ if (mLocationBar != null) { mLocationBar.removeUrlFocusChangeListener(this); } + + mToolbar.removeUrlExpansionObserver(mActivity.getStatusBarColorController()); mToolbar.destroy(); if (mTabObserver != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java index 377bb29..e2d5d0c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -23,6 +23,7 @@ import android.widget.ImageButton; import android.widget.ProgressBar; +import org.chromium.base.ObserverList; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.ThemeColorProvider; @@ -42,6 +43,7 @@ import org.chromium.chrome.browser.toolbar.TabCountProvider; import org.chromium.chrome.browser.toolbar.ToolbarDataProvider; import org.chromium.chrome.browser.toolbar.ToolbarTabController; +import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator.UrlExpansionObserver; import org.chromium.chrome.browser.util.ColorUtils; import org.chromium.chrome.browser.util.ViewUtils; import org.chromium.chrome.browser.widget.ToolbarProgressBar; @@ -57,6 +59,8 @@ extends FrameLayout implements TintObserver, ThemeColorObserver { private Invalidator mInvalidator; + protected final ObserverList<UrlExpansionObserver> mUrlExpansionObservers = + new ObserverList<>(); private final int[] mTempPosition = new int[2]; /** @@ -68,6 +72,7 @@ private ToolbarDataProvider mToolbarDataProvider; private ToolbarTabController mToolbarTabController; + @Nullable protected ToolbarProgressBar mProgressBar; @@ -135,6 +140,20 @@ } /** + * @param urlExpansionObserver The observer that observes URL expansion percentage change. + */ + void addUrlExpansionObserver(UrlExpansionObserver urlExpansionObserver) { + mUrlExpansionObservers.addObserver(urlExpansionObserver); + } + + /** + * @param urlExpansionObserver The observer that observes URL expansion percentage change. + */ + void removeUrlExpansionObserver(UrlExpansionObserver urlExpansionObserver) { + mUrlExpansionObservers.removeObserver(urlExpansionObserver); + } + + /** * @param themeColorProvider The {@link ThemeColorProvider} used for tinting the toolbar * buttons. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java index 4f8cf621..f35e9da 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -69,6 +69,7 @@ import org.chromium.chrome.browser.toolbar.TabCountProvider; import org.chromium.chrome.browser.toolbar.TabCountProvider.TabCountObserver; import org.chromium.chrome.browser.toolbar.TabSwitcherDrawable; +import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator.UrlExpansionObserver; import org.chromium.chrome.browser.util.ColorUtils; import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.MathUtils; @@ -716,13 +717,15 @@ Resources res = getResources(); switch (visualState) { case VisualState.NEW_TAB_NORMAL: - if (mUrlExpansionPercent == 1.f) { - // When the location bar reaches the top of the screen, the background needs - // to change back to the default, solid color so that the NTP content is - // not visible beneath the toolbar. - return ColorUtils.getDefaultThemeColor(getResources(), false); - } - return Color.TRANSPARENT; + // When the NTP fake search box is visible, the background color should be + // transparent. When the location bar reaches the top of the screen (i.e. location + // bar is fully expanded), the background needs to change back to the default + // toolbar color so that the NTP content is not visible beneath the toolbar. In + // between the transition, we set a translucent default toolbar color based on + // the expansion percentage of the toolbar. + return android.support.v4.graphics.ColorUtils.setAlphaComponent( + ColorUtils.getDefaultThemeColor(getResources(), false), + Math.round(mUrlExpansionPercent * 255)); case VisualState.NORMAL: return ColorUtils.getDefaultThemeColor(getResources(), false); case VisualState.INCOGNITO: @@ -912,6 +915,9 @@ private void updateUrlExpansionPercent() { mUrlExpansionPercent = Math.max(mNtpSearchBoxScrollPercent, mUrlFocusChangePercent); + for (UrlExpansionObserver observer : mUrlExpansionObservers) { + observer.onUrlExpansionPercentageChanged(mUrlExpansionPercent); + } assert mUrlExpansionPercent >= 0; assert mUrlExpansionPercent <= 1; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java index c886339..24f3dc0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -37,6 +37,19 @@ public class TopToolbarCoordinator implements Toolbar { static final int TAB_SWITCHER_MODE_NORMAL_ANIMATION_DURATION_MS = 200; + /** + * Observes toolbar URL expansion percentage change. + */ + public interface UrlExpansionObserver { + /** + * Notified when toolbar URL expansion percentage changes. + * @param percentage The toolbar expansion percentage. 0 indicates that the URL bar is not + * expanded. 1 indicates that the URL bar is expanded to the maximum + * width. + */ + void onUrlExpansionPercentageChanged(float percentage); + } + private ToolbarLayout mToolbarLayout; /** @@ -121,6 +134,20 @@ } /** + * @param urlExpansionObserver The observer that observes URL expansion percentage change. + */ + public void addUrlExpansionObserver(UrlExpansionObserver urlExpansionObserver) { + mToolbarLayout.addUrlExpansionObserver(urlExpansionObserver); + } + + /** + * @param urlExpansionObserver The observer that observes URL expansion percentage change. + */ + public void removeUrlExpansionObserver(UrlExpansionObserver urlExpansionObserver) { + mToolbarLayout.removeUrlExpansionObserver(urlExpansionObserver); + } + + /** * @see View#addOnAttachStateChangeListener(View.OnAttachStateChangeListener) */ public void addOnAttachStateChangeListener(View.OnAttachStateChangeListener listener) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java new file mode 100644 index 0000000..df32bb6 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/system/StatusBarColorController.java
@@ -0,0 +1,304 @@ +// 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. + +package org.chromium.chrome.browser.ui.system; + +import android.content.res.Resources; +import android.graphics.Color; +import android.os.Build; +import android.support.annotation.ColorInt; +import android.support.annotation.Nullable; +import android.view.View; +import android.view.Window; + +import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ActivityTabProvider; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver; +import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; +import org.chromium.chrome.browser.device.DeviceClassManager; +import org.chromium.chrome.browser.lifecycle.Destroyable; +import org.chromium.chrome.browser.ntp.NewTabPage; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabThemeColorHelper; +import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; +import org.chromium.chrome.browser.tabmodel.TabSelectionType; +import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator; +import org.chromium.chrome.browser.util.ColorUtils; +import org.chromium.chrome.browser.widget.ScrimView; +import org.chromium.ui.UiUtils; + +/** + * Maintains the status bar color for a {@link ChromeActivity}. + */ +public class StatusBarColorController + implements Destroyable, TopToolbarCoordinator.UrlExpansionObserver { + public static @ColorInt int UNDEFINED_STATUS_BAR_COLOR = Color.TRANSPARENT; + + /** + * Provides the base status bar color. + */ + public interface StatusBarColorProvider { + /** + * @return The base status bar color to override default colors used in the + * {@link StatusBarColorController}. If this returns a color other than + * {@link #UNDEFINED_STATUS_BAR_COLOR}, the {@link StatusBarColorController} will + * always use the color provided by this method to adjust the status bar color. This + * color may be used as-is or adjusted due to a scrim overlay or Android version. + */ + @ColorInt + int getBaseStatusBarColor(); + + /** + * @return Whether the color provided at {@link #getBaseStatusBarColor()} is considered a + * default theme color. If false, we use a darkened status bar color based on the + * base status bar color on pre-M instead of the default status bar color. This + * value will be ignored if {@link #getBaseStatusBarColor()} returns + * {@link #UNDEFINED_STATUS_BAR_COLOR}. + */ + boolean isStatusBarDefaultThemeColor(); + } + + private final Window mWindow; + private final boolean mIsTablet; + private final @Nullable OverviewModeBehavior mOverviewModeBehavior; + private final StatusBarColorProvider mStatusBarColorProvider; + private final ScrimView.StatusBarScrimDelegate mStatusBarScrimDelegate; + private final ActivityTabProvider.ActivityTabTabObserver mStatusBarColorTabObserver; + private final TabModelSelectorObserver mTabModelSelectorObserver; + + private final @ColorInt int mStandardPrimaryBgColor; + private final @ColorInt int mIncognitoPrimaryBgColor; + private final @ColorInt int mStandardDefaultThemeColor; + private final @ColorInt int mIncognitoDefaultThemeColor; + + private @Nullable TabModelSelector mTabModelSelector; + private @Nullable OverviewModeBehavior.OverviewModeObserver mOverviewModeObserver; + private @Nullable Tab mCurrentTab; + private boolean mIsInOverviewMode; + private boolean mIsIncognito; + + private @ColorInt int mScrimColor; + private float mStatusBarScrimFraction; + + private float mToolbarUrlExpansionPercentage; + + /** + * @param chromeActivity The {@link ChromeActivity} that this class is attached to. + */ + public StatusBarColorController(ChromeActivity chromeActivity) { + mWindow = chromeActivity.getWindow(); + mIsTablet = chromeActivity.isTablet(); + mOverviewModeBehavior = chromeActivity.getOverviewModeBehavior(); + mStatusBarColorProvider = chromeActivity; + mStatusBarScrimDelegate = (fraction) -> { + mStatusBarScrimFraction = fraction; + updateStatusBarColor(null); + }; + + Resources resources = chromeActivity.getResources(); + mStandardPrimaryBgColor = ColorUtils.getPrimaryBackgroundColor(resources, false); + mIncognitoPrimaryBgColor = ColorUtils.getPrimaryBackgroundColor(resources, true); + mStandardDefaultThemeColor = ColorUtils.getDefaultThemeColor(resources, false); + mIncognitoDefaultThemeColor = ColorUtils.getDefaultThemeColor(resources, true); + + mStatusBarColorTabObserver = new ActivityTabProvider.ActivityTabTabObserver( + chromeActivity.getActivityTabProvider()) { + @Override + public void onShown(Tab tab, @TabSelectionType int type) { + updateStatusBarColor(tab); + } + + @Override + public void onDidChangeThemeColor(Tab tab, int color) { + updateStatusBarColor(tab); + } + + @Override + protected void onObservingDifferentTab(Tab tab) { + mCurrentTab = tab; + + // |tab == null| means we're switching tabs - by the tab switcher or by swiping + // on the omnibox. These cases are dealt with differently, elsewhere. + if (tab == null) return; + updateStatusBarColor(tab); + } + }; + + mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() { + @Override + public void onTabModelSelected(TabModel newModel, TabModel oldModel) { + mIsIncognito = newModel.isIncognito(); + + // When opening a new Incognito Tab from a normal Tab (or vice versa), the + // status bar color is updated. However, this update is triggered after the + // animation, so we update here for the duration of the new Tab animation. + // See https://crbug.com/917689. + updateStatusBarColor(false); + } + }; + + if (mOverviewModeBehavior != null) { + mOverviewModeObserver = new EmptyOverviewModeObserver() { + @Override + public void onOverviewModeStartedShowing(boolean showToolbar) { + mIsInOverviewMode = true; + updateStatusBarColor(false); + } + + @Override + public void onOverviewModeFinishedHiding() { + mIsInOverviewMode = false; + updateStatusBarColor(mCurrentTab); + } + }; + mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver); + } + + chromeActivity.getLifecycleDispatcher().register(this); + } + + // Destroyable implementation. + @Override + public void destroy() { + mStatusBarColorTabObserver.destroy(); + if (mOverviewModeBehavior != null) { + mOverviewModeBehavior.removeOverviewModeObserver(mOverviewModeObserver); + } + if (mTabModelSelector != null) { + mTabModelSelector.removeObserver(mTabModelSelectorObserver); + } + } + + // TopToolbarCoordinator.UrlExpansionObserver implementation. + @Override + public void onUrlExpansionPercentageChanged(float percentage) { + mToolbarUrlExpansionPercentage = percentage; + if (isStandardNTP()) updateStatusBarColor(mCurrentTab); + } + + /** + * @param tabModelSelector The {@link TabModelSelector} to check whether incognito model is + * selected. + */ + public void setTabModelSelector(TabModelSelector tabModelSelector) { + assert mTabModelSelector == null : "mTabModelSelector should only be set once."; + mTabModelSelector = tabModelSelector; + if (mTabModelSelector != null) mTabModelSelector.addObserver(mTabModelSelectorObserver); + } + + /** + * @return The {@link ScrimView.StatusBarScrimDelegate} that adjusts the status bar color based + * on the scrim offset. + */ + public ScrimView.StatusBarScrimDelegate getStatusBarScrimDelegate() { + return mStatusBarScrimDelegate; + } + + /** + * @param isDefaultThemeColor Whether default theme color is used for the status bar color. + */ + public void updateStatusBarColor(boolean isDefaultThemeColor) { + setStatusBarColor(calculateBaseStatusBarColor(), isDefaultThemeColor); + } + + /** + * @param tab The tab that is currently showing, used to determine whether {@code color} is the + * default theme color. + */ + private void updateStatusBarColor(@Nullable Tab tab) { + setStatusBarColor(calculateBaseStatusBarColor(), isDefaultThemeColor(tab)); + } + + private @ColorInt int calculateBaseStatusBarColor() { + // Return overridden status bar color from StatusBarColorProvider if specified. + final int baseStatusBarColor = mStatusBarColorProvider.getBaseStatusBarColor(); + if (baseStatusBarColor != UNDEFINED_STATUS_BAR_COLOR) return baseStatusBarColor; + + // We don't adjust status bar color for tablet when status bar color is not overridden by + // StatusBarColorProvider. + if (mIsTablet) return Color.BLACK; + + // Return status bar color in overview mode. + if (mIsInOverviewMode) { + boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; + if (!supportsDarkStatusIcons) return Color.BLACK; + + if (!ChromeFeatureList.isInitialized() + || (!ChromeFeatureList.isEnabled( + ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID) + && !DeviceClassManager.enableAccessibilityLayout())) { + return mStandardPrimaryBgColor; + } + + return mIsIncognito ? mIncognitoPrimaryBgColor : mStandardPrimaryBgColor; + } + + // Return status bar color in standard NewTabPage. + if (isStandardNTP()) { + return ColorUtils.getColorWithOverlay( + TabThemeColorHelper.getBackgroundColor(mCurrentTab), + TabThemeColorHelper.getColor(mCurrentTab), mToolbarUrlExpansionPercentage); + } + + // Return status bar color to match the toolbar. + if (mCurrentTab != null) return TabThemeColorHelper.getColor(mCurrentTab); + + // This could happen when tab is not initialized (e.g. on startup). + return mIsIncognito ? mIncognitoDefaultThemeColor : mStandardDefaultThemeColor; + } + + private boolean isDefaultThemeColor(Tab tab) { + if (mStatusBarColorProvider.getBaseStatusBarColor() != UNDEFINED_STATUS_BAR_COLOR) { + return mStatusBarColorProvider.isStatusBarDefaultThemeColor(); + } + + return tab != null && TabThemeColorHelper.isDefaultColorUsed(tab); + } + + /** + * Set device status bar to a given color. + * @param color The color that the status bar should be set to. + * @param isDefaultThemeColor Whether {@code color} is the default theme color. + */ + private void setStatusBarColor(int color, boolean isDefaultThemeColor) { + if (UiUtils.isSystemUiThemingDisabled()) return; + + int statusBarColor = color; + boolean supportsDarkStatusIcons = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; + View root = mWindow.getDecorView().getRootView(); + Resources resources = root.getResources(); + if (supportsDarkStatusIcons) { + if (mScrimColor == 0) { + mScrimColor = ApiCompatibilityUtils.getColor(resources, R.color.black_alpha_65); + } + // Apply a color overlay if the scrim is showing. + float scrimColorAlpha = (mScrimColor >>> 24) / 255f; + int scrimColorOpaque = mScrimColor & 0xFF000000; + statusBarColor = ColorUtils.getColorWithOverlay( + statusBarColor, scrimColorOpaque, mStatusBarScrimFraction * scrimColorAlpha); + + boolean needsDarkStatusBarIcons = + !ColorUtils.shouldUseLightForegroundOnBackground(statusBarColor); + ApiCompatibilityUtils.setStatusBarIconColor(root, needsDarkStatusBarIcons); + } else { + statusBarColor = isDefaultThemeColor ? Color.BLACK + : ColorUtils.getDarkenedColorForStatusBar(color); + } + + ApiCompatibilityUtils.setStatusBarColor(mWindow, statusBarColor); + } + + /** + * @return Whether or not the current tab is a new tab page in standard mode. + */ + private boolean isStandardNTP() { + return mCurrentTab != null && NewTabPage.isNTPUrl(mCurrentTab.getUrl()) && !mIsIncognito; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java index 503967d..2b0b3d3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -771,10 +771,8 @@ // around an issue where the status bars go transparent and can't be seen on top of the page // content when users swipe them in or they appear because the on-screen keyboard was // triggered. - int statusBarColor = Color.BLACK; if (mBrandColor != null && mWebappInfo.displayMode() != WebDisplayMode.FULLSCREEN) { taskDescriptionColor = mBrandColor; - statusBarColor = mBrandColor; if (getToolbarManager() != null) { getToolbarManager().onThemeColorChanged(mBrandColor, false); } @@ -782,21 +780,21 @@ ApiCompatibilityUtils.setTaskDescription(this, title, icon, ColorUtils.getOpaqueColor(taskDescriptionColor)); - setStatusBarColor(statusBarColor, statusBarColor != Color.BLACK); + getStatusBarColorController().updateStatusBarColor(isStatusBarDefaultThemeColor()); } @Override - protected void setStatusBarColor(Tab tab, int color) { - // Ignore any color that is not the brand color. - super.setStatusBarColor( - mBrandColor == null ? Color.BLACK : mBrandColor, mBrandColor == null); + public int getBaseStatusBarColor() { + return isStatusBarDefaultThemeColor() ? Color.BLACK : mBrandColor; } @Override - protected void setStatusBarColor(int color, boolean isDefaultThemeColor) { - // Ignore any color that is not the brand color. - super.setStatusBarColor( - mBrandColor == null ? Color.BLACK : mBrandColor, mBrandColor == null); + public boolean isStatusBarDefaultThemeColor() { + // Don't use the brand color for the status bars if we're in display: fullscreen. This works + // around an issue where the status bars go transparent and can't be seen on top of the page + // content when users swipe them in or they appear because the on-screen keyboard was + // triggered. + return mBrandColor == null || mWebappInfo.displayMode() == WebDisplayMode.FULLSCREEN; } @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java index 5766fd2b..1e00f24 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -167,7 +167,7 @@ /** * Class that represents a fake tap triggered contextual search. */ - public class MutableResolvedSearchTerm extends ResolvedSearchTerm { + public static class MutableResolvedSearchTerm extends ResolvedSearchTerm { // Fields that we can override in the ResolvedSearchTerm. private String mContextLanguage; private long mLoggedEventId; @@ -193,8 +193,7 @@ * Called in response to the * {@link ContextualSearchManager#nativeStartSearchTermResolutionRequest} method. * @param isNetworkUnavailable Indicates if the network is unavailable, in which case all - * other - * parameters should be ignored. + * other parameters should be ignored. * @param responseCode The HTTP response code. If the code is not OK, the query should be * ignored. * @param searchTerm The term to use in our subsequent search. @@ -204,8 +203,7 @@ * A MID is a unique identifier for an entity in the Search Knowledge Graph. * @param doPreventPreload Whether we should prevent preloading on this search. * @param selectionStartAdjust A positive number of characters that the start of the - * existing - * selection should be expanded by. + * existing selection should be expanded by. * @param selectionEndAdjust A positive number of characters that the end of the existing * selection should be expanded by. * @param contextLanguage The language of the original search term, or an empty string. @@ -214,22 +212,24 @@ * @param quickActionUri The URI for the intent associated with the quick action. * @param quickActionCategory The {@link QuickActionCategory} for the quick action. * @param loggedEventId The EventID logged by the server, which should be recorded and sent - * back - * to the server along with user action results in a subsequent request. + * back to the server along with user action results in a subsequent request. * @param searchUrlFull The URL for the full search to present in the overlay, or empty. * @param searchUrlPreload The URL for the search to preload into the overlay, or empty. + * @param cardTag The primary internal Coca card tag for the resolution, or {@code 0} if + * none. */ MutableResolvedSearchTerm(boolean isNetworkUnavailable, int responseCode, final String searchTerm, final String displayText, final String alternateTerm, final String mid, boolean doPreventPreload, int selectionStartAdjust, int selectionEndAdjust, final String contextLanguage, final String thumbnailUrl, - final String caption, final String quickActionUri, final int quickActionCategory, - final long loggedEventId, final String searchUrlFull, - final String searchUrlPreload) { + final String caption, final String quickActionUri, + final @QuickActionCategory int quickActionCategory, final long loggedEventId, + final String searchUrlFull, final String searchUrlPreload, + final @CardTag int cardTag) { super(isNetworkUnavailable, responseCode, searchTerm, displayText, alternateTerm, mid, doPreventPreload, selectionStartAdjust, selectionEndAdjust, contextLanguage, thumbnailUrl, caption, quickActionUri, quickActionCategory, loggedEventId, - searchUrlFull, searchUrlPreload); + searchUrlFull, searchUrlPreload, cardTag); } @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index bcaf036d..a391b42a0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.contextualsearch; import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE; +import static org.chromium.chrome.browser.contextualsearch.ContextualSearchFakeServer.MutableResolvedSearchTerm; import static org.chromium.chrome.browser.multiwindow.MultiWindowTestHelper.waitForSecondChromeTabbedActivity; import static org.chromium.chrome.browser.multiwindow.MultiWindowTestHelper.waitForTabs; import static org.chromium.content_public.browser.test.util.CriteriaHelper.DEFAULT_POLLING_INTERVAL; @@ -2313,9 +2314,11 @@ clickWordNode("intelligence"); waitForPanelToPeek(); - fakeResponse(new ResolvedSearchTerm(false, 200, "Intelligence", - "United States Intelligence", "alternate-term", null, false, -14, 0, "", "", "", "", - QuickActionCategory.NONE, 0, "", "")); + MutableResolvedSearchTerm resolvedSearchTerm = + new ContextualSearchFakeServer.MutableResolvedSearchTerm( + false, 200, "Intelligence", "United States Intelligence"); + resolvedSearchTerm.setSelectionStartAdjust(-14); + fakeResponse(resolvedSearchTerm); waitForSelectionToBe("United States Intelligence"); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java index fe42d1f..c7b7479 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
@@ -99,7 +99,7 @@ public void startSearchTermResolutionRequest(String selection) { // Skip native calls and immediately "resolve" the search term. onSearchTermResolutionResponse(true, 200, selection, selection, "", "", false, 0, 10, - "", "", "", "", QuickActionCategory.NONE, 0, "", ""); + "", "", "", "", QuickActionCategory.NONE, 0, "", "", 0); } @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageTest.java index 1eb52a1..a89efdd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageTest.java
@@ -27,6 +27,7 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; @@ -113,6 +114,7 @@ @Test @SmallTest + @DisabledTest @Feature({"ExploreSites", "RenderTest"}) public void testScrolledLayout_withBack() throws Exception { final int scrollPosition = 2;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java index 3415301..9f6cfb3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
@@ -128,28 +128,32 @@ // Verify that we're actually rendering WebXR/VR content and that it's blue (the canvas // is set to blue while presenting). This could be a proper RenderTest, but it's less // overhead to just directly check a pixel. - CriteriaHelper.pollInstrumentationThread( - () - -> { - // Creating temporary directories doesn't seem to work, so use a fixed location - // that we know we can write to. - File dumpDirectory = new File(UrlUtils.getIsolatedTestFilePath( - "chrome/test/data/vr/framebuffer_dumps")); - if (!dumpDirectory.exists() && !dumpDirectory.isDirectory()) { - Assert.assertTrue("Failed to make framebuffer dump directory", - dumpDirectory.mkdirs()); - } - File baseImagePath = new File(dumpDirectory, "dump"); - NativeUiUtils.dumpNextFramesFrameBuffers(baseImagePath.getPath()); - String filepath = baseImagePath.getPath() - + NativeUiUtils.FRAME_BUFFER_SUFFIX_WEB_XR_CONTENT + ".png"; - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - Bitmap bitmap = BitmapFactory.decodeFile(filepath, options); - return bitmap != null && Color.BLUE == bitmap.getPixel(0, 0); - }, - "Immersive session started, but browser not visibly in VR", POLL_TIMEOUT_LONG_MS, - POLL_CHECK_INTERVAL_LONG_MS); + // TODO(https://crbug.com/947252): Run this part unconditionally once the cause of the + // flakiness on older devices is fixed. + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { + CriteriaHelper.pollInstrumentationThread( + () + -> { + // Creating temporary directories doesn't seem to work, so use a fixed + // location that we know we can write to. + File dumpDirectory = new File(UrlUtils.getIsolatedTestFilePath( + "chrome/test/data/vr/framebuffer_dumps")); + if (!dumpDirectory.exists() && !dumpDirectory.isDirectory()) { + Assert.assertTrue("Failed to make framebuffer dump directory", + dumpDirectory.mkdirs()); + } + File baseImagePath = new File(dumpDirectory, "dump"); + NativeUiUtils.dumpNextFramesFrameBuffers(baseImagePath.getPath()); + String filepath = baseImagePath.getPath() + + NativeUiUtils.FRAME_BUFFER_SUFFIX_WEB_XR_CONTENT + ".png"; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + Bitmap bitmap = BitmapFactory.decodeFile(filepath, options); + return bitmap != null && Color.BLUE == bitmap.getPixel(0, 0); + }, + "Immersive session started, but browser not visibly in VR", + POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_LONG_MS); + } framework.assertNoJavaScriptErrors(); }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 0bb9306..5544c32 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -6662,6 +6662,10 @@ desc="Used to indicate that there was an error starting the microphone to record speech input."> Please check your microphone. </message> + <message name="IDS_NEW_TAB_VOICE_CLOSE_TOOLTIP" + desc="Tooltip text for the voice search dialog close button."> + Close + </message> <message name="IDS_NEW_TAB_VOICE_DETAILS" desc="Used as text for a link to a help web page, in case microphone permission has not been granted by the user."> Details
diff --git a/chrome/app/generated_resources_grd/IDS_NEW_TAB_VOICE_CLOSE_TOOLTIP.png.sha1 b/chrome/app/generated_resources_grd/IDS_NEW_TAB_VOICE_CLOSE_TOOLTIP.png.sha1 new file mode 100644 index 0000000..f6bc400 --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NEW_TAB_VOICE_CLOSE_TOOLTIP.png.sha1
@@ -0,0 +1 @@ +16af3aa45e408c5d17466171d79d96f2f96317e6 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 475ad2c2..7a344843 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -146,6 +146,8 @@ "background_sync/background_sync_controller_factory.h", "background_sync/background_sync_controller_impl.cc", "background_sync/background_sync_controller_impl.h", + "background_sync/background_sync_metrics.cc", + "background_sync/background_sync_metrics.h", "background_sync/background_sync_permission_context.cc", "background_sync/background_sync_permission_context.h", "bad_message.cc",
diff --git a/chrome/browser/accessibility/accessibility_labels_service.cc b/chrome/browser/accessibility/accessibility_labels_service.cc index 64dddcc..dd31968 100644 --- a/chrome/browser/accessibility/accessibility_labels_service.cc +++ b/chrome/browser/accessibility/accessibility_labels_service.cc
@@ -55,14 +55,12 @@ &AccessibilityLabelsService::OnImageLabelsEnabledChanged, weak_factory_.GetWeakPtr())); - // Log whether the feature is enabled after startup. - // TODO(dmazzoni) re-enable. http://crbug.com/940805 -#if 0 - content::BrowserAccessibilityState::GetInstance()->AddHistogramCallback( - base::BindRepeating( + // Log whether the feature is enabled after startup. This must be run on the + // UI thread because it accesses prefs. + content::BrowserAccessibilityState::GetInstance() + ->AddUIThreadHistogramCallback(base::BindRepeating( &AccessibilityLabelsService::UpdateAccessibilityLabelsHistograms, weak_factory_.GetWeakPtr())); -#endif } AccessibilityLabelsService::AccessibilityLabelsService(Profile* profile)
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc index 46be73d..94a8fdd9 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
@@ -61,6 +61,7 @@ const char kContextualSearchThumbnail[] = "thumbnail"; const char kContextualSearchAction[] = "action"; const char kContextualSearchCategory[] = "category"; +const char kContextualSearchCardTag[] = "card_tag"; const char kContextualSearchSearchUrlFull[] = "search_url_full"; const char kContextualSearchSearchUrlPreload[] = "search_url_preload"; @@ -215,16 +216,17 @@ std::string thumbnail_url = ""; std::string caption = ""; std::string quick_action_uri = ""; - int64_t logged_event_id = 0; QuickActionCategory quick_action_category = QUICK_ACTION_CATEGORY_NONE; + int64_t logged_event_id = 0; std::string search_url_full = ""; std::string search_url_preload = ""; + int coca_card_tag = 0; DecodeSearchTermFromJsonResponse( json_string, &search_term, &display_text, &alternate_term, &mid, &prevent_preload, &mention_start, &mention_end, &context_language, &thumbnail_url, &caption, &quick_action_uri, &quick_action_category, - &logged_event_id, &search_url_full, &search_url_preload); + &logged_event_id, &search_url_full, &search_url_preload, &coca_card_tag); if (mention_start != 0 || mention_end != 0) { // Sanity check that our selection is non-zero and it is less than // 100 characters as that would make contextual search bar hide. @@ -247,7 +249,7 @@ prevent_preload == kDoPreventPreloadValue, start_adjust, end_adjust, context_language, thumbnail_url, caption, quick_action_uri, quick_action_category, logged_event_id, search_url_full, - search_url_preload)); + search_url_preload, coca_card_tag)); } std::string ContextualSearchDelegate::BuildRequestUrl( @@ -269,7 +271,11 @@ int contextual_cards_version = contextual_search::kContextualCardsUrlActionsIntegration; if (base::FeatureList::IsEnabled( - chrome::android::kContextualSearchDefinitions)) { + chrome::android::kContextualSearchTranslationModel)) { + contextual_cards_version = + contextual_search::kContextualCardsTranslationsIntegration; + } else if (base::FeatureList::IsEnabled( + chrome::android::kContextualSearchDefinitions)) { contextual_cards_version = contextual_search::kContextualCardsDefinitionsIntegration; } @@ -459,7 +465,8 @@ QuickActionCategory* quick_action_category, int64_t* logged_event_id, std::string* search_url_full, - std::string* search_url_preload) { + std::string* search_url_preload, + int* coca_card_tag) { bool contains_xssi_escape = base::StartsWith(response, kXssiEscape, base::CompareCase::SENSITIVE); const std::string& proper_json = @@ -506,13 +513,13 @@ } } - // Contextual Cards V1 Integration. + // Contextual Cards V1+ Integration. // Get the basic Bar data for Contextual Cards integration directly // from the root. dict->GetString(kContextualSearchCaption, caption); dict->GetString(kContextualSearchThumbnail, thumbnail_url); - // Contextual Cards V2 Integration. + // Contextual Cards V2+ Integration. // Get the Single Action data. dict->GetString(kContextualSearchAction, quick_action_uri); std::string quick_action_category_string; @@ -531,11 +538,16 @@ } } - // Contextual Cards V4 may also provide full search URLs to use in the + // Contextual Cards V4+ may also provide full search URLs to use in the // overlay. dict->GetString(kContextualSearchSearchUrlFull, search_url_full); dict->GetString(kContextualSearchSearchUrlPreload, search_url_preload); + // Contextual Cards V5+ integration can provide the primary card tag, so + // clients can tell what kind of card they have received. + // TODO(donnd): make sure this works with a non-integer or missing value! + dict->GetInteger(kContextualSearchCardTag, coca_card_tag); + // Any Contextual Cards integration. // For testing purposes check if there was a diagnostic from Contextual // Cards and output that into the log.
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.h b/chrome/browser/android/contextualsearch/contextual_search_delegate.h index 386da81..2fe6a4ca 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate.h +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
@@ -154,7 +154,8 @@ QuickActionCategory* quick_action_category, int64_t* logged_event_id, std::string* search_url_full, - std::string* search_url_preload); + std::string* search_url_preload, + int* coca_card_tag); // Extracts the start and end location from a mentions list, and sets the // integers referenced by |startResult| and |endResult|.
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc index 04acfee..a518f18 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
@@ -213,18 +213,25 @@ return result; } + // Accessors to response members bool is_invalid() { return is_invalid_; } int response_code() { return response_code_; } std::string search_term() { return search_term_; } std::string display_text() { return display_text_; } std::string alternate_term() { return alternate_term_; } std::string mid() { return mid_; } - std::string caption() { return caption_; } - std::string thumbnail_url() { return thumbnail_url_; } bool do_prevent_preload() { return prevent_preload_; } int start_adjust() { return start_adjust_; } int end_adjust() { return end_adjust_; } std::string context_language() { return context_language_; } + std::string thumbnail_url() { return thumbnail_url_; } + std::string caption() { return caption_; } + std::string quick_action_uri() { return quick_action_uri_; } + QuickActionCategory quick_action_category() { return quick_action_category_; } + int64_t logged_event_id() { return logged_event_id_; } + std::string search_url_full() { return search_url_full_; } + std::string search_url_preload() { return search_url_preload_; } + int coca_card_tag() { return coca_card_tag_; } // The delegate under test. std::unique_ptr<ContextualSearchDelegate> delegate_; @@ -240,12 +247,18 @@ display_text_ = resolved_search_term.display_text; alternate_term_ = resolved_search_term.alternate_term; mid_ = resolved_search_term.mid; - thumbnail_url_ = resolved_search_term.thumbnail_url; - caption_ = resolved_search_term.caption; prevent_preload_ = resolved_search_term.prevent_preload; start_adjust_ = resolved_search_term.selection_start_adjust; end_adjust_ = resolved_search_term.selection_end_adjust; context_language_ = resolved_search_term.context_language; + thumbnail_url_ = resolved_search_term.thumbnail_url; + caption_ = resolved_search_term.caption; + quick_action_uri_ = resolved_search_term.quick_action_uri; + quick_action_category_ = resolved_search_term.quick_action_category; + logged_event_id_ = resolved_search_term.logged_event_id; + search_url_full_ = resolved_search_term.search_url_full; + search_url_preload_ = resolved_search_term.search_url_preload; + coca_card_tag_ = resolved_search_term.coca_card_tag; } void recordSampleSelectionAvailable(const std::string& encoding, @@ -255,18 +268,25 @@ // unused. } + // Local response members bool is_invalid_; int response_code_; std::string search_term_; std::string display_text_; std::string alternate_term_; std::string mid_; - std::string thumbnail_url_; - std::string caption_; bool prevent_preload_; int start_adjust_; int end_adjust_; std::string context_language_; + std::string thumbnail_url_; + std::string caption_; + std::string quick_action_uri_; + QuickActionCategory quick_action_category_; + int64_t logged_event_id_; + std::string search_url_full_; + std::string search_url_preload_; + int coca_card_tag_; base::MessageLoopForIO io_message_loop_; std::unique_ptr<TemplateURLService> template_url_service_; @@ -533,7 +553,8 @@ "\"search_url_full\":\"https://www.google.com/" "search?q=define+obscure&ctxs=2\"," "\"search_url_preload\":\"https://www.google.com/" - "search?q=define+obscure&ctxs=2&pf=c&sns=1\"" + "search?q=define+obscure&ctxs=2&pf=c&sns=1\"," + "\"card_tag\":12" "}"; std::string search_term; std::string display_text; @@ -550,12 +571,13 @@ QuickActionCategory quick_action_category = QUICK_ACTION_CATEGORY_NONE; std::string search_url_full; std::string search_url_preload; + int coca_card_tag; delegate_->DecodeSearchTermFromJsonResponse( json_with_escape, &search_term, &display_text, &alternate_term, &mid, &prevent_preload, &mention_start, &mention_end, &context_language, &thumbnail_url, &caption, &quick_action_uri, &quick_action_category, - &logged_event_id, &search_url_full, &search_url_preload); + &logged_event_id, &search_url_full, &search_url_preload, &coca_card_tag); EXPECT_EQ("obama", search_term); EXPECT_EQ("Barack Obama", display_text); @@ -572,6 +594,7 @@ search_url_full); EXPECT_EQ("https://www.google.com/search?q=define+obscure&ctxs=2&pf=c&sns=1", search_url_preload); + EXPECT_EQ(12, coca_card_tag); } TEST_F(ContextualSearchDelegateTest, ResponseWithLanguage) { @@ -637,3 +660,31 @@ DestroyTestContext(); CallOnTextSurroundingSelectionAvailable(); } + +TEST_F(ContextualSearchDelegateTest, ResponseWithCocaCardTag) { + CreateDefaultSearchContextAndRequestSearchTerm(); + std::string response( + "{\"search_term\":\"obscure\"," + "\"card_tag\":11}"); + SimulateResponseReturned(response); + EXPECT_EQ("obscure", search_term()); + EXPECT_EQ(11, coca_card_tag()); +} + +TEST_F(ContextualSearchDelegateTest, ResponseWithoutCocaCardTag) { + CreateDefaultSearchContextAndRequestSearchTerm(); + std::string response("{\"search_term\":\"obscure\"}"); + SimulateResponseReturned(response); + EXPECT_EQ("obscure", search_term()); + EXPECT_EQ(0, coca_card_tag()); +} + +TEST_F(ContextualSearchDelegateTest, ResponseWithStringCocaCardTag) { + CreateDefaultSearchContextAndRequestSearchTerm(); + std::string response( + "{\"search_term\":\"obscure\"," + "\"card_tag\":\"11\"}"); + SimulateResponseReturned(response); + EXPECT_EQ("obscure", search_term()); + EXPECT_EQ(0, coca_card_tag()); +}
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc index 409fd0c..64d4031 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -195,7 +195,7 @@ j_thumbnail_url, j_caption, j_quick_action_uri, resolved_search_term.quick_action_category, resolved_search_term.logged_event_id, j_search_url_full, - j_search_url_preload); + j_search_url_preload, resolved_search_term.coca_card_tag); } void ContextualSearchManager::OnTextSurroundingSelectionAvailable(
diff --git a/chrome/browser/android/contextualsearch/resolved_search_term.cc b/chrome/browser/android/contextualsearch/resolved_search_term.cc index cb30ae5..1150c62c 100644 --- a/chrome/browser/android/contextualsearch/resolved_search_term.cc +++ b/chrome/browser/android/contextualsearch/resolved_search_term.cc
@@ -23,7 +23,8 @@ quick_action_category(QUICK_ACTION_CATEGORY_NONE), logged_event_id(0), search_url_full(""), - search_url_preload("") {} + search_url_preload(""), + coca_card_tag(0) {} ResolvedSearchTerm::ResolvedSearchTerm( bool is_invalid, @@ -42,7 +43,8 @@ const QuickActionCategory& quick_action_category, int64_t logged_event_id, const std::string& search_url_full, - const std::string& search_url_preload) + const std::string& search_url_preload, + int coca_card_tag) : is_invalid(is_invalid), response_code(response_code), search_term(search_term), @@ -59,6 +61,7 @@ quick_action_category(quick_action_category), logged_event_id(logged_event_id), search_url_full(search_url_full), - search_url_preload(search_url_preload) {} + search_url_preload(search_url_preload), + coca_card_tag(coca_card_tag) {} ResolvedSearchTerm::~ResolvedSearchTerm() {}
diff --git a/chrome/browser/android/contextualsearch/resolved_search_term.h b/chrome/browser/android/contextualsearch/resolved_search_term.h index edc8546..c26f42b 100644 --- a/chrome/browser/android/contextualsearch/resolved_search_term.h +++ b/chrome/browser/android/contextualsearch/resolved_search_term.h
@@ -43,7 +43,8 @@ const QuickActionCategory& quick_action_category, int64_t logged_event_id, const std::string& search_url_full, - const std::string& search_url_preload); + const std::string& search_url_preload, + int coca_card_tag); ~ResolvedSearchTerm(); const bool is_invalid; @@ -64,6 +65,7 @@ const int64_t logged_event_id; // Often 0. const std::string search_url_full; const std::string search_url_preload; + const int coca_card_tag; DISALLOW_COPY_AND_ASSIGN(ResolvedSearchTerm); };
diff --git a/chrome/browser/background_sync/background_sync_controller_factory.cc b/chrome/browser/background_sync/background_sync_controller_factory.cc index a85447d..47eb55f 100644 --- a/chrome/browser/background_sync/background_sync_controller_factory.cc +++ b/chrome/browser/background_sync/background_sync_controller_factory.cc
@@ -6,6 +6,7 @@ #include "chrome/browser/background_sync/background_sync_controller_impl.h" #include "chrome/browser/engagement/site_engagement_service_factory.h" +#include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" @@ -27,6 +28,7 @@ : BrowserContextKeyedServiceFactory( "BackgroundSyncService", BrowserContextDependencyManager::GetInstance()) { + DependsOn(HistoryServiceFactory::GetInstance()); DependsOn(SiteEngagementServiceFactory::GetInstance()); }
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.cc b/chrome/browser/background_sync/background_sync_controller_impl.cc index 80971e2..36c27b6 100644 --- a/chrome/browser/background_sync/background_sync_controller_impl.cc +++ b/chrome/browser/background_sync/background_sync_controller_impl.cc
@@ -6,11 +6,12 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "base/time/time.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/engagement/site_engagement_service.h" +#include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/profiles/profile.h" -#include "components/rappor/public/rappor_utils.h" -#include "components/rappor/rappor_service_impl.h" +#include "components/history/core/browser/history_service.h" #include "components/variations/variations_associated_data.h" #include "content/public/browser/background_sync_parameters.h" #include "url/gurl.h" @@ -45,7 +46,10 @@ BackgroundSyncControllerImpl::BackgroundSyncControllerImpl(Profile* profile) : profile_(profile), - site_engagement_service_(SiteEngagementService::Get(profile)) { + site_engagement_service_(SiteEngagementService::Get(profile)), + background_sync_metrics_(HistoryServiceFactory::GetForProfile( + profile_, + ServiceAccessType::EXPLICIT_ACCESS)) { DCHECK(profile_); DCHECK(site_engagement_service_); } @@ -118,15 +122,24 @@ } void BackgroundSyncControllerImpl::NotifyBackgroundSyncRegistered( - const url::Origin& origin) { + const url::Origin& origin, + bool can_fire, + bool is_reregistered) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (profile_->IsOffTheRecord()) - return; + background_sync_metrics_.MaybeRecordRegistrationEvent(origin, can_fire, + is_reregistered); +} - rappor::SampleDomainAndRegistryFromGURL(GetRapporServiceImpl(), - "BackgroundSync.Register.Origin", - origin.GetURL()); +void BackgroundSyncControllerImpl::NotifyBackgroundSyncCompleted( + const url::Origin& origin, + blink::ServiceWorkerStatusCode status_code, + int num_attempts, + int max_attempts) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + background_sync_metrics_.MaybeRecordCompletionEvent( + origin, status_code, num_attempts, max_attempts); } void BackgroundSyncControllerImpl::RunInBackground() { @@ -196,8 +209,3 @@ return parameters->initial_retry_delay * pow(parameters->retry_delay_factor, num_attempts - 1); } - -rappor::RapporServiceImpl* -BackgroundSyncControllerImpl::GetRapporServiceImpl() { - return g_browser_process->rappor_service(); -}
diff --git a/chrome/browser/background_sync/background_sync_controller_impl.h b/chrome/browser/background_sync/background_sync_controller_impl.h index 49d1efa..9b0d4c8d 100644 --- a/chrome/browser/background_sync/background_sync_controller_impl.h +++ b/chrome/browser/background_sync/background_sync_controller_impl.h
@@ -11,21 +11,18 @@ #include "base/macros.h" #include "base/time/time.h" +#include "chrome/browser/background_sync/background_sync_metrics.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/browser_thread.h" #include "third_party/blink/public/mojom/background_sync/background_sync.mojom.h" namespace content { struct BackgroundSyncParameters; -} - -namespace rappor { -class RapporServiceImpl; -} +} // namespace content namespace url { class Origin; -} +} // namespace url class Profile; class SiteEngagementService; @@ -54,7 +51,13 @@ // content::BackgroundSyncController overrides. void GetParameterOverrides( content::BackgroundSyncParameters* parameters) const override; - void NotifyBackgroundSyncRegistered(const url::Origin& origin) override; + void NotifyBackgroundSyncRegistered(const url::Origin& origin, + bool can_fire, + bool is_reregistered) override; + void NotifyBackgroundSyncCompleted(const url::Origin& origin, + blink::ServiceWorkerStatusCode status_code, + int num_attempts, + int max_attempts) override; void RunInBackground() override; base::TimeDelta GetNextEventDelay( const url::Origin& origin, @@ -63,10 +66,6 @@ blink::mojom::BackgroundSyncType sync_type, content::BackgroundSyncParameters* parameters) const override; - protected: - // Virtual for testing. - virtual rappor::RapporServiceImpl* GetRapporServiceImpl(); - private: // Gets the site engagement penalty for |url|, which is inversely proportional // to the engagement level. The lower the engagement levels with the site, @@ -80,6 +79,8 @@ // Same lifetime as |profile_|. SiteEngagementService* site_engagement_service_; + BackgroundSyncMetrics background_sync_metrics_; + DISALLOW_COPY_AND_ASSIGN(BackgroundSyncControllerImpl); };
diff --git a/chrome/browser/background_sync/background_sync_controller_impl_unittest.cc b/chrome/browser/background_sync/background_sync_controller_impl_unittest.cc index 75bd4bd..ef29813 100644 --- a/chrome/browser/background_sync/background_sync_controller_impl_unittest.cc +++ b/chrome/browser/background_sync/background_sync_controller_impl_unittest.cc
@@ -6,16 +6,21 @@ #include <stdint.h> +#include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "chrome/browser/engagement/site_engagement_score.h" #include "chrome/browser/engagement/site_engagement_service.h" +#include "chrome/browser/history/history_service_factory.h" #include "chrome/test/base/testing_profile.h" -#include "components/rappor/test_rappor_service.h" +#include "components/history/core/browser/history_database_params.h" +#include "components/history/core/browser/history_service.h" +#include "components/history/core/test/test_history_database.h" #include "components/variations/variations_associated_data.h" #include "content/public/browser/background_sync_parameters.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" +#include "url/origin.h" #if defined(OS_ANDROID) #include "chrome/browser/android/background_sync_launcher_android.h" @@ -35,32 +40,18 @@ constexpr base::TimeDelta kSmallerThanMinGap = base::TimeDelta::FromHours(11); constexpr base::TimeDelta kLargerThanMinGap = base::TimeDelta::FromHours(13); -class TestBackgroundSyncControllerImpl : public BackgroundSyncControllerImpl { - public: - TestBackgroundSyncControllerImpl( - Profile* profile, - rappor::TestRapporServiceImpl* rappor_service) - : BackgroundSyncControllerImpl(profile), - rappor_service_(rappor_service) {} - - protected: - rappor::RapporServiceImpl* GetRapporServiceImpl() override { - return rappor_service_; - } - - private: - rappor::TestRapporServiceImpl* rappor_service_; - - DISALLOW_COPY_AND_ASSIGN(TestBackgroundSyncControllerImpl); -}; +std::unique_ptr<KeyedService> BuildTestHistoryService( + const base::FilePath& file_path, + content::BrowserContext* context) { + auto service = std::make_unique<history::HistoryService>(); + service->Init(history::TestHistoryDatabaseParamsForPath(file_path)); + return service; +} class BackgroundSyncControllerImplTest : public testing::Test { protected: BackgroundSyncControllerImplTest() - : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), - controller_(std::make_unique<TestBackgroundSyncControllerImpl>( - &profile_, - &rappor_service_)) { + : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { ResetFieldTrialList(); #if defined(OS_ANDROID) BackgroundSyncLauncherAndroid::SetPlayServicesVersionCheckDisabledForTests( @@ -68,6 +59,16 @@ #endif } + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + + HistoryServiceFactory::GetInstance()->SetTestingFactory( + &profile_, base::BindRepeating( + &BuildTestHistoryService, + temp_dir_.GetPath().AppendASCII("BackgroundSyncTest"))); + controller_ = std::make_unique<BackgroundSyncControllerImpl>(&profile_); + } + void ResetFieldTrialList() { field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr /* entropy provider */); @@ -78,37 +79,13 @@ content::TestBrowserThreadBundle thread_bundle_; TestingProfile profile_; - rappor::TestRapporServiceImpl rappor_service_; - std::unique_ptr<TestBackgroundSyncControllerImpl> controller_; + std::unique_ptr<BackgroundSyncControllerImpl> controller_; std::unique_ptr<base::FieldTrialList> field_trial_list_; + base::ScopedTempDir temp_dir_; DISALLOW_COPY_AND_ASSIGN(BackgroundSyncControllerImplTest); }; -TEST_F(BackgroundSyncControllerImplTest, RapporTest) { - url::Origin origin = url::Origin::Create(GURL(kExampleUrl)); - EXPECT_EQ(0, rappor_service_.GetReportsCount()); - controller_->NotifyBackgroundSyncRegistered(origin); - EXPECT_EQ(1, rappor_service_.GetReportsCount()); - - std::string sample; - rappor::RapporType type; - LOG(ERROR) << origin; - EXPECT_TRUE(rappor_service_.GetRecordedSampleForMetric( - "BackgroundSync.Register.Origin", &sample, &type)); - EXPECT_EQ("example.com", sample); - EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type); -} - -TEST_F(BackgroundSyncControllerImplTest, NoRapporWhenOffTheRecord) { - url::Origin origin = url::Origin::Create(GURL(kExampleUrl)); - controller_ = std::make_unique<TestBackgroundSyncControllerImpl>( - profile_.GetOffTheRecordProfile(), &rappor_service_); - - controller_->NotifyBackgroundSyncRegistered(origin); - EXPECT_EQ(0, rappor_service_.GetReportsCount()); -} - TEST_F(BackgroundSyncControllerImplTest, NoFieldTrial) { content::BackgroundSyncParameters original; content::BackgroundSyncParameters overrides; @@ -173,10 +150,9 @@ sync_parameters.max_sync_event_duration); } -TEST_F(BackgroundSyncControllerImplTest, - GetNextEventDelayNoSiteEngagementPenalty) { - controller_.reset(new TestBackgroundSyncControllerImpl( - profile_.GetOffTheRecordProfile(), &rappor_service_)); +TEST_F(BackgroundSyncControllerImplTest, GetNextEventDelay) { + controller_ = std::make_unique<BackgroundSyncControllerImpl>( + profile_.GetOffTheRecordProfile()); content::BackgroundSyncParameters sync_parameters; url::Origin origin = url::Origin::Create(GURL(kExampleUrl)); SiteEngagementScore::SetParamValuesForTesting(); @@ -226,8 +202,8 @@ TEST_F(BackgroundSyncControllerImplTest, GetNextEventDelayWithSiteEngagementPenalty) { - controller_.reset(new TestBackgroundSyncControllerImpl( - profile_.GetOffTheRecordProfile(), &rappor_service_)); + controller_ = std::make_unique<BackgroundSyncControllerImpl>( + profile_.GetOffTheRecordProfile()); content::BackgroundSyncParameters sync_parameters; url::Origin origin = url::Origin::Create(GURL(kExampleUrl)); SiteEngagementScore::SetParamValuesForTesting();
diff --git a/chrome/browser/background_sync/background_sync_metrics.cc b/chrome/browser/background_sync/background_sync_metrics.cc new file mode 100644 index 0000000..fe2130c --- /dev/null +++ b/chrome/browser/background_sync/background_sync_metrics.cc
@@ -0,0 +1,102 @@ +// 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 "chrome/browser/background_sync/background_sync_metrics.h" + +#include "base/bind.h" +#include "components/history/core/browser/history_service.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "services/metrics/public/cpp/ukm_recorder.h" +#include "url/origin.h" + +BackgroundSyncMetrics::BackgroundSyncMetrics( + history::HistoryService* history_service) + : history_service_(history_service), weak_ptr_factory_(this) { + DCHECK(history_service_); +} + +BackgroundSyncMetrics::~BackgroundSyncMetrics() = default; + +void BackgroundSyncMetrics::MaybeRecordRegistrationEvent( + const url::Origin& origin, + bool can_fire, + bool is_reregistered) { + // TODO(crbug.com/952870): Move this to a better mechanism for background + // UKM recording. + history_service_->GetVisibleVisitCountToHost( + origin.GetURL(), + base::BindRepeating( + &BackgroundSyncMetrics::DidGetVisibleVisitCount, + weak_ptr_factory_.GetWeakPtr(), + base::BindRepeating(&BackgroundSyncMetrics::RecordRegistrationEvent, + weak_ptr_factory_.GetWeakPtr(), origin, can_fire, + is_reregistered)), + &task_tracker_); +} + +void BackgroundSyncMetrics::MaybeRecordCompletionEvent( + const url::Origin& origin, + blink::ServiceWorkerStatusCode status_code, + int num_attempts, + int max_attempts) { + // TODO(crbug.com/952870): Move this to a better mechanism for background + // UKM recording. + history_service_->GetVisibleVisitCountToHost( + origin.GetURL(), + base::BindRepeating( + &BackgroundSyncMetrics::DidGetVisibleVisitCount, + weak_ptr_factory_.GetWeakPtr(), + base::BindRepeating(&BackgroundSyncMetrics::RecordCompletionEvent, + weak_ptr_factory_.GetWeakPtr(), origin, + status_code, num_attempts, max_attempts)), + &task_tracker_); +} + +void BackgroundSyncMetrics::DidGetVisibleVisitCount( + base::OnceClosure visit_closure, + bool did_determine, + int num_visits, + base::Time first_visit_time) { + if (!did_determine || !num_visits) + return; + + std::move(visit_closure).Run(); + if (ukm_event_recorded_for_testing_) + std::move(ukm_event_recorded_for_testing_).Run(); +} + +void BackgroundSyncMetrics::RecordRegistrationEvent(const url::Origin& origin, + bool can_fire, + bool is_reregistered) { + ukm::SourceId source_id = ukm::UkmRecorder::GetNewSourceID(); + ukm::UkmRecorder* recorder = ukm::UkmRecorder::Get(); + DCHECK(recorder); + // |origin| was checked to exist in the profile history. This is the origin + // of the Service Worker tied to the Background Sync registration. + recorder->UpdateSourceURL(source_id, origin.GetURL()); + + ukm::builders::BackgroundSyncRegistered(source_id) + .SetCanFire(can_fire) + .SetIsReregistered(is_reregistered) + .Record(recorder); +} + +void BackgroundSyncMetrics::RecordCompletionEvent( + const url::Origin& origin, + blink::ServiceWorkerStatusCode status_code, + int num_attempts, + int max_attempts) { + ukm::SourceId source_id = ukm::UkmRecorder::GetNewSourceID(); + ukm::UkmRecorder* recorder = ukm::UkmRecorder::Get(); + DCHECK(recorder); + // |origin| was checked to exist in the profile history. This is the origin + // of the Service Worker tied to the Background Sync registration. + recorder->UpdateSourceURL(source_id, origin.GetURL()); + + ukm::builders::BackgroundSyncCompleted(source_id) + .SetStatus(static_cast<int>(status_code)) + .SetNumAttempts(num_attempts) + .SetMaxAttempts(max_attempts) + .Record(recorder); +}
diff --git a/chrome/browser/background_sync/background_sync_metrics.h b/chrome/browser/background_sync/background_sync_metrics.h new file mode 100644 index 0000000..b9401a9 --- /dev/null +++ b/chrome/browser/background_sync/background_sync_metrics.h
@@ -0,0 +1,65 @@ +// 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. + +#ifndef CHROME_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_METRICS_H_ +#define CHROME_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_METRICS_H_ + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/task/cancelable_task_tracker.h" +#include "third_party/blink/public/common/service_worker/service_worker_status_code.h" + +namespace history { +class HistoryService; +} // namespace history + +namespace url { +class Origin; +} // namespace url + +// Lives entirely on the UI thread. +class BackgroundSyncMetrics { + public: + explicit BackgroundSyncMetrics(history::HistoryService* history_service); + ~BackgroundSyncMetrics(); + + void MaybeRecordRegistrationEvent(const url::Origin& origin, + bool can_fire, + bool is_reregistered); + + void MaybeRecordCompletionEvent(const url::Origin& origin, + blink::ServiceWorkerStatusCode status_code, + int num_attempts, + int max_attempts); + + private: + friend class BackgroundSyncMetricsBrowserTest; + + void DidGetVisibleVisitCount(base::OnceClosure visit_closure, + bool did_determine, + int num_visits, + base::Time first_visit_time); + void RecordRegistrationEvent(const url::Origin& origin, + bool can_fire, + bool is_reregistered); + + void RecordCompletionEvent(const url::Origin& origin, + blink::ServiceWorkerStatusCode status_code, + int num_attempts, + int max_attempts); + + history::HistoryService* history_service_; + + // Task tracker used for querying URLs in the history service. + base::CancelableTaskTracker task_tracker_; + + // Used to signal tests that a UKM event has been recorded. + base::OnceClosure ukm_event_recorded_for_testing_; + + base::WeakPtrFactory<BackgroundSyncMetrics> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BackgroundSyncMetrics); +}; + +#endif // CHROME_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_METRICS_H_
diff --git a/chrome/browser/background_sync/background_sync_metrics_browsertest.cc b/chrome/browser/background_sync/background_sync_metrics_browsertest.cc new file mode 100644 index 0000000..b5c1719 --- /dev/null +++ b/chrome/browser/background_sync/background_sync_metrics_browsertest.cc
@@ -0,0 +1,100 @@ +// 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 "chrome/browser/background_sync/background_sync_metrics.h" + +#include <memory> + +#include "chrome/browser/history/history_service_factory.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "components/history/core/browser/history_service.h" +#include "components/ukm/test_ukm_recorder.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "url/gurl.h" +#include "url/origin.h" + +class BackgroundSyncMetricsBrowserTest : public InProcessBrowserTest { + public: + BackgroundSyncMetricsBrowserTest() = default; + ~BackgroundSyncMetricsBrowserTest() override = default; + + void SetUpOnMainThread() override { + Profile* profile = browser()->profile(); + + recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); + auto* history_service = HistoryServiceFactory::GetForProfile( + profile, ServiceAccessType::EXPLICIT_ACCESS); + DCHECK(history_service); + + background_sync_metrics_ = + std::make_unique<BackgroundSyncMetrics>(history_service); + + // Adds the URL to the history so that UKM events for this origin are + // recorded. + history_service->AddPage(GURL("https://backgroundsync.com/page"), + base::Time::Now(), history::SOURCE_BROWSED); + } + + protected: + void WaitForUkm() { + base::RunLoop run_loop; + background_sync_metrics_->ukm_event_recorded_for_testing_ = + run_loop.QuitClosure(); + run_loop.Run(); + } + + std::unique_ptr<ukm::TestAutoSetUkmRecorder> recorder_; + std::unique_ptr<BackgroundSyncMetrics> background_sync_metrics_; + + DISALLOW_COPY_AND_ASSIGN(BackgroundSyncMetricsBrowserTest); +}; + +IN_PROC_BROWSER_TEST_F(BackgroundSyncMetricsBrowserTest, + NoUkmRecordingsWithMissingHistory) { + background_sync_metrics_->MaybeRecordRegistrationEvent( + url::Origin::Create(GURL("https://notinhistory.com")), + /* can_fire= */ false, + /* is_reregistered= */ false); + + background_sync_metrics_->MaybeRecordRegistrationEvent( + url::Origin::Create(GURL("https://backgroundsync.com")), + /* can_fire= */ true, + /* is_reregistered= */ false); + WaitForUkm(); + + EXPECT_EQ(recorder_->entries_count(), 1u); + { + auto entries = recorder_->GetEntriesByName( + ukm::builders::BackgroundSyncRegistered::kEntryName); + ASSERT_EQ(entries.size(), 1u); + const auto* entry = entries[0]; + recorder_->ExpectEntryMetric( + entry, ukm::builders::BackgroundSyncRegistered::kCanFireName, true); + recorder_->ExpectEntryMetric( + entry, ukm::builders::BackgroundSyncRegistered::kIsReregisteredName, + false); + } + + background_sync_metrics_->MaybeRecordCompletionEvent( + url::Origin::Create(GURL("https://backgroundsync.com")), + /* status_code= */ blink::ServiceWorkerStatusCode::kOk, + /* num_attempts= */ 2, /* max_attempts= */ 5); + WaitForUkm(); + + ASSERT_EQ(recorder_->entries_count(), 2u); + { + auto entries = recorder_->GetEntriesByName( + ukm::builders::BackgroundSyncCompleted::kEntryName); + ASSERT_EQ(entries.size(), 1u); + const auto* entry = entries[0]; + recorder_->ExpectEntryMetric( + entry, ukm::builders::BackgroundSyncCompleted::kStatusName, + static_cast<int64_t>(blink::ServiceWorkerStatusCode::kOk)); + recorder_->ExpectEntryMetric( + entry, ukm::builders::BackgroundSyncCompleted::kNumAttemptsName, 2); + recorder_->ExpectEntryMetric( + entry, ukm::builders::BackgroundSyncCompleted::kMaxAttemptsName, 5); + } +}
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc index 4211da35..51d11d3 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -1096,9 +1096,12 @@ base::Bind(&AccessibilityManager::OnLocaleChanged, base::Unretained(this))); - content::BrowserAccessibilityState::GetInstance()->AddHistogramCallback( - base::Bind(&AccessibilityManager::UpdateChromeOSAccessibilityHistograms, - base::Unretained(this))); + // Compute these histograms on the main (UI) thread because they + // need to access PrefService. + content::BrowserAccessibilityState::GetInstance() + ->AddUIThreadHistogramCallback(base::BindOnce( + &AccessibilityManager::UpdateChromeOSAccessibilityHistograms, + base::Unretained(this))); extensions::ExtensionRegistry* registry = extensions::ExtensionRegistry::Get(profile);
diff --git a/chrome/browser/chromeos/account_manager/account_manager_migrator.cc b/chrome/browser/chromeos/account_manager/account_manager_migrator.cc index 1121c15..71cd08d 100644 --- a/chrome/browser/chromeos/account_manager/account_manager_migrator.cc +++ b/chrome/browser/chromeos/account_manager/account_manager_migrator.cc
@@ -38,6 +38,7 @@ #include "components/prefs/pref_service.h" #include "components/signin/core/browser/account_reconcilor.h" #include "components/signin/core/browser/webdata/token_web_data.h" +#include "components/user_manager/user.h" #include "components/webdata/common/web_data_service_consumer.h" #include "services/identity/public/cpp/accounts_in_cookie_jar_info.h" #include "services/identity/public/cpp/identity_manager.h" @@ -168,7 +169,8 @@ class DeviceAccountMigration : public AccountMigrationBaseStep, public WebDataServiceConsumer { public: - DeviceAccountMigration(AccountManager::AccountKey device_account, + DeviceAccountMigration(const AccountManager::AccountKey& device_account, + const std::string& device_account_raw_email, AccountManager* account_manager, identity::IdentityManager* identity_manager, scoped_refptr<TokenWebData> token_web_data) @@ -176,7 +178,8 @@ account_manager, identity_manager), token_web_data_(token_web_data), - device_account_(device_account) {} + device_account_(device_account), + device_account_raw_email_(device_account_raw_email) {} ~DeviceAccountMigration() override = default; private: @@ -233,7 +236,7 @@ } account_manager()->UpsertAccount( - device_account_, identity_manager()->GetPrimaryAccountInfo().email, + device_account_, device_account_raw_email_ /* raw_email */, it->second /* token */); is_success = true; break; @@ -254,6 +257,9 @@ // Device Account on Chrome OS. const AccountManager::AccountKey device_account_; + // Raw, un-canonicalized email for the device account. + const std::string device_account_raw_email_; + SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(DeviceAccountMigration); @@ -521,7 +527,11 @@ IdentityManagerFactory::GetForProfile(profile_); migration_runner_.AddStep(std::make_unique<DeviceAccountMigration>( - GetDeviceAccount(profile_), account_manager, identity_manager, + GetDeviceAccount(profile_), + ProfileHelper::Get() + ->GetUserByProfile(profile_) + ->display_email() /* device_account_raw_email */, + account_manager, identity_manager, WebDataServiceFactory::GetTokenWebDataForProfile( profile_, ServiceAccessType::EXPLICIT_ACCESS) /* token_web_data */));
diff --git a/chrome/browser/chromeos/power/idle_action_warning_observer.cc b/chrome/browser/chromeos/power/idle_action_warning_observer.cc index 70e5005..54f9b16db 100644 --- a/chrome/browser/chromeos/power/idle_action_warning_observer.cc +++ b/chrome/browser/chromeos/power/idle_action_warning_observer.cc
@@ -42,14 +42,16 @@ namespace chromeos { -IdleActionWarningObserver::IdleActionWarningObserver() : warning_dialog_(NULL) { +IdleActionWarningObserver::IdleActionWarningObserver() { PowerManagerClient::Get()->AddObserver(this); } IdleActionWarningObserver::~IdleActionWarningObserver() { PowerManagerClient::Get()->RemoveObserver(this); - if (warning_dialog_) + if (warning_dialog_) { + warning_dialog_->GetWidget()->RemoveObserver(this); warning_dialog_->CloseDialog(); + } } void IdleActionWarningObserver::IdleActionImminent( @@ -68,6 +70,7 @@ warning_dialog_->Update(idle_action_time); } else { warning_dialog_ = new IdleActionWarningDialogView(idle_action_time); + warning_dialog_->GetWidget()->AddObserver(this); ReportMetricsForDemoMode(IdleLogoutWarningEvent::kShown); } } @@ -83,12 +86,18 @@ power_manager::PowerSupplyProperties_BatteryState_DISCHARGING; } +void IdleActionWarningObserver::OnWidgetClosing(views::Widget* widget) { + DCHECK(warning_dialog_); + DCHECK_EQ(widget, warning_dialog_->GetWidget()); + warning_dialog_->GetWidget()->RemoveObserver(this); + warning_dialog_ = nullptr; +} + void IdleActionWarningObserver::HideDialogIfPresent() { if (warning_dialog_) { warning_dialog_->CloseDialog(); ReportMetricsForDemoMode(IdleLogoutWarningEvent::kCanceled); } - warning_dialog_ = nullptr; } } // namespace chromeos
diff --git a/chrome/browser/chromeos/power/idle_action_warning_observer.h b/chrome/browser/chromeos/power/idle_action_warning_observer.h index 47b46619..ac6d200 100644 --- a/chrome/browser/chromeos/power/idle_action_warning_observer.h +++ b/chrome/browser/chromeos/power/idle_action_warning_observer.h
@@ -8,6 +8,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "chromeos/dbus/power/power_manager_client.h" +#include "ui/views/widget/widget_observer.h" namespace chromeos { @@ -15,7 +16,8 @@ // Listens for notifications that the idle action is imminent and shows a // warning dialog to the user. -class IdleActionWarningObserver : public PowerManagerClient::Observer { +class IdleActionWarningObserver : public PowerManagerClient::Observer, + public views::WidgetObserver { public: IdleActionWarningObserver(); ~IdleActionWarningObserver() override; @@ -27,9 +29,12 @@ void PowerChanged(const power_manager::PowerSupplyProperties& proto) override; private: + // views::WidgetObserver: + void OnWidgetClosing(views::Widget* widget) override; + void HideDialogIfPresent(); - IdleActionWarningDialogView* warning_dialog_; // Not owned. + IdleActionWarningDialogView* warning_dialog_ = nullptr; // Not owned. // Used to derive the correct idle action (IdleActionAC/IdleActionBattery). bool on_battery_power_ = false;
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc index b6d4e8d..bda5769 100644 --- a/chrome/browser/client_hints/client_hints_browsertest.cc +++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -182,8 +182,8 @@ accept_ch_with_lifetime_url_ = https_server_.GetURL("/accept_ch_with_lifetime.html"); - EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS()); - EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic()); + accept_ch_with_short_lifetime_url_ = + https_server_.GetURL("/accept_ch_with_short_lifetime.html"); accept_ch_without_lifetime_url_ = https_server_.GetURL("/accept_ch_without_lifetime.html"); @@ -307,6 +307,12 @@ return http_equiv_accept_ch_with_lifetime_; } + // A URL whose response headers include Accept-CH and Accept-CH-Lifetime + // headers. The Accept-CH-Lifetime duration is set very short to 1 second. + const GURL& accept_ch_with_short_lifetime() const { + return accept_ch_with_short_lifetime_url_; + } + // A URL whose response headers include only Accept-CH header. const GURL& accept_ch_without_lifetime_url() const { return accept_ch_without_lifetime_url_; @@ -662,6 +668,7 @@ GURL accept_ch_with_lifetime_http_local_url_; GURL http_equiv_accept_ch_with_lifetime_http_local_url_; GURL accept_ch_with_lifetime_url_; + GURL accept_ch_with_short_lifetime_url_; GURL accept_ch_without_lifetime_url_; GURL http_equiv_accept_ch_without_lifetime_url_; GURL without_accept_ch_without_lifetime_url_; @@ -1163,6 +1170,59 @@ EXPECT_EQ(20u, count_client_hints_headers_seen()); } +// Verify that expired persistent client hint preferences are not used. +// Verifies this by setting Accept-CH-Lifetime value to 1 second, +// and loading a page after 1 second to verify that client hints are not +// attached. +IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, + ShortLifetimeFollowedByNoClientHint) { + const GURL gurl = accept_ch_with_short_lifetime(); + + base::HistogramTester histogram_tester; + ContentSettingsForOneType host_settings; + + HostContentSettingsMapFactory::GetForProfile(browser()->profile()) + ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(), + &host_settings); + EXPECT_EQ(0u, host_settings.size()); + + // Fetching |gurl| should persist the request for client hints. + ui_test_utils::NavigateToURL(browser(), gurl); + + histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1); + + content::FetchHistogramsFromChildProcesses(); + SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); + + histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1); + // |gurl| sets client hints persist duration to 1 second. + histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", 1 * 1000, + 1); + base::RunLoop().RunUntilIdle(); + + // Clients hints preferences for one origin should be persisted. + HostContentSettingsMapFactory::GetForProfile(browser()->profile()) + ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(), + &host_settings); + EXPECT_EQ(1u, host_settings.size()); + + // Sleep for a duration longer than 1 second (duration of persisted client + // hints). + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1001)); + + SetClientHintExpectationsOnMainFrame(false); + SetClientHintExpectationsOnSubresources(false); + ui_test_utils::NavigateToURL(browser(), + without_accept_ch_without_lifetime_url()); + + // The user agent hint is attached to all three requests: + EXPECT_EQ(3u, count_user_agent_hint_headers_seen()); + + // No client hints are attached to the requests since the persisted hints must + // be expired. + EXPECT_EQ(0u, count_client_hints_headers_seen()); +} + // The test first fetches a page that sets Accept-CH-Lifetime. Next, it fetches // a URL from a different origin. However, that URL response redirects to the // same origin from where the first page was fetched. The test verifies that @@ -1412,6 +1472,39 @@ ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT); } +// Test that if the content settings are malformed, then the browser does not +// crash. +IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, + ClientHintsMalformedContentSettings) { + ContentSettingsForOneType client_hints_settings; + HostContentSettingsMap* host_content_settings_map = + HostContentSettingsMapFactory::GetForProfile(browser()->profile()); + + // Add setting for the host. + std::unique_ptr<base::ListValue> expiration_times_list = + std::make_unique<base::ListValue>(); + expiration_times_list->AppendInteger(42 /* client hint value */); + auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>(); + expiration_times_dictionary->SetList("client_hints", + std::move(expiration_times_list)); + // Do not set |expiration_time| in the dictionary. + host_content_settings_map->SetWebsiteSettingDefaultScope( + without_accept_ch_without_lifetime_url(), GURL(), + CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(), + std::make_unique<base::Value>(expiration_times_dictionary->Clone())); + + // Reading the settings should now return one setting. + host_content_settings_map->GetSettingsForOneType( + CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(), + &client_hints_settings); + EXPECT_EQ(1U, client_hints_settings.size()); + + SetClientHintExpectationsOnMainFrame(false); + SetClientHintExpectationsOnSubresources(false); + ui_test_utils::NavigateToURL(browser(), + without_accept_ch_without_lifetime_url()); +} + // Ensure that when the JavaScript is blocked, client hints requested using // Accept-CH are not attached to the request headers for subresources. IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc index 152bf41..c99c32ea 100644 --- a/chrome/browser/extensions/extension_context_menu_model.cc +++ b/chrome/browser/extensions/extension_context_menu_model.cc
@@ -408,11 +408,9 @@ AddItemWithStringId(MANAGE_EXTENSIONS, IDS_MANAGE_EXTENSION); } - const ActionInfo* action_info = ActionInfo::GetPageActionInfo(extension); - if (!action_info) - action_info = ActionInfo::GetBrowserActionInfo(extension); - if (profile_->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode) && - delegate_ && !is_component_ && action_info && !action_info->synthesized) { + const ActionInfo* action_info = ActionInfo::GetAnyActionInfo(extension); + if (delegate_ && !is_component_ && action_info && !action_info->synthesized && + profile_->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode)) { AddSeparator(ui::NORMAL_SEPARATOR); AddItemWithStringId(INSPECT_POPUP, IDS_EXTENSION_ACTION_INSPECT_POPUP); }
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc index a8988443..a3c815a1 100644 --- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc +++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -16,8 +16,6 @@ #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/favicon/large_icon_service_factory.h" -#include "chrome/browser/gcm/gcm_profile_service_factory.h" -#include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/image_fetcher/image_decoder_impl.h" #include "chrome/browser/language/url_language_histogram_factory.h" @@ -26,8 +24,6 @@ #include "chrome/common/channel_info.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" -#include "components/gcm_driver/gcm_profile_service.h" -#include "components/gcm_driver/instance_id/instance_id_profile_service.h" #include "components/image_fetcher/core/image_decoder.h" #include "components/image_fetcher/core/image_fetcher.h" #include "components/image_fetcher/core/image_fetcher_impl.h" @@ -64,9 +60,6 @@ #include "chrome/browser/android/chrome_feature_list.h" #include "chrome/browser/android/ntp/ntp_snippets_launcher.h" #include "components/feed/feed_feature_list.h" -#include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h" -#include "components/ntp_snippets/breaking_news/subscription_manager.h" -#include "components/ntp_snippets/breaking_news/subscription_manager_impl.h" #endif #if BUILDFLAG(ENABLE_OFFLINE_PAGES) @@ -85,7 +78,6 @@ using history::HistoryService; using image_fetcher::ImageFetcherImpl; using language::UrlLanguageHistogram; -using ntp_snippets::BreakingNewsListener; using ntp_snippets::CategoryRanker; using ntp_snippets::ContentSuggestionsService; using ntp_snippets::GetFetchEndpoint; @@ -98,13 +90,6 @@ using ntp_snippets::RemoteSuggestionsStatusServiceImpl; using ntp_snippets::UserClassifier; -#if defined(OS_ANDROID) -using ntp_snippets::BreakingNewsGCMAppHandler; -using ntp_snippets::GetPushUpdatesSubscriptionEndpoint; -using ntp_snippets::GetPushUpdatesUnsubscriptionEndpoint; -using ntp_snippets::SubscriptionManagerImpl; -#endif // OS_ANDROID - #if BUILDFLAG(ENABLE_OFFLINE_PAGES) using ntp_snippets::PrefetchedPagesTrackerImpl; using offline_pages::OfflinePageModel; @@ -139,67 +124,6 @@ #endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) -#if defined(OS_ANDROID) - -bool AreGCMPushUpdatesEnabled() { - return base::FeatureList::IsEnabled(ntp_snippets::kBreakingNewsPushFeature); -} - -std::unique_ptr<BreakingNewsGCMAppHandler> -MakeBreakingNewsGCMAppHandlerIfEnabled( - Profile* profile, - const std::string& locale, - variations::VariationsService* variations_service) { - PrefService* pref_service = profile->GetPrefs(); - - if (!AreGCMPushUpdatesEnabled()) { - BreakingNewsGCMAppHandler::ClearProfilePrefs(pref_service); - SubscriptionManagerImpl::ClearProfilePrefs(pref_service); - return nullptr; - } - - gcm::GCMDriver* gcm_driver = - gcm::GCMProfileServiceFactory::GetForProfile(profile)->driver(); - - identity::IdentityManager* identity_manager = - IdentityManagerFactory::GetForProfile(profile); - - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory = - content::BrowserContext::GetDefaultStoragePartition(profile) - ->GetURLLoaderFactoryForBrowserProcess(); - - std::string api_key; - // The API is private. If we don't have the official API key, don't even try. - if (google_apis::IsGoogleChromeAPIKeyUsed()) { - bool is_stable_channel = - chrome::GetChannel() == version_info::Channel::STABLE; - api_key = is_stable_channel ? google_apis::GetAPIKey() - : google_apis::GetNonStableAPIKey(); - } - - auto subscription_manager = std::make_unique<SubscriptionManagerImpl>( - url_loader_factory, pref_service, variations_service, identity_manager, - api_key, locale, GetPushUpdatesSubscriptionEndpoint(chrome::GetChannel()), - GetPushUpdatesUnsubscriptionEndpoint(chrome::GetChannel())); - - instance_id::InstanceIDProfileService* instance_id_profile_service = - instance_id::InstanceIDProfileServiceFactory::GetForProfile(profile); - DCHECK(instance_id_profile_service); - DCHECK(instance_id_profile_service->driver()); - - return std::make_unique<BreakingNewsGCMAppHandler>( - gcm_driver, instance_id_profile_service->driver(), pref_service, - std::move(subscription_manager), - base::Bind( - &data_decoder::SafeJsonParser::Parse, - content::ServiceManagerConnection::GetForProcess()->GetConnector()), - base::DefaultClock::GetInstance(), - /*token_validation_timer=*/std::make_unique<base::OneShotTimer>(), - /*forced_subscription_timer=*/std::make_unique<base::OneShotTimer>()); -} - -#endif // OS_ANDROID - bool IsArticleProviderEnabled() { return base::FeatureList::IsEnabled(ntp_snippets::kArticleSuggestionsFeature); } @@ -253,13 +177,6 @@ content::ServiceManagerConnection::GetForProcess()->GetConnector()), GetFetchEndpoint(), api_key, user_classifier); - std::unique_ptr<BreakingNewsListener> breaking_news_raw_data_provider; -#if defined(OS_ANDROID) - breaking_news_raw_data_provider = MakeBreakingNewsGCMAppHandlerIfEnabled( - profile, g_browser_process->GetApplicationLocale(), - g_browser_process->variations_service()); -#endif // OS_ANDROID - auto provider = std::make_unique<RemoteSuggestionsProviderImpl>( service, pref_service, g_browser_process->GetApplicationLocale(), service->category_ranker(), service->remote_suggestions_scheduler(), @@ -272,8 +189,7 @@ database_dir), std::make_unique<RemoteSuggestionsStatusServiceImpl>( identity_manager->HasPrimaryAccount(), pref_service, std::string()), - std::move(prefetched_pages_tracker), - std::move(breaking_news_raw_data_provider), debug_logger, + std::move(prefetched_pages_tracker), debug_logger, std::make_unique<base::OneShotTimer>()); service->remote_suggestions_scheduler()->SetProvider(provider.get()); @@ -317,10 +233,6 @@ // Depends on OfflinePageModelFactory in SimpleDependencyManager. DependsOn(offline_pages::PrefetchServiceFactory::GetInstance()); #endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) -#if defined(OS_ANDROID) - DependsOn(gcm::GCMProfileServiceFactory::GetInstance()); - DependsOn(instance_id::InstanceIDProfileServiceFactory::GetInstance()); -#endif // defined(OS_ANDROID) } ContentSuggestionsServiceFactory::~ContentSuggestionsServiceFactory() = default;
diff --git a/chrome/browser/performance_manager/performance_manager.cc b/chrome/browser/performance_manager/performance_manager.cc index 70a6ac1..ead2c90 100644 --- a/chrome/browser/performance_manager/performance_manager.cc +++ b/chrome/browser/performance_manager/performance_manager.cc
@@ -122,6 +122,7 @@ void PerformanceManager::RegisterObserver( std::unique_ptr<GraphObserver> observer) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); graph_.RegisterObserver(observer.get()); observers_.push_back(std::move(observer)); }
diff --git a/chrome/browser/performance_manager/performance_manager.h b/chrome/browser/performance_manager/performance_manager.h index e1861b0..3b63256 100644 --- a/chrome/browser/performance_manager/performance_manager.h +++ b/chrome/browser/performance_manager/performance_manager.h
@@ -98,13 +98,18 @@ return task_runner_; } + // This allows an observer to be passed to this class, and bound to the + // lifetime of the performance manager. This will disappear post + // resource_coordinator migration, so do not use this unless you know what + // you're doing! Must be called from the performance manager sequence. + // TODO(chrisha): Kill this dead. + void RegisterObserver(std::unique_ptr<GraphObserver> observer); + private: using InterfaceRegistry = service_manager::BinderRegistryWithArgs< const service_manager::BindSourceInfo&>; PerformanceManager(); - - void RegisterObserver(std::unique_ptr<GraphObserver> observer); void PostBindInterface(const std::string& interface_name, mojo::ScopedMessagePipeHandle message_pipe);
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 5a184580..5e52095 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -206,8 +206,6 @@ #include "chrome/browser/media/android/cdm/media_drm_origin_id_manager.h" #include "components/cdm/browser/media_drm_storage_impl.h" #include "components/feed/buildflags.h" -#include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h" -#include "components/ntp_snippets/breaking_news/subscription_manager_impl.h" #include "components/ntp_snippets/category_rankers/click_based_category_ranker.h" #include "components/ntp_tiles/popular_sites_impl.h" #if BUILDFLAG(ENABLE_FEED_IN_CHROME) @@ -421,7 +419,19 @@ "ntp_suggestions.downloads.assets.dismissed_ids"; const char kDismissedOfflinePageDownloadSuggestions[] = "ntp_suggestions.downloads.offline_pages.dismissed_ids"; -#endif + +// Deprecated 4/2019. +const char kBreakingNewsSubscriptionDataToken[] = + "ntp_suggestions.breaking_news_subscription_data.token"; +const char kBreakingNewsSubscriptionDataIsAuthenticated[] = + "ntp_suggestions.breaking_news_subscription_data.is_authenticated"; +const char kBreakingNewsGCMSubscriptionTokenCache[] = + "ntp_suggestions.breaking_news_gcm_subscription_token_cache"; +const char kBreakingNewsGCMLastTokenValidationTime[] = + "ntp_suggestions.breaking_news_gcm_last_token_validation_time"; +const char kBreakingNewsGCMLastForcedSubscriptionTime[] = + "ntp_suggestions.breaking_news_gcm_last_forced_subscription_time"; +#endif // defined(OS_ANDROID) // Register prefs used only for migration (clearing or moving to a new key). void RegisterProfilePrefsForMigration( @@ -463,7 +473,16 @@ #if defined(OS_ANDROID) registry->RegisterListPref(kDismissedAssetDownloadSuggestions); registry->RegisterListPref(kDismissedOfflinePageDownloadSuggestions); -#endif + + registry->RegisterStringPref(kBreakingNewsSubscriptionDataToken, + std::string()); + registry->RegisterBooleanPref(kBreakingNewsSubscriptionDataIsAuthenticated, + false); + registry->RegisterStringPref(kBreakingNewsGCMSubscriptionTokenCache, + std::string()); + registry->RegisterInt64Pref(kBreakingNewsGCMLastTokenValidationTime, 0); + registry->RegisterInt64Pref(kBreakingNewsGCMLastForcedSubscriptionTime, 0); +#endif // defined(OS_ANDROID) } } // namespace @@ -754,9 +773,7 @@ registry); ContentSuggestionsNotifierService::RegisterProfilePrefs(registry); explore_sites::HistoryStatisticsReporter::RegisterPrefs(registry); - ntp_snippets::BreakingNewsGCMAppHandler::RegisterProfilePrefs(registry); ntp_snippets::ClickBasedCategoryRanker::RegisterProfilePrefs(registry); - ntp_snippets::SubscriptionManagerImpl::RegisterProfilePrefs(registry); OomInterventionDecider::RegisterProfilePrefs(registry); #endif // defined(OS_ANDROID) @@ -1021,6 +1038,13 @@ // Added 4/2019. profile_prefs->ClearPref(kDismissedAssetDownloadSuggestions); profile_prefs->ClearPref(kDismissedOfflinePageDownloadSuggestions); + + // Added 4/2019. + profile_prefs->ClearPref(kBreakingNewsSubscriptionDataToken); + profile_prefs->ClearPref(kBreakingNewsSubscriptionDataIsAuthenticated); + profile_prefs->ClearPref(kBreakingNewsGCMSubscriptionTokenCache); + profile_prefs->ClearPref(kBreakingNewsGCMLastTokenValidationTime); + profile_prefs->ClearPref(kBreakingNewsGCMLastForcedSubscriptionTime); #endif // defined(OS_ANDROID) #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/previews/hints_fetcher_browsertest.cc b/chrome/browser/previews/hints_fetcher_browsertest.cc index 5ffd519a..71777bf 100644 --- a/chrome/browser/previews/hints_fetcher_browsertest.cc +++ b/chrome/browser/previews/hints_fetcher_browsertest.cc
@@ -112,6 +112,8 @@ // only provides the URL. cmd->AppendSwitchASCII(previews::switches::kOptimizationGuideServiceURL, https_server_->base_url().spec()); + cmd->AppendSwitchASCII(previews::switches::kFetchHintsOverride, + "example1.com, example2.com"); } // Creates hint data for the |hint_setup_url|'s so that OnHintsUpdated in @@ -216,6 +218,15 @@ private: DISALLOW_COPY_AND_ASSIGN(OptimizationGuideServiceHintsFetcherBrowserTest); }; + +// Issues with multiple profiles likely cause the site enagement service-based +// tests to flake. +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) +#define DISABLE_ON_WIN_MAC_CHROMESOS(x) DISABLED_##x +#else +#define DISABLE_ON_WIN_MAC_CHROMESOS(x) x +#endif + // This test creates new browser with no profile and loads a random page with // the feature flags enables the PreviewsOnePlatformHints. We confirm that the // top_host_provider_impl executes and does not crash by checking UMA @@ -253,8 +264,9 @@ // only returns HTTPS-schemed hosts. We verify this with the UMA histogram // logged when the GetHintsRequest is made to the remote Optimization Guide // Service. -IN_PROC_BROWSER_TEST_F(OptimizationGuideServiceHintsFetcherBrowserTest, - PreviewsTopHostProviderHTTPSOnly) { +IN_PROC_BROWSER_TEST_F( + OptimizationGuideServiceHintsFetcherBrowserTest, + DISABLE_ON_WIN_MAC_CHROMESOS(PreviewsTopHostProviderHTTPSOnly)) { const base::HistogramTester* histogram_tester = GetHistogramTester(); // Adds two HTTP and two HTTPS sites into the Site Engagement Service.
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc index 0c51bfdb..c34834d 100644 --- a/chrome/browser/previews/previews_lite_page_browsertest.cc +++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -39,6 +39,8 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/content_settings/core/browser/cookie_settings.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" @@ -1413,6 +1415,74 @@ WaitForPingback(); } +class TestDataReductionProxyPingbackClient + : public data_reduction_proxy::DataReductionProxyPingbackClient { + public: + void WaitForPingback() { + base::RunLoop run_loop; + wait_for_pingback_closure_ = run_loop.QuitClosure(); + run_loop.Run(); + } + + data_reduction_proxy::DataReductionProxyData* data() { return data_.get(); } + + private: + void SendPingback( + const data_reduction_proxy::DataReductionProxyData& data, + const data_reduction_proxy::DataReductionProxyPageLoadTiming& timing) + override { + data_ = data.DeepCopy(); + if (wait_for_pingback_closure_) + std::move(wait_for_pingback_closure_).Run(); + } + + void SetPingbackReportingFraction( + float pingback_reporting_fraction) override {} + + base::OnceClosure wait_for_pingback_closure_; + std::unique_ptr<data_reduction_proxy::DataReductionProxyData> data_; +}; + +IN_PROC_BROWSER_TEST_P(PreviewsLitePageServerBrowserTest, + DISABLE_ON_WIN_MAC_CHROMESOS(PingbackContent)) { + TestDataReductionProxyPingbackClient* pingback_client = + new TestDataReductionProxyPingbackClient(); + DataReductionProxyChromeSettingsFactory::GetForBrowserContext( + browser()->profile()) + ->data_reduction_proxy_service() + ->SetPingbackClientForTesting(pingback_client); + + ui_test_utils::NavigateToURL(browser(), HttpsLitePageURL(kSuccess)); + VerifyPreviewLoaded(); + + PreviewsUITabHelper* ui_tab_helper = + PreviewsUITabHelper::FromWebContents(GetWebContents()); + previews::PreviewsUserData* previews_data = + ui_tab_helper->previews_user_data(); + // Grab the page id and session now because they may change after the reload. + uint64_t expected_page_id = previews_data->server_lite_page_info()->page_id; + std::string expected_session_key = + previews_data->server_lite_page_info()->drp_session_key; + + // Starting a new page load will send a pingback for the previous page load. + GetWebContents()->GetController().Reload(content::ReloadType::NORMAL, false); + pingback_client->WaitForPingback(); + + data_reduction_proxy::DataReductionProxyData* data = pingback_client->data(); + EXPECT_TRUE(data->used_data_reduction_proxy()); + EXPECT_TRUE(data->lite_page_received()); + EXPECT_FALSE(data->lofi_policy_received()); + EXPECT_FALSE(data->lofi_received()); + EXPECT_FALSE(data->was_cached_data_reduction_proxy_response()); + + // TODO(crbug.com/952523): Fix and remove this early return. + if (GetParam()) + return; + + EXPECT_EQ(data->session_key(), expected_session_key); + EXPECT_EQ(data->page_id().value(), expected_page_id); +} + class PreviewsLitePageServerTimeoutBrowserTest : public PreviewsLitePageServerBrowserTest { public:
diff --git a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc index 7bdacbf..0841b60d 100644 --- a/chrome/browser/previews/previews_lite_page_navigation_throttle.cc +++ b/chrome/browser/previews/previews_lite_page_navigation_throttle.cc
@@ -116,26 +116,27 @@ // restart. Note: This could be a navigation to the litepages server, or to // the original URL. if (restarted_navigation_url_ == handle->GetURL()) { - // Get a new page id. - PreviewsService* previews_service = PreviewsServiceFactory::GetForProfile( - Profile::FromBrowserContext(web_contents()->GetBrowserContext())); - PreviewsLitePageNavigationThrottleManager* manager = - previews_service->previews_lite_page_decider(); - uint64_t page_id = manager->GeneratePageID(); + if (!info_) { + // Create a new info_ if needed. This will use the previous page_id, + // which is desired. + PreviewsService* previews_service = + PreviewsServiceFactory::GetForProfile(Profile::FromBrowserContext( + web_contents()->GetBrowserContext())); + PreviewsLitePageNavigationThrottleManager* manager = + previews_service->previews_lite_page_decider(); + + info_ = + PreviewsLitePageNavigationThrottle::GetOrCreateServerLitePageInfo( + handle, manager) + ->Clone(); + } // Create a new PreviewsUserData if needed. PreviewsUITabHelper* ui_tab_helper = PreviewsUITabHelper::FromWebContents(web_contents()); previews::PreviewsUserData* previews_data = - ui_tab_helper->CreatePreviewsUserDataForNavigationHandle(handle, - page_id); - - // Set the lite page state on the user data. - if (!info_) { - info_ = - std::make_unique<previews::PreviewsUserData::ServerLitePageInfo>(); - info_->original_navigation_start = handle->NavigationStart(); - } + ui_tab_helper->CreatePreviewsUserDataForNavigationHandle( + handle, info_->page_id); previews_data->set_server_lite_page_info(std::move(info_)); // Reset member state.
diff --git a/chrome/browser/previews/previews_service.cc b/chrome/browser/previews/previews_service.cc index ef10bf2..2fbf933 100644 --- a/chrome/browser/previews/previews_service.cc +++ b/chrome/browser/previews/previews_service.cc
@@ -142,7 +142,8 @@ profile_path.Append(chrome::kPreviewsOptOutDBFilename)), optimization_guide_service ? std::make_unique<previews::PreviewsOptimizationGuide>( - optimization_guide_service, ui_task_runner, profile_path, + optimization_guide_service, ui_task_runner, + background_task_runner, profile_path, previews_top_host_provider_.get(), previews_url_loader_factory_) : nullptr, base::Bind(&IsPreviewsTypeEnabled),
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc index a77eee5..9dfc98e 100644 --- a/chrome/browser/profiles/off_the_record_profile_impl.cc +++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -54,6 +54,7 @@ #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/core/simple_dependency_manager.h" +#include "components/keyed_service/core/simple_key_map.h" #include "components/keyed_service/core/simple_keyed_service_factory.h" #include "components/prefs/json_pref_store.h" #include "components/sync_preferences/pref_service_syncable.h" @@ -150,6 +151,7 @@ key_ = std::make_unique<ProfileKey>(profile_->GetPath(), prefs_.get(), profile_->GetProfileKey()); + SimpleKeyMap::GetInstance()->Associate(this, key_.get()); // Register on BrowserContext. user_prefs::UserPrefs::Set(this, prefs_.get()); @@ -233,6 +235,8 @@ BrowserContextDependencyManager::GetInstance(), this, SimpleDependencyManager::GetInstance(), key_.get()); + SimpleKeyMap::GetInstance()->Dissociate(this); + #if BUILDFLAG(ENABLE_EXTENSIONS) base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO},
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 37f7610..a8014c8c 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -109,6 +109,7 @@ #include "components/history/core/common/pref_names.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/core/simple_dependency_manager.h" +#include "components/keyed_service/core/simple_key_map.h" #include "components/keyed_service/core/simple_keyed_service_factory.h" #include "components/language/core/browser/pref_names.h" #include "components/language/core/common/locale_util.h" @@ -583,6 +584,7 @@ } key_ = std::make_unique<ProfileKey>(GetPath(), prefs_.get()); + SimpleKeyMap::GetInstance()->Associate(this, key_.get()); #if defined(OS_CHROMEOS) if (is_regular_profile) { @@ -810,6 +812,8 @@ BrowserContextDependencyManager::GetInstance(), this, SimpleDependencyManager::GetInstance(), key_.get()); + SimpleKeyMap::GetInstance()->Dissociate(this); + // This causes the Preferences file to be written to disk. if (prefs_loaded) SetExitType(EXIT_NORMAL);
diff --git a/chrome/browser/resource_coordinator/resource_coordinator_parts.cc b/chrome/browser/resource_coordinator/resource_coordinator_parts.cc index 62583b3..02b42012 100644 --- a/chrome/browser/resource_coordinator/resource_coordinator_parts.cc +++ b/chrome/browser/resource_coordinator/resource_coordinator_parts.cc
@@ -19,8 +19,7 @@ , tab_manager_(page_signal_receiver_.get(), &tab_load_tracker_), tab_lifecycle_unit_source_(tab_manager_.intervention_policy_database(), - tab_manager_.usage_clock(), - page_signal_receiver_.get()) + tab_manager_.usage_clock()) #endif { #if !defined(OS_ANDROID)
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc index bdd331f..df23385 100644 --- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc +++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
@@ -7,7 +7,12 @@ #include "base/bind.h" #include "base/logging.h" #include "base/stl_util.h" +#include "base/task/post_task.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/performance_manager/graph/graph.h" +#include "chrome/browser/performance_manager/graph/page_node_impl.h" +#include "chrome/browser/performance_manager/performance_manager.h" +#include "chrome/browser/performance_manager/web_contents_proxy.h" #include "chrome/browser/resource_coordinator/discard_metrics_lifecycle_unit_observer.h" #include "chrome/browser/resource_coordinator/lifecycle_unit_source_observer.h" #include "chrome/browser/resource_coordinator/resource_coordinator_parts.h" @@ -22,6 +27,8 @@ #include "chrome/common/pref_names.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents_user_data.h" namespace resource_coordinator { @@ -54,12 +61,52 @@ WEB_CONTENTS_USER_DATA_KEY_IMPL(TabLifecycleUnitSource::TabLifecycleUnitHolder) +// A very simple graph observer that forwards events over to the +// TabLifecycleUnitSource on the UI thread. This is created on the UI thread +// and ownership passed to the performance manager. +class TabLifecycleStateObserver : public performance_manager::GraphObserver { + public: + using NodeBase = performance_manager::NodeBase; + using PageNodeImpl = performance_manager::PageNodeImpl; + using WebContentsProxy = performance_manager::WebContentsProxy; + + TabLifecycleStateObserver() = default; + ~TabLifecycleStateObserver() override = default; + + private: + bool ShouldObserve(const NodeBase* node) override { + return node->id().type == resource_coordinator::CoordinationUnitType::kPage; + } + + static void OnLifecycleStateChangedImpl( + const base::WeakPtr<WebContentsProxy>& contents_proxy, + mojom::LifecycleState state) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + // If the web contents is still alive then dispatch to the actual + // implementation in TabLifecycleUnitSource. + if (contents_proxy.get()) { + DCHECK(contents_proxy.get()->GetWebContents()); + TabLifecycleUnitSource::OnLifecycleStateChanged( + contents_proxy.get()->GetWebContents(), state); + } + } + + void OnLifecycleStateChanged(PageNodeImpl* page_node) override { + // Forward the notification over to the UI thread. + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&TabLifecycleStateObserver::OnLifecycleStateChangedImpl, + page_node->contents_proxy(), + page_node->lifecycle_state())); + } + + DISALLOW_COPY_AND_ASSIGN(TabLifecycleStateObserver); +}; + TabLifecycleUnitSource::TabLifecycleUnitSource( InterventionPolicyDatabase* intervention_policy_database, - UsageClock* usage_clock, - PageSignalReceiver* page_signal_receiver) + UsageClock* usage_clock) : browser_tab_strip_tracker_(this, nullptr, this), - page_signal_receiver_observer_(this), intervention_policy_database_(intervention_policy_database), usage_clock_(usage_clock) { // In unit tests, tabs might already exist when TabLifecycleUnitSource is @@ -67,14 +114,25 @@ DCHECK(intervention_policy_database_); browser_tab_strip_tracker_.Init(); - if (page_signal_receiver) - page_signal_receiver_observer_.Add(page_signal_receiver); + + auto* perf_man = performance_manager::PerformanceManager::GetInstance(); + if (perf_man) { + // The performance manager dies on its own sequence, so posting unretained + // is fine. + perf_man->task_runner()->PostTask( + FROM_HERE, + base::BindOnce( + &performance_manager::PerformanceManager::RegisterObserver, + base::Unretained(perf_man), + std::make_unique<TabLifecycleStateObserver>())); + } } TabLifecycleUnitSource::~TabLifecycleUnitSource() = default; +// static TabLifecycleUnitExternal* TabLifecycleUnitSource::GetTabLifecycleUnitExternal( - content::WebContents* web_contents) const { + content::WebContents* web_contents) { auto* lu = GetTabLifecycleUnit(web_contents); if (!lu) return nullptr; @@ -118,9 +176,10 @@ tab_lifecycles_enterprise_preference_monitor_.reset(); } +// static TabLifecycleUnitSource::TabLifecycleUnit* TabLifecycleUnitSource::GetTabLifecycleUnit( - content::WebContents* web_contents) const { + content::WebContents* web_contents) { auto* holder = TabLifecycleUnitHolder::FromWebContents(web_contents); if (holder) return holder->lifecycle_unit(); @@ -275,9 +334,9 @@ UpdateFocusedTab(); } +// static void TabLifecycleUnitSource::OnLifecycleStateChanged( content::WebContents* web_contents, - const PageNavigationIdentity& page_navigation_id, mojom::LifecycleState state) { TabLifecycleUnit* lifecycle_unit = GetTabLifecycleUnit(web_contents);
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h index fa6355f3..5c58462 100644 --- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h +++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
@@ -11,10 +11,10 @@ #include "base/observer_list.h" #include "base/scoped_observer.h" #include "chrome/browser/resource_coordinator/lifecycle_unit_source_base.h" -#include "chrome/browser/resource_coordinator/page_signal_receiver.h" #include "chrome/browser/ui/browser_list_observer.h" #include "chrome/browser/ui/browser_tab_strip_tracker.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" +#include "services/resource_coordinator/public/mojom/lifecycle.mojom.h" class PrefChangeRegistrar; class PrefService; @@ -29,28 +29,27 @@ class InterventionPolicyDatabase; class TabLifecylesEnterprisePreferenceMonitor; class TabLifecycleObserver; +class TabLifecycleStateObserver; class TabLifecycleUnitExternal; class UsageClock; // Creates and destroys LifecycleUnits as tabs are created and destroyed. class TabLifecycleUnitSource : public BrowserListObserver, public LifecycleUnitSourceBase, - public PageSignalObserver, public TabStripModelObserver { public: class TabLifecycleUnit; + class LifecycleStateObserver; - // |page_signal_receiver| might be null. TabLifecycleUnitSource( InterventionPolicyDatabase* intervention_policy_database, - UsageClock* usage_clock, - PageSignalReceiver* page_signal_receiver); + UsageClock* usage_clock); ~TabLifecycleUnitSource() override; // Returns the TabLifecycleUnitExternal instance associated with // |web_contents|, or nullptr if |web_contents| isn't a tab. - TabLifecycleUnitExternal* GetTabLifecycleUnitExternal( - content::WebContents* web_contents) const; + static TabLifecycleUnitExternal* GetTabLifecycleUnitExternal( + content::WebContents* web_contents); // Adds / removes an observer that is notified when the discarded or auto- // discardable state of a tab changes. @@ -78,6 +77,7 @@ void OnAllLifecycleUnitsDestroyed() override; private: + friend class TabLifecycleStateObserver; friend class TabLifecycleUnitTest; friend class TabManagerTest; FRIEND_TEST_ALL_PREFIXES(TabLifecycleUnitSourceTest, @@ -96,8 +96,8 @@ // Returns the TabLifecycleUnit instance associated with |web_contents|, or // nullptr if |web_contents| isn't a tab. - TabLifecycleUnit* GetTabLifecycleUnit( - content::WebContents* web_contents) const; + static TabLifecycleUnit* GetTabLifecycleUnit( + content::WebContents* web_contents); // Returns the TabStripModel of the focused browser window, if any. TabStripModel* GetFocusedTabStripModel() const; @@ -133,10 +133,10 @@ void OnBrowserSetLastActive(Browser* browser) override; void OnBrowserNoLongerActive(Browser* browser) override; - // PageSignalObserver: - void OnLifecycleStateChanged(content::WebContents* web_contents, - const PageNavigationIdentity& page_navigation_id, - mojom::LifecycleState state) override; + // This is called indirectly from the corresponding event on a PageNode in the + // performance_manager Graph. + static void OnLifecycleStateChanged(content::WebContents* web_contents, + mojom::LifecycleState state); // Callback for TabLifecyclesEnterprisePreferenceMonitor. void SetTabLifecyclesEnterprisePolicy(bool enabled); @@ -154,10 +154,6 @@ // changes. base::ObserverList<TabLifecycleObserver>::Unchecked tab_lifecycle_observers_; - // PageSignalReceiver is a static singleton so it outlives this object. - ScopedObserver<PageSignalReceiver, PageSignalObserver> - page_signal_receiver_observer_; - // The intervention policy database used to assist freezing/discarding // decisions. InterventionPolicyDatabase* intervention_policy_database_; @@ -196,6 +192,8 @@ PrefService* pref_service_; OnPreferenceChangedCallback callback_; std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; + + DISALLOW_COPY_AND_ASSIGN(TabLifecylesEnterprisePreferenceMonitor); }; } // namespace resource_coordinator
diff --git a/chrome/browser/resources/chromeos/switch_access/BUILD.gn b/chrome/browser/resources/chromeos/switch_access/BUILD.gn index 7033426f..094fc4f 100644 --- a/chrome/browser/resources/chromeos/switch_access/BUILD.gn +++ b/chrome/browser/resources/chromeos/switch_access/BUILD.gn
@@ -47,7 +47,7 @@ "icons/scrollUpOrBackward.svg", "icons/select.svg", "icons/showContextMenu.svg", - "keyboard_handler.js", + "key_event_handler.js", "menu_manager.js", "menu_panel.css", "menu_panel.html", @@ -160,7 +160,7 @@ ":back_button_manager", ":background", ":commands", - ":keyboard_handler", + ":key_event_handler", ":menu_manager", ":menu_panel_interface", ":navigation_manager", @@ -223,7 +223,7 @@ ] } -js_library("keyboard_handler") { +js_library("key_event_handler") { deps = [ ":switch_access_interface", ] @@ -259,7 +259,7 @@ deps = [ ":auto_scan_manager", ":commands", - ":keyboard_handler", + ":key_event_handler", ":menu_panel_interface", ":navigation_manager", ":preferences",
diff --git a/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js b/chrome/browser/resources/chromeos/switch_access/key_event_handler.js similarity index 98% rename from chrome/browser/resources/chromeos/switch_access/keyboard_handler.js rename to chrome/browser/resources/chromeos/switch_access/key_event_handler.js index 82aa748..992e39b 100644 --- a/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js +++ b/chrome/browser/resources/chromeos/switch_access/key_event_handler.js
@@ -5,7 +5,7 @@ /** * Class to handle keyboard input. */ -class KeyboardHandler { +class KeyEventHandler { /** * @param {!SwitchAccessInterface} switchAccess */ @@ -66,7 +66,6 @@ /** * Run the command associated with the passed keyboard event. - * * @param {!Event} event * @private */
diff --git a/chrome/browser/resources/chromeos/switch_access/manifest.json.jinja2 b/chrome/browser/resources/chromeos/switch_access/manifest.json.jinja2 index 5a34246..804493c 100644 --- a/chrome/browser/resources/chromeos/switch_access/manifest.json.jinja2 +++ b/chrome/browser/resources/chromeos/switch_access/manifest.json.jinja2
@@ -16,7 +16,7 @@ "closure_shim.js", "commands.js", "constants.js", - "keyboard_handler.js", + "key_event_handler.js", "menu_manager.js", "navigation_manager.js", "preferences.js",
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access.js b/chrome/browser/resources/chromeos/switch_access/switch_access.js index 364f3e0..0d2a235 100644 --- a/chrome/browser/resources/chromeos/switch_access/switch_access.js +++ b/chrome/browser/resources/chromeos/switch_access/switch_access.js
@@ -30,9 +30,9 @@ /** * Handles keyboard input. - * @private {KeyboardHandler} + * @private {KeyEventHandler} */ - this.keyboardHandler_ = null; + this.keyEventHandler_ = null; /** * Handles interactions with the accessibility tree, including moving to and @@ -65,7 +65,7 @@ this.commands_ = new Commands(this); this.switchAccessPreferences_ = new SwitchAccessPreferences(this); this.autoScanManager_ = new AutoScanManager(this); - this.keyboardHandler_ = new KeyboardHandler(this); + this.keyEventHandler_ = new KeyEventHandler(this); chrome.automation.getDesktop(function(desktop) { this.navigationManager_ = new NavigationManager(desktop); @@ -145,14 +145,14 @@ * @param {function(number)} callback */ listenForKeycodes(callback) { - this.keyboardHandler_.listenForKeycodes(callback); + this.keyEventHandler_.listenForKeycodes(callback); } /** * Stops forwarding keycodes. */ stopListeningForKeycodes() { - this.keyboardHandler_.stopListeningForKeycodes(); + this.keyEventHandler_.stopListeningForKeycodes(); } /** @@ -188,7 +188,7 @@ break; default: if (this.commands_.getCommands().includes(key)) - this.keyboardHandler_.updateSwitchAccessKeys(); + this.keyEventHandler_.updateSwitchAccessKeys(); } } }
diff --git a/chrome/browser/resources/local_ntp/externs.js b/chrome/browser/resources/local_ntp/externs.js index 8b3735d..4b4aa1c 100644 --- a/chrome/browser/resources/local_ntp/externs.js +++ b/chrome/browser/resources/local_ntp/externs.js
@@ -378,4 +378,5 @@ configData.translatedStrings.undoThumbnailRemove; configData.translatedStrings.uploadImage; configData.translatedStrings.urlField; +configData.translatedStrings.voiceCloseTooltip; configData.translatedStrings.waiting;
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html index 6617081..de6b857 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.html +++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -193,7 +193,7 @@ </div> </span> </div> - <div class="text-container"> + <div id="text-container" aria-live="polite"> <!-- Low confidence text underneath high confidence text. --> <span id="voice-text-i" class="voice-text"></span> <!-- High confidence text on top of low confidence text. -->
diff --git a/chrome/browser/resources/local_ntp/voice.css b/chrome/browser/resources/local_ntp/voice.css index 76c00da..57c350a 100644 --- a/chrome/browser/resources/local_ntp/voice.css +++ b/chrome/browser/resources/local_ntp/voice.css
@@ -284,13 +284,13 @@ * - voice-text-5l - 5 line style class */ /* Styles applied to the positioning text-container element. */ -.text-container { +#text-container { pointer-events: none; } /* Full Page UI style for the text-container. */ -.overlay .text-container, -.overlay-hidden .text-container { +.overlay #text-container, +.overlay-hidden #text-container { position: absolute; }
diff --git a/chrome/browser/resources/local_ntp/voice.js b/chrome/browser/resources/local_ntp/voice.js index fe95c7df..060972c 100644 --- a/chrome/browser/resources/local_ntp/voice.js +++ b/chrome/browser/resources/local_ntp/voice.js
@@ -363,6 +363,7 @@ waiting: translatedStrings.waiting, }; view.init(speech.onClick_); + view.setTitles(translatedStrings); speech.initWebkitSpeech_(); speech.reset_(); }; @@ -1443,7 +1444,7 @@ /** * ID for the close button in the speech output container. - * @const @private + * @const */ view.CLOSE_BUTTON_ID = 'voice-close-button'; @@ -1634,6 +1635,17 @@ /** + * Sets accessibility titles/labels for the page elements. + * @param {!Object} translatedStrings Dictionary of localized title strings. + */ +view.setTitles = function(translatedStrings) { + let closeButton = $(view.CLOSE_BUTTON_ID); + closeButton.title = translatedStrings.voiceCloseTooltip; + closeButton.setAttribute('aria-label', translatedStrings.voiceCloseTooltip); +}; + + +/** * Displays an error message and stops animations. * @param {RecognitionError} error The error type. */
diff --git a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html index b1bc15f4..253cd5c3 100644 --- a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html +++ b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
@@ -3,24 +3,24 @@ <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html"> <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="../controls/settings_slider.html"> <link rel="import" href="../controls/settings_toggle_button.html"> <link rel="import" href="../i18n_setup.html"> <link rel="import" href="../route.html"> <link rel="import" href="../settings_shared_css.html"> -<link rel="import" href="../settings_vars_css.html"> <link rel="import" href="tts_subpage.html"> <dom-module id="settings-manage-a11y-page"> <template> <style include="settings-shared"> h2 { - padding-inline-start: var(--settings-box-row-padding); + padding-inline-start: var(--cr-section-padding); } .sub-item { - margin-inline-start: var(--settings-indent-width); + margin-inline-start: var(--cr-section-indent-width); } h2 ~ .settings-box, @@ -29,8 +29,8 @@ iron-collapse .settings-box, iron-collapse settings-toggle-button, iron-collapse cr-link-row { - margin-inline-end: var(--settings-box-row-padding); - margin-inline-start: var(--settings-box-row-indent); + margin-inline-end: var(--cr-section-padding); + margin-inline-start: var(--cr-section-indent-padding); padding-inline-end: 0; padding-inline-start: 0; }
diff --git a/chrome/browser/resources/settings/a11y_page/tts_subpage.html b/chrome/browser/resources/settings/a11y_page/tts_subpage.html index 7f0ec20..5866fcc 100644 --- a/chrome/browser/resources/settings/a11y_page/tts_subpage.html +++ b/chrome/browser/resources/settings/a11y_page/tts_subpage.html
@@ -1,7 +1,8 @@ <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html" <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html" +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> @@ -10,18 +11,17 @@ <link rel="import" href="../i18n_setup.html"> <link rel="import" href="../languages_page/languages_browser_proxy.html"> <link rel="import" href="../settings_shared_css.html"> -<link rel="import" href="../settings_vars_css.html"> <dom-module id="settings-tts-subpage"> <template> <style include="settings-shared md-select"> h2 { - padding-inline-start: var(--settings-box-row-padding); + padding-inline-start: var(--cr-section-padding); } .settings-box { - margin-inline-end: var(--settings-box-row-padding); - margin-inline-start: var(--settings-box-row-indent); + margin-inline-end: var(--cr-section-padding); + margin-inline-start: var(--cr-section-indent-padding); padding-inline-end: 0; padding-inline-start: 0; }
diff --git a/chrome/browser/resources/settings/change_password_page/change_password_page.html b/chrome/browser/resources/settings/change_password_page/change_password_page.html index 8bb78ad..50554b2 100644 --- a/chrome/browser/resources/settings/change_password_page/change_password_page.html +++ b/chrome/browser/resources/settings/change_password_page/change_password_page.html
@@ -11,7 +11,7 @@ <template> <style include="settings-shared"> .icon-container { - padding-inline-end: var(--settings-box-row-padding); + padding-inline-end: var(--cr-section-padding); } .change-password-icon { @@ -25,7 +25,7 @@ .top-aligned-settings-box { align-items: start; min-height: 0; - padding: 12px var(--settings-box-row-padding); + padding: 12px var(--cr-section-padding); } </style> <div class="settings-box first top-aligned-settings-box">
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.html b/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.html index 6fda33ac..2ff69ed6d 100644 --- a/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.html +++ b/chrome/browser/resources/settings/chrome_cleanup_page/items_to_remove_list.html
@@ -12,7 +12,7 @@ :host { display: block; margin: 0; - padding: 0 var(--settings-box-row-padding); + padding: 0 var(--cr-section-padding); word-break: break-all; }
diff --git a/chrome/browser/resources/settings/device_page/pointers.html b/chrome/browser/resources/settings/device_page/pointers.html index 3208555..95301b1 100644 --- a/chrome/browser/resources/settings/device_page/pointers.html +++ b/chrome/browser/resources/settings/device_page/pointers.html
@@ -1,6 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="../controls/settings_radio_group.html"> <link rel="import" href="../controls/settings_slider.html"> <link rel="import" href="../controls/settings_toggle_button.html"> @@ -11,12 +12,12 @@ <template> <style include="settings-shared"> h2 { - padding-inline-start: var(--settings-box-row-padding); + padding-inline-start: var(--cr-section-padding); } .subsection { - padding-inline-end: var(--settings-box-row-padding); - padding-inline-start: var(--settings-box-row-indent); + padding-inline-end: var(--cr-section-padding); + padding-inline-start: var(--cr-section-indent-padding); } .subsection > settings-toggle-button,
diff --git a/chrome/browser/resources/settings/device_page/stylus.html b/chrome/browser/resources/settings/device_page/stylus.html index 67e0572..7dad79f 100644 --- a/chrome/browser/resources/settings/device_page/stylus.html +++ b/chrome/browser/resources/settings/device_page/stylus.html
@@ -2,6 +2,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html"> <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/action_link.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> <link rel="import" href="../controls/settings_toggle_button.html"> @@ -27,7 +28,7 @@ } #note-taking-app-lock-screen-settings { - padding: 0 var(--settings-box-row-padding); + padding: 0 var(--cr-section-padding); } </style>
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html index cea0cb8c..e178d57 100644 --- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html +++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -24,6 +24,7 @@ <link rel="import" href="../controls/settings_toggle_button.html"> <link rel="import" href="../prefs/prefs.html"> <link rel="import" href="../route.html"> +<link rel="import" href="internet_page_browser_proxy.html"> <link rel="import" href="internet_shared_css.html"> <link rel="import" href="network_proxy_section.html"> <link rel="import" href="tether_connection_dialog.html">
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.html b/chrome/browser/resources/settings/internet_page/internet_page.html index 451eadba..14ba902 100644 --- a/chrome/browser/resources/settings/internet_page/internet_page.html +++ b/chrome/browser/resources/settings/internet_page/internet_page.html
@@ -16,6 +16,7 @@ <link rel="import" href="internet_config.html"> <link rel="import" href="internet_detail_page.html"> <link rel="import" href="internet_known_networks_page.html"> +<link rel="import" href="internet_page_browser_proxy.html"> <link rel="import" href="internet_subpage.html"> <link rel="import" href="network_summary.html">
diff --git a/chrome/browser/resources/settings/internet_page/internet_shared_css.html b/chrome/browser/resources/settings/internet_page/internet_shared_css.html index a3b39fb..fb67a79 100644 --- a/chrome/browser/resources/settings/internet_page/internet_shared_css.html +++ b/chrome/browser/resources/settings/internet_page/internet_shared_css.html
@@ -1,12 +1,12 @@ +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="../settings_shared_css.html"> -<link rel="import" href="internet_page_browser_proxy.html"> <!-- Common styles for Internet settings. --> <dom-module id="internet-shared"> <template> <style include="settings-shared"> cr-network-icon { - padding-inline-end: var(--settings-box-row-padding); + padding-inline-end: var(--cr-section-padding); } iron-icon.policy { @@ -14,7 +14,7 @@ } .indented { - margin-inline-start: var(--settings-box-row-padding); + margin-inline-start: var(--cr-section-padding); } .stretch {
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.html b/chrome/browser/resources/settings/internet_page/internet_subpage.html index 8b4ce8ff..f042c25 100644 --- a/chrome/browser/resources/settings/internet_page/internet_subpage.html +++ b/chrome/browser/resources/settings/internet_page/internet_subpage.html
@@ -7,6 +7,7 @@ <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> +<link rel="import" href="internet_page_browser_proxy.html"> <link rel="import" href="../settings_shared_css.html"> <dom-module id="settings-internet-subpage"> @@ -21,9 +22,9 @@ separator lines can fill the entire width of the page. */ #networkListDiv > * { /* cr-network-list is padded to the right to allow space for a ripple */ - padding-inline-end: calc(var(--settings-box-row-padding) - + padding-inline-end: calc(var(--cr-section-padding) - var(--cr-icon-ripple-padding)); - padding-inline-start: var(--settings-box-row-padding); + padding-inline-start: var(--cr-section-padding); } #addButton {
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html index d9b0ad0e..e5326a65 100644 --- a/chrome/browser/resources/settings/internet_page/network_summary_item.html +++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -9,17 +9,16 @@ <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> <link rel="import" href="../settings_page/settings_subpage.html"> -<link rel="import" href="../settings_shared_css.html"> <dom-module id="network-summary-item"> <template> <style include="internet-shared iron-flex"> network-siminfo { - padding-inline-start: var(--settings-box-row-padding); + padding-inline-start: var(--cr-section-padding); } #outerBox { - padding: 0 var(--settings-box-row-padding); + padding: 0 var(--cr-section-padding); @apply(--network-summary-item-outer-box); }
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html index b8deca0..3548eb6 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.html +++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -280,8 +280,7 @@ <settings-toggle-button id="enableSpellcheckingToggle" label="$i18n{spellCheckTitle}" - pref="{{prefs.browser.enable_spellchecking}}" - on-change="onEnableSpellCheckingChange_"> + pref="{{prefs.browser.enable_spellchecking}}"> </settings-toggle-button> <if expr="_google_chrome or not is_macosx"> <iron-collapse id="spellCheckCollapse"
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.js b/chrome/browser/resources/settings/languages_page/languages_page.js index 2274cdf..332477f 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.js +++ b/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -573,19 +573,6 @@ settings.navigateTo(settings.routes.EDIT_DICTIONARY); }, - /** @private */ - onEnableSpellCheckingChange_: function() { - // <if expr="not is_macosx"> - if (this.getPref('browser.enable_spellchecking').value) { - this.spellCheckLanguages_.forEach(item => { - if (!item.isManaged && item.language.supportsSpellcheck) { - this.languageHelper.toggleSpellCheck(item.language.code, true); - } - }); - } - // </if> - }, - /** * Handler for enabling or disabling spell check for a specific language. * @param {!{target: Element, model: !{item: !LanguageState}}} e @@ -598,18 +585,6 @@ this.languageHelper.toggleSpellCheck( item.language.code, !item.spellCheckEnabled); - - // <if expr="not is_macosx"> - // When the user toggles off spellcheck for all languages, disable - // spellcheck entirely to signal to the user that no spellcheck will occur. - const allSpellcheckLanguagesDisabled = - this.spellCheckLanguages_.every(item => !item.spellCheckEnabled); - if (allSpellcheckLanguagesDisabled && - this.getPref('browser.enable_spellchecking').enforcement !== - chrome.settingsPrivate.Enforcement.ENFORCED) { - this.setPrefValue('browser.enable_spellchecking', false); - } - // </if> }, /**
diff --git a/chrome/browser/resources/settings/people_page/signout_dialog.html b/chrome/browser/resources/settings/people_page/signout_dialog.html index af7c0a5..4a93842 100644 --- a/chrome/browser/resources/settings/people_page/signout_dialog.html +++ b/chrome/browser/resources/settings/people_page/signout_dialog.html
@@ -3,6 +3,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html"> <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="profile_info_browser_proxy.html"> @@ -13,7 +14,7 @@ <template> <style include="settings-shared"> #dialog [slot=footer] .settings-box { - --settings-box-row-padding: 0; + --cr-section-padding: 0; } .delete-profile-warning {
diff --git a/chrome/browser/resources/settings/people_page/sync_page.html b/chrome/browser/resources/settings/people_page/sync_page.html index d15fdf1..c68b40c 100644 --- a/chrome/browser/resources/settings/people_page/sync_page.html +++ b/chrome/browser/resources/settings/people_page/sync_page.html
@@ -37,7 +37,7 @@ #create-password-box { /* In order to line up with the encryption radio box text. */ - margin-inline-start: var(--settings-indent-width); + margin-inline-start: var(--cr-section-indent-width); } #create-password-box { @@ -56,7 +56,7 @@ border-bottom: var(--cr-separator-line); border-top: var(--cr-separator-line); /* This particular list frame is not indented. */ - padding-inline-start: var(--settings-box-row-padding); + padding-inline-start: var(--cr-section-padding); } #submitExistingPassphrase {
diff --git a/chrome/browser/resources/settings/people_page/users_page.html b/chrome/browser/resources/settings/people_page/users_page.html index 597cfba..afdbbe7 100644 --- a/chrome/browser/resources/settings/people_page/users_page.html +++ b/chrome/browser/resources/settings/people_page/users_page.html
@@ -1,7 +1,8 @@ <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/html/action_link.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/action_link_css.html"> +<link rel="import" href="chrome://resources/html/action_link.html"> <link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> @@ -19,7 +20,7 @@ #add-user-button { /* Add user button must be lined up with the start of users' names. */ - margin-inline-start: var(--settings-box-row-indent); + margin-inline-start: var(--cr-section-indent-padding); } #add-user-button a {
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html index e18531b..d2797c0 100644 --- a/chrome/browser/resources/settings/search_page/search_page.html +++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -2,6 +2,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/md_select_css.html"> @@ -37,7 +38,7 @@ } .indented { - margin-inline-start: var(--settings-indent-width); + margin-inline-start: var(--cr-section-indent-width); } </style> <settings-animated-pages id="pages" section="search"
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html index a6eb0f2a..5585da8 100644 --- a/chrome/browser/resources/settings/settings_shared_css.html +++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -248,7 +248,7 @@ /* A settings-box that is embedded in another settings-box (e.g. a control * that is associated with a toggle button). */ .settings-box.embedded { - padding-inline-start: var(--settings-box-row-indent); + padding-inline-start: var(--cr-section-indent-padding); } /* The lower line of text in a two-line row. */
diff --git a/chrome/browser/resources/settings/settings_vars_css.html b/chrome/browser/resources/settings/settings_vars_css.html index 344d4f2..23ba190 100644 --- a/chrome/browser/resources/settings/settings_vars_css.html +++ b/chrome/browser/resources/settings/settings_vars_css.html
@@ -12,15 +12,12 @@ /* Some colors use non-MD colors. These custom colors are specified by * UX design (bettes@). */ - --settings-box-row-padding: var(--cr-section-padding); - --settings-box-row-indent: var(--cr-section-indent-padding); - --settings-indent-width: var(--cr-section-indent-width); --settings-disabled-opacity: .65; --settings-error-color: var(--google-red-700); --settings-list-frame-padding: { - padding-inline-end: var(--settings-box-row-padding); - padding-inline-start: var(--settings-box-row-indent); + padding-inline-end: var(--cr-section-padding); + padding-inline-start: var(--cr-section-indent-padding); padding-bottom: 0; padding-top: 0; }
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.html b/chrome/browser/resources/settings/site_settings/all_sites.html index 8be1d503..eb14758 100644 --- a/chrome/browser/resources/settings/site_settings/all_sites.html +++ b/chrome/browser/resources/settings/site_settings/all_sites.html
@@ -1,12 +1,12 @@ <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="../global_scroll_target_behavior.html"> <link rel="import" href="../route.html"> <link rel="import" href="../settings_shared_css.html"> -<link rel="import" href="../settings_vars_css.html"> <link rel="import" href="site_entry.html"> <link rel="import" href="site_settings_behavior.html"> @@ -18,7 +18,7 @@ display: flex; margin: 0 var(--cr-icon-button-margin-start); margin-bottom: 50px; - padding: 0 var(--settings-box-row-padding); + padding: 0 var(--cr-section-padding); } #sortMethod { @@ -28,7 +28,7 @@ /* There is only one top-level heading for All Sites, so remove the * additional leading padding used for lists. */ .list-frame.without-heading { - padding-inline-start: var(--settings-box-row-padding); + padding-inline-start: var(--cr-section-padding); } </style> <div id="sort">
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html index d1f0b2db..16e1db8 100644 --- a/chrome/browser/resources/settings/site_settings/site_details.html +++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -8,6 +8,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="../icons.html"> <link rel="import" href="../route.html"> <link rel="import" href="../settings_shared_css.html"> @@ -35,7 +36,7 @@ * that would normally be provided by the subheading. */ .list-frame.without-heading { margin-top: 12px; - padding-inline-start: var(--settings-box-row-padding); + padding-inline-start: var(--cr-section-padding); } #resetSettingsButton {
diff --git a/chrome/browser/resources/snippets_internals/snippets_internals.html b/chrome/browser/resources/snippets_internals/snippets_internals.html index b59f1e9..4c240d4 100644 --- a/chrome/browser/resources/snippets_internals/snippets_internals.html +++ b/chrome/browser/resources/snippets_internals/snippets_internals.html
@@ -116,9 +116,6 @@ <button id="background-fetch-button"> Fetch remote suggestions in the background in 2 seconds </button> - <button id="push-dummy-suggestion"> - Push dummy suggestion in 10 seconds - </button> <button id="last-json-button">Show the last JSON</button> <div id="last-json-container" class="hidden"> <div id="last-json-text"></div>
diff --git a/chrome/browser/resources/snippets_internals/snippets_internals.js b/chrome/browser/resources/snippets_internals/snippets_internals.js index 71bd8db5..27b09c3 100644 --- a/chrome/browser/resources/snippets_internals/snippets_internals.js +++ b/chrome/browser/resources/snippets_internals/snippets_internals.js
@@ -102,13 +102,6 @@ }); } -/* Check if pushing dummy suggestions is possible. */ -function checkIfPushingDummySuggestionPossible() { - pageHandler.isPushingDummySuggestionPossible().then(function(response) { - $('push-dummy-suggestion').disabled = !response.result; - }); -} - /* Retrieve the remote content suggestions properties. */ function getRemoteContentSuggestionsProperties() { pageHandler.getRemoteContentSuggestionsProperties().then(function(response) { @@ -194,7 +187,6 @@ getUserClassifierProperties(); getCategoryRankerProperties(); getRemoteContentSuggestionsProperties(); - checkIfPushingDummySuggestionPossible(); } /* Setup buttons and other event listeners. */ @@ -233,14 +225,6 @@ }); }); - $('push-dummy-suggestion').addEventListener('click', function(event) { - const content = $('push-dummy-suggestion').textContent; - $('push-dummy-suggestion').textContent = '...'; - pageHandler.pushDummySuggestionInBackground(10).then(function(response) { - $('push-dummy-suggestion').textContent = content; - }); - }); - $('last-json-button').addEventListener('click', function(event) { pageHandler.getLastJson().then(function(response) { const container = $('last-json-container');
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc index 60c5503..cd5bda9c 100644 --- a/chrome/browser/search/local_ntp_source.cc +++ b/chrome/browser/search/local_ntp_source.cc
@@ -300,6 +300,8 @@ AddString(translated_strings.get(), "waiting", IDS_NEW_TAB_VOICE_WAITING); AddString(translated_strings.get(), "otherError", IDS_NEW_TAB_VOICE_OTHER_ERROR); + AddString(translated_strings.get(), "voiceCloseTooltip", + IDS_NEW_TAB_VOICE_CLOSE_TOOLTIP); } return translated_strings;
diff --git a/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc index 96e93313..6d3958da 100644 --- a/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
@@ -506,8 +506,11 @@ EXPECT_TRUE(local_address_0.EqualsForSyncPurposes(*local_addresses_1[0])); } +// TODO(crbug.com/953152): Flaky on multiple builders and recently regressed on +// Mac, apparently with +// https://chromium-review.googlesource.com/c/chromium/src/+/1566296. IN_PROC_BROWSER_TEST_P(TwoClientWalletSyncTest, - DeleteServerCardMetadataWhenDataGetsRemoved) { + DISABLED_DeleteServerCardMetadataWhenDataGetsRemoved) { GetFakeServer()->SetWalletData( {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001", kDefaultBillingAddressID),
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc index befa827..d451b6c 100644 --- a/chrome/browser/translate/chrome_translate_client.cc +++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -18,7 +18,6 @@ #include "chrome/browser/language/language_model_manager_factory.h" #include "chrome/browser/language/url_language_histogram_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/sync/user_event_service_factory.h" #include "chrome/browser/translate/translate_accept_languages_factory.h" #include "chrome/browser/translate/translate_ranker_factory.h" #include "chrome/browser/translate/translate_service.h" @@ -34,9 +33,6 @@ #include "components/language/core/browser/language_model_manager.h" #include "components/language/core/browser/pref_names.h" #include "components/prefs/pref_service.h" -#include "components/sync/driver/sync_driver_switches.h" -#include "components/sync/protocol/user_event_specifics.pb.h" -#include "components/sync/user_events/user_event_service.h" #include "components/translate/core/browser/language_state.h" #include "components/translate/core/browser/page_translated_details.h" #include "components/translate/core/browser/translate_accept_languages.h" @@ -181,9 +177,6 @@ ->GetPrimaryModel()); } -void ChromeTranslateClient::RecordTranslateEvent( - const TranslateEventProto& translate_event) {} - translate::TranslateManager* ChromeTranslateClient::GetTranslateManager() { return translate_manager_.get(); } @@ -276,9 +269,6 @@ manager->SetPredefinedTargetLanguage(translate_language_code); } -void ChromeTranslateClient::RecordLanguageDetectionEvent( - const translate::LanguageDetectionDetails& details) const {} - bool ChromeTranslateClient::IsTranslatableURL(const GURL& url) { return TranslateService::IsTranslatableURL(url); } @@ -319,8 +309,6 @@ content::Source<content::WebContents>(web_contents()), content::Details<const translate::LanguageDetectionDetails>(&details)); - RecordLanguageDetectionEvent(details); - #if defined(OS_ANDROID) // See ChromeTranslateClient::ManualTranslateOnReady if (manual_translate_on_ready_) {
diff --git a/chrome/browser/translate/chrome_translate_client.h b/chrome/browser/translate/chrome_translate_client.h index 07ea49f6..e2a51fe 100644 --- a/chrome/browser/translate/chrome_translate_client.h +++ b/chrome/browser/translate/chrome_translate_client.h
@@ -86,7 +86,6 @@ PrefService* GetPrefs() override; std::unique_ptr<translate::TranslatePrefs> GetTranslatePrefs() override; translate::TranslateAcceptLanguages* GetTranslateAcceptLanguages() override; - void RecordTranslateEvent(const metrics::TranslateEventProto&) override; #if defined(OS_ANDROID) std::unique_ptr<infobars::InfoBar> CreateInfoBar( std::unique_ptr<translate::TranslateInfoBarDelegate> delegate) @@ -99,8 +98,6 @@ #endif void SetPredefinedTargetLanguage(const std::string& translate_language_code); - void RecordLanguageDetectionEvent( - const translate::LanguageDetectionDetails& details) const override; bool ShowTranslateUI(translate::TranslateStep step, const std::string& source_language, const std::string& target_language,
diff --git a/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc b/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc index 642d21df..b531ded 100644 --- a/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc +++ b/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc
@@ -286,7 +286,9 @@ generator.Wait(); } -IN_PROC_BROWSER_TEST_P(OverviewWindowDragTest, DragToClose) { +// The test is flaky because close notification is not the right singal. +// crbug.com/953355 +IN_PROC_BROWSER_TEST_P(OverviewWindowDragTest, DISABLED_DragToClose) { BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow(); ui_controls::SendKeyPress(browser_window, ui::VKEY_MEDIA_LAUNCH_APP1,
diff --git a/chrome/browser/ui/ash/system_tray_client.cc b/chrome/browser/ui/ash/system_tray_client.cc index 8b3d42a..16a9d757 100644 --- a/chrome/browser/ui/ash/system_tray_client.cc +++ b/chrome/browser/ui/ash/system_tray_client.cc
@@ -303,10 +303,8 @@ return; } - // Otherwise show enterprise help in a browser tab. - chrome::ScopedTabbedBrowserDisplayer displayer( - ProfileManager::GetActiveUserProfile()); - ShowSingletonTab(displayer.browser(), GURL(chrome::kLearnMoreEnterpriseURL)); + // Otherwise show enterprise special settings subpage. + chrome::ShowManagementPageForProfile(ProfileManager::GetActiveUserProfile()); } void SystemTrayClient::ShowNetworkConfigure(const std::string& network_id) {
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc index 23ef2ed9..36014411 100644 --- a/chrome/browser/ui/chrome_pages.cc +++ b/chrome/browser/ui/chrome_pages.cc
@@ -383,6 +383,15 @@ ShowSettingsSubPage(browser, kSearchEnginesSubPage); } +#if defined(OS_CHROMEOS) +void ShowManagementPageForProfile(Profile* profile) { + const std::string page_path = "chrome://management"; + base::RecordAction(base::UserMetricsAction("ShowOptions")); + SettingsWindowManager::GetInstance()->ShowChromePageForProfile( + profile, GURL(page_path)); +} +#endif + #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) void ShowBrowserSignin(Browser* browser, signin_metrics::AccessPoint access_point) {
diff --git a/chrome/browser/ui/chrome_pages.h b/chrome/browser/ui/chrome_pages.h index bced34e..0aa6ebb 100644 --- a/chrome/browser/ui/chrome_pages.h +++ b/chrome/browser/ui/chrome_pages.h
@@ -109,6 +109,10 @@ void ShowAboutChrome(Browser* browser); void ShowSearchEngineSettings(Browser* browser); +#if defined(OS_CHROMEOS) +void ShowManagementPageForProfile(Profile* profile); +#endif + #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) // Initiates signin in a new browser tab. void ShowBrowserSignin(Browser* browser,
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc index 47f62608..053370f 100644 --- a/chrome/browser/ui/views/find_bar_view.cc +++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -192,8 +192,6 @@ close_button_->SetFocusForPlatform(); close_button_->SetTooltipText( l10n_util::GetStringUTF16(IDS_FIND_IN_PAGE_CLOSE_TOOLTIP)); - close_button_->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); close_button_->SetAnimationDuration(0); AddChildView(close_button_);
diff --git a/chrome/browser/ui/views/ime/ime_warning_bubble_view.cc b/chrome/browser/ui/views/ime/ime_warning_bubble_view.cc index f59fb3cb..9b5a396 100644 --- a/chrome/browser/ui/views/ime/ime_warning_bubble_view.cc +++ b/chrome/browser/ui/views/ime/ime_warning_bubble_view.cc
@@ -132,8 +132,7 @@ views::View* reference_view = nullptr; anchor_to_action_ = - extensions::ActionInfo::GetBrowserActionInfo(extension_) || - extensions::ActionInfo::GetPageActionInfo(extension_); + extensions::ActionInfo::GetAnyActionInfo(extension_) != nullptr; if (anchor_to_action_) { // Anchors the bubble to the browser action of the extension. reference_view = container_->GetViewForId(extension_->id());
diff --git a/chrome/browser/ui/views/webauthn/authenticator_client_pin_entry_view.cc b/chrome/browser/ui/views/webauthn/authenticator_client_pin_entry_view.cc index e1687af..561eca35 100644 --- a/chrome/browser/ui/views/webauthn/authenticator_client_pin_entry_view.cc +++ b/chrome/browser/ui/views/webauthn/authenticator_client_pin_entry_view.cc
@@ -30,7 +30,6 @@ auto field = std::make_unique<views::Textfield>(); field->SetTextInputType(ui::TextInputType::TEXT_INPUT_TYPE_PASSWORD); - field->SetBackgroundColor(gfx::kGoogleGrey100); field->SetMinimumWidthInChars(kMinWidthInChars); field->SetDefaultWidthInChars(kDefaultWidthInChars); field->SetBorder(views::CreateSolidSidedBorder(0, 0, kBottomBorderThickness,
diff --git a/chrome/browser/ui/views/webauthn/ble_pin_entry_view.cc b/chrome/browser/ui/views/webauthn/ble_pin_entry_view.cc index fe87f583..108d48d 100644 --- a/chrome/browser/ui/views/webauthn/ble_pin_entry_view.cc +++ b/chrome/browser/ui/views/webauthn/ble_pin_entry_view.cc
@@ -46,7 +46,6 @@ AddChildView(textfield_label_ptr); pin_text_field_ = new views::Textfield(); - pin_text_field_->SetBackgroundColor(gfx::kGoogleGrey100); pin_text_field_->SetMinimumWidthInChars(kExpectedPincodeCharLength); pin_text_field_->SetDefaultWidthInChars(kPreferredTextfieldCharLength); pin_text_field_->SetBorder(views::CreateSolidSidedBorder(
diff --git a/chrome/browser/ui/webui/snippets_internals/snippets_internals.mojom b/chrome/browser/ui/webui/snippets_internals/snippets_internals.mojom index d7793d4a0..fc2b659 100644 --- a/chrome/browser/ui/webui/snippets_internals/snippets_internals.mojom +++ b/chrome/browser/ui/webui/snippets_internals/snippets_internals.mojom
@@ -58,12 +58,6 @@ // Fetch suggestions in background after the given delay. FetchSuggestionsInBackground(int64 delaySeconds) => (); - // Returns if it's possible to push a dummy suggestion. - IsPushingDummySuggestionPossible() => (bool result); - - // Push dummy suggestion in background after the given delay. - PushDummySuggestionInBackground(int64 delaySeconds) => (); - // Download the last suggestions in json form. GetLastJson() => (string json); @@ -80,4 +74,4 @@ // Frontend interface. interface Page { OnSuggestionsChanged(); -}; \ No newline at end of file +};
diff --git a/chrome/browser/ui/webui/snippets_internals/snippets_internals_page_handler.cc b/chrome/browser/ui/webui/snippets_internals/snippets_internals_page_handler.cc index a357381..9102e5dd 100644 --- a/chrome/browser/ui/webui/snippets_internals/snippets_internals_page_handler.cc +++ b/chrome/browser/ui/webui/snippets_internals/snippets_internals_page_handler.cc
@@ -11,7 +11,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "base/time/time_to_iso8601.h" #include "chrome/browser/android/ntp/android_content_suggestions_notifier.h" #include "chrome/common/pref_names.h" #include "components/ntp_snippets/category_info.h" @@ -62,16 +61,6 @@ return value ? "True" : "False"; } -ntp_snippets::BreakingNewsListener* GetBreakingNewsListener( - ntp_snippets::ContentSuggestionsService* service) { - DCHECK(service); - RemoteSuggestionsProvider* provider = - service->remote_suggestions_provider_for_debugging(); - DCHECK(provider); - return static_cast<ntp_snippets::RemoteSuggestionsProviderImpl*>(provider) - ->breaking_news_listener_for_debugging(); -} - std::string GetCategoryStatusName(CategoryStatus status) { switch (status) { case CategoryStatus::INITIALIZING: @@ -278,67 +267,6 @@ std::move(callback).Run(); } -void SnippetsInternalsPageHandler::IsPushingDummySuggestionPossible( - IsPushingDummySuggestionPossibleCallback callback) { - ntp_snippets::BreakingNewsListener* listener = - GetBreakingNewsListener(content_suggestions_service_); - - std::move(callback).Run(listener != nullptr && listener->IsListening()); -} - -void SnippetsInternalsPageHandler::PushDummySuggestionInBackground( - int64_t delaySeconds, - PushDummySuggestionInBackgroundCallback callback) { - DCHECK(delaySeconds >= 0); - suggestion_push_timer_.Start( - FROM_HERE, base::TimeDelta::FromSeconds(delaySeconds), - base::BindRepeating( - &SnippetsInternalsPageHandler::PushDummySuggestionInBackgroundImpl, - weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(callback)))); -} - -void SnippetsInternalsPageHandler::PushDummySuggestionInBackgroundImpl( - PushDummySuggestionInBackgroundCallback callback) { - std::string json = R"( - {"categories" : [{ - "id": 1, - "localizedTitle": "section title", - "suggestions" : [{ - "ids" : ["http://url.com"], - "title" : "Pushed Dummy Title %s", - "snippet" : "Pushed Dummy Snippet", - "fullPageUrl" : "http://url.com", - "creationTime" : "%s", - "expirationTime" : "%s", - "attribution" : "Pushed Dummy Publisher", - "imageUrl" : "https://www.google.com/favicon.ico", - "notificationInfo": { - "shouldNotify": true, - "deadline": "2100-01-01T00:00:01.000Z" - } - }] - }]} - )"; - - const base::Time now = base::Time::Now(); - json = base::StringPrintf( - json.c_str(), base::UTF16ToUTF8(base::TimeFormatTimeOfDay(now)).c_str(), - base::TimeToISO8601(now).c_str(), - base::TimeToISO8601(now + base::TimeDelta::FromMinutes(60)).c_str()); - - gcm::IncomingMessage message; - message.data["payload"] = json; - - ntp_snippets::BreakingNewsListener* listener = - GetBreakingNewsListener(content_suggestions_service_); - DCHECK(listener); - DCHECK(listener->IsListening()); - static_cast<ntp_snippets::BreakingNewsGCMAppHandler*>(listener)->OnMessage( - "com.google.breakingnews.gcm", message); - - std::move(callback).Run(); -} - void SnippetsInternalsPageHandler::GetLastJson(GetLastJsonCallback callback) { std::string json = ""; if (remote_suggestions_provider_) {
diff --git a/chrome/browser/ui/webui/snippets_internals/snippets_internals_page_handler.h b/chrome/browser/ui/webui/snippets_internals/snippets_internals_page_handler.h index b134684..ae81aa2 100644 --- a/chrome/browser/ui/webui/snippets_internals/snippets_internals_page_handler.h +++ b/chrome/browser/ui/webui/snippets_internals/snippets_internals_page_handler.h
@@ -41,11 +41,6 @@ void FetchSuggestionsInBackground( int64_t, FetchSuggestionsInBackgroundCallback) override; - void IsPushingDummySuggestionPossible( - IsPushingDummySuggestionPossibleCallback) override; - void PushDummySuggestionInBackground( - int64_t, - PushDummySuggestionInBackgroundCallback) override; void GetLastJson(GetLastJsonCallback) override; void ResetNotificationState() override; void GetSuggestionsByCategory(GetSuggestionsByCategoryCallback) override; @@ -64,8 +59,6 @@ void FetchSuggestionsInBackgroundImpl(FetchSuggestionsInBackgroundCallback); void GetSuggestionsByCategoryImpl(GetSuggestionsByCategoryCallback); - void PushDummySuggestionInBackgroundImpl( - PushDummySuggestionInBackgroundCallback); // Misc. methods. void CollectDismissedSuggestions( @@ -94,7 +87,6 @@ // Timers to delay actions. base::OneShotTimer suggestion_fetch_timer_; - base::OneShotTimer suggestion_push_timer_; // Handle back to the page by which we can update. snippets_internals::mojom::PagePtr page_;
diff --git a/chrome/chrome_cleaner/engines/broker/cleaner_engine_requests_impl.cc b/chrome/chrome_cleaner/engines/broker/cleaner_engine_requests_impl.cc index 16e2c8f..3a0e61a 100644 --- a/chrome/chrome_cleaner/engines/broker/cleaner_engine_requests_impl.cc +++ b/chrome/chrome_cleaner/engines/broker/cleaner_engine_requests_impl.cc
@@ -22,15 +22,12 @@ std::unique_ptr<chrome_cleaner::FileRemoverAPI> CreateFileRemoverWithDigestVerifier( const std::vector<UwSId>& enabled_uws, - std::unique_ptr<SandboxedZipArchiver> archiver, + std::unique_ptr<ZipArchiver> archiver, const base::RepeatingClosure& reboot_needed_callback) { auto digest = GetDigestVerifier(); auto lsp = chrome_cleaner::LayeredServiceProviderWrapper(); - auto deletion_allowed_paths = - PUPData::GetFilesDetectedInServices(enabled_uws); return std::make_unique<chrome_cleaner::FileRemover>( - digest, std::move(archiver), lsp, deletion_allowed_paths, - reboot_needed_callback); + digest, std::move(archiver), lsp, reboot_needed_callback); } CleanerEngineRequestsImpl::CleanerEngineRequestsImpl(
diff --git a/chrome/chrome_cleaner/engines/broker/cleaner_engine_requests_impl.h b/chrome/chrome_cleaner/engines/broker/cleaner_engine_requests_impl.h index 1ed5cab3..dd1fc123 100644 --- a/chrome/chrome_cleaner/engines/broker/cleaner_engine_requests_impl.h +++ b/chrome/chrome_cleaner/engines/broker/cleaner_engine_requests_impl.h
@@ -15,7 +15,7 @@ #include "chrome/chrome_cleaner/engines/broker/interface_metadata_observer.h" #include "chrome/chrome_cleaner/interfaces/cleaner_engine_requests.mojom.h" #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h" -#include "chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h" +#include "chrome/chrome_cleaner/zip_archiver/zip_archiver.h" #include "mojo/public/cpp/bindings/associated_binding.h" namespace chrome_cleaner { @@ -23,7 +23,7 @@ std::unique_ptr<chrome_cleaner::FileRemoverAPI> CreateFileRemoverWithDigestVerifier( const std::vector<UwSId>& enabled_uws, - std::unique_ptr<SandboxedZipArchiver> archiver, + std::unique_ptr<ZipArchiver> archiver, const base::RepeatingClosure& reboot_needed_callback); class CleanerEngineRequestsImpl : public mojom::CleanerEngineRequests {
diff --git a/chrome/chrome_cleaner/engines/broker/cleaner_sandbox_interface_unittest.cc b/chrome/chrome_cleaner/engines/broker/cleaner_sandbox_interface_unittest.cc index 9925699b..5bcd26b 100644 --- a/chrome/chrome_cleaner/engines/broker/cleaner_sandbox_interface_unittest.cc +++ b/chrome/chrome_cleaner/engines/broker/cleaner_sandbox_interface_unittest.cc
@@ -158,7 +158,6 @@ file_remover_ = std::make_unique<chrome_cleaner::FileRemover>( /*digest_verifier=*/nullptr, /*archiver=*/nullptr, chrome_cleaner::LayeredServiceProviderWrapper(), - chrome_cleaner::FilePathSet(), base::BindRepeating( &CleanerSandboxInterfaceDeleteFileTest::RebootRequired, base::Unretained(this))); @@ -223,7 +222,7 @@ EXPECT_TRUE(base::DirectoryExists(dir_path)); } -TEST_F(CleanerSandboxInterfaceDeleteFileTest, NotActiveFileType) { +TEST_F(CleanerSandboxInterfaceDeleteFileTest, NotExecutableFileType) { base::ScopedTempDir temp; ASSERT_TRUE(temp.CreateUniqueTempDir()); base::FilePath file_path = temp.GetPath().Append(L"temp_file.txt"); @@ -231,7 +230,7 @@ file_path.DirName(), file_path.BaseName().value().c_str())); chrome_cleaner::VerifyRemoveNowSuccess(file_path, file_remover_.get()); - EXPECT_TRUE(base::PathExists(file_path)); + EXPECT_FALSE(base::PathExists(file_path)); } TEST_F(CleanerSandboxInterfaceDeleteFileTest, DeleteFile_RelativeFilePath) { @@ -439,7 +438,7 @@ EXPECT_FALSE(base::PathExists(executable_path)); } -TEST_F(CleanerSandboxInterfaceDeleteFileTest, IgnoreTextWithDefaultStream) { +TEST_F(CleanerSandboxInterfaceDeleteFileTest, TextWithDefaultStream) { base::ScopedTempDir temp; ASSERT_TRUE(temp.CreateUniqueTempDir()); base::FilePath file_path = temp.GetPath().Append(L"temp_file.txt"); @@ -452,40 +451,6 @@ chrome_cleaner::VerifyRemoveNowSuccess(path_with_datatype, file_remover_.get()); - EXPECT_TRUE(base::PathExists(file_path)); -} - -TEST_F(CleanerSandboxInterfaceDeleteFileTest, DeleteDosMzExecutables) { - base::ScopedTempDir temp; - ASSERT_TRUE(temp.CreateUniqueTempDir()); - base::FilePath file_path = temp.GetPath().Append(L"temp_file.txt"); - const char kExecutableFileContents[] = "MZ I am so executable"; - chrome_cleaner::CreateFileWithContent(file_path, kExecutableFileContents, - sizeof(kExecutableFileContents)); - - chrome_cleaner::VerifyRemoveNowSuccess(file_path, file_remover_.get()); - EXPECT_FALSE(base::PathExists(file_path)); -} - -TEST_F(CleanerSandboxInterfaceDeleteFileTest, DeletesWhitelisted) { - base::ScopedTempDir temp; - ASSERT_TRUE(temp.CreateUniqueTempDir()); - base::FilePath file_path = temp.GetPath().Append(L"temp_file.txt"); - ASSERT_TRUE(chrome_cleaner::CreateFileInFolder( - file_path.DirName(), file_path.BaseName().value().c_str())); - - chrome_cleaner::VerifyRemoveNowSuccess(file_path, file_remover_.get()); - EXPECT_TRUE(base::PathExists(file_path)); - - chrome_cleaner::FilePathSet whitelist; - whitelist.Insert(file_path); - auto remover_with_whitelist = std::make_unique<chrome_cleaner::FileRemover>( - /*digest_verifier=*/nullptr, /*archiver=*/nullptr, - chrome_cleaner::LayeredServiceProviderWrapper(), whitelist, - base::DoNothing()); - - chrome_cleaner::VerifyRemoveNowSuccess(file_path, - remover_with_whitelist.get()); EXPECT_FALSE(base::PathExists(file_path)); } @@ -500,27 +465,11 @@ std::make_unique<chrome_cleaner::FileRemover>( chrome_cleaner::DigestVerifier::CreateFromFile(file_path), /*archiver=*/nullptr, chrome_cleaner::LayeredServiceProviderWrapper(), - chrome_cleaner::FilePathSet(), base::DoNothing()); + base::DoNothing()); chrome_cleaner::VerifyRemoveNowFailure(file_path, remover_with_digest_verifier.get()); EXPECT_TRUE(base::PathExists(file_path)); - - // The whitelist should not override the DigestVerifier. - base::FilePath txt_file_path = temp.GetPath().Append(L"temp_file.txt"); - ASSERT_TRUE(chrome_cleaner::CreateFileInFolder( - txt_file_path.DirName(), txt_file_path.BaseName().value().c_str())); - - chrome_cleaner::FilePathSet whitelist; - whitelist.Insert(txt_file_path); - auto remover_with_whitelist = std::make_unique<chrome_cleaner::FileRemover>( - chrome_cleaner::DigestVerifier::CreateFromFile(txt_file_path), - /*archiver=*/nullptr, chrome_cleaner::LayeredServiceProviderWrapper(), - whitelist, base::DoNothing()); - - chrome_cleaner::VerifyRemoveNowFailure(txt_file_path, - remover_with_whitelist.get()); - EXPECT_TRUE(base::PathExists(txt_file_path)); } class CleanerInterfaceRegistryTest : public ::testing::Test {
diff --git a/chrome/chrome_cleaner/engines/broker/engine_client.cc b/chrome/chrome_cleaner/engines/broker/engine_client.cc index 8fd80c8d5..fd3e575 100644 --- a/chrome/chrome_cleaner/engines/broker/engine_client.cc +++ b/chrome/chrome_cleaner/engines/broker/engine_client.cc
@@ -31,7 +31,6 @@ #include "chrome/chrome_cleaner/pup_data/pup_data.h" #include "chrome/chrome_cleaner/settings/settings.h" #include "chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h" -#include "components/chrome_cleaner/public/constants/constants.h" #include "components/chrome_cleaner/public/constants/result_codes.h" #include "mojo/public/cpp/bindings/callback_helpers.h" #include "sandbox/win/src/sandbox_factory.h" @@ -136,9 +135,10 @@ bool EngineClient::InitializeCleaningCallbacks( const std::vector<UwSId>& enabled_uws) { - // |archive| = nullptr means the quarantine feature is disabled. - std::unique_ptr<SandboxedZipArchiver> archiver = nullptr; - if (base::CommandLine::ForCurrentProcess()->HasSwitch(kQuarantineSwitch)) { + std::unique_ptr<ZipArchiver> archiver = nullptr; + if (archiver_for_testing_) { + archiver = std::move(archiver_for_testing_); + } else { if (!InitializeQuarantine(&archiver)) return false; } @@ -158,20 +158,24 @@ } bool EngineClient::InitializeQuarantine( - std::unique_ptr<SandboxedZipArchiver>* archiver) { + std::unique_ptr<ZipArchiver>* archiver) { base::FilePath quarantine_folder; if (!InitializeQuarantineFolder(&quarantine_folder)) { LOG(ERROR) << "Failed to initialize quarantine folder."; return false; } + + std::unique_ptr<SandboxedZipArchiver> sbox_archiver; ResultCode result_code = SpawnZipArchiverSandbox( quarantine_folder, kQuarantinePassword, mojo_task_runner_, - connection_error_callback_, archiver); + connection_error_callback_, &sbox_archiver); if (result_code != RESULT_CODE_SUCCESS) { LOG(ERROR) << "Zip archiver initialization returned an error code: " << result_code; return false; } + + *archiver = std::move(sbox_archiver); return true; }
diff --git a/chrome/chrome_cleaner/engines/broker/engine_client.h b/chrome/chrome_cleaner/engines/broker/engine_client.h index 45b4408..d3b0a77 100644 --- a/chrome/chrome_cleaner/engines/broker/engine_client.h +++ b/chrome/chrome_cleaner/engines/broker/engine_client.h
@@ -29,6 +29,7 @@ #include "chrome/chrome_cleaner/ipc/sandbox.h" #include "chrome/chrome_cleaner/pup_data/pup_data.h" #include "chrome/chrome_cleaner/settings/settings_types.h" +#include "chrome/chrome_cleaner/zip_archiver/zip_archiver.h" #include "mojo/public/cpp/system/message_pipe.h" namespace chrome_cleaner { @@ -164,7 +165,7 @@ void InitializeReadOnlyCallbacks(); bool InitializeCleaningCallbacks(const std::vector<UwSId>& enabled_uws); - bool InitializeQuarantine(std::unique_ptr<SandboxedZipArchiver>* archiver); + bool InitializeQuarantine(std::unique_ptr<ZipArchiver>* archiver); // TODO(joenotcharles): When the synchronous Initialize method is removed, // rename this to Initialize and name the public accessor PostInitialize. @@ -229,6 +230,9 @@ // sandbox. std::unique_ptr<CleanerEngineRequestsImpl> sandbox_cleaner_requests_; + // Allow tests overwrite the archiver used. + std::unique_ptr<ZipArchiver> archiver_for_testing_; + // Keep track of if this cleaning requires a reboot to be fully completed. bool needs_reboot_ = false;
diff --git a/chrome/chrome_cleaner/engines/broker/noop_cleaner_engine_requests_impl.cc b/chrome/chrome_cleaner/engines/broker/noop_cleaner_engine_requests_impl.cc index 7ef576e..c1aad2b 100644 --- a/chrome/chrome_cleaner/engines/broker/noop_cleaner_engine_requests_impl.cc +++ b/chrome/chrome_cleaner/engines/broker/noop_cleaner_engine_requests_impl.cc
@@ -5,13 +5,13 @@ #include <utility> #include "chrome/chrome_cleaner/engines/broker/cleaner_engine_requests_impl.h" -#include "chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h" +#include "chrome/chrome_cleaner/zip_archiver/zip_archiver.h" namespace chrome_cleaner { std::unique_ptr<chrome_cleaner::FileRemoverAPI> CreateFileRemoverWithDigestVerifier( const std::vector<UwSId>& enabled_uws, - std::unique_ptr<SandboxedZipArchiver> archiver, + std::unique_ptr<ZipArchiver> archiver, const base::RepeatingClosure& reboot_needed_callback) { return nullptr; }
diff --git a/chrome/chrome_cleaner/engines/controllers/BUILD.gn b/chrome/chrome_cleaner/engines/controllers/BUILD.gn index 3b3d031..3c129a0 100644 --- a/chrome/chrome_cleaner/engines/controllers/BUILD.gn +++ b/chrome/chrome_cleaner/engines/controllers/BUILD.gn
@@ -204,6 +204,7 @@ "//chrome/chrome_cleaner/test:test_util", "//chrome/chrome_cleaner/test:test_uws_catalog", "//chrome/chrome_cleaner/ui:cleaner_ui", + "//chrome/chrome_cleaner/zip_archiver:common", "//components/chrome_cleaner/public/interfaces", "//components/chrome_cleaner/test:test_name_helper", "//sandbox/win:sandbox",
diff --git a/chrome/chrome_cleaner/engines/controllers/extension_removal_unittest.cc b/chrome/chrome_cleaner/engines/controllers/extension_removal_unittest.cc index 216c4d6..b52c5d6 100644 --- a/chrome/chrome_cleaner/engines/controllers/extension_removal_unittest.cc +++ b/chrome/chrome_cleaner/engines/controllers/extension_removal_unittest.cc
@@ -49,6 +49,7 @@ #include "chrome/chrome_cleaner/test/test_pup_data.h" #include "chrome/chrome_cleaner/test/test_settings_util.h" #include "chrome/chrome_cleaner/ui/silent_main_dialog.h" +#include "chrome/chrome_cleaner/zip_archiver/zip_archiver.h" #include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom-test-utils.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/system/message_pipe.h" @@ -113,6 +114,13 @@ } test_rebooter_; }; +class NoopZipArchiver : public ZipArchiver { + void Archive(const base::FilePath& /*src_file_path*/, + ArchiveResultCallback callback) override { + std::move(callback).Run(mojom::ZipArchiverResultCode::kSuccess); + } +}; + base::FilePath CreateStartupDirectory() { base::FilePath start_menu_folder; CHECK(base::PathService::Get(base::DIR_START_MENU, &start_menu_folder)); @@ -277,13 +285,15 @@ chrome_cleaner::UwS_TraceLocation_FOUND_IN_SHELL}; base::test::ScopedTaskEnvironment scoped_task_environment_; - scoped_refptr<chrome_cleaner::EngineClient> SetupEngineClient() { - chrome_cleaner::SandboxConnectionErrorCallback connection_error_callback = + scoped_refptr<EngineClient> SetupEngineClient() { + SandboxConnectionErrorCallback connection_error_callback = base::BindRepeating(&ExtensionCleanupTest::SandboxErrorCallback, base::Unretained(this)); - return EngineClient::CreateEngineClient( - chrome_cleaner::Engine::TEST_ONLY, base::DoNothing::Repeatedly<int>(), + scoped_refptr<EngineClient> client = EngineClient::CreateEngineClient( + Engine::TEST_ONLY, base::DoNothing::Repeatedly<int>(), std::move(connection_error_callback), mojo_task_runner_.get()); + client->archiver_for_testing_ = std::make_unique<NoopZipArchiver>(); + return client; } void SandboxErrorCallback(SandboxType type) {
diff --git a/chrome/chrome_cleaner/engines/target/sandboxed_test_helpers.h b/chrome/chrome_cleaner/engines/target/sandboxed_test_helpers.h index 3a414a1..089b9e92 100644 --- a/chrome/chrome_cleaner/engines/target/sandboxed_test_helpers.h +++ b/chrome/chrome_cleaner/engines/target/sandboxed_test_helpers.h
@@ -64,7 +64,7 @@ std::make_unique<chrome_cleaner::FileRemover>( verifier, /*archiver=*/nullptr, chrome_cleaner::LayeredServiceProviderWrapper(), - chrome_cleaner::FilePathSet(), base::DoNothing::Repeatedly()); + base::DoNothing::Repeatedly()); cleaner_impl_ = std::make_unique<CleanerEngineRequestsImpl>( this->mojo_task_runner(), metadata_observer, std::move(file_remover)); cleanup_results_impl_ =
diff --git a/chrome/chrome_cleaner/logging/cleaner_logging_service.cc b/chrome/chrome_cleaner/logging/cleaner_logging_service.cc index 6f6bdc5..2dc72cf 100644 --- a/chrome/chrome_cleaner/logging/cleaner_logging_service.cc +++ b/chrome/chrome_cleaner/logging/cleaner_logging_service.cc
@@ -681,8 +681,7 @@ if (removal_status != REMOVAL_STATUS_REMOVED && removal_status != REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL && removal_status != REMOVAL_STATUS_NOT_FOUND && - removal_status != REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK && - removal_status != REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION) { + removal_status != REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK) { return false; } }
diff --git a/chrome/chrome_cleaner/logging/cleaner_logging_service_unittest.cc b/chrome/chrome_cleaner/logging/cleaner_logging_service_unittest.cc index a07d7c648..bfbd9df 100644 --- a/chrome/chrome_cleaner/logging/cleaner_logging_service_unittest.cc +++ b/chrome/chrome_cleaner/logging/cleaner_logging_service_unittest.cc
@@ -1267,8 +1267,10 @@ // by the cleaner code. Also, ensures that all RemovalStatus enumerators are // checked. std::vector<RemovalStatus> all_removal_status; - for (int i = RemovalStatus_MIN + 1; i <= RemovalStatus_MAX; ++i) - all_removal_status.push_back(static_cast<RemovalStatus>(i)); + for (int i = RemovalStatus_MIN + 1; i <= RemovalStatus_MAX; ++i) { + if (RemovalStatus_IsValid(i)) + all_removal_status.push_back(static_cast<RemovalStatus>(i)); + } FileRemovalStatusUpdater* removal_status_updater = FileRemovalStatusUpdater::GetInstance();
diff --git a/chrome/chrome_cleaner/logging/proto/BUILD.gn b/chrome/chrome_cleaner/logging/proto/BUILD.gn index ac4ca0c3..b7a33fc 100644 --- a/chrome/chrome_cleaner/logging/proto/BUILD.gn +++ b/chrome/chrome_cleaner/logging/proto/BUILD.gn
@@ -46,6 +46,7 @@ deps = [ ":chrome_cleaner_report_proto", ":reporter_logs_proto", + "//chrome/chrome_cleaner/proto:spec_footprints_proto", "//third_party/protobuf:py_proto", ] }
diff --git a/chrome/chrome_cleaner/logging/proto/removal_status.proto b/chrome/chrome_cleaner/logging/proto/removal_status.proto index a25fbc0..e995841 100644 --- a/chrome/chrome_cleaner/logging/proto/removal_status.proto +++ b/chrome/chrome_cleaner/logging/proto/removal_status.proto
@@ -10,6 +10,8 @@ // Removal status for files and folder. enum RemovalStatus { + reserved 9; + reserved "REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION"; // Default value found in logs for records sent by cleaner versions that don't // write removal_status fields, and should never be used in the cleaner code. REMOVAL_STATUS_UNSPECIFIED = 0; @@ -30,9 +32,6 @@ REMOVAL_STATUS_NOT_FOUND = 7; // File registered for post-reboot removal after failed regular deletion. REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK = 8; - // File deletion was requested, not performed due to non-executable file - // extension, but reported as success. - REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION = 9; // There is an error in the archiver. REMOVAL_STATUS_ERROR_IN_ARCHIVER = 10; }
diff --git a/chrome/chrome_cleaner/os/disk_util.cc b/chrome/chrome_cleaner/os/disk_util.cc index 4430814..3d042c80 100644 --- a/chrome/chrome_cleaner/os/disk_util.cc +++ b/chrome/chrome_cleaner/os/disk_util.cc
@@ -368,34 +368,6 @@ g_active_extensions.end(); } -bool HasAlternateFileStream(const base::FilePath& path) { - // Detect if an alternate file stream is specified in the file path. - // The full name of a stream is "filename:stream_name:stream_type", but the - // type is optional, so "filename:stream_name" is also possible. - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364404%28v=vs.85%29.aspx - - // Unless the default stream is specified, simply detect colons in the base - // name. - if (base::EndsWith(path.value(), kDefaultDataStream, - base::CompareCase::INSENSITIVE_ASCII)) { - return false; - } - base::string16 base_name = path.BaseName().value(); - CHECK_EQ(base::FilePath::StringType::npos, base_name.find(L"::")) - << "Stream type other than $DATA was specified for default file stream: " - << base_name; - return base_name.find(L':') != base::FilePath::StringType::npos; -} - -bool HasDosExecutableHeader(const base::FilePath& path) { - // DOS executable files start with "MZ" magic number. - constexpr char kDosExecutableMagicNumber[] = "MZ"; - std::string file_header; - base::ReadFileToStringWithMaxSize(path, &file_header, - strlen(kDosExecutableMagicNumber)); - return file_header == kDosExecutableMagicNumber; -} - void InitializeDiskUtil() { // Only do this once. static bool init_once = []() -> bool {
diff --git a/chrome/chrome_cleaner/os/disk_util.h b/chrome/chrome_cleaner/os/disk_util.h index f580982..5d69ed72a 100644 --- a/chrome/chrome_cleaner/os/disk_util.h +++ b/chrome/chrome_cleaner/os/disk_util.h
@@ -78,12 +78,6 @@ // Return true if |path| has a active file extension. bool PathHasActiveExtension(const base::FilePath& file_path); -// Return true if an alternate file stream is specified in |file_path|. -bool HasAlternateFileStream(const base::FilePath& file_path); - -// Returns true if the file at |path| contains a DOS executable file header. -bool HasDosExecutableHeader(const base::FilePath& path); - // Expand environment variables in path into expanded_path. When called // expanded_path must be an empty path. If any component of path contains // environment variables expands to more than MAX_PATH characters the function
diff --git a/chrome/chrome_cleaner/os/disk_util_unittest.cc b/chrome/chrome_cleaner/os/disk_util_unittest.cc index a1cb7d09..b81e30c 100644 --- a/chrome/chrome_cleaner/os/disk_util_unittest.cc +++ b/chrome/chrome_cleaner/os/disk_util_unittest.cc
@@ -543,31 +543,6 @@ EXPECT_FALSE(PathHasActiveExtension(base::FilePath(L"C:\\file.txt::$DATA"))); } -TEST(DiskUtilTests, HasDosExecutableHeader) { - base::ScopedTempDir temp; - ASSERT_TRUE(temp.CreateUniqueTempDir()); - base::FilePath executable = temp.GetPath().Append(L"executable.txt"); - const char kExecutableFileContents[] = "MZ I am executable"; - chrome_cleaner::CreateFileWithContent(executable, kExecutableFileContents, - sizeof(kExecutableFileContents)); - EXPECT_TRUE(HasDosExecutableHeader(executable)); - - base::FilePath non_executable = temp.GetPath().Append(L"text.exe"); - const char kTextFileContents[] = "I am benign text"; - chrome_cleaner::CreateFileWithContent(non_executable, kTextFileContents, - sizeof(kTextFileContents)); - EXPECT_FALSE(HasDosExecutableHeader(non_executable)); -} - -TEST(DiskUtilTests, HasAlternateFileStream) { - EXPECT_FALSE(HasAlternateFileStream(base::FilePath(L"C:\\file.txt"))); - EXPECT_FALSE(HasAlternateFileStream(base::FilePath(L"C:\\file.txt::$DATA"))); - - EXPECT_TRUE(HasAlternateFileStream(base::FilePath(L"C:\\file.txt:stream"))); - EXPECT_TRUE( - HasAlternateFileStream(base::FilePath(L"C:\\file.txt:stream:$TYPE"))); -} - TEST(DiskUtilTests, ExpandEnvPath) { ASSERT_TRUE( ::SetEnvironmentVariable(L"CLEANER_TEST_VAR", L"CLEANER_TEST_VALUE"));
diff --git a/chrome/chrome_cleaner/os/file_removal_status_updater.cc b/chrome/chrome_cleaner/os/file_removal_status_updater.cc index ed8a7bd3..56544af4 100644 --- a/chrome/chrome_cleaner/os/file_removal_status_updater.cc +++ b/chrome/chrome_cleaner/os/file_removal_status_updater.cc
@@ -50,7 +50,6 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kOkToOverride}, {REMOVAL_STATUS_NOT_FOUND, kOkToOverride}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kOkToOverride}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kOkToOverride}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kOkToOverride}, }; @@ -64,7 +63,6 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kOkToOverride}, {REMOVAL_STATUS_NOT_FOUND, kOkToOverride}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kOkToOverride}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kOkToOverride}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kOkToOverride}, }; @@ -78,7 +76,6 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kNotAllowed}, {REMOVAL_STATUS_NOT_FOUND, kNotAllowed}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kNotAllowed}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kNotAllowed}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kNotAllowed}, }; @@ -92,7 +89,6 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kOkToOverride}, {REMOVAL_STATUS_NOT_FOUND, kSkip}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kOkToOverride}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kNotAllowed}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kNotAllowed}, }; @@ -106,7 +102,6 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kOkToOverride}, {REMOVAL_STATUS_NOT_FOUND, kOkToOverride}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kOkToOverride}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kNotAllowed}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kOkToOverride}, }; @@ -120,7 +115,6 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kSkip}, {REMOVAL_STATUS_NOT_FOUND, kOkToOverride}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kOkToOverride}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kNotAllowed}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kSkip}, }; @@ -134,7 +128,6 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kOkToOverride}, {REMOVAL_STATUS_NOT_FOUND, kOkToOverride}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kOkToOverride}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kNotAllowed}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kOkToOverride}, }; @@ -148,7 +141,6 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kOkToOverride}, {REMOVAL_STATUS_NOT_FOUND, kOkToOverride}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kOkToOverride}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kNotAllowed}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kOkToOverride}, }; @@ -162,24 +154,9 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kSkip}, {REMOVAL_STATUS_NOT_FOUND, kOkToOverride}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kOkToOverride}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kNotAllowed}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kSkip}, }; - (*overriding_decisions)[REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION] = { - {REMOVAL_STATUS_UNSPECIFIED, kNotAllowed}, - {REMOVAL_STATUS_MATCHED_ONLY, kNotAllowed}, - {REMOVAL_STATUS_BLACKLISTED_FOR_REMOVAL, kNotAllowed}, - {REMOVAL_STATUS_REMOVED, kNotAllowed}, - {REMOVAL_STATUS_FAILED_TO_REMOVE, kNotAllowed}, - {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL, kNotAllowed}, - {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kNotAllowed}, - {REMOVAL_STATUS_NOT_FOUND, kNotAllowed}, - {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kNotAllowed}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kNotAllowed}, - {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kNotAllowed}, - }; - (*overriding_decisions)[REMOVAL_STATUS_ERROR_IN_ARCHIVER] = { {REMOVAL_STATUS_UNSPECIFIED, kNotAllowed}, {REMOVAL_STATUS_MATCHED_ONLY, kNotAllowed}, @@ -190,7 +167,6 @@ {REMOVAL_STATUS_FAILED_TO_SCHEDULE_FOR_REMOVAL, kOkToOverride}, {REMOVAL_STATUS_NOT_FOUND, kOkToOverride}, {REMOVAL_STATUS_SCHEDULED_FOR_REMOVAL_FALLBACK, kOkToOverride}, - {REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, kNotAllowed}, {REMOVAL_STATUS_ERROR_IN_ARCHIVER, kOkToOverride}, }; return overriding_decisions;
diff --git a/chrome/chrome_cleaner/os/file_removal_status_updater_unittest.cc b/chrome/chrome_cleaner/os/file_removal_status_updater_unittest.cc index d979f0f7..21e5400 100644 --- a/chrome/chrome_cleaner/os/file_removal_status_updater_unittest.cc +++ b/chrome/chrome_cleaner/os/file_removal_status_updater_unittest.cc
@@ -69,7 +69,7 @@ // Status cannot be set to REMOVAL_STATUS_UNSPECIFIED - this is guarded by // an assert. RemovalStatus status = static_cast<RemovalStatus>(i); - if (status != REMOVAL_STATUS_UNSPECIFIED) + if (status != REMOVAL_STATUS_UNSPECIFIED && RemovalStatus_IsValid(i)) all_removal_status.push_back(status); }
diff --git a/chrome/chrome_cleaner/os/file_remover.cc b/chrome/chrome_cleaner/os/file_remover.cc index d13c0d9..76a064b 100644 --- a/chrome/chrome_cleaner/os/file_remover.cc +++ b/chrome/chrome_cleaner/os/file_remover.cc
@@ -101,13 +101,11 @@ } // namespace FileRemover::FileRemover(scoped_refptr<DigestVerifier> digest_verifier, - std::unique_ptr<SandboxedZipArchiver> archiver, + std::unique_ptr<ZipArchiver> archiver, const LayeredServiceProviderAPI& lsp, - const FilePathSet& deletion_allowed_paths, base::RepeatingClosure reboot_needed_callback) : digest_verifier_(digest_verifier), archiver_(std::move(archiver)), - deletion_allowed_paths_(deletion_allowed_paths), reboot_needed_callback_(reboot_needed_callback) { LSPPathToGUIDs providers; GetLayeredServiceProviders(lsp, &providers); @@ -129,11 +127,6 @@ path, REMOVAL_STATUS_BLACKLISTED_FOR_REMOVAL); std::move(callback).Run(false); return; - case DeletionValidationStatus::INACTIVE: - removal_status_updater->UpdateRemovalStatus( - path, REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION); - std::move(callback).Run(true); - return; case DeletionValidationStatus::ALLOWED: // No-op. Proceed to removal. break; @@ -161,11 +154,6 @@ file_path, REMOVAL_STATUS_BLACKLISTED_FOR_REMOVAL); std::move(callback).Run(false); return; - case DeletionValidationStatus::INACTIVE: - removal_status_updater->UpdateRemovalStatus( - file_path, REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION); - std::move(callback).Run(true); - return; case DeletionValidationStatus::ALLOWED: // No-op. Proceed to removal. break; @@ -210,36 +198,12 @@ if (base::DirectoryExists(file)) return DeletionValidationStatus::FORBIDDEN; - // If the file was blacklisted, allow its deletion regardless of the extension - if (deletion_allowed_paths_.Contains(file)) - return DeletionValidationStatus::ALLOWED; - - // Allow deletion of files with active (i.e. executable) extensions, files - // with explicit alternate file streams specified and files with DOS - // executable headers regardless of the extension. - if (chrome_cleaner::PathHasActiveExtension(file) || - chrome_cleaner::HasAlternateFileStream(file) || - chrome_cleaner::HasDosExecutableHeader(file)) { - return DeletionValidationStatus::ALLOWED; - } - - if (archiver_) { - // Quarantine is enabled. Allow deletion of "non-executable" files. - return DeletionValidationStatus::ALLOWED; - // TODO(veranika): enable quarantine for all runs and remove the concept - // of "inactive" files. - } else { - // If this line is reached, the file has a non-executable file extension. - LOG(ERROR) << "Cannot delete non-executable file with extension '" - << file.Extension() << "'. Full path '" - << chrome_cleaner::SanitizePath(file) << "'"; - return DeletionValidationStatus::INACTIVE; - } + return DeletionValidationStatus::ALLOWED; } void FileRemover::TryToQuarantine(const base::FilePath& path, QuarantineResultCallback callback) const { - // The quarantine feature is disabled. + // Archiver may not be provided in tests. if (archiver_ == nullptr) { std::move(callback).Run(QUARANTINE_STATUS_DISABLED); return;
diff --git a/chrome/chrome_cleaner/os/file_remover.h b/chrome/chrome_cleaner/os/file_remover.h index 6c9c0c356..5a59184 100644 --- a/chrome/chrome_cleaner/os/file_remover.h +++ b/chrome/chrome_cleaner/os/file_remover.h
@@ -17,7 +17,7 @@ #include "chrome/chrome_cleaner/os/file_path_set.h" #include "chrome/chrome_cleaner/os/file_remover_api.h" #include "chrome/chrome_cleaner/os/layered_service_provider_api.h" -#include "chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h" +#include "chrome/chrome_cleaner/zip_archiver/zip_archiver.h" namespace chrome_cleaner { @@ -30,9 +30,8 @@ // If it is an instance of DigestVerifier, any files known to the // DigestVerifier will not be removed. FileRemover(scoped_refptr<DigestVerifier> digest_verifier, - std::unique_ptr<SandboxedZipArchiver> archiver, + std::unique_ptr<ZipArchiver> archiver, const LayeredServiceProviderAPI& lsp, - const FilePathSet& deletion_allowed_paths, base::RepeatingClosure reboot_needed_callback); ~FileRemover() override; @@ -58,9 +57,8 @@ QuarantineStatus quarantine_status) const; scoped_refptr<DigestVerifier> digest_verifier_; - std::unique_ptr<SandboxedZipArchiver> archiver_; + std::unique_ptr<ZipArchiver> archiver_; FilePathSet deletion_forbidden_paths_; - FilePathSet deletion_allowed_paths_; base::RepeatingClosure reboot_needed_callback_; };
diff --git a/chrome/chrome_cleaner/os/file_remover_api.h b/chrome/chrome_cleaner/os/file_remover_api.h index 9d371c7..49e20de4 100644 --- a/chrome/chrome_cleaner/os/file_remover_api.h +++ b/chrome/chrome_cleaner/os/file_remover_api.h
@@ -20,7 +20,6 @@ enum class DeletionValidationStatus { ALLOWED, FORBIDDEN, - INACTIVE, }; // Callback used for the asynchronous versions of RemoveNow // and RegisterPostRebootRemoval.
diff --git a/chrome/chrome_cleaner/os/file_remover_unittest.cc b/chrome/chrome_cleaner/os/file_remover_unittest.cc index 50f18d0..3339611a 100644 --- a/chrome/chrome_cleaner/os/file_remover_unittest.cc +++ b/chrome/chrome_cleaner/os/file_remover_unittest.cc
@@ -66,7 +66,6 @@ /*digest_verifier=*/nullptr, /*archiver=*/nullptr, LayeredServiceProviderWrapper(), - /*deletion_allowed_paths=*/{}, base::BindRepeating(&FileRemoverTest::RebootRequired, base::Unretained(this))) { FileRemovalStatusUpdater::GetInstance()->Clear(); @@ -150,7 +149,7 @@ FileRemover remover( DigestVerifier::CreateFromResource(IDS_TEST_SAMPLE_DLL_DIGEST), /*archiver=*/nullptr, LayeredServiceProviderWrapper(), - /*deletion_allowed_paths=*/{}, base::DoNothing::Repeatedly()); + base::DoNothing::Repeatedly()); // Copy the sample DLL to the temp folder. base::FilePath dll_path = GetSampleDLLPath(); @@ -190,7 +189,6 @@ lsp.AddProvider(kGUID1, provider_path); FileRemover remover(/*digest_verifier=*/nullptr, /*archiver=*/nullptr, lsp, - /*deletion_allowed_paths=*/{}, base::DoNothing::Repeatedly()); TestBlacklistedRemoval(&remover, provider_path); @@ -371,57 +369,6 @@ REMOVAL_STATUS_BLACKLISTED_FOR_REMOVAL); } -TEST_F(FileRemoverTest, NotActiveFileType) { - base::ScopedTempDir temp; - ASSERT_TRUE(temp.CreateUniqueTempDir()); - base::FilePath path = temp.GetPath().Append(L"temp_file.txt"); - ASSERT_TRUE( - CreateFileInFolder(path.DirName(), path.BaseName().value().c_str())); - - EXPECT_EQ(ValidationStatus::INACTIVE, default_file_remover_.CanRemove(path)); - VerifyRemoveNowSuccess(path, &default_file_remover_); - EXPECT_EQ(REMOVAL_STATUS_NOT_REMOVED_INACTIVE_EXTENSION, - FileRemovalStatusUpdater::GetInstance()->GetRemovalStatus(path)); - EXPECT_TRUE(base::PathExists(path)); -} - -TEST_F(FileRemoverTest, NotActiveFileAllowed) { - base::ScopedTempDir temp; - ASSERT_TRUE(temp.CreateUniqueTempDir()); - base::FilePath path = temp.GetPath().Append(L"temp_file.txt"); - ASSERT_TRUE( - CreateFileInFolder(path.DirName(), path.BaseName().value().c_str())); - - FileRemover remover(/*digest_verifier=*/nullptr, /*archiver=*/nullptr, - LayeredServiceProviderWrapper(), {path.value().c_str()}, - base::DoNothing::Repeatedly()); - - EXPECT_EQ(ValidationStatus::ALLOWED, remover.CanRemove(path)); - VerifyRemoveNowSuccess(path, &remover); - EXPECT_EQ(REMOVAL_STATUS_REMOVED, - FileRemovalStatusUpdater::GetInstance()->GetRemovalStatus(path)); - EXPECT_FALSE(base::PathExists(path)); -} - -TEST_F(FileRemoverTest, DosMzExecutable) { - base::ScopedTempDir temp; - ASSERT_TRUE(temp.CreateUniqueTempDir()); - base::FilePath path = temp.GetPath().Append(L"temp_file.txt"); - constexpr char kMzExecutable[] = "MZ executable"; - CreateFileWithContent(path, kMzExecutable, sizeof(kMzExecutable)); - ASSERT_TRUE(base::PathExists(path)); - - FileRemover remover(/*digest_verifier=*/nullptr, /*archiver=*/nullptr, - LayeredServiceProviderWrapper(), {path.value().c_str()}, - base::DoNothing::Repeatedly()); - - EXPECT_EQ(ValidationStatus::ALLOWED, remover.CanRemove(path)); - VerifyRemoveNowSuccess(path, &remover); - EXPECT_EQ(REMOVAL_STATUS_REMOVED, - FileRemovalStatusUpdater::GetInstance()->GetRemovalStatus(path)); - EXPECT_FALSE(base::PathExists(path)); -} - namespace { constexpr char kTestPassword[] = "1234"; @@ -453,8 +400,7 @@ kTestPassword); file_remover_ = std::make_unique<FileRemover>( /*digest_verifier=*/nullptr, std::move(zip_archiver), - LayeredServiceProviderWrapper(), FilePathSet(), - base::DoNothing::Repeatedly()); + LayeredServiceProviderWrapper(), base::DoNothing::Repeatedly()); } protected:
diff --git a/chrome/chrome_cleaner/os/rebooter.cc b/chrome/chrome_cleaner/os/rebooter.cc index a8d5d9d..9e73d61 100644 --- a/chrome/chrome_cleaner/os/rebooter.cc +++ b/chrome/chrome_cleaner/os/rebooter.cc
@@ -29,7 +29,6 @@ kChromeVersionSwitch, kDumpRawLogsSwitch, kEnableCrashReportingSwitch, kEngineSwitch, kExecutionModeSwitch, kLogUploadRetryIntervalSwitch, kNoSelfDeleteSwitch, kTestingSwitch, kUmaUserSwitch, - kQuarantineSwitch, }; // The name of the task to run post reboot.
diff --git a/chrome/chrome_cleaner/pup_data/pup_cleaner_util.cc b/chrome/chrome_cleaner/pup_data/pup_cleaner_util.cc index 617c22b..34c3d7b 100644 --- a/chrome/chrome_cleaner/pup_data/pup_cleaner_util.cc +++ b/chrome/chrome_cleaner/pup_data/pup_cleaner_util.cc
@@ -18,14 +18,10 @@ FilePathSet* pup_files) { bool valid_removal = true; - FilePathSet files_detected_in_services = - PUPData::GetFilesDetectedInServices(pup_ids); - auto lsp = chrome_cleaner::LayeredServiceProviderWrapper(); chrome_cleaner::FileRemover file_remover(digest_verifier, /*archiver=*/nullptr, lsp, - files_detected_in_services, base::DoNothing()); for (const auto& pup_id : pup_ids) {
diff --git a/chrome/chrome_cleaner/pup_data/pup_cleaner_util_unittest.cc b/chrome/chrome_cleaner/pup_data/pup_cleaner_util_unittest.cc index ae65832..96646e5 100644 --- a/chrome/chrome_cleaner/pup_data/pup_cleaner_util_unittest.cc +++ b/chrome/chrome_cleaner/pup_data/pup_cleaner_util_unittest.cc
@@ -98,9 +98,8 @@ ContainerEq(expected_collected_paths.file_paths())); } -TEST_F(PUPCleanerUtilTest, CollectRemovablePupFiles_InactiveFiles) { - // Files with inactive extensions should be collected only if they were - // detected as part of UwS service registration. +TEST_F(PUPCleanerUtilTest, CollectRemovablePupFiles_NonExecutableFiles) { + // Files with non-executable extensions should be also collected. PUPData pup_data; TestPUPData test_pup_data; test_pup_data.AddPUP(kFakePupId1, @@ -108,22 +107,21 @@ nullptr, PUPData::kMaxFilesToRemoveSmallUwS); - base::FilePath inactive_path = CreateFileInTopDir(L"file.jpg", kFileContent); - EXPECT_FALSE(PathHasActiveExtension(inactive_path)); - base::FilePath found_in_service_path = - CreateFileInTopDir(L"file.log", kFileContent); - EXPECT_FALSE(PathHasActiveExtension(found_in_service_path)); + base::FilePath jpg_path = CreateFileInTopDir(L"file.jpg", kFileContent); + EXPECT_FALSE(PathHasActiveExtension(jpg_path)); + base::FilePath log_path = CreateFileInTopDir(L"file.log", kFileContent); + EXPECT_FALSE(PathHasActiveExtension(log_path)); PUPData::PUP* pup = pup_data.GetPUP(kFakePupId1); ASSERT_TRUE(pup); - pup->AddDiskFootprint(inactive_path); - pup->AddDiskFootprintTraceLocation(inactive_path, UwS::FOUND_IN_MEMORY); - pup->AddDiskFootprint(found_in_service_path); - pup->AddDiskFootprintTraceLocation(found_in_service_path, - UwS::FOUND_IN_SERVICE); + pup->AddDiskFootprint(jpg_path); + pup->AddDiskFootprintTraceLocation(jpg_path, UwS::FOUND_IN_MEMORY); + pup->AddDiskFootprint(log_path); + pup->AddDiskFootprintTraceLocation(log_path, UwS::FOUND_IN_SERVICE); FilePathSet expected_collected_paths; - expected_collected_paths.Insert(found_in_service_path); + expected_collected_paths.Insert(jpg_path); + expected_collected_paths.Insert(log_path); FilePathSet collected_paths; EXPECT_TRUE(
diff --git a/chrome/chrome_cleaner/pup_data/pup_data.cc b/chrome/chrome_cleaner/pup_data/pup_data.cc index 65d58ea9..d394b4af 100644 --- a/chrome/chrome_cleaner/pup_data/pup_data.cc +++ b/chrome/chrome_cleaner/pup_data/pup_data.cc
@@ -257,24 +257,6 @@ } // static -FilePathSet PUPData::GetFilesDetectedInServices( - const std::vector<UwSId>& uws_list) { - FilePathSet detected_in_services; - for (chrome_cleaner::UwSId uws_id : uws_list) { - const PUP* uws = GetPUP(uws_id); - for (auto path_location_it = uws->disk_footprints_info.map().begin(); - path_location_it != uws->disk_footprints_info.map().end(); - ++path_location_it) { - const std::set<UwS::TraceLocation>& found_in = - path_location_it->second.found_in; - if (found_in.find(UwS::FOUND_IN_SERVICE) != found_in.end()) - detected_in_services.Insert(path_location_it->first); - } - } - return detected_in_services; -} - -// static bool PUPData::GetRootKeyFromRegistryRoot(RegistryRoot registry_root, HKEY* key, base::FilePath* policy_file) {
diff --git a/chrome/chrome_cleaner/pup_data/pup_data.h b/chrome/chrome_cleaner/pup_data/pup_data.h index 968665c..9d450b1f 100644 --- a/chrome/chrome_cleaner/pup_data/pup_data.h +++ b/chrome/chrome_cleaner/pup_data/pup_data.h
@@ -395,9 +395,6 @@ static bool HasFlaggedPUP(const std::vector<UwSId>& input_pup_list, bool (*chooser)(Flags)); - // Returns set of files found in service registrations of |uws|. - static FilePathSet GetFilesDetectedInServices(const std::vector<UwSId>& uws); - // Convert a RegistryRoot to its corresponding HKEY. If // |registry_root| is a group policy, and |policy_file| is not null, the path // to the group policy file is set in |policy_file|.
diff --git a/chrome/chrome_cleaner/pup_data/pup_data_unittest.cc b/chrome/chrome_cleaner/pup_data/pup_data_unittest.cc index 3fca53c..127529c 100644 --- a/chrome/chrome_cleaner/pup_data/pup_data_unittest.cc +++ b/chrome/chrome_cleaner/pup_data/pup_data_unittest.cc
@@ -659,27 +659,6 @@ EXPECT_FALSE(base::ContainsValue(*pup_ids, k12ID)); } -TEST_F(PUPDataTest, GetFilesDetectedInServices) { - test_data().AddPUP(k12ID, - PUPData::FLAGS_ACTION_REMOVE, - nullptr, - PUPData::kMaxFilesToRemoveSmallUwS); - pup_data().GetPUP(k12ID)->AddDiskFootprintTraceLocation( - base::FilePath(k12DiskPath), UwS::FOUND_IN_SERVICE); - - test_data().AddPUP(k24ID, - PUPData::FLAGS_ACTION_REMOVE, - nullptr, - PUPData::kMaxFilesToRemoveSmallUwS); - pup_data().GetPUP(k24ID)->AddDiskFootprintTraceLocation( - base::FilePath(k42AbsoluteDiskPath), UwS::FOUND_IN_MEMORY); - - FilePathSet expected_files_from_services = {k12DiskPath}; - FilePathSet files_from_services = - PUPData::GetFilesDetectedInServices({k12ID, k24ID}); - EXPECT_EQ(expected_files_from_services, files_from_services); -} - TEST_F(PUPDataTest, InitializeTest) { PUPData::InitializePUPData({}); EXPECT_EQ(PUPData::GetUwSIds()->size(), 0UL);
diff --git a/chrome/chrome_cleaner/test/BUILD.gn b/chrome/chrome_cleaner/test/BUILD.gn index d5216c5..487c124 100644 --- a/chrome/chrome_cleaner/test/BUILD.gn +++ b/chrome/chrome_cleaner/test/BUILD.gn
@@ -2,12 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//chrome/chrome_cleaner/chrome_cleaner_args.gni") - -if (is_internal_chrome_cleaner_build) { - import("//chrome/chrome_cleaner_internal/internal_test_args.gni") -} - # Targets used by tests. shared_library("empty_dll") {
diff --git a/chrome/chrome_cleaner/ui/chrome_proxy_main_dialog_unittest.cc b/chrome/chrome_cleaner/ui/chrome_proxy_main_dialog_unittest.cc index 1688427..d3fa1f5 100644 --- a/chrome/chrome_cleaner/ui/chrome_proxy_main_dialog_unittest.cc +++ b/chrome/chrome_cleaner/ui/chrome_proxy_main_dialog_unittest.cc
@@ -99,8 +99,8 @@ set_logs_allowed_in_cleanup_mode(Eq(logs_allowed))) .Times(1); - // Add a PUP and some disk footprints. Both the normal and forced-active - // footprints should be passed along via the IPC. + // Add a PUP and some disk footprints. Footprints should be passed along via + // the IPC. TestPUPData test_pup_data; test_pup_data.AddPUP(kFakePupId, PUPData::FLAGS_ACTION_REMOVE, "", PUPData::kMaxFilesToRemoveSmallUwS); @@ -109,7 +109,6 @@ base::FilePath(FILE_PATH_LITERAL("c:\\file1.exe")))); EXPECT_TRUE(pup->AddDiskFootprint( base::FilePath(FILE_PATH_LITERAL("c:\\file2.exe")))); - // This inactive file path should not be included in what is sent. EXPECT_TRUE(pup->AddDiskFootprint( base::FilePath(FILE_PATH_LITERAL("c:\\file3.txt")))); @@ -131,7 +130,7 @@ StrictMock<MockChromePromptIPC> chrome_prompt_ipc; EXPECT_CALL(chrome_prompt_ipc, - MockPostPromptUserTask(/*files_to_delete*/ SizeIs(2), + MockPostPromptUserTask(/*files_to_delete*/ SizeIs(3), /*registry_keys*/ SizeIs(1), /*extensions*/ SizeIs(0), _)) .WillOnce(Invoke([prompt_acceptance](
diff --git a/chrome/chrome_cleaner/ui/silent_main_dialog_unittest.cc b/chrome/chrome_cleaner/ui/silent_main_dialog_unittest.cc index 1ffd3c5..a33a01f 100644 --- a/chrome/chrome_cleaner/ui/silent_main_dialog_unittest.cc +++ b/chrome/chrome_cleaner/ui/silent_main_dialog_unittest.cc
@@ -48,18 +48,22 @@ } enum class FileTypeToTest { - kActive, - kInactive, + kNone, + kExecutable, + kText, }; std::ostream& operator<<(std::ostream& stream, FileTypeToTest file_type_to_test) { switch (file_type_to_test) { - case FileTypeToTest::kActive: - stream << "ActiveFile"; + case FileTypeToTest::kExecutable: + stream << "ExecutableFile"; break; - case FileTypeToTest::kInactive: - stream << "InactiveFile"; + case FileTypeToTest::kText: + stream << "TextFile"; + break; + case FileTypeToTest::kNone: + stream << "NoFile"; break; } return stream; @@ -91,15 +95,19 @@ PUPData::kMaxFilesToRemoveSmallUwS); PUPData::PUP* pup = PUPData::GetPUP(kFakePupId); switch (file_type_to_test) { - case FileTypeToTest::kActive: + case FileTypeToTest::kExecutable: ASSERT_TRUE(pup->AddDiskFootprint( base::FilePath(FILE_PATH_LITERAL("c:\\file.exe")))); EXPECT_CALL(delegate_, AcceptedCleanup(true)).Times(1); break; - case FileTypeToTest::kInactive: + case FileTypeToTest::kText: ASSERT_TRUE(pup->AddDiskFootprint( base::FilePath(FILE_PATH_LITERAL("c:\\file.txt")))); - // If only an inactive file is found, the user should not be prompted. + // Even if only a non-executable file is found, the user should be + // prompted. + EXPECT_CALL(delegate_, AcceptedCleanup(true)).Times(1); + break; + case FileTypeToTest::kNone: EXPECT_CALL(delegate_, OnClose()).Times(1); break; } @@ -110,8 +118,9 @@ INSTANTIATE_TEST_SUITE_P(All, ConfirmCleanupSilentMainDialogTest, - ::testing::Values(FileTypeToTest::kActive, - FileTypeToTest::kInactive), + ::testing::Values(FileTypeToTest::kNone, + FileTypeToTest::kExecutable, + FileTypeToTest::kText), GetParamNameForTest()); } // namespace
diff --git a/chrome/chrome_cleaner/zip_archiver/BUILD.gn b/chrome/chrome_cleaner/zip_archiver/BUILD.gn index e650e5a..f1ca219 100644 --- a/chrome/chrome_cleaner/zip_archiver/BUILD.gn +++ b/chrome/chrome_cleaner/zip_archiver/BUILD.gn
@@ -6,6 +6,7 @@ sources = [ "sandboxed_zip_archiver.cc", "sandboxed_zip_archiver.h", + "zip_archiver.h", ] deps = [
diff --git a/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h b/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h index a6bf1e9..6758cfe 100644 --- a/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h +++ b/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h
@@ -17,6 +17,7 @@ #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h" #include "chrome/chrome_cleaner/ipc/sandbox.h" #include "chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.h" +#include "chrome/chrome_cleaner/zip_archiver/zip_archiver.h" namespace chrome_cleaner { @@ -27,19 +28,16 @@ } // namespace internal -class SandboxedZipArchiver { +class SandboxedZipArchiver : public ZipArchiver { public: - using ArchiveResultCallback = - base::OnceCallback<void(mojom::ZipArchiverResultCode)>; - SandboxedZipArchiver(scoped_refptr<MojoTaskRunner> mojo_task_runner, UniqueZipArchiverPtr zip_archiver_ptr, const base::FilePath& dst_archive_folder, const std::string& zip_password); - ~SandboxedZipArchiver(); + ~SandboxedZipArchiver() override; void Archive(const base::FilePath& src_file_path, - ArchiveResultCallback result_callback); + ArchiveResultCallback result_callback) override; private: mojom::ZipArchiverResultCode CheckFileSize(base::File* file);
diff --git a/chrome/chrome_cleaner/zip_archiver/zip_archiver.h b/chrome/chrome_cleaner/zip_archiver/zip_archiver.h new file mode 100644 index 0000000..a7f2370 --- /dev/null +++ b/chrome/chrome_cleaner/zip_archiver/zip_archiver.h
@@ -0,0 +1,27 @@ +// 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. + +#ifndef CHROME_CHROME_CLEANER_ZIP_ARCHIVER_ZIP_ARCHIVER_H_ +#define CHROME_CHROME_CLEANER_ZIP_ARCHIVER_ZIP_ARCHIVER_H_ + +#include "base/callback.h" +#include "base/files/file_path.h" +#include "chrome/chrome_cleaner/interfaces/zip_archiver.mojom.h" + +namespace chrome_cleaner { + +class ZipArchiver { + public: + using ArchiveResultCallback = + base::OnceCallback<void(mojom::ZipArchiverResultCode)>; + + virtual ~ZipArchiver() = default; + + virtual void Archive(const base::FilePath& src_file_path, + ArchiveResultCallback result_callback) = 0; +}; + +} // namespace chrome_cleaner + +#endif // CHROME_CHROME_CLEANER_ZIP_ARCHIVER_ZIP_ARCHIVER_H_
diff --git a/chrome/common/DEPS b/chrome/common/DEPS index 6a8b7f9..467fdcbe 100644 --- a/chrome/common/DEPS +++ b/chrome/common/DEPS
@@ -24,6 +24,7 @@ "+components/metrics/call_stack_profile_params.h", "+components/metrics/child_call_stack_profile_collector.h", "+components/metrics/client_info.h", + "+components/metrics/metadata_recorder.h", "+components/metrics/metrics_pref_names.h", "+components/nacl/common", "+components/net_log",
diff --git a/chrome/common/client_hints/client_hints.cc b/chrome/common/client_hints/client_hints.cc index 60fc601..ec7bff5 100644 --- a/chrome/common/client_hints/client_hints.cc +++ b/chrome/common/client_hints/client_hints.cc
@@ -35,6 +35,11 @@ DCHECK(rule.setting_value.is_dict()); const base::Value* expiration_time = rule.setting_value.FindKey("expiration_time"); + + // |expiration_time| may be null in rare cases. See + // https://bugs.chromium.org/p/chromium/issues/detail?id=942398. + if (expiration_time == nullptr) + continue; DCHECK(expiration_time->is_double()); if (base::Time::Now().ToDoubleT() > expiration_time->GetDouble()) { @@ -43,6 +48,8 @@ } const base::Value* list_value = rule.setting_value.FindKey("client_hints"); + if (list_value == nullptr) + continue; DCHECK(list_value->is_list()); const base::Value::ListStorage& client_hints_list = list_value->GetList(); for (const auto& client_hint : client_hints_list) {
diff --git a/chrome/common/extensions/chrome_extensions_client.cc b/chrome/common/extensions/chrome_extensions_client.cc index ca4cd15..a338dc2 100644 --- a/chrome/common/extensions/chrome_extensions_client.cc +++ b/chrome/common/extensions/chrome_extensions_client.cc
@@ -247,14 +247,9 @@ } } - const ActionInfo* page_action = ActionInfo::GetPageActionInfo(extension); - if (page_action && !page_action->default_icon.empty()) - page_action->default_icon.GetPaths(&image_paths); - - const ActionInfo* browser_action = - ActionInfo::GetBrowserActionInfo(extension); - if (browser_action && !browser_action->default_icon.empty()) - browser_action->default_icon.GetPaths(&image_paths); + const ActionInfo* action = ActionInfo::GetAnyActionInfo(extension); + if (action && !action->default_icon.empty()) + action->default_icon.GetPaths(&image_paths); return image_paths; }
diff --git a/chrome/common/heap_profiler_controller.cc b/chrome/common/heap_profiler_controller.cc index b70c7e7..a1f2020 100644 --- a/chrome/common/heap_profiler_controller.cc +++ b/chrome/common/heap_profiler_controller.cc
@@ -17,6 +17,7 @@ #include "base/strings/string_number_conversions.h" #include "base/task/post_task.h" #include "components/metrics/call_stack_profile_builder.h" +#include "components/metrics/metadata_recorder.h" #include "content/public/common/content_switches.h" namespace { @@ -31,24 +32,6 @@ return -std::log(base::RandDouble()) * mean; } -class SampleMetadataRecorder : public metrics::MetadataRecorder { - public: - SampleMetadataRecorder() - : field_hash_(base::HashMetricName(kMetadataSizeField)) {} - - void SetCurrentSampleSize(size_t size) { current_sample_size_ = size; } - - std::pair<uint64_t, int64_t> GetHashAndValue() const override { - return std::make_pair(field_hash_, current_sample_size_); - } - - private: - const uint64_t field_hash_; - size_t current_sample_size_ = 0; - - DISALLOW_COPY_AND_ASSIGN(SampleMetadataRecorder); -}; - } // namespace HeapProfilerController::HeapProfilerController() @@ -97,7 +80,8 @@ return; base::ModuleCache module_cache; - SampleMetadataRecorder metadata_recorder; + metrics::MetadataRecorder metadata_recorder; + const uint64_t metadata_name_hash = base::HashMetricName(kMetadataSizeField); metrics::CallStackProfileParams params( metrics::CallStackProfileParams::BROWSER_PROCESS, metrics::CallStackProfileParams::UNKNOWN_THREAD, @@ -114,7 +98,7 @@ module_cache.GetModuleForAddress(address); frames.emplace_back(address, module); } - metadata_recorder.SetCurrentSampleSize(sample.total); + metadata_recorder.Set(metadata_name_hash, sample.total); profile_builder.RecordMetadata(); profile_builder.OnSampleCompleted(std::move(frames)); }
diff --git a/chrome/common/safe_browsing/zip_analyzer.cc b/chrome/common/safe_browsing/zip_analyzer.cc index 6851d04..b02218ed 100644 --- a/chrome/common/safe_browsing/zip_analyzer.cc +++ b/chrome/common/safe_browsing/zip_analyzer.cc
@@ -25,41 +25,6 @@ namespace safe_browsing { namespace zip_analyzer { -namespace { - -const int kLFHBlockSize = 8192; -const char kLocalFileHeaderSize = 4; -const char kLocalFileHeader[kLocalFileHeaderSize] = {0x50, 0x4b, 0x03, 0x04}; - -} // namespace - -// Returns the number of Local File Headers present in the zip file. -int CountLocalFileHeaders(base::File* zip_file) { - int lfh_count = 0; - char block[kLFHBlockSize + 3]; // The extra 3 bytes will be used to hold - // the last bytes of the previous block - block[0] = 0; - block[1] = 0; - block[2] = 0; - - zip_file->Seek(base::File::Whence::FROM_BEGIN, 0); - int bytes_read = 0; - while ((bytes_read = zip_file->ReadAtCurrentPos(block + 3, kLFHBlockSize)) > - 0) { - for (int i = 0; i < bytes_read; i++) { - if (!memcmp(block + i, kLocalFileHeader, kLocalFileHeaderSize)) - lfh_count++; - } - - // Copy the end of this block to the new block - block[0] = block[bytes_read]; - block[1] = block[bytes_read + 1]; - block[2] = block[bytes_read + 2]; - } - - return lfh_count; -} - void AnalyzeZipFile(base::File zip_file, base::File temp_file, ArchiveAnalyzerResults* results) { @@ -117,16 +82,6 @@ } results->success = true; - - if (base::RandDouble() < 0.01 && !contains_zip) { - int lfh_count = CountLocalFileHeaders(&zip_file); - - DCHECK_LE(zip_entry_count, lfh_count); - - base::UmaHistogramSparse( - "SBClientDownload.ZipFileLocalFileHeadersSkipped", - base::ClampToRange(lfh_count - zip_entry_count, 0, 100)); - } } } // namespace zip_analyzer
diff --git a/chrome/common/safe_browsing/zip_analyzer.h b/chrome/common/safe_browsing/zip_analyzer.h index 2e8bf63..176ab651 100644 --- a/chrome/common/safe_browsing/zip_analyzer.h +++ b/chrome/common/safe_browsing/zip_analyzer.h
@@ -20,8 +20,6 @@ base::File temp_file, ArchiveAnalyzerResults* results); -int CountLocalFileHeaders(base::File* zip_file); - } // namespace zip_analyzer } // namespace safe_browsing
diff --git a/chrome/common/safe_browsing/zip_analyzer_unittest.cc b/chrome/common/safe_browsing/zip_analyzer_unittest.cc deleted file mode 100644 index 16be6ea9..0000000 --- a/chrome/common/safe_browsing/zip_analyzer_unittest.cc +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright (c) 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 "chrome/common/safe_browsing/zip_analyzer.h" - -#include "base/path_service.h" -#include "chrome/common/chrome_paths.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace safe_browsing { -namespace zip_analyzer { - -TEST(CountLocalFileHeaders, CountsOneBinary) { - base::FilePath test_file_path; - ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_file_path)); - test_file_path = test_file_path.AppendASCII( - "safe_browsing/download_protection/zipfile_one_unsigned_binary.zip"); - - base::File test_file(test_file_path, - base::File::FLAG_OPEN | base::File::FLAG_READ); - ASSERT_EQ(1, CountLocalFileHeaders(&test_file)); -} - -TEST(CountLocalFileHeaders, CountsTwoBinaries) { - base::FilePath test_file_path; - ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_file_path)); - test_file_path = test_file_path.AppendASCII( - "safe_browsing/download_protection/zipfile_two_binaries_one_signed.zip"); - - base::File test_file(test_file_path, - base::File::FLAG_OPEN | base::File::FLAG_READ); - ASSERT_EQ(2, CountLocalFileHeaders(&test_file)); -} - -} // namespace zip_analyzer -} // namespace safe_browsing
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 2827de4..b72da29 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -608,6 +608,7 @@ "../browser/autofill/content_autofill_driver_browsertest.cc", "../browser/autofill/form_structure_browsertest.cc", "../browser/background_fetch/background_fetch_browsertest.cc", + "../browser/background_sync/background_sync_metrics_browsertest.cc", "../browser/banners/app_banner_manager_browsertest.cc", "../browser/banners/app_banner_manager_browsertest_base.cc", "../browser/banners/app_banner_manager_browsertest_base.h", @@ -4268,7 +4269,6 @@ "../common/safe_browsing/ipc_protobuf_message_unittest.cc", "../common/safe_browsing/mach_o_image_reader_mac_unittest.cc", "../common/safe_browsing/pe_image_reader_win_unittest.cc", - "../common/safe_browsing/zip_analyzer_unittest.cc", "../renderer/safe_browsing/features_unittest.cc", "../renderer/safe_browsing/murmurhash3_util_unittest.cc", "../renderer/safe_browsing/phishing_term_feature_extractor_unittest.cc",
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index 5aa7081..853b39e 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -81,6 +81,7 @@ #include "components/keyed_service/core/refcounted_keyed_service.h" #include "components/keyed_service/core/simple_dependency_manager.h" #include "components/keyed_service/core/simple_factory_key.h" +#include "components/keyed_service/core/simple_key_map.h" #include "components/offline_pages/buildflags/buildflags.h" #include "components/omnibox/browser/autocomplete_classifier.h" #include "components/omnibox/browser/history_index_restore_observer.h" @@ -431,6 +432,7 @@ } else { key_ = std::make_unique<ProfileKey>(profile_path_, prefs_.get()); } + SimpleKeyMap::GetInstance()->Associate(this, key_.get()); if (!base::PathExists(profile_path_)) base::CreateDirectory(profile_path_); @@ -551,6 +553,8 @@ browser_context_dependency_manager_, this, simple_dependency_manager_, key_.get()); + SimpleKeyMap::GetInstance()->Dissociate(this); + if (host_content_settings_map_.get()) host_content_settings_map_->ShutdownOnUIThread();
diff --git a/chrome/test/data/client_hints/accept_ch_with_short_lifetime.html b/chrome/test/data/client_hints/accept_ch_with_short_lifetime.html new file mode 100644 index 0000000..8b0c3ac --- /dev/null +++ b/chrome/test/data/client_hints/accept_ch_with_short_lifetime.html
@@ -0,0 +1,6 @@ +<html> +<link rel="icon" href="data:;base64,="> +<head></head> +Empty file which uses link-rel to disable favicon fetches. The corresponding +.mock-http-headers sets client hints. +</html>
diff --git a/chrome/test/data/client_hints/accept_ch_with_short_lifetime.html.mock-http-headers b/chrome/test/data/client_hints/accept_ch_with_short_lifetime.html.mock-http-headers new file mode 100644 index 0000000..0f405cf --- /dev/null +++ b/chrome/test/data/client_hints/accept_ch_with_short_lifetime.html.mock-http-headers
@@ -0,0 +1,3 @@ +HTTP/1.1 200 OK +Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,ua,arch,platform,model +Accept-CH-Lifetime: 1
diff --git a/chrome/test/data/local_ntp/local_ntp_browsertest.html b/chrome/test/data/local_ntp/local_ntp_browsertest.html index dd57ab1c..9efda37b 100644 --- a/chrome/test/data/local_ntp/local_ntp_browsertest.html +++ b/chrome/test/data/local_ntp/local_ntp_browsertest.html
@@ -180,7 +180,7 @@ </div> </span> </div> - <div class="text-container"> + <div id="text-container" aria-live="polite"> <!-- Low confidence text underneath high confidence text. --> <span id="voice-text-i" class="voice-text"></span> <!-- High confidence text on top of low confidence text. -->
diff --git a/chrome/test/data/local_ntp/voice_browsertest.html b/chrome/test/data/local_ntp/voice_browsertest.html index 40641388..114bcdbd 100644 --- a/chrome/test/data/local_ntp/voice_browsertest.html +++ b/chrome/test/data/local_ntp/voice_browsertest.html
@@ -25,7 +25,7 @@ </div> </template> <template id="voice-text-template"> - <div class="text-container"> + <div id="text-container" aria-live="polite"> <!-- Low confidence text underneath high confidence text. --> <span id="voice-text-i" class="voice-text"></span> <!-- High confidence text on top of low confidence text. --> @@ -53,7 +53,7 @@ </div> </span> </div> - <div class="text-container"> + <div id="text-container" aria-live="polite"> <!-- Low confidence text underneath high confidence text. --> <span id="voice-text-i" class="voice-text"></span> <!-- High confidence text on top of low confidence text. -->
diff --git a/chrome/test/data/local_ntp/voice_speech_browsertest.js b/chrome/test/data/local_ntp/voice_speech_browsertest.js index db6511d..3a9a129 100644 --- a/chrome/test/data/local_ntp/voice_speech_browsertest.js +++ b/chrome/test/data/local_ntp/voice_speech_browsertest.js
@@ -139,6 +139,7 @@ // Mock view functions. test.speech.stubs.replace(view, 'hide', () => test.speech.viewActiveCount--); test.speech.stubs.replace(view, 'init', () => {}); + test.speech.stubs.replace(view, 'setTitles', () => {}); test.speech.stubs.replace(view, 'onWindowClick_', (event) => { test.speech.viewClickTarget = event.target; });
diff --git a/chrome/test/data/webui/settings/languages_page_tests.js b/chrome/test/data/webui/settings/languages_page_tests.js index af81a2c..4579c55 100644 --- a/chrome/test/data/webui/settings/languages_page_tests.js +++ b/chrome/test/data/webui/settings/languages_page_tests.js
@@ -676,40 +676,6 @@ Polymer.dom.flush(); assertFalse(moreInfo.hidden); }); - - test('disabling all languages disables spellcheck', () => { - if (cr.isMac) { - return; - } - - languageHelper.setPrefValue('browser.enable_spellchecking', true); - const spellCheckToggles = - languagesPage.$.spellCheckCollapse.querySelectorAll( - '.list-item cr-toggle'); - spellCheckToggles.forEach((language) => { - language.click(); - }); - assertFalse( - languageHelper.getPref('browser.enable_spellchecking').value); - }); - - test('enabling spellcheck should enable all spellcheck', () => { - if (cr.isMac) { - return; - } - - languagesPage.setPrefValue('browser.enable_spellchecking', false); - languagesPage.setPrefValue('spellcheck.dictionaries', []); - languagesPage.$.enableSpellcheckingToggle.click(); - - // Assert that the enabled languages are all the languages that have - // spell check enabled in FakeLanguageSettingsPrivate. - const enabledLanguages = - languageHelper.getPref('spellcheck.dictionaries').value; - assertEquals(enabledLanguages.length, 2); - assertEquals(enabledLanguages[0], 'en-US'); - assertEquals(enabledLanguages[1], 'sw'); - }); }); suite(TestNames.SpellcheckOfficialBuild, function() {
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index 427e0510..db9ef80 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -993,6 +993,10 @@ int render_process_id, int render_frame_id, NonNetworkURLLoaderFactoryMap* factories) { + if (render_frame_id == MSG_ROUTING_NONE) { + NOTREACHED() << "Service worker not supported."; + return; + } content::RenderFrameHost* frame_host = content::RenderFrameHost::FromID(render_process_id, render_frame_id);
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index 7ceec59..7084fdc7 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -9,6 +9,8 @@ #include <algorithm> #include <map> #include <memory> +#include <unordered_map> +#include <unordered_set> #include <utility> #include <vector> @@ -461,6 +463,22 @@ base::UTF16ToUTF8(field.placeholder)); } +// Creates the type relationship rules map. The keys represent the type that has +// rules, and the value represents the list of required types for the given +// key. In order to respect the rule, only one of the required types is needed. +// For example, for Autofill to support fields of type +// "PHONE_HOME_COUNTRY_CODE", there would need to be at least one other field +// of type "PHONE_HOME_NUMBER" or "PHONE_HOME_CITY_AND_NUMBER". +const std::unordered_map<ServerFieldType, ServerFieldTypeSet>& +GetTypeRelationshipMap() { + // Initialized and cached on first use. + static const auto* const rules = + new std::unordered_map<ServerFieldType, ServerFieldTypeSet>( + {{PHONE_HOME_COUNTRY_CODE, + {PHONE_HOME_NUMBER, PHONE_HOME_CITY_AND_NUMBER}}}); + return *rules; +} + } // namespace FormStructure::FormStructure(const FormData& form) @@ -1720,6 +1738,7 @@ field->SetTypeTo(field->Type()); } } + RationalizeTypeRelationships(); } void FormStructure::EncodeFormForQuery( @@ -2030,4 +2049,38 @@ randomized_encoder_ = std::move(encoder); } +void FormStructure::RationalizeTypeRelationships() { + // Create a local set of all the types for faster lookup. + std::unordered_set<ServerFieldType> types; + for (const auto& field : fields_) { + types.insert(field->Type().GetStorableType()); + } + + const auto& type_relationship_rules = GetTypeRelationshipMap(); + + for (const auto& field : fields_) { + ServerFieldType field_type = field->Type().GetStorableType(); + const auto& ruleset_iterator = type_relationship_rules.find(field_type); + if (ruleset_iterator != type_relationship_rules.end()) { + // We have relationship rules for this type. Verify that at least one of + // the required related type is present. + bool found = false; + for (ServerFieldType required_type : ruleset_iterator->second) { + if (types.find(required_type) != types.end()) { + // Found a required type, we can break as we only need one required + // type to respect the rule. + found = true; + break; + } + } + + if (!found) { + // No required type was found, the current field failed the relationship + // requirements for its type. Disabling Autofill for this field. + field->SetTypeTo(AutofillType(UNKNOWN_TYPE)); + } + } + } +} + } // namespace autofill
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h index bd2a619..965a0157 100644 --- a/components/autofill/core/browser/form_structure.h +++ b/components/autofill/core/browser/form_structure.h
@@ -442,6 +442,10 @@ // Tunes the fields with identical predictions. void RationalizeRepeatedFields(AutofillMetrics::FormInteractionsUkmLogger*); + // Filters out fields that don't meet the relationship ruleset for their type + // defined in |type_relationships_rules_|. + void RationalizeTypeRelationships(); + // A helper function to review the predictions and do appropriate adjustments // when it considers necessary. void RationalizeFieldTypePredictions();
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc index 9aa7326..cff3806 100644 --- a/components/autofill/core/browser/form_structure_unittest.cc +++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -6588,9 +6588,7 @@ EXPECT_EQ(ADDRESS_HOME_STATE, forms[0]->field(5)->Type().GetStorableType()); } -INSTANTIATE_TEST_SUITE_P(, - ParameterizedFormStructureTest, - testing::Values(true, false)); +INSTANTIATE_TEST_SUITE_P(, ParameterizedFormStructureTest, testing::Bool()); // Tests that, when the flag is off, we will not set the predicted type to // unknown for fields that have no server data and autocomplete off, and when @@ -6663,6 +6661,151 @@ EXPECT_EQ(ADDRESS_HOME_COUNTRY, forms[0]->field(3)->Type().GetStorableType()); } +struct RationalizationTypeRelationshipsTestParams { + ServerFieldType server_type; + ServerFieldType required_type; +}; +class RationalizationFieldTypeFilterTest + : public FormStructureTest, + public testing::WithParamInterface<ServerFieldType> {}; +class RationalizationFieldTypeRelationshipsTest + : public FormStructureTest, + public testing::WithParamInterface< + RationalizationTypeRelationshipsTestParams> {}; + +INSTANTIATE_TEST_SUITE_P(, + RationalizationFieldTypeFilterTest, + testing::Values(PHONE_HOME_COUNTRY_CODE)); + +INSTANTIATE_TEST_SUITE_P(, + RationalizationFieldTypeRelationshipsTest, + testing::Values( + RationalizationTypeRelationshipsTestParams{ + PHONE_HOME_COUNTRY_CODE, PHONE_HOME_NUMBER}, + RationalizationTypeRelationshipsTestParams{ + PHONE_HOME_COUNTRY_CODE, + PHONE_HOME_CITY_AND_NUMBER})); + +// Tests that the rationalization logic will filter out fields of type |param| +// when there is no other required type. +TEST_P(RationalizationFieldTypeFilterTest, Rationalization_Rules_Filter_Out) { + ServerFieldType filtered_off_field = GetParam(); + + FormData form; + form.url = GURL("http://foo.com"); + FormFieldData field; + field.form_control_type = "text"; + field.max_length = 10000; + field.should_autocomplete = true; + + // Just adding >=3 random fields to trigger rationalization. + field.label = ASCIIToUTF16("First Name"); + field.name = ASCIIToUTF16("firstName"); + form.fields.push_back(field); + field.label = ASCIIToUTF16("Last Name"); + field.name = ASCIIToUTF16("lastName"); + form.fields.push_back(field); + field.label = ASCIIToUTF16("Address"); + field.name = ASCIIToUTF16("address"); + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Something under test"); + field.name = ASCIIToUTF16("tested-thing"); + form.fields.push_back(field); + + AutofillQueryResponseContents response; + response.add_field()->set_overall_type_prediction(NAME_FIRST); + response.add_field()->set_overall_type_prediction(NAME_LAST); + response.add_field()->set_overall_type_prediction(ADDRESS_HOME_LINE1); + response.add_field()->set_overall_type_prediction(filtered_off_field); + + std::string response_string; + ASSERT_TRUE(response.SerializeToString(&response_string)); + + FormStructure form_structure(form); + + // Will identify the sections based on the heuristics types. + form_structure.DetermineHeuristicTypes(); + + std::vector<FormStructure*> forms; + forms.push_back(&form_structure); + + // Will call RationalizeFieldTypePredictions + FormStructure::ParseQueryResponse(response_string, forms, nullptr); + + ASSERT_EQ(1U, forms.size()); + ASSERT_EQ(4U, forms[0]->field_count()); + + EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType()); + EXPECT_EQ(NAME_LAST, forms[0]->field(1)->Type().GetStorableType()); + EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(2)->Type().GetStorableType()); + + // Last field's type should have been overwritten to expected. + EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(3)->Type().GetStorableType()); +} + +// Tests that the rationalization logic will not filter out fields of type +// |param| when there is another field with a required type. +TEST_P(RationalizationFieldTypeRelationshipsTest, + Rationalization_Rules_Relationships) { + RationalizationTypeRelationshipsTestParams test_params = GetParam(); + + FormData form; + form.url = GURL("http://foo.com"); + FormFieldData field; + field.form_control_type = "text"; + field.max_length = 10000; + field.should_autocomplete = true; + + // Just adding >=3 random fields to trigger rationalization. + field.label = ASCIIToUTF16("First Name"); + field.name = ASCIIToUTF16("firstName"); + form.fields.push_back(field); + field.label = ASCIIToUTF16("Last Name"); + field.name = ASCIIToUTF16("lastName"); + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Some field with required type"); + field.name = ASCIIToUTF16("some-name"); + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Something under test"); + field.name = ASCIIToUTF16("tested-thing"); + form.fields.push_back(field); + + AutofillQueryResponseContents response; + response.add_field()->set_overall_type_prediction(NAME_FIRST); + response.add_field()->set_overall_type_prediction(NAME_LAST); + response.add_field()->set_overall_type_prediction(test_params.required_type); + response.add_field()->set_overall_type_prediction(test_params.server_type); + + std::string response_string; + ASSERT_TRUE(response.SerializeToString(&response_string)); + + FormStructure form_structure(form); + + // Will identify the sections based on the heuristics types. + form_structure.DetermineHeuristicTypes(); + + std::vector<FormStructure*> forms; + forms.push_back(&form_structure); + + // Will call RationalizeFieldTypePredictions + FormStructure::ParseQueryResponse(response_string, forms, nullptr); + + ASSERT_EQ(1U, forms.size()); + ASSERT_EQ(4U, forms[0]->field_count()); + + EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType()); + EXPECT_EQ(NAME_LAST, forms[0]->field(1)->Type().GetStorableType()); + EXPECT_EQ(test_params.required_type, + forms[0]->field(2)->Type().GetStorableType()); + + // Last field's type should have been overwritten to expected. + EXPECT_EQ(test_params.server_type, + forms[0]->field(3)->Type().GetStorableType()); +} + TEST_F(FormStructureTest, AllowBigForms) { FormData form; form.url = GURL("http://foo.com");
diff --git a/components/contextual_search/core/browser/public.cc b/components/contextual_search/core/browser/public.cc index 31831d5..e5acbd8 100644 --- a/components/contextual_search/core/browser/public.cc +++ b/components/contextual_search/core/browser/public.cc
@@ -14,10 +14,11 @@ const int kContextualCardsQuickActionsIntegration = 2; const int kContextualCardsUrlActionsIntegration = 3; const int kContextualCardsDefinitionsIntegration = 4; -const int kContextualCardsDiagnosticIntegration = 9; +const int kContextualCardsTranslationsIntegration = 5; +const int kContextualCardsDiagnosticIntegration = 99; const int kContextualCardsSimplifiedServerMixin = 100; const char kContextualCardsSimplifiedServerMixinChar[] = "100"; -const char kContextualCardsSimplifiedServerWithDiagnosticChar[] = "109"; +const char kContextualCardsSimplifiedServerWithDiagnosticChar[] = "199"; } // namespace contextual_search
diff --git a/components/contextual_search/core/browser/public.h b/components/contextual_search/core/browser/public.h index 1aabfc6..48e619c0 100644 --- a/components/contextual_search/core/browser/public.h +++ b/components/contextual_search/core/browser/public.h
@@ -25,6 +25,8 @@ extern const int kContextualCardsUrlActionsIntegration; // Support of dictionary definitions in the bar. extern const int kContextualCardsDefinitionsIntegration; +// Support of translations in the bar as part of the resolve request. +extern const int kContextualCardsTranslationsIntegration; // Support of unlimited cards with diagnostics enabled, for development. extern const int kContextualCardsDiagnosticIntegration;
diff --git a/components/cronet/test/test_server.cc b/components/cronet/test/test_server.cc index ac4f367..e7456f0 100644 --- a/components/cronet/test/test_server.cc +++ b/components/cronet/test/test_server.cc
@@ -184,6 +184,7 @@ return true; } +/* static */ bool TestServer::Start() { base::FilePath src_root; CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root));
diff --git a/components/keyed_service/core/BUILD.gn b/components/keyed_service/core/BUILD.gn index bf7fbb42..26cfa413 100644 --- a/components/keyed_service/core/BUILD.gn +++ b/components/keyed_service/core/BUILD.gn
@@ -28,6 +28,8 @@ "simple_dependency_manager.h", "simple_factory_key.cc", "simple_factory_key.h", + "simple_key_map.cc", + "simple_key_map.h", "simple_keyed_service_factory.cc", "simple_keyed_service_factory.h", ]
diff --git a/components/keyed_service/core/simple_key_map.cc b/components/keyed_service/core/simple_key_map.cc new file mode 100644 index 0000000..1c3eee9 --- /dev/null +++ b/components/keyed_service/core/simple_key_map.cc
@@ -0,0 +1,41 @@ +// 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/keyed_service/core/simple_key_map.h" + +#include "base/logging.h" + +SimpleKeyMap::SimpleKeyMap() = default; + +SimpleKeyMap::~SimpleKeyMap() = default; + +// static +SimpleKeyMap* SimpleKeyMap::GetInstance() { + static base::NoDestructor<SimpleKeyMap> provider; + return provider.get(); +} + +void SimpleKeyMap::Associate(content::BrowserContext* browser_context, + SimpleFactoryKey* key) { + DCHECK(browser_context); + DCHECK(key); + DCHECK(mapping_.find(browser_context) == mapping_.end()); + mapping_[browser_context] = key; +} + +SimpleFactoryKey* SimpleKeyMap::GetForBrowserContext( + content::BrowserContext* browser_context) { + const auto& it = mapping_.find(browser_context); + if (it == mapping_.end()) { + DCHECK(false); + return nullptr; + } + + return it->second; +} + +void SimpleKeyMap::Dissociate(content::BrowserContext* browser_context) { + DCHECK(mapping_.find(browser_context) != mapping_.end()); + mapping_.erase(browser_context); +}
diff --git a/components/keyed_service/core/simple_key_map.h b/components/keyed_service/core/simple_key_map.h new file mode 100644 index 0000000..46783db --- /dev/null +++ b/components/keyed_service/core/simple_key_map.h
@@ -0,0 +1,59 @@ +// 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. + +#ifndef COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_KEY_MAP_H_ +#define COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_KEY_MAP_H_ + +#include <map> + +#include "base/macros.h" +#include "base/no_destructor.h" +#include "components/keyed_service/core/keyed_service_export.h" + +namespace content { +class BrowserContext; +} // namespace content + +class SimpleFactoryKey; + +// Stores a mapping from BrowserContexts to SimpleFactoryKeys. +// +// Use this class to get the SimpleFactoryKey that is associated with a given +// BrowserContext, when the BrowserContext is available and a +// SimpleKeyedServiceFactory for that BrowserContext is needed. For example, +// inside BuildServiceInstanceFor() in a BrowserContextKeyedServiceFactory that +// depends on a SimpleKeyedServiceFactory. +// +// This mapping is not stored as a member in BrowserContext because +// SimpleFactoryKeys are not a content layer concept, but a components level +// concept. +class KEYED_SERVICE_EXPORT SimpleKeyMap { + public: + static SimpleKeyMap* GetInstance(); + + // When |browser_context| creates or takes ownership of a SimpleFactoryKey + // |key|, it should register this association in this map. + void Associate(content::BrowserContext* browser_context, + SimpleFactoryKey* key); + + // When |browser_context| is destroyed or loses ownership of a + // SimpleFactoryKey, it should erase its association from this map. + void Dissociate(content::BrowserContext* browser_context); + + // Gets the SimpleFactoryKey associated with |browser_context|. + SimpleFactoryKey* GetForBrowserContext( + content::BrowserContext* browser_context); + + private: + friend class base::NoDestructor<SimpleKeyMap>; + + SimpleKeyMap(); + ~SimpleKeyMap(); + + std::map<content::BrowserContext*, SimpleFactoryKey*> mapping_; + + DISALLOW_COPY_AND_ASSIGN(SimpleKeyMap); +}; + +#endif // COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_KEY_MAP_H_
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn index aab66ed6..e17673e 100644 --- a/components/metrics/BUILD.gn +++ b/components/metrics/BUILD.gn
@@ -279,10 +279,12 @@ public = [ "call_stack_profile_builder.h", "child_call_stack_profile_collector.h", + "metadata_recorder.h", ] sources = [ "call_stack_profile_builder.cc", "child_call_stack_profile_collector.cc", + "metadata_recorder.cc", ] public_deps = [ ":call_stack_profile_params", @@ -374,6 +376,7 @@ "file_metrics_provider_unittest.cc", "histogram_encoder_unittest.cc", "machine_id_provider_win_unittest.cc", + "metadata_recorder_unittest.cc", "metrics_log_manager_unittest.cc", "metrics_log_store_unittest.cc", "metrics_log_unittest.cc",
diff --git a/components/metrics/OWNERS b/components/metrics/OWNERS index e20d9e7..f8be8f808 100644 --- a/components/metrics/OWNERS +++ b/components/metrics/OWNERS
@@ -1,6 +1,7 @@ file://base/metrics/OWNERS per-file *call_stack_profile*=wittman@chromium.org +per-file metadata_recorder*=wittman@chromium.org per-file BUILD.gn=wittman@chromium.org per-file DEPS=wittman@chromium.org
diff --git a/components/metrics/call_stack_profile_builder.cc b/components/metrics/call_stack_profile_builder.cc index 22af31b0..3505f11 100644 --- a/components/metrics/call_stack_profile_builder.cc +++ b/components/metrics/call_stack_profile_builder.cc
@@ -72,14 +72,17 @@ // suspended so must not take any locks, including indirectly through use of // heap allocation, LOG, CHECK, or DCHECK. void CallStackProfileBuilder::RecordMetadata() { - if (!work_id_recorder_) - return; - unsigned int work_id = work_id_recorder_->RecordWorkId(); - // A work id of 0 indicates that the message loop has not yet started. - if (work_id == 0) - return; - is_continued_work_ = (last_work_id_ == work_id); - last_work_id_ = work_id; + if (work_id_recorder_) { + unsigned int work_id = work_id_recorder_->RecordWorkId(); + // A work id of 0 indicates that the message loop has not yet started. + if (work_id != 0) { + is_continued_work_ = (last_work_id_ == work_id); + last_work_id_ = work_id; + } + } + + if (metadata_recorder_) + metadata_item_count_ = metadata_recorder_->GetItems(&metadata_items_); } void CallStackProfileBuilder::OnSampleCompleted( @@ -134,22 +137,21 @@ if (is_continued_work_) stack_sample_proto->set_continued_work(is_continued_work_); - // TODO(crbug.com/913570): Update metadata recording to not heap allocate - // and move to RecordMetadata(). - if (metadata_recorder_) { - uint64_t item_hash; - int64_t item_value; - std::tie(item_hash, item_value) = metadata_recorder_->GetHashAndValue(); + for (size_t i = 0; i < metadata_item_count_; ++i) { + const MetadataRecorder::Item recorder_item = metadata_items_[i]; int next_item_index = call_stack_profile->metadata_name_hash_size(); - auto result = metadata_hashes_cache_.emplace(item_hash, next_item_index); + auto result = metadata_hashes_cache_.emplace(recorder_item.name_hash, + next_item_index); if (result.second) - call_stack_profile->add_metadata_name_hash(item_hash); - CallStackProfile::MetadataItem* item = stack_sample_proto->add_metadata(); - // TODO(crbug.com/913570): Only add metadata items if different than - // the value for the previous sample, per + call_stack_profile->add_metadata_name_hash(recorder_item.name_hash); + CallStackProfile::MetadataItem* profile_item = + stack_sample_proto->add_metadata(); + // TODO(crbug.com/913570): Before uploading real metadata, ensure that we + // add metadata items only if the value differs from the value for the + // previous sample, per // https://cs.chromium.org/chromium/src/third_party/metrics_proto/call_stack_profile.proto?rcl=8811ddb099&l=108-110. - item->set_name_hash_index(result.first->second); - item->set_value(item_value); + profile_item->set_name_hash_index(result.first->second); + profile_item->set_value(recorder_item.value); } }
diff --git a/components/metrics/call_stack_profile_builder.h b/components/metrics/call_stack_profile_builder.h index 69c6ede..877944c 100644 --- a/components/metrics/call_stack_profile_builder.h +++ b/components/metrics/call_stack_profile_builder.h
@@ -18,6 +18,7 @@ #include "base/time/time.h" #include "components/metrics/call_stack_profile_params.h" #include "components/metrics/child_call_stack_profile_collector.h" +#include "components/metrics/metadata_recorder.h" #include "third_party/metrics_proto/sampled_profile.pb.h" namespace metrics { @@ -39,17 +40,6 @@ WorkIdRecorder& operator=(const WorkIdRecorder&) = delete; }; -// Records a metadata item to associate with the sample. -// TODO(crbug.com/913570): Extend to support multiple metadata items per sample. -class MetadataRecorder { - public: - MetadataRecorder() = default; - virtual ~MetadataRecorder() = default; - virtual std::pair<uint64_t, int64_t> GetHashAndValue() const = 0; - - DISALLOW_COPY_AND_ASSIGN(MetadataRecorder); -}; - // An instance of the class is meant to be passed to base::StackSamplingProfiler // to collect profiles. The profiles collected are uploaded via the metrics log. // @@ -130,6 +120,10 @@ // The start time of a profile collection. const base::TimeTicks profile_start_time_; + // The data fetched from the MetadataRecorder for each sample. + MetadataRecorder::ItemArray metadata_items_; + size_t metadata_item_count_ = 0; + // Maps metadata hash to index in |metadata_name_hash| array. std::unordered_map<uint64_t, int> metadata_hashes_cache_;
diff --git a/components/metrics/call_stack_profile_builder_unittest.cc b/components/metrics/call_stack_profile_builder_unittest.cc index ed8eef0..0778b2a 100644 --- a/components/metrics/call_stack_profile_builder_unittest.cc +++ b/components/metrics/call_stack_profile_builder_unittest.cc
@@ -405,24 +405,22 @@ } TEST(CallStackProfileBuilderTest, MetadataRecorder) { - class TestMetadataRecorder : public MetadataRecorder { - public: - std::pair<uint64_t, int64_t> GetHashAndValue() const override { - return std::make_pair(0x5A105E8B9D40E132ull, current_value); - } - int64_t current_value; - }; - - TestMetadataRecorder metadata_recorder; + MetadataRecorder metadata_recorder; auto profile_builder = std::make_unique<TestingCallStackProfileBuilder>( kProfileParams, nullptr, &metadata_recorder); TestModule module; base::Frame frame = {0x10, &module}; - metadata_recorder.current_value = 5; + metadata_recorder.Set(100, 10); + metadata_recorder.Set(200, 20); + metadata_recorder.Set(300, 30); + profile_builder->RecordMetadata(); profile_builder->OnSampleCompleted({frame}); - metadata_recorder.current_value = 8; + metadata_recorder.Remove(300); + metadata_recorder.Set(200, 21); + metadata_recorder.Set(400, 40); + profile_builder->RecordMetadata(); profile_builder->OnSampleCompleted({frame}); profile_builder->OnProfileCompleted(base::TimeDelta::FromMilliseconds(500), @@ -433,17 +431,29 @@ ASSERT_TRUE(proto.has_call_stack_profile()); const CallStackProfile& profile = proto.call_stack_profile(); + ASSERT_EQ(4, profile.metadata_name_hash_size()); + EXPECT_EQ(100u, profile.metadata_name_hash(0)); + EXPECT_EQ(200u, profile.metadata_name_hash(1)); + EXPECT_EQ(300u, profile.metadata_name_hash(2)); + EXPECT_EQ(400u, profile.metadata_name_hash(3)); + ASSERT_EQ(2, profile.stack_sample_size()); - EXPECT_EQ(1, profile.stack_sample(0).metadata_size()); - EXPECT_EQ(1, profile.stack_sample(1).metadata_size()); - ASSERT_EQ(1, profile.metadata_name_hash_size()); - EXPECT_EQ(0x5A105E8B9D40E132ull, profile.metadata_name_hash(0)); - + ASSERT_EQ(3, profile.stack_sample(0).metadata_size()); EXPECT_EQ(0, profile.stack_sample(0).metadata(0).name_hash_index()); - EXPECT_EQ(5, profile.stack_sample(0).metadata(0).value()); + EXPECT_EQ(10, profile.stack_sample(0).metadata(0).value()); + EXPECT_EQ(1, profile.stack_sample(0).metadata(1).name_hash_index()); + EXPECT_EQ(20, profile.stack_sample(0).metadata(1).value()); + EXPECT_EQ(2, profile.stack_sample(0).metadata(2).name_hash_index()); + EXPECT_EQ(30, profile.stack_sample(0).metadata(2).value()); + + ASSERT_EQ(3, profile.stack_sample(1).metadata_size()); EXPECT_EQ(0, profile.stack_sample(1).metadata(0).name_hash_index()); - EXPECT_EQ(8, profile.stack_sample(1).metadata(0).value()); + EXPECT_EQ(10, profile.stack_sample(1).metadata(0).value()); + EXPECT_EQ(1, profile.stack_sample(1).metadata(1).name_hash_index()); + EXPECT_EQ(21, profile.stack_sample(1).metadata(1).value()); + EXPECT_EQ(3, profile.stack_sample(1).metadata(2).name_hash_index()); + EXPECT_EQ(40, profile.stack_sample(1).metadata(2).value()); } } // namespace metrics
diff --git a/components/metrics/metadata_recorder.cc b/components/metrics/metadata_recorder.cc new file mode 100644 index 0000000..30a6af9 --- /dev/null +++ b/components/metrics/metadata_recorder.cc
@@ -0,0 +1,102 @@ +// 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/metrics/metadata_recorder.h" + +namespace metrics { + +bool MetadataRecorder::Item::operator==(const Item& rhs) const { + return name_hash == rhs.name_hash && value == rhs.value; +} + +MetadataRecorder::ItemInternal::ItemInternal() = default; + +MetadataRecorder::ItemInternal::~ItemInternal() = default; + +MetadataRecorder::MetadataRecorder() { + // Ensure that we have necessary atomic support. + DCHECK(items_[0].is_active.is_lock_free()); + DCHECK(items_[0].value.is_lock_free()); +} + +MetadataRecorder::~MetadataRecorder() = default; + +void MetadataRecorder::Set(uint64_t name_hash, int64_t value) { + base::AutoLock lock(write_lock_); + + // Acquiring the |write_lock_| guarantees that two simultaneous writes don't + // attempt to create items in the same slot. Use of memory_order_release + // guarantees that all writes performed by other threads to the metadata items + // will be seen by the time we reach this point. + size_t item_slots_used = item_slots_used_.load(std::memory_order_relaxed); + for (size_t i = 0; i < item_slots_used; ++i) { + auto& item = items_[i]; + if (item.name_hash == name_hash) { + item.value.store(value, std::memory_order_relaxed); + item.is_active.store(true, std::memory_order_release); + return; + } + } + + // There should always be room in this data structure because there are more + // reserved slots than there are unique metadata names in Chromium. + DCHECK_NE(item_slots_used, items_.size()) + << "Cannot add a new sampling profiler metadata item to an already full " + "map."; + + // Wait until the item is fully created before setting |is_active| to true and + // incrementing |item_slots_used_|, which will signal to readers that the item + // is ready. + auto& item = items_[item_slots_used_]; + item.name_hash = name_hash; + item.value.store(value, std::memory_order_relaxed); + item.is_active.store(true, std::memory_order_release); + item_slots_used_.fetch_add(1, std::memory_order_release); +} + +void MetadataRecorder::Remove(uint64_t name_hash) { + base::AutoLock lock(write_lock_); + + size_t item_slots_used = item_slots_used_.load(std::memory_order_relaxed); + for (size_t i = 0; i < item_slots_used; ++i) { + auto& item = items_[i]; + if (item.name_hash == name_hash) { + // A removed item will occupy its slot indefinitely. + item.is_active.store(false, std::memory_order_release); + } + } +} + +size_t MetadataRecorder::GetItems(ItemArray* const items) const { + // TODO(charliea): Defragment the item array if we can successfully acquire + // the write lock here. This will require either making this function + // non-const or |items_| mutable. + + // If a writer adds a new item after this load, it will be ignored. We do + // this instead of calling item_slots_used_.load() explicitly in the for loop + // bounds checking, which would be expensive. + // + // Also note that items are snapshotted sequentially and that items can be + // modified mid-snapshot by non-suspended threads. This means that there's a + // small chance that some items, especially those that occur later in the + // array, may have values slightly "in the future" from when the sample was + // actually collected. It also means that the array as returned may have never + // existed in its entirety, although each name/value pair represents a + // consistent item that existed very shortly after the thread was supended. + size_t item_slots_used = item_slots_used_.load(std::memory_order_acquire); + size_t write_index = 0; + for (size_t read_index = 0; read_index < item_slots_used; ++read_index) { + const auto& item = items_[read_index]; + // Because we wait until |is_active| is set to consider an item active and + // that field is always set last, we ignore half-created items. + if (item.is_active.load(std::memory_order_acquire)) { + (*items)[write_index++] = + Item{item.name_hash, item.value.load(std::memory_order_relaxed)}; + } + } + + return write_index; +} + +} // namespace metrics
diff --git a/components/metrics/metadata_recorder.h b/components/metrics/metadata_recorder.h new file mode 100644 index 0000000..d4b7e2fe --- /dev/null +++ b/components/metrics/metadata_recorder.h
@@ -0,0 +1,107 @@ +// 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. + +#ifndef COMPONENTS_METRICS_METADATA_RECORDER_H_ +#define COMPONENTS_METRICS_METADATA_RECORDER_H_ + +#include <array> +#include <atomic> +#include <utility> + +#include "base/synchronization/lock.h" + +namespace metrics { + +// MetadataRecorder provides a data structure to store metadata key/value pairs +// to be associated with samples taken by the sampling profiler. Whatever +// metadata is present in this map when a sample is recorded is then associated +// with the sample. +// +// Methods on this class are safe to call unsynchronized from arbitrary threads. +class MetadataRecorder { + public: + MetadataRecorder(); + virtual ~MetadataRecorder(); + MetadataRecorder(const MetadataRecorder&) = delete; + MetadataRecorder& operator=(const MetadataRecorder&) = delete; + + // Sets a name hash/value pair, overwriting any previous value set for that + // name hash. + void Set(uint64_t name_hash, int64_t value); + + // Removes the item with the specified name hash. + // + // If such an item does not exist, this has no effect. + void Remove(uint64_t name_hash); + + struct Item { + // The hash of the metadata name, as produced by base::HashMetricName(). + uint64_t name_hash; + // The value of the metadata item. + int64_t value; + + bool operator==(const Item& rhs) const; + }; + + static const size_t MAX_METADATA_COUNT = 50; + typedef std::array<Item, MAX_METADATA_COUNT> ItemArray; + // Retrieves the first |available_slots| items in the metadata recorder and + // copies them into |items|, returning the number of metadata items that were + // copied. To ensure that all items can be copied, |available slots| should be + // greater than or equal to |MAX_METADATA_COUNT|. + size_t GetItems(ItemArray* const items) const; + + private: + // TODO(charliea): Support large quantities of metadata efficiently. + struct ItemInternal { + ItemInternal(); + ~ItemInternal(); + + // Indicates whether the metadata item is still active (i.e. not removed). + // + // Requires atomic reads and writes to avoid word tearing when reading and + // writing unsynchronized. Requires acquire/release semantics to ensure that + // the other state in this struct is visible to the reading thread before it + // is marked as active. + std::atomic<bool> is_active{false}; + + // Doesn't need atomicity or memory order constraints because no reader will + // attempt to read it mid-write. Specifically, readers wait until + // |is_active| is true to read |name_hash|. Because |is_active| is always + // stored with a memory_order_release fence, we're guaranteed that + // |name_hash| will be finished writing before |is_active| is set to true. + uint64_t name_hash; + // Requires atomic reads and writes to avoid word tearing when updating an + // existing item unsynchronized. Does not require acquire/release semantics + // because we rely on the |is_active| acquire/release semantics to ensure + // that an item is fully created before we attempt to read it. + std::atomic<int64_t> value; + }; + + // Metadata items that the recorder has seen. Rather than implementing the + // metadata recorder as a dense array, we implement it as a sparse array where + // removed metadata items keep their slot with their |is_active| bit set to + // false. This avoids race conditions caused by reusing slots that might + // otherwise cause mismatches between metadata name hashes and values. + // + // For the rationale behind this design (along with others considered), see + // https://docs.google.com/document/d/18shLhVwuFbLl_jKZxCmOfRB98FmNHdKl0yZZZ3aEO4U/edit#. + std::array<ItemInternal, MAX_METADATA_COUNT> items_; + + // The number of item slots used in the metadata map. + // + // Requires atomic reads and writes to avoid word tearing when reading and + // writing unsynchronized. Requires acquire/release semantics to ensure that a + // newly-allocated slot is fully initialized before the reader becomes aware + // of its existence. + std::atomic<size_t> item_slots_used_{0}; + + // A lock that guards against multiple threads trying to modify the same item + // at once. + base::Lock write_lock_; +}; + +} // namespace metrics + +#endif // COMPONENTS_METRICS_METADATA_RECORDER_H_
diff --git a/components/metrics/metadata_recorder_unittest.cc b/components/metrics/metadata_recorder_unittest.cc new file mode 100644 index 0000000..b0b6e458 --- /dev/null +++ b/components/metrics/metadata_recorder_unittest.cc
@@ -0,0 +1,111 @@ +// 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/metrics/metadata_recorder.h" + +#include "base/test/gtest_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace metrics { + +TEST(MetadataRecorderTest, GetItems_Empty) { + MetadataRecorder recorder; + MetadataRecorder::ItemArray items; + size_t item_count = recorder.GetItems(&items); + + ASSERT_EQ(0u, item_count); +} + +TEST(MetadataRecorderTest, Set_NewNameHash) { + MetadataRecorder recorder; + + recorder.Set(10, 20); + + MetadataRecorder::ItemArray items; + size_t item_count = recorder.GetItems(&items); + ASSERT_EQ(1u, item_count); + ASSERT_EQ(10u, items[0].name_hash); + ASSERT_EQ(20, items[0].value); + + recorder.Set(20, 30); + + item_count = recorder.GetItems(&items); + ASSERT_EQ(2u, item_count); + ASSERT_EQ(20u, items[1].name_hash); + ASSERT_EQ(30, items[1].value); +} + +TEST(MetadataRecorderTest, Set_ExistingNameNash) { + MetadataRecorder recorder; + recorder.Set(10, 20); + recorder.Set(10, 30); + + MetadataRecorder::ItemArray items; + size_t item_count = recorder.GetItems(&items); + ASSERT_EQ(1u, item_count); + ASSERT_EQ(10u, items[0].name_hash); + ASSERT_EQ(30, items[0].value); +} + +TEST(MetadataRecorderTest, Set_ReAddRemovedNameNash) { + MetadataRecorder recorder; + MetadataRecorder::ItemArray items; + std::vector<MetadataRecorder::Item> expected; + for (size_t i = 0; i < items.size(); ++i) { + expected.push_back(MetadataRecorder::Item{i, 0}); + recorder.Set(i, 0); + } + + // By removing an item from a full recorder, re-setting the same item, and + // verifying that the item is returned, we can verify that the recorder is + // reusing the inactive slot for the same name hash instead of trying (and + // failing) to allocate a new slot. + recorder.Remove(3); + recorder.Set(3, 0); + + size_t item_count = recorder.GetItems(&items); + EXPECT_EQ(items.size(), item_count); + ASSERT_THAT(expected, ::testing::ElementsAreArray(items)); +} + +TEST(MetadataRecorderTest, Set_AddPastMaxCount) { + MetadataRecorder recorder; + MetadataRecorder::ItemArray items; + for (size_t i = 0; i < items.size(); ++i) { + recorder.Set(i, 0); + } + + ASSERT_DCHECK_DEATH(recorder.Set(items.size(), 0)); +} + +TEST(MetadataRecorderTest, Remove) { + MetadataRecorder recorder; + recorder.Set(10, 20); + recorder.Set(30, 40); + recorder.Set(50, 60); + recorder.Remove(30); + + MetadataRecorder::ItemArray items; + size_t item_count = recorder.GetItems(&items); + ASSERT_EQ(2u, item_count); + ASSERT_EQ(10u, items[0].name_hash); + ASSERT_EQ(20, items[0].value); + ASSERT_EQ(50u, items[1].name_hash); + ASSERT_EQ(60, items[1].value); +} + +TEST(MetadataRecorderTest, Remove_DoesntExist) { + MetadataRecorder recorder; + recorder.Set(10, 20); + recorder.Remove(20); + + MetadataRecorder::ItemArray items; + size_t item_count = recorder.GetItems(&items); + ASSERT_EQ(1u, item_count); + ASSERT_EQ(10u, items[0].name_hash); + ASSERT_EQ(20, items[0].value); +} + +} // namespace metrics
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn index a6b5c77..01d899cd 100644 --- a/components/ntp_snippets/BUILD.gn +++ b/components/ntp_snippets/BUILD.gn
@@ -13,15 +13,6 @@ static_library("ntp_snippets") { sources = [ - "breaking_news/breaking_news_listener.h", - "breaking_news/breaking_news_metrics.cc", - "breaking_news/breaking_news_metrics.h", - "breaking_news/subscription_json_request.cc", - "breaking_news/subscription_json_request.h", - "breaking_news/subscription_manager.cc", - "breaking_news/subscription_manager.h", - "breaking_news/subscription_manager_impl.cc", - "breaking_news/subscription_manager_impl.h", "callbacks.h", "category.cc", "category.h", @@ -123,13 +114,6 @@ "user_classifier.h", ] - if (is_android) { - sources += [ - "breaking_news/breaking_news_gcm_app_handler.cc", - "breaking_news/breaking_news_gcm_app_handler.h", - ] - } - public_deps = [ "//base", "//components/keyed_service/core", @@ -148,7 +132,6 @@ "//components/data_use_measurement/core", "//components/favicon/core", "//components/favicon_base", - "//components/gcm_driver", "//components/history/core/browser", "//components/image_fetcher/core", "//components/language/core/browser", @@ -197,8 +180,6 @@ source_set("unit_tests") { testonly = true sources = [ - "breaking_news/subscription_json_request_unittest.cc", - "breaking_news/subscription_manager_impl_unittest.cc", "category_rankers/click_based_category_ranker_unittest.cc", "category_rankers/constant_category_ranker_unittest.cc", "category_unittest.cc", @@ -231,18 +212,12 @@ "user_classifier_unittest.cc", ] - if (is_android) { - sources += [ "breaking_news/breaking_news_gcm_app_handler_unittest.cc" ] - } - deps = [ ":explore_protos", ":ntp_snippets", ":test_support", "//base", "//base/test:test_support", - "//components/gcm_driver", - "//components/gcm_driver/instance_id", "//components/image_fetcher/core", "//components/image_fetcher/core:test_support", "//components/leveldb_proto:test_support", @@ -259,7 +234,6 @@ "//components/variations:test_support", "//components/variations/net", "//components/web_resource:web_resource", - "//google_apis/gcm", "//net:test_support", "//services/identity/public/cpp", "//services/identity/public/cpp:test_support",
diff --git a/components/ntp_snippets/DEPS b/components/ntp_snippets/DEPS index 7d666c3..cba9db42 100644 --- a/components/ntp_snippets/DEPS +++ b/components/ntp_snippets/DEPS
@@ -2,7 +2,6 @@ "+components/data_use_measurement/core", "+components/favicon/core", "+components/favicon_base", - "+components/gcm_driver", "+components/history/core", "+components/image_fetcher", "+components/keyed_service/core",
diff --git a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc deleted file mode 100644 index f63cfee..0000000 --- a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.cc +++ /dev/null
@@ -1,474 +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/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h" - -#include "base/bind.h" -#include "base/json/json_writer.h" -#include "base/strings/string_util.h" -#include "base/task/post_task.h" -#include "build/build_config.h" -#include "components/gcm_driver/gcm_driver.h" -#include "components/gcm_driver/gcm_profile_service.h" -#include "components/gcm_driver/instance_id/instance_id.h" -#include "components/gcm_driver/instance_id/instance_id_driver.h" -#include "components/ntp_snippets/breaking_news/breaking_news_metrics.h" -#include "components/ntp_snippets/features.h" -#include "components/ntp_snippets/pref_names.h" -#include "components/ntp_snippets/time_serialization.h" -#include "components/variations/variations_associated_data.h" - -using instance_id::InstanceID; - -namespace ntp_snippets { - -namespace { - -const char kBreakingNewsGCMAppID[] = "com.google.breakingnews.gcm"; - -// The sender ID is used in the registration process. -// See: https://developers.google.com/cloud-messaging/gcm#senderid -const char kBreakingNewsGCMSenderId[] = "667617379155"; - -// OAuth2 Scope passed to getToken to obtain GCM registration tokens. -// Must match Java GoogleCloudMessaging.INSTANCE_ID_SCOPE. -const char kGCMScope[] = "GCM"; - -// The action key in pushed GCM message. -const char kPushedActionKey[] = "action"; -// Allowed action key values: -const char kPushToRefreshAction[] = "push-to-refresh"; -const char kPushByValueAction[] = "push-by-value"; - -// Key of the news json in the data in the pushed breaking news. -const char kPushedNewsKey[] = "payload"; - -// Lower bound time between two token validations when listening. -const int kTokenValidationPeriodMinutesDefault = 60 * 24; -const char kTokenValidationPeriodMinutesParamName[] = - "token_validation_period_minutes"; - -base::TimeDelta GetTokenValidationPeriod() { - return base::TimeDelta::FromMinutes( - variations::GetVariationParamByFeatureAsInt( - kBreakingNewsPushFeature, kTokenValidationPeriodMinutesParamName, - kTokenValidationPeriodMinutesDefault)); -} - -const bool kEnableTokenValidationDefault = true; -const char kEnableTokenValidationParamName[] = "enable_token_validation"; - -bool IsTokenValidationEnabled() { - return variations::GetVariationParamByFeatureAsBool( - kBreakingNewsPushFeature, kEnableTokenValidationParamName, - kEnableTokenValidationDefault); -} - -// Lower bound time between two forced subscriptions when listening. A -// forced subscription is a normal subscription to the content -// suggestions server, which cannot be omitted. -const int kForcedSubscriptionPeriodMinutesDefault = 60 * 24 * 7; -const char kForcedSubscriptionPeriodMinutesParamName[] = - "forced_subscription_period_minutes"; - -base::TimeDelta GetForcedSubscriptionPeriod() { - return base::TimeDelta::FromMinutes( - variations::GetVariationParamByFeatureAsInt( - kBreakingNewsPushFeature, kForcedSubscriptionPeriodMinutesParamName, - kForcedSubscriptionPeriodMinutesDefault)); -} - -const bool kEnableForcedSubscriptionDefault = true; -const char kEnableForcedSubscriptionParamName[] = "enable_forced_subscription"; - -bool IsForcedSubscriptionEnabled() { - return variations::GetVariationParamByFeatureAsBool( - kBreakingNewsPushFeature, kEnableForcedSubscriptionParamName, - kEnableForcedSubscriptionDefault); -} - -} // namespace - -BreakingNewsGCMAppHandler::BreakingNewsGCMAppHandler( - gcm::GCMDriver* gcm_driver, - instance_id::InstanceIDDriver* instance_id_driver, - PrefService* pref_service, - std::unique_ptr<SubscriptionManager> subscription_manager, - const ParseJSONCallback& parse_json_callback, - const base::Clock* clock, - std::unique_ptr<base::OneShotTimer> token_validation_timer, - std::unique_ptr<base::OneShotTimer> forced_subscription_timer) - : gcm_driver_(gcm_driver), - instance_id_driver_(instance_id_driver), - pref_service_(pref_service), - subscription_manager_(std::move(subscription_manager)), - parse_json_callback_(parse_json_callback), - clock_(clock), - token_validation_timer_(std::move(token_validation_timer)), - forced_subscription_timer_(std::move(forced_subscription_timer)), - weak_ptr_factory_(this) { -#if !defined(OS_ANDROID) -#error The BreakingNewsGCMAppHandler should only be used on Android. -#endif // !OS_ANDROID - DCHECK(token_validation_timer_); - DCHECK(!token_validation_timer_->IsRunning()); - DCHECK(forced_subscription_timer_); - DCHECK(!forced_subscription_timer_->IsRunning()); -} - -BreakingNewsGCMAppHandler::~BreakingNewsGCMAppHandler() { - if (IsListening()) { - StopListening(); - } -} - -void BreakingNewsGCMAppHandler::StartListening( - OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback, - OnRefreshRequestedCallback on_refresh_requested_callback) { - DCHECK(!IsListening()); - DCHECK(!on_new_remote_suggestion_callback.is_null()); - on_new_remote_suggestion_callback_ = - std::move(on_new_remote_suggestion_callback); - - DCHECK(!on_refresh_requested_callback.is_null()); - on_refresh_requested_callback_ = std::move(on_refresh_requested_callback); - - Subscribe(/*force_token_retrieval=*/false); - gcm_driver_->AddAppHandler(kBreakingNewsGCMAppID, this); - if (IsTokenValidationEnabled()) { - ScheduleNextTokenValidation(); - } - if (IsForcedSubscriptionEnabled()) { - ScheduleNextForcedSubscription(); - } -} - -void BreakingNewsGCMAppHandler::StopListening() { - DCHECK(IsListening()); - token_validation_timer_->Stop(); - forced_subscription_timer_->Stop(); - DCHECK_EQ(gcm_driver_->GetAppHandler(kBreakingNewsGCMAppID), this); - gcm_driver_->RemoveAppHandler(kBreakingNewsGCMAppID); - on_new_remote_suggestion_callback_ = OnNewRemoteSuggestionCallback(); - subscription_manager_->Unsubscribe(); -} - -bool BreakingNewsGCMAppHandler::IsListening() const { - return !on_new_remote_suggestion_callback_.is_null(); -} - -void BreakingNewsGCMAppHandler::Subscribe(bool force_token_retrieval) { - // TODO(mamir): "Whether to subscribe to content suggestions server" logic - // should be moved to the SubscriptionManager. - std::string token = - pref_service_->GetString(prefs::kBreakingNewsGCMSubscriptionTokenCache); - // If a token has been already obtained, subscribe directly at the content - // suggestions server. Otherwise, obtain a GCM token first. - if (!token.empty() && !force_token_retrieval) { - if (!subscription_manager_->IsSubscribed() || - subscription_manager_->NeedsToResubscribe()) { - subscription_manager_->Subscribe(token); - } - return; - } - - // TODO(vitaliii): Use |BindOnce| instead of |Bind|, because the callback is - // meant to be run only once. - instance_id_driver_->GetInstanceID(kBreakingNewsGCMAppID) - ->GetToken(kBreakingNewsGCMSenderId, kGCMScope, - /*options=*/std::map<std::string, std::string>(), - /*is_lazy=*/false, - base::Bind(&BreakingNewsGCMAppHandler::DidRetrieveToken, - weak_ptr_factory_.GetWeakPtr())); -} - -void BreakingNewsGCMAppHandler::DidRetrieveToken( - const std::string& subscription_token, - InstanceID::Result result) { - if (!IsListening()) { - // After we requested the token, |StopListening| has been called. Thus, - // ignore the token. - return; - } - - metrics::OnTokenRetrieved(result); - - switch (result) { - case InstanceID::SUCCESS: - // The received token is assumed to be valid, therefore, we reschedule - // validation. - pref_service_->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(clock_->Now())); - if (IsTokenValidationEnabled()) { - ScheduleNextTokenValidation(); - } - pref_service_->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - subscription_token); - subscription_manager_->Subscribe(subscription_token); - return; - case InstanceID::INVALID_PARAMETER: - case InstanceID::DISABLED: - case InstanceID::ASYNC_OPERATION_PENDING: - case InstanceID::SERVER_ERROR: - case InstanceID::UNKNOWN_ERROR: - DLOG(WARNING) - << "Push messaging subscription failed; InstanceID::Result = " - << result; - break; - case InstanceID::NETWORK_ERROR: - break; - } -} - -void BreakingNewsGCMAppHandler::ResubscribeIfInvalidToken() { - DCHECK(IsListening()); - DCHECK(IsTokenValidationEnabled()); - - // InstanceIDAndroid::ValidateToken just returns |true| on Android. Instead it - // is ok to retrieve a token, because it is cached. - // TODO(vitaliii): Use |BindOnce| instead of |Bind|, because the callback is - // meant to be run only once. - instance_id_driver_->GetInstanceID(kBreakingNewsGCMAppID) - ->GetToken( - kBreakingNewsGCMSenderId, kGCMScope, - /*options=*/std::map<std::string, std::string>(), /*is_lazy=*/false, - base::Bind(&BreakingNewsGCMAppHandler::DidReceiveTokenForValidation, - weak_ptr_factory_.GetWeakPtr())); -} - -void BreakingNewsGCMAppHandler::DidReceiveTokenForValidation( - const std::string& new_token, - InstanceID::Result result) { - if (!IsListening()) { - // After we requested the token, |StopListening| has been called. Thus, - // ignore the token. - return; - } - - metrics::OnTokenRetrieved(result); - - base::Optional<base::TimeDelta> time_since_last_validation; - if (pref_service_->HasPrefPath( - prefs::kBreakingNewsGCMLastTokenValidationTime)) { - const base::Time last_validation_time = - DeserializeTime(pref_service_->GetInt64( - prefs::kBreakingNewsGCMLastTokenValidationTime)); - time_since_last_validation = clock_->Now() - last_validation_time; - } - - // We intentionally reschedule as normal even if we don't get a token. - pref_service_->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(clock_->Now())); - ScheduleNextTokenValidation(); - - base::Optional<bool> was_token_valid; - if (result == InstanceID::SUCCESS) { - const std::string old_token = - pref_service_->GetString(prefs::kBreakingNewsGCMSubscriptionTokenCache); - - was_token_valid = old_token == new_token; - if (!*was_token_valid) { - subscription_manager_->Resubscribe(new_token); - } - } - - metrics::OnTokenValidationAttempted(time_since_last_validation, - was_token_valid); -} - -void BreakingNewsGCMAppHandler::ScheduleNextTokenValidation() { - DCHECK(IsListening()); - DCHECK(IsTokenValidationEnabled()); - - const base::Time last_validation_time = DeserializeTime( - pref_service_->GetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime)); - // Timer runs the task immediately if delay is <= 0. - token_validation_timer_->Start( - FROM_HERE, - /*delay=*/last_validation_time + GetTokenValidationPeriod() - - clock_->Now(), - base::Bind(&BreakingNewsGCMAppHandler::ResubscribeIfInvalidToken, - weak_ptr_factory_.GetWeakPtr())); -} - -void BreakingNewsGCMAppHandler::ForceSubscribe() { - DCHECK(IsForcedSubscriptionEnabled()); - - // We intentionally reschedule as normal even if there is no token or - // subscription fails. - pref_service_->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime, - SerializeTime(clock_->Now())); - ScheduleNextForcedSubscription(); - - const std::string token = - pref_service_->GetString(prefs::kBreakingNewsGCMSubscriptionTokenCache); - if (!token.empty()) { - subscription_manager_->Subscribe(token); - } -} - -void BreakingNewsGCMAppHandler::ScheduleNextForcedSubscription() { - DCHECK(IsListening()); - DCHECK(IsForcedSubscriptionEnabled()); - - const base::Time last_forced_subscription_time = - DeserializeTime(pref_service_->GetInt64( - prefs::kBreakingNewsGCMLastForcedSubscriptionTime)); - // Timer runs the task immediately if delay is <= 0. - forced_subscription_timer_->Start( - FROM_HERE, - /*delay=*/last_forced_subscription_time + GetForcedSubscriptionPeriod() - - clock_->Now(), - base::Bind(&BreakingNewsGCMAppHandler::ForceSubscribe, - weak_ptr_factory_.GetWeakPtr())); -} - -void BreakingNewsGCMAppHandler::ShutdownHandler() {} - -void BreakingNewsGCMAppHandler::OnStoreReset() { - pref_service_->ClearPref(prefs::kBreakingNewsGCMSubscriptionTokenCache); -} - -void BreakingNewsGCMAppHandler::OnMessage(const std::string& app_id, - const gcm::IncomingMessage& message) { - DCHECK_EQ(app_id, kBreakingNewsGCMAppID); - - if (!IsListening()) { - // The content suggestions server may push a message right when the client - // unsubscribes leading to a race condition. Ignore such messages. - DLOG(WARNING) << "Received a pushed message while not listening."; - return; - } - - gcm::MessageData::const_iterator it = message.data.find(kPushedActionKey); - - bool contains_pushed_action = (it != message.data.end()); - if (!contains_pushed_action) { - LOG(WARNING) << "Receiving pushed content failure: Action is missing."; - metrics::OnMessageReceived(metrics::ReceivedMessageAction::NO_ACTION); - return; - } - const std::string& action = it->second; - - if (action == kPushToRefreshAction) { - metrics::OnMessageReceived(metrics::ReceivedMessageAction::PUSH_TO_REFRESH); - OnPushToRefreshMessage(); - return; - } - - if (action == kPushByValueAction) { - metrics::OnMessageReceived(metrics::ReceivedMessageAction::PUSH_BY_VALUE); - OnPushByValueMessage(message); - return; - } - - LOG(WARNING) << "Receiving pushed content failure: Invalid action."; - metrics::OnMessageReceived(metrics::ReceivedMessageAction::INVALID_ACTION); -} - -void BreakingNewsGCMAppHandler::OnPushByValueMessage( - const gcm::IncomingMessage& message) { - gcm::MessageData::const_iterator it = message.data.find(kPushedNewsKey); - bool contains_pushed_news = (it != message.data.end()); - if (!contains_pushed_news) { - LOG(WARNING) - << "Receiving pushed content failure: Breaking News ID missing."; - } - - const std::string& news = it->second; - parse_json_callback_.Run(news, - base::Bind(&BreakingNewsGCMAppHandler::OnJsonSuccess, - weak_ptr_factory_.GetWeakPtr()), - base::Bind(&BreakingNewsGCMAppHandler::OnJsonError, - weak_ptr_factory_.GetWeakPtr(), news)); -} - -void BreakingNewsGCMAppHandler::OnPushToRefreshMessage() { - on_refresh_requested_callback_.Run(); -} - -void BreakingNewsGCMAppHandler::OnMessagesDeleted(const std::string& app_id) { - // Messages don't get deleted. - NOTREACHED() << "BreakingNewsGCMAppHandler messages don't get deleted."; -} - -void BreakingNewsGCMAppHandler::OnSendError( - const std::string& app_id, - const gcm::GCMClient::SendErrorDetails& details) { - // Should never be called because we don't send GCM messages to - // the server. - NOTREACHED() << "BreakingNewsGCMAppHandler doesn't send GCM messages."; -} - -void BreakingNewsGCMAppHandler::OnSendAcknowledged( - const std::string& app_id, - const std::string& message_id) { - // Should never be called because we don't send GCM messages to - // the server. - NOTREACHED() << "BreakingNewsGCMAppHandler doesn't send GCM messages."; -} - -// static -void BreakingNewsGCMAppHandler::RegisterProfilePrefs( - PrefRegistrySimple* registry) { - registry->RegisterStringPref(prefs::kBreakingNewsGCMSubscriptionTokenCache, - /*default_value=*/std::string()); - registry->RegisterInt64Pref(prefs::kBreakingNewsGCMLastTokenValidationTime, - /*default_value=*/0); - registry->RegisterInt64Pref(prefs::kBreakingNewsGCMLastForcedSubscriptionTime, - /*default_value=*/0); -} - -// TODO(vitaliii): Add a test to ensure that this clears everything. -// static -void BreakingNewsGCMAppHandler::ClearProfilePrefs(PrefService* pref_service) { - pref_service->ClearPref(prefs::kBreakingNewsGCMSubscriptionTokenCache); - pref_service->ClearPref(prefs::kBreakingNewsGCMLastTokenValidationTime); - pref_service->ClearPref(prefs::kBreakingNewsGCMSubscriptionTokenCache); -} - -void BreakingNewsGCMAppHandler::OnJsonSuccess( - std::unique_ptr<base::Value> content) { - DCHECK(content); - - if (!IsListening()) { - // |StopListening| might be called after JSON parse request is submitted, - // but the request cannot be canceled, so we just ignore the parsed JSON. - return; - } - - std::vector<FetchedCategory> fetched_categories; - if (!JsonToCategories(*content, &fetched_categories, - /*fetch_time=*/base::Time::Now())) { - std::string content_json; - base::JSONWriter::Write(*content, &content_json); - LOG(WARNING) - << "Received invalid breaking news: can't interpret value, json is " - << content_json; - return; - } - if (fetched_categories.size() != 1) { - LOG(WARNING) - << "Received invalid breaking news: expected 1 category, but got " - << fetched_categories.size(); - return; - } - if (fetched_categories[0].suggestions.size() != 1) { - LOG(WARNING) - << "Received invalid breaking news: expected 1 suggestion, but got " - << fetched_categories[0].suggestions.size(); - return; - } - - on_new_remote_suggestion_callback_.Run( - std::move(fetched_categories[0].suggestions[0])); -} - -void BreakingNewsGCMAppHandler::OnJsonError(const std::string& json_str, - const std::string& error) { - LOG(WARNING) << "Error parsing JSON:" << error - << " when parsing:" << json_str; -} - -} // namespace ntp_snippets
diff --git a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h deleted file mode 100644 index 248dcb8..0000000 --- a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h +++ /dev/null
@@ -1,150 +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_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_GCM_APP_HANDLER_H_ -#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_GCM_APP_HANDLER_H_ - -#include "base/memory/weak_ptr.h" -#include "base/time/clock.h" -#include "base/timer/timer.h" -#include "components/gcm_driver/gcm_app_handler.h" -#include "components/gcm_driver/instance_id/instance_id.h" -#include "components/ntp_snippets/breaking_news/breaking_news_listener.h" -#include "components/ntp_snippets/breaking_news/subscription_manager.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service.h" - -class PrefRegistrySimple; - -namespace gcm { -class GCMDriver; -} - -namespace instance_id { -class InstanceIDDriver; -} - -namespace ntp_snippets { - -// Handler for pushed GCM breaking news and refresh requests. It retrieves a -// subscription token from the GCM server and registers/unregisters itself with -// the GCM service to be called upon received push breaking news or refresh -// requests. When there is a listener, the token is periodically validated. The -// validation may happen during StartListening if enough time has passed since -// the last validation. -class BreakingNewsGCMAppHandler : public BreakingNewsListener, - public gcm::GCMAppHandler { - public: - // Callbacks for JSON parsing to allow injecting platform-dependent code. - using SuccessCallback = - base::Callback<void(std::unique_ptr<base::Value> result)>; - using ErrorCallback = base::Callback<void(const std::string& error)>; - using ParseJSONCallback = - base::Callback<void(const std::string& raw_json_string, - const SuccessCallback& success_callback, - const ErrorCallback& error_callback)>; - - // When provided, |timer_task_runner| and |timer_tick_clock| are used inside - // internal validation timer (e.g. for testing). - BreakingNewsGCMAppHandler( - gcm::GCMDriver* gcm_driver, - instance_id::InstanceIDDriver* instance_id_driver, - PrefService* pref_service_, - std::unique_ptr<SubscriptionManager> subscription_manager, - const ParseJSONCallback& parse_json_callback, - const base::Clock* clock, - std::unique_ptr<base::OneShotTimer> token_validation_timer, - std::unique_ptr<base::OneShotTimer> forced_subscription_timer); - - // If still listening, calls StopListening(). - ~BreakingNewsGCMAppHandler() override; - - // BreakingNewsListener overrides. - void StartListening( - OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback, - OnRefreshRequestedCallback on_refresh_requested_callback) override; - void StopListening() override; - bool IsListening() const override; - - // GCMAppHandler overrides. - void ShutdownHandler() override; - void OnStoreReset() override; - void OnMessage(const std::string& app_id, - const gcm::IncomingMessage& message) override; - void OnMessagesDeleted(const std::string& app_id) override; - void OnSendError(const std::string& app_id, - const gcm::GCMClient::SendErrorDetails& details) override; - void OnSendAcknowledged(const std::string& app_id, - const std::string& message_id) override; - - static void RegisterProfilePrefs(PrefRegistrySimple* registry); - static void ClearProfilePrefs(PrefService* pref_service); - - private: - // If there is no subscription token or |force_token_retrieval|, retrieves a - // GCM subscription token and subscribes to content suggestions server with - // it. Otherwise, subscribes to content suggestions server with the existing - // token. - void Subscribe(bool force_token_retrieval); - - // Called when a subscription token is obtained from the GCM server. - void DidRetrieveToken(const std::string& subscription_token, - instance_id::InstanceID::Result result); - - // Called periodically to validate the subscription token (it is stored on - // disk and may become corrupted) and resubscribe with the new token if the - // old one is invalid. - void ResubscribeIfInvalidToken(); - - // Called when token obtained from the GCM server for its validation. - void DidReceiveTokenForValidation(const std::string& new_token, - instance_id::InstanceID::Result result); - - // If the validation is due, it may be scheduled immediately. - void ScheduleNextTokenValidation(); - - // Subscribe to content suggestions service using the existing token. - void ForceSubscribe(); - - // If the subscription is due, it may be scheduled immediately. - void ScheduleNextForcedSubscription(); - - // Called from OnMessage if the received message is push-by-value message. - void OnPushByValueMessage(const gcm::IncomingMessage& message); - - // Called from OnMessage if the received message is push-to-refresh message. - void OnPushToRefreshMessage(); - - // Called after successfully parsing the received suggestion JSON. - void OnJsonSuccess(std::unique_ptr<base::Value> content); - - // Called in case the received suggestion JSON inside the GCM has a parse - // error. - void OnJsonError(const std::string& json_str, const std::string& error); - - gcm::GCMDriver* const gcm_driver_; - instance_id::InstanceIDDriver* const instance_id_driver_; - PrefService* const pref_service_; - const std::unique_ptr<SubscriptionManager> subscription_manager_; - const ParseJSONCallback parse_json_callback_; - const base::Clock* clock_; - - // Called every time a push-by-value message is received to notify the - // observer. - OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback_; - - // Called every time a push-to-refresh message is received to notify the - // observer. - OnRefreshRequestedCallback on_refresh_requested_callback_; - - std::unique_ptr<base::OneShotTimer> token_validation_timer_; - std::unique_ptr<base::OneShotTimer> forced_subscription_timer_; - - base::WeakPtrFactory<BreakingNewsGCMAppHandler> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(BreakingNewsGCMAppHandler); -}; -} // namespace ntp_snippets - -#endif // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_GCM_APP_HANDLER_H_
diff --git a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc b/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc deleted file mode 100644 index 93e43a8..0000000 --- a/components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler_unittest.cc +++ /dev/null
@@ -1,1137 +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/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h" - -#include <memory> -#include <string> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/json/json_reader.h" -#include "base/test/metrics/histogram_tester.h" -#include "base/test/mock_callback.h" -#include "base/test/scoped_task_environment.h" -#include "base/test/simple_test_clock.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/time/clock.h" -#include "base/time/tick_clock.h" -#include "base/timer/timer.h" -#include "build/build_config.h" -#include "components/gcm_driver/gcm_driver.h" -#include "components/gcm_driver/instance_id/instance_id.h" -#include "components/gcm_driver/instance_id/instance_id_driver.h" -#include "components/ntp_snippets/breaking_news/breaking_news_metrics.h" -#include "components/ntp_snippets/breaking_news/subscription_manager.h" -#include "components/ntp_snippets/features.h" -#include "components/ntp_snippets/pref_names.h" -#include "components/ntp_snippets/remote/test_utils.h" -#include "components/ntp_snippets/time_serialization.h" -#include "components/prefs/testing_pref_service.h" -#include "components/variations/variations_params_manager.h" -#include "google_apis/gcm/engine/account_mapping.h" -#include "testing/gmock/include/gmock/gmock.h" - -using base::Clock; -using base::TestMockTimeTaskRunner; -using base::TickClock; -using base::TimeTicks; -using gcm::InstanceIDHandler; -using instance_id::InstanceID; -using instance_id::InstanceIDDriver; -using testing::_; -using testing::AnyNumber; -using testing::AtMost; -using testing::ElementsAre; -using testing::IsEmpty; -using testing::NiceMock; -using testing::SaveArg; -using testing::StrictMock; - -namespace ntp_snippets { - -namespace { - -// The action key in pushed GCM message. -const char kPushedActionKey[] = "action"; - -class MockSubscriptionManager : public SubscriptionManager { - public: - MockSubscriptionManager() = default; - ~MockSubscriptionManager() override = default; - - MOCK_METHOD1(Subscribe, void(const std::string& token)); - MOCK_METHOD0(Unsubscribe, void()); - MOCK_METHOD0(IsSubscribed, bool()); - MOCK_METHOD1(Resubscribe, void(const std::string& new_token)); - MOCK_METHOD0(NeedsToResubscribe, bool()); - - private: - DISALLOW_COPY_AND_ASSIGN(MockSubscriptionManager); -}; - -class MockInstanceIDDriver : public InstanceIDDriver { - public: - MockInstanceIDDriver() : InstanceIDDriver(/*gcm_driver=*/nullptr) {} - ~MockInstanceIDDriver() override = default; - - MOCK_METHOD1(GetInstanceID, InstanceID*(const std::string& app_id)); - MOCK_METHOD1(RemoveInstanceID, void(const std::string& app_id)); - MOCK_CONST_METHOD1(ExistsInstanceID, bool(const std::string& app_id)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockInstanceIDDriver); -}; - -class MockInstanceID : public InstanceID { - public: - MockInstanceID() : InstanceID("app_id", /*gcm_driver=*/nullptr) {} - ~MockInstanceID() override = default; - - MOCK_METHOD1(GetID, void(const GetIDCallback& callback)); - MOCK_METHOD1(GetCreationTime, void(const GetCreationTimeCallback& callback)); - MOCK_METHOD5(GetToken, - void(const std::string& authorized_entity, - const std::string& scope, - const std::map<std::string, std::string>& options, - bool is_lazy, - const GetTokenCallback& callback)); - MOCK_METHOD4(ValidateToken, - void(const std::string& authorized_entity, - const std::string& scope, - const std::string& token, - const ValidateTokenCallback& callback)); - - protected: - MOCK_METHOD3(DeleteTokenImpl, - void(const std::string& authorized_entity, - const std::string& scope, - const DeleteTokenCallback& callback)); - MOCK_METHOD1(DeleteIDImpl, void(const DeleteIDCallback& callback)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockInstanceID); -}; - -class MockGCMDriver : public gcm::GCMDriver { - public: - MockGCMDriver() - : GCMDriver(/*store_path=*/base::FilePath(), - /*blocking_task_runner=*/nullptr) {} - ~MockGCMDriver() override = default; - - MOCK_METHOD4(ValidateRegistration, - void(const std::string& app_id, - const std::vector<std::string>& sender_ids, - const std::string& registration_id, - const ValidateRegistrationCallback& callback)); - MOCK_METHOD0(OnSignedIn, void()); - MOCK_METHOD0(OnSignedOut, void()); - MOCK_METHOD1(AddConnectionObserver, - void(gcm::GCMConnectionObserver* observer)); - MOCK_METHOD1(RemoveConnectionObserver, - void(gcm::GCMConnectionObserver* observer)); - MOCK_METHOD0(Enable, void()); - MOCK_METHOD0(Disable, void()); - MOCK_CONST_METHOD0(GetGCMClientForTesting, gcm::GCMClient*()); - MOCK_CONST_METHOD0(IsStarted, bool()); - MOCK_CONST_METHOD0(IsConnected, bool()); - MOCK_METHOD2(GetGCMStatistics, - void(const GetGCMStatisticsCallback& callback, - ClearActivityLogs clear_logs)); - MOCK_METHOD2(SetGCMRecording, - void(const GetGCMStatisticsCallback& callback, bool recording)); - MOCK_METHOD1(SetAccountTokens, - void(const std::vector<gcm::GCMClient::AccountTokenInfo>& - account_tokens)); - MOCK_METHOD1(UpdateAccountMapping, - void(const gcm::AccountMapping& account_mapping)); - MOCK_METHOD1(RemoveAccountMapping, void(const std::string& account_id)); - MOCK_METHOD0(GetLastTokenFetchTime, base::Time()); - MOCK_METHOD1(SetLastTokenFetchTime, void(const base::Time& time)); - MOCK_METHOD1(WakeFromSuspendForHeartbeat, void(bool wake)); - MOCK_METHOD0(GetInstanceIDHandlerInternal, InstanceIDHandler*()); - MOCK_METHOD2(AddHeartbeatInterval, - void(const std::string& scope, int interval_ms)); - MOCK_METHOD1(RemoveHeartbeatInterval, void(const std::string& scope)); - - protected: - MOCK_METHOD1(EnsureStarted, - gcm::GCMClient::Result(gcm::GCMClient::StartMode start_mode)); - MOCK_METHOD2(RegisterImpl, - void(const std::string& app_id, - const std::vector<std::string>& sender_ids)); - MOCK_METHOD1(UnregisterImpl, void(const std::string& app_id)); - MOCK_METHOD3(SendImpl, - void(const std::string& app_id, - const std::string& receiver_id, - const gcm::OutgoingMessage& message)); - MOCK_METHOD2(RecordDecryptionFailure, - void(const std::string& app_id, - gcm::GCMDecryptionResult result)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockGCMDriver); -}; - -class MockOnNewRemoteSuggestionCallback { - public: - // Workaround for gMock's lack of support for movable-only arguments. - void WrappedRun(std::unique_ptr<RemoteSuggestion> remote_suggestion) { - Run(remote_suggestion.get()); - } - - BreakingNewsListener::OnNewRemoteSuggestionCallback Get() { - return base::Bind(&MockOnNewRemoteSuggestionCallback::WrappedRun, - base::Unretained(this)); - } - - MOCK_METHOD1(Run, void(RemoteSuggestion* remote_suggestion)); -}; - -void ParseJson( - const std::string& json, - const BreakingNewsGCMAppHandler::SuccessCallback& success_callback, - const BreakingNewsGCMAppHandler::ErrorCallback& error_callback) { - base::JSONReader json_reader; - std::unique_ptr<base::Value> value = json_reader.ReadToValueDeprecated(json); - if (value) { - success_callback.Run(std::move(value)); - } else { - error_callback.Run(json_reader.GetErrorMessage()); - } -} - -ACTION_TEMPLATE(InvokeCallbackArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_1_VALUE_PARAMS(p0)) { - std::get<k>(args).Run(p0); -} - -ACTION_TEMPLATE(InvokeCallbackArgument, - HAS_1_TEMPLATE_PARAMS(int, k), - AND_2_VALUE_PARAMS(p0, p1)) { - std::get<k>(args).Run(p0, p1); -} - -base::TimeDelta GetTokenValidationPeriod() { - return base::TimeDelta::FromHours(24); -} - -base::TimeDelta GetForcedSubscriptionPeriod() { - return base::TimeDelta::FromDays(7); -} - -const char kBreakingNewsGCMAppID[] = "com.google.breakingnews.gcm"; - -std::string BoolToString(bool value) { - return value ? "true" : "false"; -} - -} // namespace - -class BreakingNewsGCMAppHandlerTest : public testing::Test { - public: - BreakingNewsGCMAppHandlerTest() - : scoped_task_environment_( - base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME), - start_time_(scoped_task_environment_.GetMockClock()->Now()) { - // Our app handler obtains InstanceID through InstanceIDDriver. We mock - // InstanceIDDriver and return MockInstanceID through it. - mock_instance_id_driver_ = - std::make_unique<StrictMock<MockInstanceIDDriver>>(); - mock_instance_id_ = std::make_unique<StrictMock<MockInstanceID>>(); - mock_gcm_driver_ = std::make_unique<StrictMock<MockGCMDriver>>(); - BreakingNewsGCMAppHandler::RegisterProfilePrefs( - utils_.pref_service()->registry()); - - // This is called in BreakingNewsGCMAppHandler. - EXPECT_CALL(*mock_instance_id_driver_, GetInstanceID(kBreakingNewsGCMAppID)) - .WillRepeatedly(Return(mock_instance_id_.get())); - } - - std::unique_ptr<BreakingNewsGCMAppHandler> MakeHandler() { - // TODO(vitaliii): Initialize MockSubscriptionManager in the constructor, so - // that one could set up expectations before creating the handler. - auto wrapped_mock_subscription_manager = - std::make_unique<NiceMock<MockSubscriptionManager>>(); - mock_subscription_manager_ = wrapped_mock_subscription_manager.get(); - - auto token_validation_timer = std::make_unique<base::OneShotTimer>( - scoped_task_environment_.GetMockTickClock()); - token_validation_timer->SetTaskRunner( - scoped_task_environment_.GetMainThreadTaskRunner()); - - auto forced_subscription_timer = std::make_unique<base::OneShotTimer>( - scoped_task_environment_.GetMockTickClock()); - forced_subscription_timer->SetTaskRunner( - scoped_task_environment_.GetMainThreadTaskRunner()); - - return std::make_unique<BreakingNewsGCMAppHandler>( - mock_gcm_driver_.get(), mock_instance_id_driver_.get(), pref_service(), - std::move(wrapped_mock_subscription_manager), base::Bind(&ParseJson), - scoped_task_environment_.GetMockClock(), - std::move(token_validation_timer), - std::move(forced_subscription_timer)); - } - - void SetFeatureParams(bool enable_token_validation, - bool enable_forced_subscription) { - // VariationParamsManager supports only one - // |SetVariationParamsWithFeatureAssociations| at a time, so we clear - // previous settings first to make this explicit. - params_manager_.ClearAllVariationParams(); - params_manager_.SetVariationParamsWithFeatureAssociations( - kBreakingNewsPushFeature.name, - { - {"enable_token_validation", BoolToString(enable_token_validation)}, - {"enable_forced_subscription", - BoolToString(enable_forced_subscription)}, - }, - {kBreakingNewsPushFeature.name}); - } - - PrefService* pref_service() { return utils_.pref_service(); } - NiceMock<MockSubscriptionManager>* mock_subscription_manager() { - return mock_subscription_manager_; - } - StrictMock<MockInstanceID>* mock_instance_id() { - return mock_instance_id_.get(); - } - - void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); } - - void FastForwardBy(const base::TimeDelta& delta) { - scoped_task_environment_.FastForwardBy(delta); - } - - base::Time GetDummyNow() { return start_time_; } - - private: - base::test::ScopedTaskEnvironment scoped_task_environment_; - const base::Time start_time_; - variations::testing::VariationParamsManager params_manager_; - test::RemoteSuggestionsTestUtils utils_; - NiceMock<MockSubscriptionManager>* mock_subscription_manager_; - std::unique_ptr<StrictMock<MockGCMDriver>> mock_gcm_driver_; - std::unique_ptr<StrictMock<MockInstanceIDDriver>> mock_instance_id_driver_; - std::unique_ptr<StrictMock<MockInstanceID>> mock_instance_id_; -}; - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldValidateTokenImmediatelyIfValidationIsDue) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // Last validation was long time ago. - const base::Time last_validation = - GetDummyNow() - 10 * GetTokenValidationPeriod(); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - // Check that the handler validates the token through GetToken. ValidateToken - // always returns true on Android, so it's not useful. Instead, the handler - // must check that the result from GetToken is unchanged. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0); - handler->StartListening(base::DoNothing(), base::DoNothing()); - RunUntilIdle(); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldScheduleTokenValidationIfNotYetDue) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // The next validation will be soon. - const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1); - const base::Time last_validation = - GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - // Check that handler does not validate the token yet. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)).Times(0); - EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0); - handler->StartListening(base::DoNothing(), base::DoNothing()); - FastForwardBy(time_to_validation - base::TimeDelta::FromSeconds(1)); - - // But when it is time, validation happens. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - FastForwardBy(base::TimeDelta::FromSeconds(1)); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, ShouldNotValidateTokenBeforeListening) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // Last validation was long time ago. - const base::Time last_validation = - GetDummyNow() - 10 * GetTokenValidationPeriod(); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - - // Check that handler does not validate the token before StartListening even - // though a validation is due. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)).Times(0); - EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0); - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - FastForwardBy(10 * GetTokenValidationPeriod()); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldNotValidateTokenAfterStopListening) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // The next validation will be soon. - const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1); - const base::Time last_validation = - GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - // Check that handler does not validate the token after StopListening even - // though a validation is due. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)).Times(0); - EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0); - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - handler->StopListening(); - FastForwardBy(10 * GetTokenValidationPeriod()); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldRescheduleTokenValidationWhenRetrievingToken) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // The next validation will be soon. - const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1); - const base::Time last_validation = - GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - // There is no token yet, thus, handler retrieves it on StartListening. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - // Check that the validation schedule has changed. "Old validation" should not - // happen because the token was retrieved recently. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)).Times(0); - FastForwardBy(GetTokenValidationPeriod() - base::TimeDelta::FromSeconds(1)); - - // The new validation should happen. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - FastForwardBy(base::TimeDelta::FromSeconds(1)); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldScheduleNewTokenValidationAfterValidation) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // The next validation will be soon. - const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1); - const base::Time last_validation = - GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - // Handler validates the token. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0); - FastForwardBy(time_to_validation); - - // Check that the next validation is scheduled in time. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)).Times(0); - FastForwardBy(GetTokenValidationPeriod() - base::TimeDelta::FromSeconds(1)); - - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - FastForwardBy(base::TimeDelta::FromSeconds(1)); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldResubscribeWithNewTokenIfOldIsInvalidAfterValidation) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // Last validation was long time ago. - const base::Time last_validation = - GetDummyNow() - 10 * GetTokenValidationPeriod(); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "old_token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - // Check that handler resubscribes with the new token after a validation, if - // old is invalid. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("new_token", InstanceID::Result::SUCCESS)); - EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0); - EXPECT_CALL(*mock_subscription_manager(), Resubscribe("new_token")); - EXPECT_CALL(*mock_subscription_manager(), Subscribe(_)).Times(0); - RunUntilIdle(); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldDoNothingIfOldTokenIsValidAfterValidation) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // Last validation was long time ago. - const base::Time last_validation = - GetDummyNow() - 10 * GetTokenValidationPeriod(); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - // Check that provider does not resubscribe if the old token is still valid - // after validation. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - EXPECT_CALL(*mock_instance_id(), ValidateToken(_, _, _, _)).Times(0); - EXPECT_CALL(*mock_subscription_manager(), Subscribe(_)).Times(0); - EXPECT_CALL(*mock_subscription_manager(), Resubscribe(_)).Times(0); - RunUntilIdle(); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldIgnoreTokenReceivedAfterStopListening) { - // The last validation time is used to ensure that GetToken callback is - // ignored. Thus, enable validation. - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // The next validation won't be soon. - const base::TimeDelta time_to_validation = base::TimeDelta::FromDays(5); - const base::Time last_validation = - GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - // Save the GetToken callback during the subscription. - base::RepeatingCallback<void(const std::string&, InstanceID::Result)> - get_token_callback; - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce(SaveArg<4>(&get_token_callback)); - handler->StartListening( - base::BindRepeating( - [](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}), - base::DoNothing()); - - // The client stops listening for the push updates. - handler->StopListening(); - - // The GCM returns the new token (it does not know that we are not interested - // anymore). Imitate an asynchronous call via time delay. - FastForwardBy(base::TimeDelta::FromSeconds(1)); - get_token_callback.Run("new_token", InstanceID::Result::SUCCESS); - - // The new token must be completely ignored. It should not be saved. - EXPECT_EQ("", pref_service()->GetString( - prefs::kBreakingNewsGCMSubscriptionTokenCache)); - // The validation should not be rescheduled. - EXPECT_EQ(last_validation, - DeserializeTime(pref_service()->GetInt64( - prefs::kBreakingNewsGCMLastTokenValidationTime))); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldIgnoreTokenReceivedForValidationAfterStopListening) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // The next validation will be soon. - const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1); - const base::Time last_validation = - GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "old_token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening( - base::BindRepeating( - [](std::unique_ptr<RemoteSuggestion> remote_suggestion) {}), - base::DoNothing()); - - FastForwardBy(time_to_validation - base::TimeDelta::FromSeconds(1)); - - // Save the GetToken callback during the validation. - base::RepeatingCallback<void(const std::string&, InstanceID::Result)> - get_token_callback; - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce(SaveArg<4>(&get_token_callback)); - FastForwardBy(base::TimeDelta::FromSeconds(1)); - - // The client stops listening for the push updates. - handler->StopListening(); - - // The GCM returns the new token (it does not know that we are not interested - // anymore). - FastForwardBy(base::TimeDelta::FromSeconds(1)); - get_token_callback.Run("new_token", InstanceID::Result::SUCCESS); - - // The new token must be completely ignored. It should not be saved. - EXPECT_EQ("old_token", pref_service()->GetString( - prefs::kBreakingNewsGCMSubscriptionTokenCache)); - // The validation should not occur. - EXPECT_EQ(last_validation, - DeserializeTime(pref_service()->GetInt64( - prefs::kBreakingNewsGCMLastTokenValidationTime))); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - IsListeningShouldReturnFalseBeforeListening) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - EXPECT_FALSE(handler->IsListening()); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - IsListeningShouldReturnTrueAfterStartListening) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - ASSERT_FALSE(handler->IsListening()); - - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillRepeatedly( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - EXPECT_TRUE(handler->IsListening()); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - IsListeningShouldReturnFalseAfterStopListening) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - ASSERT_FALSE(handler->IsListening()); - - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillRepeatedly( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - handler->StartListening(base::DoNothing(), base::DoNothing()); - ASSERT_TRUE(handler->IsListening()); - - handler->StopListening(); - - EXPECT_FALSE(handler->IsListening()); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - IsListeningShouldReturnTrueAfterSecondStartListening) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - ASSERT_FALSE(handler->IsListening()); - - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillRepeatedly( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - handler->StartListening(base::DoNothing(), base::DoNothing()); - ASSERT_TRUE(handler->IsListening()); - - handler->StopListening(); - ASSERT_FALSE(handler->IsListening()); - - handler->StartListening(base::DoNothing(), base::DoNothing()); - - EXPECT_TRUE(handler->IsListening()); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, ShouldForceSubscribeImmediatelyIfDue) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/true); - - // Last subscription was long time ago. - const base::Time last_subscription = - GetDummyNow() - 10 * GetForcedSubscriptionPeriod(); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime, - SerializeTime(last_subscription)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - handler->StartListening(base::DoNothing(), base::DoNothing()); - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")); - RunUntilIdle(); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldScheduleForcedSubscribtionIfNotYetDue) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/true); - - // The next forced subscription will be soon. - const base::TimeDelta time_to_subscription = base::TimeDelta::FromHours(1); - const base::Time last_subscription = - GetDummyNow() - (GetForcedSubscriptionPeriod() - time_to_subscription); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime, - SerializeTime(last_subscription)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - // Check that handler does not force subscribe yet. - handler->StartListening(base::DoNothing(), base::DoNothing()); - // TODO(vitaliii): Consider making FakeSubscriptionManager, because - // IsSubscribed() affects forced subscriptions. Currently we have to carefully - // avoid the initial subscription. - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0); - FastForwardBy(time_to_subscription - base::TimeDelta::FromSeconds(1)); - - // But when it is time, forced subscription happens. - testing::Mock::VerifyAndClearExpectations(mock_subscription_manager()); - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")); - FastForwardBy(base::TimeDelta::FromSeconds(1)); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, ShouldNotForceSubscribeBeforeListening) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/true); - - // Last subscription was long time ago. - const base::Time last_subscription = - GetDummyNow() - 10 * GetForcedSubscriptionPeriod(); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime, - SerializeTime(last_subscription)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - // Check that handler does not force subscribe before StartListening even - // though a forced subscription is due. - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0); - FastForwardBy(10 * GetForcedSubscriptionPeriod()); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldNotForceSubscribeAfterStopListening) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/true); - - // The next forced subscription will be soon. - const base::TimeDelta time_to_subscription = base::TimeDelta::FromHours(1); - const base::Time last_subscription = - GetDummyNow() - (GetForcedSubscriptionPeriod() - time_to_subscription); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime, - SerializeTime(last_subscription)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - // Check that handler does not force subscribe after StopListening even - // though a forced subscription is due. - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - handler->StopListening(); - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0); - FastForwardBy(10 * GetForcedSubscriptionPeriod()); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldScheduleNewForcedSubscriptionAfterForcedSubscription) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/true); - - // The next forced subscription will be soon. - const base::TimeDelta time_to_subscription = base::TimeDelta::FromHours(1); - const base::Time last_subscription = - GetDummyNow() - (GetForcedSubscriptionPeriod() - time_to_subscription); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime, - SerializeTime(last_subscription)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - // Handler force subscribes. - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")); - FastForwardBy(time_to_subscription); - - // Check that the next forced subscription is scheduled in time. - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0); - FastForwardBy(GetForcedSubscriptionPeriod() - - base::TimeDelta::FromSeconds(1)); - - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")); - FastForwardBy(base::TimeDelta::FromSeconds(1)); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - TokenValidationAndForcedSubscriptionShouldNotAffectEachOther) { - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/true); - - // The next forced subscription will be soon. - const base::TimeDelta time_to_subscription = base::TimeDelta::FromHours(1); - const base::Time last_subscription = - GetDummyNow() - (GetForcedSubscriptionPeriod() - time_to_subscription); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastForcedSubscriptionTime, - SerializeTime(last_subscription)); - - // The next validation will be sooner. - const base::TimeDelta time_to_validation = base::TimeDelta::FromMinutes(30); - const base::Time last_validation = - GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - // Check that the next validation is scheduled in time. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)).Times(0); - FastForwardBy(time_to_validation - base::TimeDelta::FromSeconds(1)); - - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - FastForwardBy(base::TimeDelta::FromSeconds(1)); - - // Check that the next forced subscription is scheduled in time. - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")).Times(0); - FastForwardBy((time_to_subscription - time_to_validation) - - base::TimeDelta::FromSeconds(1)); - - EXPECT_CALL(*mock_subscription_manager(), Subscribe("token")); - FastForwardBy(base::TimeDelta::FromSeconds(1)); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, ShouldReportMissingAction) { - base::HistogramTester histogram_tester; - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - handler->OnMessage("com.google.breakingnews.gcm", gcm::IncomingMessage()); - - EXPECT_THAT( - histogram_tester.GetAllSamples( - "NewTabPage.ContentSuggestions.BreakingNews.ReceivedMessageAction"), - ElementsAre(base::Bucket( - /*min=*/static_cast<int>(metrics::ReceivedMessageAction::NO_ACTION), - /*count=*/1))); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, ShouldReportInvalidAction) { - base::HistogramTester histogram_tester; - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - gcm::IncomingMessage message; - message.data[kPushedActionKey] = "invalid_action"; - - handler->OnMessage("com.google.breakingnews.gcm", message); - - EXPECT_THAT( - histogram_tester.GetAllSamples( - "NewTabPage.ContentSuggestions.BreakingNews.ReceivedMessageAction"), - ElementsAre( - base::Bucket(/*min=*/static_cast<int>( - metrics::ReceivedMessageAction::INVALID_ACTION), - /*count=*/1))); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, ShouldReportPushToRefreshAction) { - base::HistogramTester histogram_tester; - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - gcm::IncomingMessage message; - message.data[kPushedActionKey] = "push-to-refresh"; - - handler->OnMessage("com.google.breakingnews.gcm", message); - - EXPECT_THAT( - histogram_tester.GetAllSamples( - "NewTabPage.ContentSuggestions.BreakingNews.ReceivedMessageAction"), - ElementsAre( - base::Bucket(/*min=*/static_cast<int>( - metrics::ReceivedMessageAction::PUSH_TO_REFRESH), - /*count=*/1))); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, ShouldReportPushByValueAction) { - base::HistogramTester histogram_tester; - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - gcm::IncomingMessage message; - message.data[kPushedActionKey] = "push-by-value"; - message.data["payload"] = "news"; - - handler->OnMessage("com.google.breakingnews.gcm", message); - - EXPECT_THAT( - histogram_tester.GetAllSamples( - "NewTabPage.ContentSuggestions.BreakingNews.ReceivedMessageAction"), - ElementsAre(base::Bucket( - /*min=*/static_cast<int>( - metrics::ReceivedMessageAction::PUSH_BY_VALUE), - /*count=*/1))); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldCallOnNewRemoteSuggestionCallbackOnPushByValueMessage) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - std::string json = R"( - {"categories" : [{ - "id": 1, - "localizedTitle": "section title", - "suggestions" : [{ - "ids" : ["http://url.com"], - "title" : "Pushed Dummy Title", - "snippet" : "Pushed Dummy Snippet", - "fullPageUrl" : "http://url.com", - "creationTime" : "2017-01-01T00:00:01.000Z", - "expirationTime" : "2100-01-01T00:00:01.000Z", - "attribution" : "Pushed Dummy Publisher", - "imageUrl" : "https://www.google.com/favicon.ico" - }] - }]} - )"; - - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - MockOnNewRemoteSuggestionCallback mock_on_new_remote_suggestion_callback; - - handler->StartListening(mock_on_new_remote_suggestion_callback.Get(), - base::DoNothing()); - - gcm::IncomingMessage message; - message.data[kPushedActionKey] = "push-by-value"; - message.data["payload"] = json; - - EXPECT_CALL(mock_on_new_remote_suggestion_callback, Run(_)).Times(1); - handler->OnMessage("com.google.breakingnews.gcm", message); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldCallOnRefreshRequestedCallbackOnPushToRefreshMessage) { - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - base::MockCallback<BreakingNewsListener::OnRefreshRequestedCallback> - on_refresh_requested_callback; - - handler->StartListening(base::DoNothing(), - on_refresh_requested_callback.Get()); - - gcm::IncomingMessage message; - message.data[kPushedActionKey] = "push-to-refresh"; - - EXPECT_CALL(on_refresh_requested_callback, Run()).Times(1); - handler->OnMessage("com.google.breakingnews.gcm", message); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, ShouldReportTokenRetrievalResult) { - base::HistogramTester histogram_tester; - SetFeatureParams(/*enable_token_validation=*/false, - /*enable_forced_subscription=*/false); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce(InvokeCallbackArgument<4>(/*token=*/"", - InstanceID::Result::NETWORK_ERROR)); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - EXPECT_THAT( - histogram_tester.GetAllSamples( - "NewTabPage.ContentSuggestions.BreakingNews.TokenRetrievalResult"), - ElementsAre(base::Bucket( - /*min=*/static_cast<int>(InstanceID::Result::NETWORK_ERROR), - /*count=*/1))); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldReportTimeSinceLastTokenValidation) { - base::HistogramTester histogram_tester; - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // The next validation will be soon. - const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1); - const base::Time last_validation = - GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - // Check that handler does not report the metric before the validation. - FastForwardBy(time_to_validation - base::TimeDelta::FromSeconds(1)); - EXPECT_THAT( - histogram_tester.GetAllSamples( - "NewTabPage.ContentSuggestions.BreakingNews.TokenRetrievalResult"), - IsEmpty()); - - // But when the validation happens, the time is reported. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - FastForwardBy(base::TimeDelta::FromSeconds(1)); - - histogram_tester.ExpectTimeBucketCount( - "NewTabPage.ContentSuggestions.BreakingNews.TimeSinceLastTokenValidation", - GetTokenValidationPeriod(), /*count=*/1); - // |ExpectTimeBucketCount| allows other buckets. Let's ensure that there are - // none. - histogram_tester.ExpectTotalCount( - "NewTabPage.ContentSuggestions.BreakingNews.TimeSinceLastTokenValidation", - /*count=*/1); -} - -TEST_F(BreakingNewsGCMAppHandlerTest, - ShouldReportWhetherTokenWasValidBeforeValidation) { - base::HistogramTester histogram_tester; - SetFeatureParams(/*enable_token_validation=*/true, - /*enable_forced_subscription=*/false); - - // The next validation will be soon. - const base::TimeDelta time_to_validation = base::TimeDelta::FromHours(1); - const base::Time last_validation = - GetDummyNow() - (GetTokenValidationPeriod() - time_to_validation); - pref_service()->SetInt64(prefs::kBreakingNewsGCMLastTokenValidationTime, - SerializeTime(last_validation)); - // Omit receiving the token by putting it there directly. - pref_service()->SetString(prefs::kBreakingNewsGCMSubscriptionTokenCache, - "token"); - - std::unique_ptr<BreakingNewsGCMAppHandler> handler = MakeHandler(); - handler->StartListening(base::DoNothing(), base::DoNothing()); - - // Check that handler does not report the metric before the validation. - FastForwardBy(time_to_validation - base::TimeDelta::FromSeconds(1)); - EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.ContentSuggestions." - "BreakingNews." - "WasTokenValidBeforeValidation"), - IsEmpty()); - - // But when the validation happens, the old token validness is reported. - EXPECT_CALL(*mock_instance_id(), GetToken(_, _, _, _, _)) - .WillOnce( - InvokeCallbackArgument<4>("token", InstanceID::Result::SUCCESS)); - FastForwardBy(base::TimeDelta::FromSeconds(1)); - - EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.ContentSuggestions." - "BreakingNews." - "WasTokenValidBeforeValidation"), - ElementsAre(base::Bucket( - /*min=*/1, - /*count=*/1))); -} - -} // namespace ntp_snippets
diff --git a/components/ntp_snippets/breaking_news/breaking_news_listener.h b/components/ntp_snippets/breaking_news/breaking_news_listener.h deleted file mode 100644 index f130c77..0000000 --- a/components/ntp_snippets/breaking_news/breaking_news_listener.h +++ /dev/null
@@ -1,41 +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_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_LISTENER_H_ -#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_LISTENER_H_ - -#include <vector> - -#include "base/callback_forward.h" -#include "components/ntp_snippets/remote/json_to_categories.h" - -namespace ntp_snippets { - -// Listens to pushed breaking news and refresh requests from the content -// suggestion servers. -class BreakingNewsListener { - public: - using OnNewRemoteSuggestionCallback = - base::Callback<void(std::unique_ptr<RemoteSuggestion> remote_suggestion)>; - using OnRefreshRequestedCallback = base::Callback<void()>; - - virtual ~BreakingNewsListener() = default; - - // Subscribe to the breaking news service and start listening for pushed - // messages from the content suggestion server. Must not be called if already - // listening. - virtual void StartListening( - OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback, - OnRefreshRequestedCallback on_refresh_requested_callback) = 0; - - // Stop listening for pushed messages from the content suggestion server. Any - // further pushed messages will be ignored. Must be called while listening. - virtual void StopListening() = 0; - - virtual bool IsListening() const = 0; -}; - -} // namespace ntp_snippets - -#endif // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_LISTENER_H_
diff --git a/components/ntp_snippets/breaking_news/breaking_news_metrics.cc b/components/ntp_snippets/breaking_news/breaking_news_metrics.cc deleted file mode 100644 index 645253b..0000000 --- a/components/ntp_snippets/breaking_news/breaking_news_metrics.cc +++ /dev/null
@@ -1,72 +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/ntp_snippets/breaking_news/breaking_news_metrics.h" - -#include "base/metrics/histogram_macros.h" - -using instance_id::InstanceID; - -namespace ntp_snippets { -namespace metrics { - -namespace { - -const char kHistogramSubscriptionRequestStatus[] = - "NewTabPage.ContentSuggestions.BreakingNews.SubscriptionRequestStatus"; -const char kHistogramUnsubscriptionRequestStatus[] = - "NewTabPage.ContentSuggestions.BreakingNews.UnsubscriptionRequestStatus"; - -const char kHistogramReceivedMessageAction[] = - "NewTabPage.ContentSuggestions.BreakingNews.ReceivedMessageAction"; - -const char kHistogramTokenRetrievalResult[] = - "NewTabPage.ContentSuggestions.BreakingNews.TokenRetrievalResult"; - -const char kHistogramTimeSinceLastTokenValidation[] = - "NewTabPage.ContentSuggestions.BreakingNews.TimeSinceLastTokenValidation"; - -const char kHistogramWasTokenValidBeforeValidation[] = - "NewTabPage.ContentSuggestions.BreakingNews.WasTokenValidBeforeValidation"; - -} // namespace - -void OnSubscriptionRequestCompleted(const Status& status) { - UMA_HISTOGRAM_ENUMERATION(kHistogramSubscriptionRequestStatus, status.code, - StatusCode::STATUS_CODE_COUNT); -} - -void OnUnsubscriptionRequestCompleted(const Status& status) { - UMA_HISTOGRAM_ENUMERATION(kHistogramUnsubscriptionRequestStatus, status.code, - StatusCode::STATUS_CODE_COUNT); -} - -void OnMessageReceived(ReceivedMessageAction action) { - UMA_HISTOGRAM_ENUMERATION(kHistogramReceivedMessageAction, action, - ReceivedMessageAction::COUNT); -} - -void OnTokenRetrieved(InstanceID::Result result) { - UMA_HISTOGRAM_ENUMERATION(kHistogramTokenRetrievalResult, result, - InstanceID::Result::LAST_RESULT + 1); -} - -void OnTokenValidationAttempted( - const base::Optional<base::TimeDelta>& time_since_last_validation, - const base::Optional<bool>& was_token_valid_before_validation) { - if (time_since_last_validation.has_value()) { - UMA_HISTOGRAM_CUSTOM_TIMES(kHistogramTimeSinceLastTokenValidation, - *time_since_last_validation, - /*min=*/base::TimeDelta::FromSeconds(1), - /*max=*/base::TimeDelta::FromDays(7), - /*bucket_count=*/50); - } - if (was_token_valid_before_validation.has_value()) { - UMA_HISTOGRAM_BOOLEAN(kHistogramWasTokenValidBeforeValidation, - *was_token_valid_before_validation); - } -} - -} // namespace metrics -} // namespace ntp_snippets
diff --git a/components/ntp_snippets/breaking_news/breaking_news_metrics.h b/components/ntp_snippets/breaking_news/breaking_news_metrics.h deleted file mode 100644 index a80e78ae..0000000 --- a/components/ntp_snippets/breaking_news/breaking_news_metrics.h +++ /dev/null
@@ -1,46 +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_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_METRICS_H_ -#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_METRICS_H_ - -#include "base/optional.h" -#include "base/time/time.h" -#include "components/gcm_driver/instance_id/instance_id.h" -#include "components/ntp_snippets/status.h" - -namespace ntp_snippets { -namespace metrics { - -void OnSubscriptionRequestCompleted(const Status& status); -void OnUnsubscriptionRequestCompleted(const Status& status); - -// Received message action. This enum is used in a UMA histogram, therefore, -// don't remove or reorder elements, only add new ones at the end (before -// COUNT), and keep in sync with ContentSuggestionsBreakingNewsMessageAction in -// enums.xml. -enum class ReceivedMessageAction { - NO_ACTION = 0, - INVALID_ACTION = 1, - PUSH_BY_VALUE = 2, - PUSH_TO_REFRESH = 3, - // Insert new values here! - COUNT -}; - -void OnMessageReceived(ReceivedMessageAction action); - -void OnTokenRetrieved(instance_id::InstanceID::Result result); - -// |time_since_last_validation| can be absent for the first validation. -// |was_token_valid_before_validation| may be absent if it is not known (e.g. an -// error happened and a token was not received). -void OnTokenValidationAttempted( - const base::Optional<base::TimeDelta>& time_since_last_validation, - const base::Optional<bool>& was_token_valid_before_validation); - -} // namespace metrics -} // namespace ntp_snippets - -#endif // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_BREAKING_NEWS_METRICS_H_
diff --git a/components/ntp_snippets/breaking_news/subscription_json_request.cc b/components/ntp_snippets/breaking_news/subscription_json_request.cc deleted file mode 100644 index 8f7856f4..0000000 --- a/components/ntp_snippets/breaking_news/subscription_json_request.cc +++ /dev/null
@@ -1,195 +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/ntp_snippets/breaking_news/subscription_json_request.h" - -#include "base/bind.h" -#include "base/json/json_writer.h" -#include "base/memory/ptr_util.h" -#include "base/strings/stringprintf.h" -#include "base/values.h" -#include "components/data_use_measurement/core/data_use_user_data.h" -#include "components/variations/net/variations_http_headers.h" -#include "net/base/load_flags.h" -#include "net/http/http_status_code.h" -#include "services/network/public/cpp/resource_request.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/network/public/cpp/simple_url_loader.h" - -using net::HttpRequestHeaders; - -namespace ntp_snippets { - -namespace internal { - -SubscriptionJsonRequest::SubscriptionJsonRequest() = default; - -SubscriptionJsonRequest::~SubscriptionJsonRequest() = default; - -void SubscriptionJsonRequest::Start(CompletedCallback callback) { - DCHECK(request_completed_callback_.is_null()) << "Request already running!"; - DCHECK(url_loader_factory_); - request_completed_callback_ = std::move(callback); - simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - url_loader_factory_.get(), - base::BindOnce(&SubscriptionJsonRequest::OnSimpleLoaderComplete, - base::Unretained(this))); -} - -void SubscriptionJsonRequest::OnSimpleLoaderComplete( - std::unique_ptr<std::string> response_body) { - int net_error = simple_url_loader_->NetError(); - - if (net_error != net::OK) { - std::move(request_completed_callback_) - .Run(Status(StatusCode::TEMPORARY_ERROR, - base::StringPrintf("Network Error: %d", net_error))); - } else if (!response_body) { - int response_code = -1; - if (simple_url_loader_->ResponseInfo() && - simple_url_loader_->ResponseInfo()->headers) { - response_code = - simple_url_loader_->ResponseInfo()->headers->response_code(); - } - std::move(request_completed_callback_) - .Run(Status(StatusCode::PERMANENT_ERROR, - base::StringPrintf("HTTP Error: %d", response_code))); - } else { - std::move(request_completed_callback_) - .Run(Status(StatusCode::SUCCESS, std::string())); - } -} - -SubscriptionJsonRequest::Builder::Builder() = default; -SubscriptionJsonRequest::Builder::Builder(SubscriptionJsonRequest::Builder&&) = - default; -SubscriptionJsonRequest::Builder::~Builder() = default; - -std::unique_ptr<SubscriptionJsonRequest> -SubscriptionJsonRequest::Builder::Build() const { - DCHECK(!url_.is_empty()); - DCHECK(url_loader_factory_); - auto request = base::WrapUnique(new SubscriptionJsonRequest()); - - std::string body = BuildBody(); - request->simple_url_loader_ = BuildURLLoader(body); - request->url_loader_factory_ = std::move(url_loader_factory_); - - return request; -} - -SubscriptionJsonRequest::Builder& SubscriptionJsonRequest::Builder::SetToken( - const std::string& token) { - token_ = token; - return *this; -} - -SubscriptionJsonRequest::Builder& SubscriptionJsonRequest::Builder::SetUrl( - const GURL& url) { - url_ = url; - return *this; -} - -SubscriptionJsonRequest::Builder& -SubscriptionJsonRequest::Builder::SetUrlLoaderFactory( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { - url_loader_factory_ = std::move(url_loader_factory); - return *this; -} - -SubscriptionJsonRequest::Builder& -SubscriptionJsonRequest::Builder::SetAuthenticationHeader( - const std::string& auth_header) { - auth_header_ = auth_header; - return *this; -} - -SubscriptionJsonRequest::Builder& SubscriptionJsonRequest::Builder::SetLocale( - const std::string& locale) { - locale_ = locale; - return *this; -} - -SubscriptionJsonRequest::Builder& -SubscriptionJsonRequest::Builder::SetCountryCode( - const std::string& country_code) { - country_code_ = country_code; - return *this; -} - -std::string SubscriptionJsonRequest::Builder::BuildBody() const { - base::DictionaryValue request; - request.SetString("token", token_); - - request.SetString("locale", locale_); - request.SetString("country_code", country_code_); - - std::string request_json; - bool success = base::JSONWriter::Write(request, &request_json); - DCHECK(success); - return request_json; -} - -std::unique_ptr<network::SimpleURLLoader> -SubscriptionJsonRequest::Builder::BuildURLLoader( - const std::string& body) const { - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("gcm_subscription", R"( - semantics { - sender: "Subscribe for breaking news delivered via GCM push messages" - description: - "Chromium can receive breaking news via GCM push messages. " - "This request suscribes the client to receiving them." - trigger: - "Subscription takes place only once per profile lifetime. " - data: - "The subscription token that identifies this Chromium profile." - destination: GOOGLE_OWNED_SERVICE - } - policy { - cookies_allowed: NO - setting: - "This feature cannot be disabled by settings now" - chrome_policy { - NTPContentSuggestionsEnabled { - policy_options {mode: MANDATORY} - NTPContentSuggestionsEnabled: false - } - } - })"); - auto resource_request = std::make_unique<network::ResourceRequest>(); - resource_request->url = url_; - resource_request->load_flags = - net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES; - resource_request->method = "POST"; - if (!auth_header_.empty()) { - resource_request->headers.SetHeader(HttpRequestHeaders::kAuthorization, - auth_header_); - } - // Add X-Client-Data header with experiment IDs from field trials. - // TODO: We should call AppendVariationHeaders with explicit - // variations::SignedIn::kNo If the auth_header_ is empty - variations::AppendVariationsHeaderUnknownSignedIn( - url_, variations::InIncognito::kNo, resource_request.get()); - - // Log the request for debugging network issues. - DVLOG(1) << "Building a subscription request to " << url_ << ":\n" - << resource_request->headers.ToString() << "\n" - << body; - - // TODO(https://crbug.com/808498): Re-add data use measurement once - // SimpleURLLoader supports it. - // ID=data_use_measurement::DataUseUserData::NTP_SNIPPETS_SUGGESTIONS - std::unique_ptr<network::SimpleURLLoader> loader = - network::SimpleURLLoader::Create(std::move(resource_request), - traffic_annotation); - loader->AttachStringForUpload(body, "application/json; charset=UTF-8"); - loader->SetRetryOptions(1, network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE); - - return loader; -} - -} // namespace internal - -} // namespace ntp_snippets
diff --git a/components/ntp_snippets/breaking_news/subscription_json_request.h b/components/ntp_snippets/breaking_news/subscription_json_request.h deleted file mode 100644 index 217b512..0000000 --- a/components/ntp_snippets/breaking_news/subscription_json_request.h +++ /dev/null
@@ -1,110 +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_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_JSON_REQUEST_H_ -#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_JSON_REQUEST_H_ - -#include <memory> -#include <string> -#include <utility> - -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "base/optional.h" -#include "base/time/time.h" -#include "components/ntp_snippets/status.h" -#include "net/http/http_request_headers.h" -#include "url/gurl.h" - -namespace network { -class SharedURLLoaderFactory; -class SimpleURLLoader; -} // namespace network - -namespace ntp_snippets { - -namespace internal { - -// A single request to subscribe for breaking news via GCM. The Request has to -// stay alive in order to be successfully completed. -class SubscriptionJsonRequest { - public: - // A client can expect a message in the status only, if there was any error - // during the subscription. In successful cases, it will be an empty string. - using CompletedCallback = base::OnceCallback<void(const Status& status)>; - - // Builds non-authenticated and authenticated SubscriptionJsonRequests. - class Builder { - public: - Builder(); - Builder(Builder&&); - ~Builder(); - - // Builds a Request object that contains all data to fetch new snippets. - std::unique_ptr<SubscriptionJsonRequest> Build() const; - - Builder& SetToken(const std::string& token); - Builder& SetUrl(const GURL& url); - Builder& SetUrlLoaderFactory( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); - Builder& SetAuthenticationHeader(const std::string& auth_header); - - // The application language represented as an IETF language tag, defined in - // BCP 47, e.g. "de", "de-AT". - Builder& SetLocale(const std::string& locale); - - // The device country represented as lowercase ISO 3166-1 alpha-2, e.g. - // "us", "in". - // TODO(vitaliii): Use CLDR. Currently this is not possible, because the - // variations permanent country is not provided in CLDR. - Builder& SetCountryCode(const std::string& country_code); - - private: - std::string BuildBody() const; - std::unique_ptr<network::SimpleURLLoader> BuildURLLoader( - const std::string& body) const; - - // GCM subscription token obtained from GCM driver (instanceID::getToken()). - std::string token_; - - std::string locale_; - std::string country_code_; - - GURL url_; - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - std::string auth_header_; - - DISALLOW_COPY_AND_ASSIGN(Builder); - }; - - ~SubscriptionJsonRequest(); - - // Starts an async request. The callback is invoked when the request succeeds - // or fails. The callback is not called if the request is destroyed. - void Start(CompletedCallback callback); - - private: - friend class Builder; - SubscriptionJsonRequest(); - void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body); - - // The loader for subscribing. - std::unique_ptr<network::SimpleURLLoader> simple_url_loader_; - - // The loader factory for subscribing. - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - - // The callback to notify when SimpleURLLoader finished and results are - // available. When the request is finished/aborted/destroyed, it's called in - // the dtor! - CompletedCallback request_completed_callback_; - - DISALLOW_COPY_AND_ASSIGN(SubscriptionJsonRequest); -}; - -} // namespace internal - -} // namespace ntp_snippets - -#endif // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_JSON_REQUEST_H_
diff --git a/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc b/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc deleted file mode 100644 index 2f09e91..0000000 --- a/components/ntp_snippets/breaking_news/subscription_json_request_unittest.cc +++ /dev/null
@@ -1,192 +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/ntp_snippets/breaking_news/subscription_json_request.h" - -#include "base/json/json_reader.h" -#include "base/run_loop.h" -#include "base/test/bind_test_util.h" -#include "base/test/gtest_util.h" -#include "base/test/mock_callback.h" -#include "base/test/scoped_task_environment.h" -#include "base/values.h" -#include "net/http/http_util.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" -#include "services/network/test/test_url_loader_factory.h" -#include "services/network/test/test_utils.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace ntp_snippets { - -namespace internal { - -namespace { - -using testing::_; -using testing::SaveArg; - -// TODO(mamir): Create a test_helper.cc file instead of duplicating all this -// code. -MATCHER_P(EqualsJSON, json, "equals JSON") { - std::unique_ptr<base::Value> expected = - base::JSONReader::ReadDeprecated(json); - if (!expected) { - *result_listener << "INTERNAL ERROR: couldn't parse expected JSON"; - return false; - } - - std::string err_msg; - int err_line, err_col; - std::unique_ptr<base::Value> actual = - base::JSONReader::ReadAndReturnErrorDeprecated( - arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col); - if (!actual) { - *result_listener << "input:" << err_line << ":" << err_col << ": " - << "parse error: " << err_msg; - return false; - } - return *expected == *actual; -} - -} // namespace - -class SubscriptionJsonRequestTest : public testing::Test { - public: - SubscriptionJsonRequestTest() - : test_shared_loader_factory_( - base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( - &test_url_loader_factory_)) {} - - protected: - scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory() { - return test_shared_loader_factory_; - } - - network::TestURLLoaderFactory* GetURLLoaderFactory() { - return &test_url_loader_factory_; - } - - void RespondWithData(const GURL& url, const std::string& data) { - GetURLLoaderFactory()->AddResponse(url.spec(), data); - base::RunLoop().RunUntilIdle(); - } - - void RespondWithError(const GURL& url, int error_code) { - network::URLLoaderCompletionStatus status(error_code); - test_url_loader_factory_.AddResponse(url, network::ResourceResponseHead(), - "", status); - base::RunLoop().RunUntilIdle(); - } - - private: - base::test::ScopedTaskEnvironment scoped_task_environment_; - network::TestURLLoaderFactory test_url_loader_factory_; - scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; - - DISALLOW_COPY_AND_ASSIGN(SubscriptionJsonRequestTest); -}; - -TEST_F(SubscriptionJsonRequestTest, BuildRequest) { - std::string token = "1234567890"; - GURL url("http://valid-url.test"); - - base::MockCallback<SubscriptionJsonRequest::CompletedCallback> callback; - - std::string expected_body = R"( - { - "token": "1234567890", - "locale": "en-US", - "country_code": "us" - } - )"; - std::string header; - std::string actual_body; - GetURLLoaderFactory()->SetInterceptor( - base::BindLambdaForTesting([&](const network::ResourceRequest& request) { - EXPECT_FALSE(request.headers.GetHeader("Authorization", &header)); - EXPECT_TRUE(request.headers.GetHeader( - net::HttpRequestHeaders::kContentType, &header)); - EXPECT_EQ(header, "application/json; charset=UTF-8"); - actual_body = network::GetUploadData(request); - EXPECT_THAT(actual_body, EqualsJSON(expected_body)); - })); - - SubscriptionJsonRequest::Builder builder; - std::unique_ptr<SubscriptionJsonRequest> request = - builder.SetToken(token) - .SetUrl(url) - .SetUrlLoaderFactory(GetSharedURLLoaderFactory()) - .SetLocale("en-US") - .SetCountryCode("us") - .Build(); - request->Start(callback.Get()); -} - -TEST_F(SubscriptionJsonRequestTest, ShouldNotInvokeCallbackWhenCancelled) { - std::string token = "1234567890"; - GURL url("http://valid-url.test"); - - base::MockCallback<SubscriptionJsonRequest::CompletedCallback> callback; - EXPECT_CALL(callback, Run(_)).Times(0); - - SubscriptionJsonRequest::Builder builder; - std::unique_ptr<SubscriptionJsonRequest> request = - builder.SetToken(token) - .SetUrl(url) - .SetUrlLoaderFactory(GetSharedURLLoaderFactory()) - .Build(); - GetURLLoaderFactory()->AddResponse(url.spec(), "{}"); - request->Start(callback.Get()); - - // Destroy the request before getting any response. - request.reset(); -} - -TEST_F(SubscriptionJsonRequestTest, SubscribeWithoutErrors) { - std::string token = "1234567890"; - GURL url("http://valid-url.test"); - - base::MockCallback<SubscriptionJsonRequest::CompletedCallback> callback; - ntp_snippets::Status status(StatusCode::PERMANENT_ERROR, "initial"); - EXPECT_CALL(callback, Run(_)).WillOnce(SaveArg<0>(&status)); - - SubscriptionJsonRequest::Builder builder; - std::unique_ptr<SubscriptionJsonRequest> request = - builder.SetToken(token) - .SetUrl(url) - .SetUrlLoaderFactory(GetSharedURLLoaderFactory()) - .Build(); - request->Start(callback.Get()); - - RespondWithData(url, "{}"); - - EXPECT_EQ(status.code, StatusCode::SUCCESS); -} - -TEST_F(SubscriptionJsonRequestTest, SubscribeWithErrors) { - std::string token = "1234567890"; - GURL url("http://valid-url.test"); - - base::MockCallback<SubscriptionJsonRequest::CompletedCallback> callback; - ntp_snippets::Status status(StatusCode::SUCCESS, "initial"); - EXPECT_CALL(callback, Run(_)).WillOnce(SaveArg<0>(&status)); - - SubscriptionJsonRequest::Builder builder; - std::unique_ptr<SubscriptionJsonRequest> request = - builder.SetToken(token) - .SetUrl(url) - .SetUrlLoaderFactory(GetSharedURLLoaderFactory()) - .Build(); - request->Start(callback.Get()); - - RespondWithError(url, net::ERR_TIMED_OUT); - - EXPECT_EQ(status.code, StatusCode::TEMPORARY_ERROR); -} - -} // namespace internal - -} // namespace ntp_snippets
diff --git a/components/ntp_snippets/breaking_news/subscription_manager.cc b/components/ntp_snippets/breaking_news/subscription_manager.cc deleted file mode 100644 index 1dbd535..0000000 --- a/components/ntp_snippets/breaking_news/subscription_manager.cc +++ /dev/null
@@ -1,65 +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/ntp_snippets/breaking_news/subscription_manager.h" - -#include "base/metrics/field_trial_params.h" -#include "components/ntp_snippets/features.h" -#include "components/ntp_snippets/ntp_snippets_constants.h" - -namespace ntp_snippets { - -namespace { - -// Variation parameter for chrome-push-subscription backend. -const char kPushSubscriptionBackendParam[] = "push_subscription_backend"; - -// Variation parameter for chrome-push-unsubscription backend. -const char kPushUnsubscriptionBackendParam[] = "push_unsubscription_backend"; - -} // namespace - -GURL GetPushUpdatesSubscriptionEndpoint(version_info::Channel channel) { - std::string endpoint = base::GetFieldTrialParamValueByFeature( - kBreakingNewsPushFeature, kPushSubscriptionBackendParam); - if (!endpoint.empty()) { - return GURL{endpoint}; - } - - switch (channel) { - case version_info::Channel::STABLE: - case version_info::Channel::BETA: - return GURL{kPushUpdatesSubscriptionServer}; - - case version_info::Channel::DEV: - case version_info::Channel::CANARY: - case version_info::Channel::UNKNOWN: - return GURL{kPushUpdatesSubscriptionStagingServer}; - } - NOTREACHED(); - return GURL{kPushUpdatesSubscriptionStagingServer}; -} - -GURL GetPushUpdatesUnsubscriptionEndpoint(version_info::Channel channel) { - std::string endpoint = base::GetFieldTrialParamValueByFeature( - kBreakingNewsPushFeature, kPushUnsubscriptionBackendParam); - if (!endpoint.empty()) { - return GURL{endpoint}; - } - - switch (channel) { - case version_info::Channel::STABLE: - case version_info::Channel::BETA: - return GURL{kPushUpdatesUnsubscriptionServer}; - - case version_info::Channel::DEV: - case version_info::Channel::CANARY: - case version_info::Channel::UNKNOWN: - return GURL{kPushUpdatesUnsubscriptionStagingServer}; - } - NOTREACHED(); - return GURL{kPushUpdatesUnsubscriptionStagingServer}; -} - -} // namespace ntp_snippets
diff --git a/components/ntp_snippets/breaking_news/subscription_manager.h b/components/ntp_snippets/breaking_news/subscription_manager.h deleted file mode 100644 index fc2343e..0000000 --- a/components/ntp_snippets/breaking_news/subscription_manager.h +++ /dev/null
@@ -1,42 +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_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_H_ -#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_H_ - -#include <string> - -#include "components/version_info/version_info.h" -#include "url/gurl.h" - -namespace ntp_snippets { - -// Returns the appropriate API endpoint for subscribing for push updates, in -// consideration of the channel and field trial parameters. -GURL GetPushUpdatesSubscriptionEndpoint(version_info::Channel channel); - -// Returns the appropriate API endpoint for unsubscribing for push updates, in -// consideration of the channel and field trial parameters. -GURL GetPushUpdatesUnsubscriptionEndpoint(version_info::Channel channel); - -// Handles subscription to content suggestions server for push updates (e.g. via -// GCM). -class SubscriptionManager { - public: - virtual ~SubscriptionManager() = default; - - virtual void Subscribe(const std::string& token) = 0; - virtual void Unsubscribe() = 0; - virtual bool IsSubscribed() = 0; - - virtual void Resubscribe(const std::string& new_token) = 0; - - // Checks if some data that has been used when subscribing has changed. For - // example, the user has signed in. - virtual bool NeedsToResubscribe() = 0; -}; - -} // namespace ntp_snippets - -#endif // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_H_
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl.cc b/components/ntp_snippets/breaking_news/subscription_manager_impl.cc deleted file mode 100644 index 317fe972..0000000 --- a/components/ntp_snippets/breaking_news/subscription_manager_impl.cc +++ /dev/null
@@ -1,269 +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/ntp_snippets/breaking_news/subscription_manager_impl.h" - -#include "base/bind.h" -#include "base/metrics/field_trial_params.h" -#include "base/strings/stringprintf.h" -#include "components/ntp_snippets/breaking_news/breaking_news_metrics.h" -#include "components/ntp_snippets/breaking_news/subscription_json_request.h" -#include "components/ntp_snippets/features.h" -#include "components/ntp_snippets/ntp_snippets_constants.h" -#include "components/ntp_snippets/pref_names.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service.h" -#include "components/variations/service/variations_service.h" -#include "net/base/url_util.h" -#include "services/identity/public/cpp/primary_account_access_token_fetcher.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" - -namespace ntp_snippets { - -using internal::SubscriptionJsonRequest; - -namespace { - -const char kApiKeyParamName[] = "key"; -const char kAuthorizationRequestHeaderFormat[] = "Bearer %s"; - -} // namespace - -SubscriptionManagerImpl::SubscriptionManagerImpl( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - PrefService* pref_service, - variations::VariationsService* variations_service, - identity::IdentityManager* identity_manager, - const std::string& locale, - const std::string& api_key, - const GURL& subscribe_url, - const GURL& unsubscribe_url) - : url_loader_factory_(std::move(url_loader_factory)), - pref_service_(pref_service), - variations_service_(variations_service), - identity_manager_(identity_manager), - locale_(locale), - api_key_(api_key), - subscribe_url_(subscribe_url), - unsubscribe_url_(unsubscribe_url) { - identity_manager_->AddObserver(this); -} - -SubscriptionManagerImpl::~SubscriptionManagerImpl() { - identity_manager_->RemoveObserver(this); -} - -void SubscriptionManagerImpl::Subscribe(const std::string& subscription_token) { - // If there is a request in flight, cancel it. - if (request_) { - request_ = nullptr; - } - if (identity_manager_->HasPrimaryAccount()) { - StartAccessTokenRequest(subscription_token); - } else { - SubscribeInternal(subscription_token, /*access_token=*/std::string()); - } -} - -void SubscriptionManagerImpl::SubscribeInternal( - const std::string& subscription_token, - const std::string& access_token) { - SubscriptionJsonRequest::Builder builder; - builder.SetToken(subscription_token).SetUrlLoaderFactory(url_loader_factory_); - - if (!access_token.empty()) { - builder.SetUrl(subscribe_url_); - builder.SetAuthenticationHeader(base::StringPrintf( - kAuthorizationRequestHeaderFormat, access_token.c_str())); - } else { - // When not providing OAuth token, we need to pass the Google API key. - builder.SetUrl( - net::AppendQueryParameter(subscribe_url_, kApiKeyParamName, api_key_)); - } - - builder.SetLocale(locale_); - builder.SetCountryCode(variations_service_ - ? variations_service_->GetStoredPermanentCountry() - : ""); - - request_ = builder.Build(); - request_->Start(base::BindOnce(&SubscriptionManagerImpl::DidSubscribe, - base::Unretained(this), subscription_token, - /*is_authenticated=*/!access_token.empty())); -} - -void SubscriptionManagerImpl::StartAccessTokenRequest( - const std::string& subscription_token) { - // If there is already an ongoing token request, destroy it. - if (access_token_fetcher_) { - access_token_fetcher_ = nullptr; - } - - identity::ScopeSet scopes = {kContentSuggestionsApiScope}; - access_token_fetcher_ = std::make_unique< - identity::PrimaryAccountAccessTokenFetcher>( - "ntp_snippets", identity_manager_, scopes, - base::BindOnce(&SubscriptionManagerImpl::AccessTokenFetchFinished, - base::Unretained(this), subscription_token), - identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable); -} - -void SubscriptionManagerImpl::AccessTokenFetchFinished( - const std::string& subscription_token, - GoogleServiceAuthError error, - identity::AccessTokenInfo access_token_info) { - access_token_fetcher_.reset(); - - if (error.state() != GoogleServiceAuthError::NONE) { - // In case of error, we will retry on next Chrome restart. - return; - } - DCHECK(!access_token_info.token.empty()); - SubscribeInternal(subscription_token, access_token_info.token); -} - -void SubscriptionManagerImpl::DidSubscribe( - const std::string& subscription_token, - bool is_authenticated, - const Status& status) { - metrics::OnSubscriptionRequestCompleted(status); - - // Delete the request only after we leave this method (which is called from - // the request itself). - std::unique_ptr<internal::SubscriptionJsonRequest> request_deleter( - std::move(request_)); - - switch (status.code) { - case StatusCode::SUCCESS: - // In case of successful subscription, store the same data used for - // subscription in order to be able to resubscribe in case of data - // change. - // TODO(mamir): Store region and language. - pref_service_->SetString(prefs::kBreakingNewsSubscriptionDataToken, - subscription_token); - pref_service_->SetBoolean( - prefs::kBreakingNewsSubscriptionDataIsAuthenticated, - is_authenticated); - break; - default: - // TODO(mamir): Handle failure. - break; - } -} - -void SubscriptionManagerImpl::Unsubscribe() { - std::string token = - pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken); - ResubscribeInternal(/*old_token=*/token, /*new_token=*/std::string()); -} - -void SubscriptionManagerImpl::ResubscribeInternal( - const std::string& old_token, - const std::string& new_token) { - // If there is an request in flight, cancel it. - if (request_) { - request_ = nullptr; - } - - SubscriptionJsonRequest::Builder builder; - builder.SetToken(old_token).SetUrlLoaderFactory(url_loader_factory_); - builder.SetUrl( - net::AppendQueryParameter(unsubscribe_url_, kApiKeyParamName, api_key_)); - - request_ = builder.Build(); - request_->Start(base::BindOnce(&SubscriptionManagerImpl::DidUnsubscribe, - base::Unretained(this), new_token)); -} - -bool SubscriptionManagerImpl::IsSubscribed() { - std::string subscription_token = - pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken); - return !subscription_token.empty(); -} - -bool SubscriptionManagerImpl::NeedsToResubscribe() { - // Check if authentication state changed after subscription. - bool is_auth_subscribe = pref_service_->GetBoolean( - prefs::kBreakingNewsSubscriptionDataIsAuthenticated); - bool is_authenticated = identity_manager_->HasPrimaryAccount(); - return is_auth_subscribe != is_authenticated; -} - -void SubscriptionManagerImpl::Resubscribe(const std::string& new_token) { - std::string old_token = - pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken); - if (old_token == new_token) { - // If the token didn't change, subscribe directly. The server handles the - // unsubscription if previous subscriptions exists. - Subscribe(old_token); - } else { - ResubscribeInternal(old_token, new_token); - } -} - -void SubscriptionManagerImpl::DidUnsubscribe(const std::string& new_token, - const Status& status) { - metrics::OnUnsubscriptionRequestCompleted(status); - - // Delete the request only after we leave this method (which is called from - // the request itself). - std::unique_ptr<internal::SubscriptionJsonRequest> request_deleter( - std::move(request_)); - - switch (status.code) { - case StatusCode::SUCCESS: - // In case of successful unsubscription, clear the previously stored data. - // TODO(mamir): Clear stored region and language. - pref_service_->ClearPref(prefs::kBreakingNewsSubscriptionDataToken); - pref_service_->ClearPref( - prefs::kBreakingNewsSubscriptionDataIsAuthenticated); - if (!new_token.empty()) { - Subscribe(new_token); - } - break; - default: - // TODO(mamir): Handle failure. - break; - } -} - -void SubscriptionManagerImpl::OnPrimaryAccountSet( - const CoreAccountInfo& account_info) { - SigninStatusChanged(); -} - -void SubscriptionManagerImpl::OnPrimaryAccountCleared( - const CoreAccountInfo& account_info) { - SigninStatusChanged(); -} - -void SubscriptionManagerImpl::SigninStatusChanged() { - // If subscribed already, resubscribe. - if (IsSubscribed()) { - if (request_) { - request_ = nullptr; - } - std::string token = - pref_service_->GetString(prefs::kBreakingNewsSubscriptionDataToken); - Subscribe(token); - } -} - -// static -void SubscriptionManagerImpl::RegisterProfilePrefs( - PrefRegistrySimple* registry) { - registry->RegisterStringPref(prefs::kBreakingNewsSubscriptionDataToken, - std::string()); - registry->RegisterBooleanPref( - prefs::kBreakingNewsSubscriptionDataIsAuthenticated, false); -} - -// TODO(vitaliii): Add a test to ensure that this clears everything. -// static -void SubscriptionManagerImpl::ClearProfilePrefs(PrefService* pref_service) { - pref_service->ClearPref(prefs::kBreakingNewsSubscriptionDataToken); - pref_service->ClearPref(prefs::kBreakingNewsSubscriptionDataIsAuthenticated); -} - -} // namespace ntp_snippets
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl.h b/components/ntp_snippets/breaking_news/subscription_manager_impl.h deleted file mode 100644 index 5090c464..0000000 --- a/components/ntp_snippets/breaking_news/subscription_manager_impl.h +++ /dev/null
@@ -1,123 +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_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_IMPL_H_ -#define COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_IMPL_H_ - -#include <memory> -#include <string> - -#include "base/memory/ref_counted.h" -#include "components/ntp_snippets/breaking_news/subscription_json_request.h" -#include "components/ntp_snippets/breaking_news/subscription_manager.h" -#include "services/identity/public/cpp/access_token_info.h" -#include "services/identity/public/cpp/identity_manager.h" -#include "url/gurl.h" - -class PrefRegistrySimple; -class PrefService; - -namespace identity { -class PrimaryAccountAccessTokenFetcher; -} - -namespace network { -class SharedURLLoaderFactory; -} - -namespace variations { -class VariationsService; -} - -namespace ntp_snippets { - -// Class that wraps around the functionality of SubscriptionJsonRequest. It uses -// the SubscriptionJsonRequest to send subscription and unsubscription requests -// to the content suggestions server and does the bookkeeping for the data used -// for subscription. Bookkeeping is required to detect any change (e.g. the -// token render invalid), and resubscribe accordingly. -class SubscriptionManagerImpl : public SubscriptionManager, - public identity::IdentityManager::Observer { - public: - SubscriptionManagerImpl( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - PrefService* pref_service, - variations::VariationsService* variations_service, - identity::IdentityManager* identity_manager, - const std::string& locale, - const std::string& api_key, - const GURL& subscribe_url, - const GURL& unsubscribe_url); - - ~SubscriptionManagerImpl() override; - - // SubscriptionManager implementation. - void Subscribe(const std::string& token) override; - void Unsubscribe() override; - bool IsSubscribed() override; - - void Resubscribe(const std::string& new_token) override; - - // Checks if some data that has been used when subscribing has changed. For - // example, the user has signed in. - bool NeedsToResubscribe() override; - - static void RegisterProfilePrefs(PrefRegistrySimple* registry); - static void ClearProfilePrefs(PrefService* pref_service); - - private: - // identity:IdentityManager::Observer implementation. - void OnPrimaryAccountSet(const CoreAccountInfo& account_info) override; - void OnPrimaryAccountCleared(const CoreAccountInfo& account_info) override; - - void SigninStatusChanged(); - - void DidSubscribe(const std::string& subscription_token, - bool is_authenticated, - const Status& status); - void DidUnsubscribe(const std::string& new_token, const Status& status); - void SubscribeInternal(const std::string& subscription_token, - const std::string& access_token); - - // If |new_token| is empty, this will just unsubscribe. If |new_token| is - // non-empty, a subscription request with the |new_token| will be started upon - // successful unsubscription. - void ResubscribeInternal(const std::string& old_token, - const std::string& new_token); - - // |subscription_token| is the token when subscribing after obtaining the - // access token. - void StartAccessTokenRequest(const std::string& subscription_token); - void AccessTokenFetchFinished(const std::string& subscription_token, - GoogleServiceAuthError error, - identity::AccessTokenInfo access_token_info); - - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - - std::unique_ptr<internal::SubscriptionJsonRequest> request_; - std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> - access_token_fetcher_; - - PrefService* pref_service_; - - variations::VariationsService* const variations_service_; - - // Authentication for signed-in users. - identity::IdentityManager* identity_manager_; - - const std::string locale_; - - // API key to use for non-authenticated requests. - const std::string api_key_; - - // API endpoint for subscribing and unsubscribing. - const GURL subscribe_url_; - const GURL unsubscribe_url_; - - DISALLOW_COPY_AND_ASSIGN(SubscriptionManagerImpl); -}; - -} // namespace ntp_snippets - -#endif // COMPONENTS_NTP_SNIPPETS_BREAKING_NEWS_SUBSCRIPTION_MANAGER_IMPL_H_
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc b/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc deleted file mode 100644 index a5633d1..0000000 --- a/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc +++ /dev/null
@@ -1,327 +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/ntp_snippets/breaking_news/subscription_manager_impl.h" - -#include "base/bind.h" -#include "base/run_loop.h" -#include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_task_environment.h" -#include "build/build_config.h" -#include "components/ntp_snippets/pref_names.h" -#include "components/ntp_snippets/remote/test_utils.h" -#include "components/prefs/testing_pref_service.h" -#include "net/base/net_errors.h" -#include "services/identity/public/cpp/identity_test_environment.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" -#include "services/network/test/test_url_loader_factory.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::ElementsAre; - -namespace ntp_snippets { - -#if !defined(OS_CHROMEOS) -const char kTestEmail[] = "test@email.com"; -#endif - -const char kAPIKey[] = "fakeAPIkey"; -const char kSubscriptionUrl[] = "http://valid-url.test/subscribe"; -const char kSubscriptionUrlSignedIn[] = "http://valid-url.test/subscribe"; - -const char kSubscriptionUrlSignedOut[] = - "http://valid-url.test/subscribe?key=fakeAPIkey"; -const char kUnsubscriptionUrl[] = "http://valid-url.test/unsubscribe"; -const char kUnsubscriptionUrlSignedIn[] = "http://valid-url.test/unsubscribe"; -const char kUnsubscriptionUrlSignedOut[] = - "http://valid-url.test/unsubscribe?key=fakeAPIkey"; - -class SubscriptionManagerImplTest : public testing::Test { - public: - SubscriptionManagerImplTest() - : test_shared_loader_factory_( - base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( - &test_url_loader_factory_)) {} - - void SetUp() override { - SubscriptionManagerImpl::RegisterProfilePrefs( - utils_.pref_service()->registry()); - } - - scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory() { - return test_shared_loader_factory_; - } - - PrefService* GetPrefService() { return utils_.pref_service(); } - - identity::IdentityTestEnvironment* GetIdentityTestEnv() { - return &identity_test_env_; - } - - std::unique_ptr<SubscriptionManagerImpl> BuildSubscriptionManager() { - return std::make_unique<SubscriptionManagerImpl>( - GetSharedURLLoaderFactory(), GetPrefService(), - /*variations_service=*/nullptr, - GetIdentityTestEnv()->identity_manager(), - /*locale=*/"", kAPIKey, GURL(kSubscriptionUrl), - GURL(kUnsubscriptionUrl)); - } - - void RespondToSubscriptionRequestSuccessfully(bool is_signed_in) { - if (is_signed_in) { - RespondSuccessfully(GURL(kSubscriptionUrlSignedIn)); - } else { - RespondSuccessfully(GURL(kSubscriptionUrlSignedOut)); - } - } - - void RespondToUnsubscriptionRequestSuccessfully(bool is_signed_in) { - if (is_signed_in) { - RespondSuccessfully(GURL(kUnsubscriptionUrlSignedIn)); - } else { - RespondSuccessfully(GURL(kUnsubscriptionUrlSignedOut)); - } - } - - void RespondToSubscriptionWithError(bool is_signed_in, int error_code) { - if (is_signed_in) { - RespondWithError(GURL(kSubscriptionUrlSignedIn), error_code); - } else { - RespondWithError(GURL(kSubscriptionUrlSignedOut), error_code); - } - } - - void RespondToUnsubscriptionWithError(bool is_signed_in, int error_code) { - if (is_signed_in) { - RespondWithError(GURL(kUnsubscriptionUrlSignedIn), error_code); - } else { - RespondWithError(GURL(kUnsubscriptionUrlSignedOut), error_code); - } - } - -#if !defined(OS_CHROMEOS) - void SignIn() { - GetIdentityTestEnv()->MakePrimaryAccountAvailable(kTestEmail); - } - - void SignOut() { GetIdentityTestEnv()->ClearPrimaryAccount(); } -#endif // !defined(OS_CHROMEOS) - - private: - void RespondSuccessfully(const GURL& url) { - test_url_loader_factory_.AddResponse(url.spec(), ""); - base::RunLoop().RunUntilIdle(); - } - - void RespondWithError(const GURL& url, int error_code) { - network::URLLoaderCompletionStatus status(error_code); - test_url_loader_factory_.AddResponse(url, network::ResourceResponseHead(), - "", status); - base::RunLoop().RunUntilIdle(); - } - - base::test::ScopedTaskEnvironment scoped_task_environment_; - test::RemoteSuggestionsTestUtils utils_; - identity::IdentityTestEnvironment identity_test_env_; - network::TestURLLoaderFactory test_url_loader_factory_; - scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; -}; - -TEST_F(SubscriptionManagerImplTest, SubscribeSuccessfully) { - std::string subscription_token = "1234567890"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - manager->Subscribe(subscription_token); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false); - ASSERT_TRUE(manager->IsSubscribed()); - EXPECT_EQ(subscription_token, GetPrefService()->GetString( - prefs::kBreakingNewsSubscriptionDataToken)); - EXPECT_FALSE(GetPrefService()->GetBoolean( - prefs::kBreakingNewsSubscriptionDataIsAuthenticated)); -} - -// This test is relevant only on non-ChromeOS platforms, as the flow being -// tested here is not possible on ChromeOS. -#if !defined(OS_CHROMEOS) -TEST_F(SubscriptionManagerImplTest, - ShouldSubscribeWithAuthenticationWhenAuthenticated) { - // Sign in. - SignIn(); - - // Create manager and subscribe. - std::string subscription_token = "1234567890"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - manager->Subscribe(subscription_token); - - // Wait for the access token request and issue the access token. - GetIdentityTestEnv()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - "access_token", base::Time::Max()); - - ASSERT_FALSE(manager->IsSubscribed()); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/true); - ASSERT_TRUE(manager->IsSubscribed()); - - // Check that we are now subscribed correctly with authentication. - EXPECT_EQ(subscription_token, GetPrefService()->GetString( - prefs::kBreakingNewsSubscriptionDataToken)); - EXPECT_TRUE(GetPrefService()->GetBoolean( - prefs::kBreakingNewsSubscriptionDataIsAuthenticated)); -} -#endif - -TEST_F(SubscriptionManagerImplTest, ShouldNotSubscribeIfError) { - std::string subscription_token = "1234567890"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - - manager->Subscribe(subscription_token); - RespondToSubscriptionWithError(/*is_signed_in=*/false, net::ERR_TIMED_OUT); - EXPECT_FALSE(manager->IsSubscribed()); -} - -TEST_F(SubscriptionManagerImplTest, UnsubscribeSuccessfully) { - std::string subscription_token = "1234567890"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - manager->Subscribe(subscription_token); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false); - ASSERT_TRUE(manager->IsSubscribed()); - manager->Unsubscribe(); - RespondToUnsubscriptionRequestSuccessfully(/*is_signed_in=*/false); - EXPECT_FALSE(manager->IsSubscribed()); - EXPECT_FALSE( - GetPrefService()->HasPrefPath(prefs::kBreakingNewsSubscriptionDataToken)); -} - -TEST_F(SubscriptionManagerImplTest, - ShouldRemainSubscribedIfErrorDuringUnsubscribe) { - std::string subscription_token = "1234567890"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - manager->Subscribe(subscription_token); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false); - ASSERT_TRUE(manager->IsSubscribed()); - manager->Unsubscribe(); - RespondToUnsubscriptionWithError(/*is_signed_in=*/false, net::ERR_TIMED_OUT); - ASSERT_TRUE(manager->IsSubscribed()); - EXPECT_EQ(subscription_token, GetPrefService()->GetString( - prefs::kBreakingNewsSubscriptionDataToken)); -} - -// This test is relevant only on non-ChromeOS platforms, as the flow being -// tested here is not possible on ChromeOS. -#if !defined(OS_CHROMEOS) -TEST_F(SubscriptionManagerImplTest, - ShouldResubscribeIfSignInAfterSubscription) { - // Create manager and subscribe. - std::string subscription_token = "1234567890"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - manager->Subscribe(subscription_token); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false); - ASSERT_FALSE(manager->NeedsToResubscribe()); - - // Sign in. This should trigger a resubscribe. - SignIn(); - ASSERT_TRUE(manager->NeedsToResubscribe()); - - // Wait for the access token request that should occur and grant the access - // token. - GetIdentityTestEnv()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - "access_token", base::Time::Max()); - - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/true); - - // Check that we are now subscribed with authentication. - EXPECT_TRUE(GetPrefService()->GetBoolean( - prefs::kBreakingNewsSubscriptionDataIsAuthenticated)); -} -#endif - -// This test is relevant only on non-ChromeOS platforms, as the flow being -// tested here is not possible on ChromeOS. -#if !defined(OS_CHROMEOS) -TEST_F(SubscriptionManagerImplTest, - ShouldResubscribeIfSignOutAfterSubscription) { - // Signin and subscribe. - SignIn(); - std::string subscription_token = "1234567890"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - manager->Subscribe(subscription_token); - - GetIdentityTestEnv()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - "access_token", base::Time::Max()); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/true); - - // Sign out; this should trigger a resubscribe. - SignOut(); - EXPECT_TRUE(manager->NeedsToResubscribe()); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false); - - // Check that we are now subscribed without authentication. - EXPECT_FALSE(GetPrefService()->GetBoolean( - prefs::kBreakingNewsSubscriptionDataIsAuthenticated)); -} -#endif - -TEST_F(SubscriptionManagerImplTest, - ShouldUpdateTokenInPrefWhenResubscribeWithChangeInToken) { - // Create manager and subscribe. - std::string old_subscription_token = "1234567890"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - manager->Subscribe(old_subscription_token); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false); - EXPECT_EQ( - old_subscription_token, - GetPrefService()->GetString(prefs::kBreakingNewsSubscriptionDataToken)); - - // Resubscribe with a new token. - std::string new_subscription_token = "0987654321"; - manager->Resubscribe(new_subscription_token); - // Resubscribe with a new token should issue an unsubscribe request before - // subscribing. - RespondToUnsubscriptionRequestSuccessfully(/*is_signed_in=*/false); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false); - - // Check we are now subscribed with the new token. - EXPECT_EQ( - new_subscription_token, - GetPrefService()->GetString(prefs::kBreakingNewsSubscriptionDataToken)); -} - -TEST_F(SubscriptionManagerImplTest, ShouldReportSubscriptionResult) { - base::HistogramTester histogram_tester; - // Create manager and subscribe. - const std::string subscription_token = "token"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - manager->Subscribe(subscription_token); - // TODO(vitaliii): Mock subscription request to avoid this low level errors. - RespondToSubscriptionWithError(/*is_signed_in=*/false, - /*error_code=*/net::ERR_INVALID_RESPONSE); - - EXPECT_THAT( - histogram_tester.GetAllSamples("NewTabPage.ContentSuggestions." - "BreakingNews.SubscriptionRequestStatus"), - ElementsAre(base::Bucket( - /*min=*/static_cast<int>(StatusCode::TEMPORARY_ERROR), - /*count=*/1))); -} - -TEST_F(SubscriptionManagerImplTest, ShouldReportUnsubscriptionResult) { - base::HistogramTester histogram_tester; - // Create manager and subscribe. - const std::string subscription_token = "token"; - std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager(); - manager->Subscribe(subscription_token); - RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/false); - manager->Unsubscribe(); - - RespondToUnsubscriptionWithError(/*is_signed_in=*/false, - /*error_code=*/net::ERR_INVALID_RESPONSE); - EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.ContentSuggestions." - "BreakingNews." - "UnsubscriptionRequestStatus"), - ElementsAre(base::Bucket( - /*min=*/static_cast<int>(StatusCode::TEMPORARY_ERROR), - /*count=*/1))); -} - -} // namespace ntp_snippets
diff --git a/components/ntp_snippets/content_suggestions_service.h b/components/ntp_snippets/content_suggestions_service.h index 7e86d13..c6870928 100644 --- a/components/ntp_snippets/content_suggestions_service.h +++ b/components/ntp_snippets/content_suggestions_service.h
@@ -20,7 +20,6 @@ #include "components/history/core/browser/history_service.h" #include "components/history/core/browser/history_service_observer.h" #include "components/keyed_service/core/keyed_service.h" -#include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h" #include "components/ntp_snippets/callbacks.h" #include "components/ntp_snippets/category.h" #include "components/ntp_snippets/category_rankers/category_ranker.h"
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc index 58ba104a..728fb24 100644 --- a/components/ntp_snippets/features.cc +++ b/components/ntp_snippets/features.cc
@@ -35,7 +35,6 @@ // Keep sorted, and keep nullptr at the end. const base::Feature* const kAllFeatures[] = { &kArticleSuggestionsFeature, - &kBreakingNewsPushFeature, &kContentSuggestionsDebugLog, &kKeepPrefetchedContentSuggestions, &kNotificationsFeature, @@ -44,9 +43,6 @@ const base::Feature kArticleSuggestionsFeature{ "NTPArticleSuggestions", base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kBreakingNewsPushFeature{"BreakingNewsPush", - base::FEATURE_DISABLED_BY_DEFAULT}; - const base::Feature kRemoteSuggestionsEmulateM58FetchingSchedule{ "RemoteSuggestionsEmulateM58FetchingSchedule", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/ntp_snippets/features.h b/components/ntp_snippets/features.h index 736023eb..8b54bf2 100644 --- a/components/ntp_snippets/features.h +++ b/components/ntp_snippets/features.h
@@ -32,9 +32,6 @@ extern const base::Feature kArticleSuggestionsFeature; -// Feature to listen for GCM push updates from the server. -extern const base::Feature kBreakingNewsPushFeature; - // Feature for simple experimental comparison and validation of changes since // M58: enabling this brings back the M58 Stable fetching schedule (which is // suitable for Holdback groups).
diff --git a/components/ntp_snippets/pref_names.cc b/components/ntp_snippets/pref_names.cc index 6e29f1b7..0489f23 100644 --- a/components/ntp_snippets/pref_names.cc +++ b/components/ntp_snippets/pref_names.cc
@@ -75,20 +75,5 @@ const char kClickBasedCategoryRankerLastDecayTime[] = "ntp_suggestions.click_based_category_ranker.last_decay_time"; -const char kBreakingNewsSubscriptionDataToken[] = - "ntp_suggestions.breaking_news_subscription_data.token"; - -const char kBreakingNewsSubscriptionDataIsAuthenticated[] = - "ntp_suggestions.breaking_news_subscription_data.is_authenticated"; - -const char kBreakingNewsGCMSubscriptionTokenCache[] = - "ntp_suggestions.breaking_news_gcm_subscription_token_cache"; - -const char kBreakingNewsGCMLastTokenValidationTime[] = - "ntp_suggestions.breaking_news_gcm_last_token_validation_time"; - -const char kBreakingNewsGCMLastForcedSubscriptionTime[] = - "ntp_suggestions.breaking_news_gcm_last_forced_subscription_time"; - } // namespace prefs } // namespace ntp_snippets
diff --git a/components/ntp_snippets/pref_names.h b/components/ntp_snippets/pref_names.h index 22c8101..4bb28940 100644 --- a/components/ntp_snippets/pref_names.h +++ b/components/ntp_snippets/pref_names.h
@@ -91,32 +91,6 @@ // The pref name for the time when last click decay has happened. extern const char kClickBasedCategoryRankerLastDecayTime[]; -// The folllowing prefs hold the data used when subscribing for content -// suggestions via GCM push updates. They are stored in pref such that in case -// of change (e.g. the token renders invalid), re-subscription is required. -// They are stored in prefs for persisting them across Chrome restarts. -/////////////////////////////////////////////////////////////////////////////// -// The pref name for the subscription token used when subscription for -// breaking news push updates. -extern const char kBreakingNewsSubscriptionDataToken[]; -// The pref name for whether the subscription is authenticated or not. -extern const char kBreakingNewsSubscriptionDataIsAuthenticated[]; -//////////////////////// End of breaking news subscription-related prefs. - -// The pref name for the subscription token received from the gcm server. As -// recommended by the GCM team, it is cached in pref for faster bookkeeping to -// see if subscription exists. This is pref holds the valid token even if -// different from the one used for subscription. When they are different, Chrome -// unsubscribes the old token from the content suggestions server, subscribe -// with the new one and update kBreakingNewsSubscriptionDataToken. -extern const char kBreakingNewsGCMSubscriptionTokenCache[]; - -// When the last GCM token validation was. -extern const char kBreakingNewsGCMLastTokenValidationTime[]; - -// When the last forced subscription to content suggestions service was. -extern const char kBreakingNewsGCMLastForcedSubscriptionTime[]; - } // namespace prefs } // namespace ntp_snippets
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc index 12ab327..ac840fe 100644 --- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc +++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
@@ -24,7 +24,6 @@ #include "base/values.h" #include "components/data_use_measurement/core/data_use_user_data.h" #include "components/image_fetcher/core/image_fetcher.h" -#include "components/ntp_snippets/breaking_news/breaking_news_listener.h" #include "components/ntp_snippets/category_rankers/category_ranker.h" #include "components/ntp_snippets/features.h" #include "components/ntp_snippets/pref_names.h" @@ -166,30 +165,6 @@ kEnablePushedSuggestionsNotificationsDefault); } -// Whether signed-in users should be subscribed for pushed suggestions. -const bool kEnableSignedInUsersSubscriptionForPushedSuggestionsDefault = true; -const char kEnableSignedInUsersSubscriptionForPushedSuggestionsParamName[] = - "enable_signed_in_users_subscription_for_pushed_suggestions"; - -bool IsSignedInUsersSubscriptionForPushedSuggestionsEnabled() { - return base::GetFieldTrialParamByFeatureAsBool( - kBreakingNewsPushFeature, - kEnableSignedInUsersSubscriptionForPushedSuggestionsParamName, - kEnableSignedInUsersSubscriptionForPushedSuggestionsDefault); -} - -// Whether signed-out users should be subscribed for pushed suggestions. -const bool kEnableSignedOutUsersSubscriptionForPushedSuggestionsDefault = false; -const char kEnableSignedOutUsersSubscriptionForPushedSuggestionsParamName[] = - "enable_signed_out_users_subscription_for_pushed_suggestions"; - -bool IsSignedOutUsersSubscriptionForPushedSuggestionsEnabled() { - return base::GetFieldTrialParamByFeatureAsBool( - kBreakingNewsPushFeature, - kEnableSignedOutUsersSubscriptionForPushedSuggestionsParamName, - kEnableSignedOutUsersSubscriptionForPushedSuggestionsDefault); -} - // Whether notification info is overriden for fetched suggestions. Note that // this param does not overwrite other switches which could disable these // notifications. @@ -368,7 +343,6 @@ std::unique_ptr<RemoteSuggestionsDatabase> database, std::unique_ptr<RemoteSuggestionsStatusService> status_service, std::unique_ptr<PrefetchedPagesTracker> prefetched_pages_tracker, - std::unique_ptr<BreakingNewsListener> breaking_news_raw_data_provider, Logger* debug_logger, std::unique_ptr<base::OneShotTimer> fetch_timeout_timer) : RemoteSuggestionsProvider(observer), @@ -387,8 +361,6 @@ clear_cached_suggestions_when_initialized_(false), clock_(base::DefaultClock::GetInstance()), prefetched_pages_tracker_(std::move(prefetched_pages_tracker)), - breaking_news_raw_data_provider_( - std::move(breaking_news_raw_data_provider)), debug_logger_(debug_logger), fetch_timeout_timer_(std::move(fetch_timeout_timer)), request_status_(FetchRequestStatus::NONE) { @@ -423,10 +395,6 @@ } RemoteSuggestionsProviderImpl::~RemoteSuggestionsProviderImpl() { - if (breaking_news_raw_data_provider_ && - breaking_news_raw_data_provider_->IsListening()) { - breaking_news_raw_data_provider_->StopListening(); - } } // static @@ -1465,46 +1433,6 @@ ntp_snippets::ImageFetchedCallback()); } -void RemoteSuggestionsProviderImpl:: - UpdatePushedSuggestionsSubscriptionDueToStatusChange( - RemoteSuggestionsStatus new_status) { - if (!breaking_news_raw_data_provider_) { - return; - } - - bool should_be_subscribed = false; - switch (new_status) { - case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN: - should_be_subscribed = - IsSignedInUsersSubscriptionForPushedSuggestionsEnabled(); - break; - - case RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT: - should_be_subscribed = - IsSignedOutUsersSubscriptionForPushedSuggestionsEnabled(); - break; - - case RemoteSuggestionsStatus::EXPLICITLY_DISABLED: - should_be_subscribed = false; - break; - } - - if (should_be_subscribed) { - if (!breaking_news_raw_data_provider_->IsListening()) { - breaking_news_raw_data_provider_->StartListening( - base::Bind(&RemoteSuggestionsProviderImpl::PrependArticleSuggestion, - base::Unretained(this)), - base::Bind(&RemoteSuggestionsProviderImpl:: - RefreshSuggestionsUponPushToRefreshRequest, - base::Unretained(this))); - } - } else { - if (breaking_news_raw_data_provider_->IsListening()) { - breaking_news_raw_data_provider_->StopListening(); - } - } -} - void RemoteSuggestionsProviderImpl::FinishInitialization() { // Note: Initializing the status service will run the callback right away with // the current state. @@ -1560,8 +1488,6 @@ EnterState(State::DISABLED); break; } - - UpdatePushedSuggestionsSubscriptionDueToStatusChange(new_status); } void RemoteSuggestionsProviderImpl::EnterState(State state) { @@ -1620,10 +1546,6 @@ ClearCachedSuggestionsImpl(); clear_cached_suggestions_when_initialized_ = false; - if (breaking_news_raw_data_provider_ && - breaking_news_raw_data_provider_->IsListening()) { - breaking_news_raw_data_provider_->StopListening(); - } UpdateAllCategoryStatus(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); break;
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h index 8a9c830e..9e2a393 100644 --- a/components/ntp_snippets/remote/remote_suggestions_provider_impl.h +++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl.h
@@ -45,7 +45,6 @@ namespace ntp_snippets { -class BreakingNewsListener; class CategoryRanker; class RemoteSuggestionsDatabase; class RemoteSuggestionsScheduler; @@ -72,7 +71,6 @@ std::unique_ptr<RemoteSuggestionsDatabase> database, std::unique_ptr<RemoteSuggestionsStatusService> status_service, std::unique_ptr<PrefetchedPagesTracker> prefetched_pages_tracker, - std::unique_ptr<BreakingNewsListener> breaking_news_raw_data_provider, Logger* debug_logger, std::unique_ptr<base::OneShotTimer> fetch_timeout_timer); @@ -143,10 +141,6 @@ // the constructor. CachedImageFetcher& GetImageFetcherForTesting() { return image_fetcher_; } - BreakingNewsListener* breaking_news_listener_for_debugging() { - return breaking_news_raw_data_provider_.get(); - } - private: friend class RemoteSuggestionsProviderImplTest; @@ -382,11 +376,6 @@ // SetProviderStatusCallback(). void NotifyStateChanged(); - // Subscribes or unsubcribes from pushed suggestions depending on the new - // status. - void UpdatePushedSuggestionsSubscriptionDueToStatusChange( - RemoteSuggestionsStatus new_status); - // Converts the given |suggestions| to content suggestions and notifies the // observer with them for category |category|. void NotifyNewSuggestions(Category category, @@ -468,10 +457,6 @@ // |nullptr| is handled gracefully and just disables the functionality. std::unique_ptr<PrefetchedPagesTracker> prefetched_pages_tracker_; - // Listens for BreakingNews updates (e.g. through GCM) and notifies the - // provider. - std::unique_ptr<BreakingNewsListener> breaking_news_raw_data_provider_; - // Additional logging, accesible through snippets-internals. Logger* debug_logger_;
diff --git a/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc index fadbb0c..7a77213 100644 --- a/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc +++ b/components/ntp_snippets/remote/remote_suggestions_provider_impl_unittest.cc
@@ -34,7 +34,6 @@ #include "components/image_fetcher/core/mock_image_fetcher.h" #include "components/image_fetcher/core/request_metadata.h" #include "components/leveldb_proto/testing/fake_db.h" -#include "components/ntp_snippets/breaking_news/breaking_news_listener.h" #include "components/ntp_snippets/category.h" #include "components/ntp_snippets/category_info.h" #include "components/ntp_snippets/category_rankers/category_ranker.h" @@ -224,37 +223,6 @@ MOCK_CONST_METHOD1(PrefetchedOfflinePageExists, bool(const GURL& url)); }; -class FakeBreakingNewsListener : public BreakingNewsListener { - public: - ~FakeBreakingNewsListener() override = default; - - // BreakingNewsListener implementation. - void StartListening( - OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback, - OnRefreshRequestedCallback on_refresh_requested_callback) override { - on_new_remote_suggestion_callback_ = on_new_remote_suggestion_callback; - on_refresh_requested_callback_ = on_refresh_requested_callback; - } - - void StopListening() override { - on_new_remote_suggestion_callback_ = OnNewRemoteSuggestionCallback(); - on_refresh_requested_callback_ = OnRefreshRequestedCallback(); - } - - bool IsListening() const override { - return !on_new_remote_suggestion_callback_.is_null(); - } - - void PushSuggestion(std::unique_ptr<RemoteSuggestion> suggestion) { - EXPECT_TRUE(IsListening()); - on_new_remote_suggestion_callback_.Run(std::move(suggestion)); - } - - private: - OnNewRemoteSuggestionCallback on_new_remote_suggestion_callback_; - OnRefreshRequestedCallback on_refresh_requested_callback_; -}; - class MockRemoteSuggestionsStatusService : public RemoteSuggestionsStatusService { public: @@ -306,17 +274,17 @@ void MakeSuggestionsProvider( bool use_mock_prefetched_pages_tracker, - bool use_fake_breaking_news_listener, + bool use_mock_remote_suggestions_status_service) { MakeSuggestionsProviderWithoutInitialization( - use_mock_prefetched_pages_tracker, use_fake_breaking_news_listener, + use_mock_prefetched_pages_tracker, use_mock_remote_suggestions_status_service); WaitForSuggestionsProviderInitialization(); } void MakeSuggestionsProviderWithoutInitialization( bool use_mock_prefetched_pages_tracker, - bool use_fake_breaking_news_listener, + bool use_mock_remote_suggestions_status_service) { auto mock_suggestions_fetcher = std::make_unique<StrictMock<MockRemoteSuggestionsFetcher>>(); @@ -330,13 +298,6 @@ } mock_prefetched_pages_tracker_ = mock_prefetched_pages_tracker.get(); - std::unique_ptr<FakeBreakingNewsListener> fake_breaking_news_listener; - if (use_fake_breaking_news_listener) { - fake_breaking_news_listener = - std::make_unique<FakeBreakingNewsListener>(); - } - fake_breaking_news_listener_ = fake_breaking_news_listener.get(); - std::unique_ptr<RemoteSuggestionsStatusService> remote_suggestions_status_service; if (use_mock_remote_suggestions_status_service) { @@ -384,8 +345,7 @@ scheduler_.get(), std::move(mock_suggestions_fetcher), std::move(image_fetcher), std::move(database), std::move(remote_suggestions_status_service), - std::move(mock_prefetched_pages_tracker), - std::move(fake_breaking_news_listener), &debug_logger_, + std::move(mock_prefetched_pages_tracker), &debug_logger_, std::move(fetch_timeout_timer)); } @@ -393,7 +353,6 @@ scheduler_ = std::make_unique<StrictMock<MockScheduler>>(); MakeSuggestionsProviderWithoutInitialization( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); } @@ -406,23 +365,23 @@ void ResetSuggestionsProvider( bool use_mock_prefetched_pages_tracker, - bool use_fake_breaking_news_listener, + bool use_mock_remote_suggestions_status_service) { provider_.reset(); observer_.reset(); MakeSuggestionsProvider(use_mock_prefetched_pages_tracker, - use_fake_breaking_news_listener, + use_mock_remote_suggestions_status_service); } void ResetSuggestionsProviderWithoutInitialization( bool use_mock_prefetched_pages_tracker, - bool use_fake_breaking_news_listener, + bool use_mock_remote_suggestions_status_service) { provider_.reset(); observer_.reset(); MakeSuggestionsProviderWithoutInitialization( - use_mock_prefetched_pages_tracker, use_fake_breaking_news_listener, + use_mock_prefetched_pages_tracker, use_mock_remote_suggestions_status_service); } @@ -470,9 +429,6 @@ PrefService* pref_service() { return utils_.pref_service(); } RemoteSuggestionsDatabase* database() { return database_; } MockScheduler* scheduler() { return scheduler_.get(); } - FakeBreakingNewsListener* fake_breaking_news_listener() { - return fake_breaking_news_listener_; - } void FetchTheseSuggestions( bool interactive_request, @@ -541,12 +497,6 @@ return snippets_callback; } - void PushArticleSuggestionToTheFront( - std::unique_ptr<RemoteSuggestion> suggestion) { - ASSERT_TRUE(fake_breaking_news_listener_); - fake_breaking_news_listener_->PushSuggestion(std::move(suggestion)); - } - void ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus old_status, RemoteSuggestionsStatus new_status) { EXPECT_FALSE(status_change_callback_.is_null()); @@ -605,7 +555,7 @@ {"enable_signed_out_users_subscription_for_pushed_suggestions", BoolToString(subscribe_signed_out)}, }, - {kNotificationsFeature.name, kBreakingNewsPushFeature.name}); + {kNotificationsFeature.name}); } void SetFetchedNotificationsParams(bool enable, bool force) { @@ -662,7 +612,6 @@ NiceMock<MockImageFetcher>* image_fetcher_; image_fetcher::FakeImageDecoder image_decoder_; std::unique_ptr<MockScheduler> scheduler_; - FakeBreakingNewsListener* fake_breaking_news_listener_; RemoteSuggestionsStatusService* remote_suggestions_status_service_; base::test::ScopedTaskEnvironment scoped_task_environment_; @@ -685,7 +634,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, Full) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -728,7 +676,6 @@ // server status. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // The articles category should be there by default, and have a title. @@ -768,7 +715,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, MultipleCategories) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -846,7 +792,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ArticleCategoryInfo) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); CategoryInfo article_info = provider()->GetCategoryInfo(articles_category()); EXPECT_THAT(article_info.additional_action(), @@ -857,7 +802,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ExperimentalCategoryInfo) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -916,7 +860,6 @@ } MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); FetchTheseSuggestions(/*interactive_request=*/true, Status::Success(), std::move(fetched_categories)); @@ -971,7 +914,6 @@ } MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); FetchTheseSuggestions(/*interactive_request=*/true, Status::Success(), std::move(fetched_categories)); @@ -996,7 +938,6 @@ AppendCategoryIfNecessary(Category::FromRemoteCategory(11))); MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); FetchTheseSuggestions(/*interactive_request=*/true, Status::Success(), std::move(fetched_categories)); @@ -1005,7 +946,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, PersistCategoryInfos) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -1035,7 +975,6 @@ // Recreate the provider to simulate a Chrome restart. ResetSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // The categories should have been restored. @@ -1064,7 +1003,6 @@ // We create a provider with a normal ranker to store the order. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -1109,14 +1047,12 @@ } ResetSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); } TEST_F(RemoteSuggestionsProviderImplTest, PersistSuggestions) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -1143,7 +1079,6 @@ // Recreate the provider to simulate a Chrome restart. ResetSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // The suggestions in both categories should have been restored. @@ -1158,7 +1093,6 @@ // Add suggestions. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -1185,7 +1119,6 @@ // Reset the provider and clear the suggestions before it is inited. ResetSuggestionsProviderWithoutInitialization( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); provider()->ClearCachedSuggestions(); @@ -1202,7 +1135,6 @@ // Get some suggestions into the database. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -1230,7 +1162,6 @@ // Recreate the provider to simulate a Chrome start. ResetSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); ASSERT_THAT(RemoteSuggestionsProviderImpl::State::DISABLED, @@ -1247,7 +1178,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, Clear) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1270,7 +1200,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ReplaceSuggestions) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::string first("http://first"); @@ -1303,7 +1232,6 @@ ShouldResolveFetchedSuggestionThumbnail) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1333,7 +1261,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ShouldFetchMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1369,7 +1296,6 @@ ShouldResolveFetchedMoreSuggestionThumbnail) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1408,7 +1334,6 @@ ShouldNotChangeSuggestionsInOtherSurfacesWhenFetchingMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Fetch a suggestion. @@ -1462,7 +1387,6 @@ ShouldNotAffectFetchMoreInOtherSurfacesWhenFetchingMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Fetch more on the surface A. @@ -1531,7 +1455,6 @@ ClearHistoryShouldDeleteArchivedSuggestions) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // First get suggestions into the archived state which happens through // subsequent fetches. Then we verify the entries are gone from the 'archived' @@ -1607,7 +1530,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ReturnFetchRequestEmptyBeforeInit) { MakeSuggestionsProviderWithoutInitialization( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); EXPECT_CALL(*mock_suggestions_fetcher(), FetchSnippets(_, _)).Times(0); MockFunction<void(Status, const std::vector<ContentSuggestion>&)> loaded; @@ -1621,7 +1543,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ReturnRefetchRequestEmptyBeforeInit) { MakeSuggestionsProviderWithoutInitialization( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); EXPECT_CALL(*mock_suggestions_fetcher(), FetchSnippets(_, _)).Times(0); MockFunction<void(Status)> loaded; @@ -1634,7 +1555,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, IgnoreRefetchRequestEmptyBeforeInit) { MakeSuggestionsProviderWithoutInitialization( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); EXPECT_CALL(*mock_suggestions_fetcher(), FetchSnippets(_, _)).Times(0); provider()->RefetchInTheBackground( @@ -1646,7 +1566,6 @@ ShouldForwardTemporaryErrorFromFetcher) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); RemoteSuggestionsFetcher::SnippetsAvailableCallback snippets_callback; @@ -1672,7 +1591,6 @@ ShouldNotAddNewSuggestionsAfterFetchError) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); FetchTheseSuggestions( @@ -1687,7 +1605,6 @@ ShouldNotClearOldSuggestionsAfterFetchError) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1717,7 +1634,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, Dismiss) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1770,7 +1686,6 @@ // The suggestion should stay dismissed even after re-creating the provider. ResetSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); fetched_categories.clear(); fetched_categories.push_back(category_builder.Build()); @@ -1794,7 +1709,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, GetDismissed) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1841,7 +1755,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, RemoveExpiredDismissedContent) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1895,7 +1808,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ExpiredContentNotRemoved) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1915,7 +1827,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, TestSingleSource) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1944,7 +1855,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, TestSingleSourceWithMissingData) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -1964,7 +1874,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, LogNumArticlesHistogram) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); base::HistogramTester tester; @@ -2057,7 +1966,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, DismissShouldRespectAllKnownUrls) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); const std::vector<std::string> source_urls = { @@ -2110,7 +2018,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ImageReturnedWithTheSameId) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -2136,7 +2043,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, EmptyImageReturnedForNonExistentId) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Create a non-empty image so that we can test the image gets updated. @@ -2160,7 +2066,6 @@ // the database, it will get a wrong answer. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); ContentSuggestion::ID unknown_id = MakeArticleID(kSuggestionUrl2); @@ -2185,7 +2090,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ClearHistoryRemovesAllSuggestions) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -2228,7 +2132,6 @@ // at all in the UI and the user cannot load new data :-/. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); ASSERT_THAT(observer().StatusForCategory(articles_category()), @@ -2243,7 +2146,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ShouldClearOrphanedImagesOnRestart) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -2281,7 +2183,6 @@ EXPECT_FALSE(FetchImage(MakeArticleID(kSuggestionUrl)).IsEmpty()); ResetSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // After the restart, the image should be garbage collected. EXPECT_CALL(*this, OnImageFetched(Property(&gfx::Image::IsEmpty, Eq(true)))); @@ -2295,7 +2196,6 @@ ShouldHandleMoreThanMaxSuggestionsInResponse) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -2323,7 +2223,6 @@ // not be initialized until the test clock is set. MakeSuggestionsProviderWithoutInitialization( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); base::SimpleTestClock simple_test_clock; @@ -2485,7 +2384,6 @@ ShouldExcludeKnownSuggestionsWithoutTruncatingWhenFetchingMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::set<std::string> known_ids; @@ -2508,7 +2406,6 @@ ShouldExcludeDismissedSuggestionsWhenFetchingMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -2542,7 +2439,6 @@ ShouldTruncateExcludedDismissedSuggestionsWhenFetchingMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -2580,7 +2476,6 @@ ShouldPreferLatestExcludedDismissedSuggestionsWhenFetchingMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -2628,7 +2523,6 @@ // future fetches. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); FetchedCategoryBuilder category_builder; @@ -2676,7 +2570,6 @@ TEST_F(RemoteSuggestionsProviderImplTest, ClearDismissedAfterFetchMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); FetchedCategoryBuilder category_builder; category_builder.SetCategory(articles_category()); @@ -2725,7 +2618,6 @@ ShouldExcludeDismissedSuggestionsFromAllCategoriesWhenFetchingMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Add article suggestions. @@ -2783,7 +2675,6 @@ ShouldPreferTargetCategoryExcludedDismissedSuggestionsWhenFetchingMore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Add article suggestions. @@ -2841,7 +2732,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -2863,7 +2753,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/true, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); StrictMock<MockPrefetchedPagesTracker>* mock_tracker = mock_prefetched_pages_tracker(); @@ -2915,7 +2804,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/true, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); StrictMock<MockPrefetchedPagesTracker>* mock_tracker = mock_prefetched_pages_tracker(); @@ -2965,7 +2853,6 @@ MakeSuggestionsProviderWithoutInitialization( /*use_mock_prefetched_pages_tracker=*/true, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); StrictMock<MockPrefetchedPagesTracker>* mock_tracker = mock_prefetched_pages_tracker(); @@ -3022,7 +2909,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/true, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); StrictMock<MockPrefetchedPagesTracker>* mock_tracker = mock_prefetched_pages_tracker(); @@ -3093,7 +2979,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/true, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); StrictMock<MockPrefetchedPagesTracker>* mock_tracker = mock_prefetched_pages_tracker(); @@ -3149,7 +3034,6 @@ MakeSuggestionsProviderWithoutInitialization( /*use_mock_prefetched_pages_tracker=*/true, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); StrictMock<MockPrefetchedPagesTracker>* mock_tracker = mock_prefetched_pages_tracker(); @@ -3237,7 +3121,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/true, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); StrictMock<MockPrefetchedPagesTracker>* mock_tracker = mock_prefetched_pages_tracker(); @@ -3270,7 +3153,6 @@ ShouldRestoreSuggestionsFromDatabaseInSameOrderAsFetched) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; @@ -3301,7 +3183,6 @@ ResetSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); EXPECT_THAT( observer().SuggestionsForCategory(articles_category()), @@ -3316,7 +3197,6 @@ ShouldSortSuggestionsWithoutRanksByScore) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Write suggestions without ranks (i.e. with default values) directly to @@ -3345,7 +3225,6 @@ ResetSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); EXPECT_THAT( observer().SuggestionsForCategory(articles_category()), @@ -3356,410 +3235,6 @@ } TEST_F(RemoteSuggestionsProviderImplTest, - PrependingShouldNotAffectOtherSuggestions) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - // Set up the provider with some article suggestions. - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - std::vector<FetchedCategory> fetched_categories; - FetchedCategoryBuilder category_builder = - FetchedCategoryBuilder().SetCategory(articles_category()); - for (int i = 0; i < 10; ++i) { - const std::string url = "http://other.com/" + base::NumberToString(i); - category_builder.AddSuggestionViaBuilder( - RemoteSuggestionBuilder().AddId(url).SetUrl(url)); - } - fetched_categories.push_back(category_builder.Build()); - FetchTheseSuggestions(/*interactive_request=*/true, Status::Success(), - std::move(fetched_categories)); - - // Prepend an article suggestion. - const std::string prepended_url = "http://prepended.com/"; - std::unique_ptr<RemoteSuggestion> prepended_suggestion = - RemoteSuggestionBuilder() - .AddId(prepended_url) - .SetUrl(prepended_url) - .Build(); - - PushArticleSuggestionToTheFront(std::move(prepended_suggestion)); - - // Check that the prepended suggestion is in the front, and all the others are - // still there in the same order. - std::vector<Matcher<const ContentSuggestion&>> expected; - expected.push_back( - Property(&ContentSuggestion::id, MakeArticleID(prepended_url))); - for (int i = 0; i < 10; ++i) { - expected.push_back( - Property(&ContentSuggestion::id, - MakeArticleID("http://other.com/" + base::NumberToString(i)))); - } - - EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), - ElementsAreArray(expected)); -} - -TEST_F(RemoteSuggestionsProviderImplTest, - ShouldNotPrependIncompleteSuggestion) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - - // Prepend an article suggestion. - const RemoteSuggestionBuilder suggestion_builder = - RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com") - .SetTitle(std::string()); - - PushArticleSuggestionToTheFront(suggestion_builder.Build()); - EXPECT_THAT(provider()->GetSuggestionsForTesting(articles_category()), - IsEmpty()); -} - -TEST_F(RemoteSuggestionsProviderImplTest, ShouldNotPrependDismissedSuggestion) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - - // Prepend an article suggestion. - const RemoteSuggestionBuilder suggestion_builder = - RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com"); - - PushArticleSuggestionToTheFront(suggestion_builder.Build()); - ASSERT_THAT(provider()->GetSuggestionsForTesting(articles_category()), - SizeIs(1)); - - // Dismiss it. - provider()->DismissSuggestion(MakeArticleID("http://prepended.com")); - ASSERT_THAT(provider()->GetSuggestionsForTesting(articles_category()), - IsEmpty()); - - // Prepend it again and verify that it is ignored. - PushArticleSuggestionToTheFront(suggestion_builder.Build()); - EXPECT_THAT(provider()->GetSuggestionsForTesting(articles_category()), - IsEmpty()); -} - -TEST_F(RemoteSuggestionsProviderImplTest, ShouldNotPrependExistingSuggestion) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - - base::Time first_time; - ASSERT_TRUE(base::Time::FromUTCString("2017-01-02T00:00:01Z", &first_time)); - base::Time second_time; - ASSERT_TRUE(base::Time::FromUTCString("2017-01-02T00:00:02Z", &second_time)); - - std::vector<FetchedCategory> fetched_categories; - fetched_categories.push_back( - FetchedCategoryBuilder() - .SetCategory(articles_category()) - .AddSuggestionViaBuilder(RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com") - .SetFetchDate(first_time)) - .Build()); - - FetchTheseSuggestions(/*interactive_request=*/true, Status::Success(), - std::move(fetched_categories)); - fetched_categories.clear(); - - EXPECT_THAT(provider()->GetSuggestionsForTesting(articles_category()), - ElementsAre(Pointee( - Property(&RemoteSuggestion::fetch_date, first_time)))); - - // Prepend the same article suggestion. - const RemoteSuggestionBuilder suggestion_builder = - RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com") - .SetFetchDate(second_time); - - PushArticleSuggestionToTheFront(suggestion_builder.Build()); - - // The prepended suggestion should be ignored, because it was fetched - // previously and is shown on NTP already. - EXPECT_THAT(provider()->GetSuggestionsForTesting(articles_category()), - ElementsAre(Pointee( - Property(&RemoteSuggestion::fetch_date, first_time)))); -} - -TEST_F(RemoteSuggestionsProviderImplTest, ShouldNotPrependArchivedSuggestion) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - - std::vector<FetchedCategory> fetched_categories; - fetched_categories.push_back( - FetchedCategoryBuilder() - .SetCategory(articles_category()) - .AddSuggestionViaBuilder(RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com")) - .Build()); - - FetchTheseSuggestions(/*interactive_request=*/true, Status::Success(), - std::move(fetched_categories)); - fetched_categories.clear(); - - EXPECT_THAT(provider()->GetSuggestionsForTesting(articles_category()), - ElementsAre(Pointee(Property(&RemoteSuggestion::url, - GURL("http://prepended.com"))))); - - // Do another fetch to achive the existing article. - fetched_categories.push_back( - FetchedCategoryBuilder() - .SetCategory(articles_category()) - .AddSuggestionViaBuilder(RemoteSuggestionBuilder() - .AddId("http://newly_fetched.com") - .SetUrl("http://newly_fetched.com")) - .Build()); - - FetchTheseSuggestions(/*interactive_request=*/true, Status::Success(), - std::move(fetched_categories)); - fetched_categories.clear(); - - EXPECT_THAT(provider()->GetSuggestionsForTesting(articles_category()), - ElementsAre(Pointee(Property(&RemoteSuggestion::url, - GURL("http://newly_fetched.com"))))); - - // Prepend the previous article suggestion. - const RemoteSuggestionBuilder suggestion_builder = - RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com"); - PushArticleSuggestionToTheFront(suggestion_builder.Build()); - - // The prepended suggestion should be ignored again, because it was fetched - // previously and may be shown on older NTPs. - EXPECT_THAT(provider()->GetSuggestionsForTesting(articles_category()), - ElementsAre(Pointee(Property(&RemoteSuggestion::url, - GURL("http://newly_fetched.com"))))); -} - -TEST_F(RemoteSuggestionsProviderImplTest, - ShouldRestorePrependedSuggestionOnTopAfterRestart) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - // Set up the provider with some article suggestions. - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - std::vector<FetchedCategory> fetched_categories; - FetchedCategoryBuilder category_builder = - FetchedCategoryBuilder().SetCategory(articles_category()); - for (int i = 0; i < 10; ++i) { - const std::string url = "http://other.com/" + base::NumberToString(i); - category_builder.AddSuggestionViaBuilder( - RemoteSuggestionBuilder().AddId(url).SetUrl(url)); - } - fetched_categories.push_back(category_builder.Build()); - FetchTheseSuggestions(/*interactive_request=*/true, Status::Success(), - std::move(fetched_categories)); - - // Prepend an article suggestion. - const std::string prepended_url = "http://prepended.com"; - std::unique_ptr<RemoteSuggestion> prepended_suggestion = - RemoteSuggestionBuilder() - .AddId(prepended_url) - .SetUrl(prepended_url) - .Build(); - - PushArticleSuggestionToTheFront(std::move(prepended_suggestion)); - - // Reset the provider to imitate browser restart. - ResetSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - - // Check that prepended suggestion is in the front of the restored list and - // all other suggestions are present in the same order. - std::vector<Matcher<const ContentSuggestion&>> expected; - expected.push_back( - Property(&ContentSuggestion::id, MakeArticleID(prepended_url))); - for (int i = 0; i < 10; ++i) { - expected.push_back( - Property(&ContentSuggestion::id, - MakeArticleID("http://other.com/" + base::NumberToString(i)))); - } - - EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), - ElementsAreArray(expected)); -} - -TEST_F( - RemoteSuggestionsProviderImplTest, - PrependingShouldNotTriggerFetchedSuggestionNotificationForTheSecondTime) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/true, - /*pushed_notifications_enabled=*/true, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - // Set up the provider with an article suggestion triggering a notification. - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - - std::vector<FetchedCategory> fetched_categories; - fetched_categories.push_back( - FetchedCategoryBuilder() - .SetCategory(articles_category()) - .AddSuggestionViaBuilder( - RemoteSuggestionBuilder() - .AddId("http://fetched.com/") - .SetUrl("http://fetched.com/") - .SetShouldNotify(true) - .SetNotificationDeadline(GetDefaultExpirationTime())) - .Build()); - FetchTheseSuggestions(/*interactive_request=*/true, Status::Success(), - std::move(fetched_categories)); - ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), - ElementsAre(Property(&ContentSuggestion::notification_extra, - Not(nullptr)))); - - // Prepend an article suggestion. - std::unique_ptr<RemoteSuggestion> prepended_suggestion = - RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com") - .SetShouldNotify(true) - .SetNotificationDeadline(GetDefaultExpirationTime()) - .Build(); - - PushArticleSuggestionToTheFront(std::move(prepended_suggestion)); - - // Previously fetched suggestion should not trigger a notification. - EXPECT_THAT( - observer().SuggestionsForCategory(articles_category()), - ElementsAre( - Property(&ContentSuggestion::notification_extra, Not(nullptr)), - Property(&ContentSuggestion::notification_extra, nullptr))); -} - -TEST_F( - RemoteSuggestionsProviderImplTest, - PrependingShouldNotTriggerPrependedSuggestionNotificationForTheSecondTime) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/true, - /*pushed_notifications_enabled=*/true, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - - // Prepend an article suggestion. - std::unique_ptr<RemoteSuggestion> prepended_suggestion = - RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com") - .SetShouldNotify(true) - .SetNotificationDeadline(GetDefaultExpirationTime()) - .Build(); - - PushArticleSuggestionToTheFront(std::move(prepended_suggestion)); - ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), - ElementsAre(Property(&ContentSuggestion::notification_extra, - Not(nullptr)))); - - // Prepend another article suggestion. - std::unique_ptr<RemoteSuggestion> another_prepended_suggestion = - RemoteSuggestionBuilder() - .AddId("http://another_prepended.com") - .SetUrl("http://another_prepended.com") - .SetShouldNotify(true) - .SetNotificationDeadline(GetDefaultExpirationTime()) - .Build(); - - PushArticleSuggestionToTheFront(std::move(another_prepended_suggestion)); - - // Previously prepended suggestion should not trigger a notification. - EXPECT_THAT( - observer().SuggestionsForCategory(articles_category()), - ElementsAre( - Property(&ContentSuggestion::notification_extra, Not(nullptr)), - Property(&ContentSuggestion::notification_extra, nullptr))); -} - -TEST_F(RemoteSuggestionsProviderImplTest, - PrependingShouldNotTriggerNotificationWhenDisabled) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/true, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - - // Prepend an article suggestion triggering a notification. - std::unique_ptr<RemoteSuggestion> prepended_suggestion = - RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com") - .SetShouldNotify(true) - .SetNotificationDeadline(GetDefaultExpirationTime()) - .Build(); - - PushArticleSuggestionToTheFront(std::move(prepended_suggestion)); - - // The prepended suggestion should not trigger a notification because such - // notifications are disabled. - EXPECT_THAT( - observer().SuggestionsForCategory(articles_category()), - ElementsAre(Property(&ContentSuggestion::notification_extra, nullptr))); -} - -TEST_F(RemoteSuggestionsProviderImplTest, FetchingShouldNotTriggerNotificationWhenDisabled) { SetTriggeringNotificationsAndSubscriptionParams( /*fetched_notifications_enabled=*/false, @@ -3769,7 +3244,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Fetch a suggestion triggering a notification. @@ -3795,37 +3269,6 @@ } TEST_F(RemoteSuggestionsProviderImplTest, - PrependingShouldTriggerNotificationEvenIfFetchedNotificationsDisabled) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/true, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/false); - - // Prepend an article suggestion triggering a notification. - std::unique_ptr<RemoteSuggestion> prepended_suggestion = - RemoteSuggestionBuilder() - .AddId("http://prepended.com") - .SetUrl("http://prepended.com") - .SetShouldNotify(true) - .SetNotificationDeadline(GetDefaultExpirationTime()) - .Build(); - - PushArticleSuggestionToTheFront(std::move(prepended_suggestion)); - - // The prepended suggestion should trigger a notification even though fetched - // notifications are disabled. - EXPECT_THAT(observer().SuggestionsForCategory(articles_category()), - ElementsAre(Property(&ContentSuggestion::notification_extra, - Not(nullptr)))); -} - -TEST_F(RemoteSuggestionsProviderImplTest, FetchingShouldTriggerNotificationEvenIfPrependedNotificationsDisabled) { SetTriggeringNotificationsAndSubscriptionParams( /*fetched_notifications_enabled=*/true, @@ -3835,7 +3278,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Fetch a suggestion triggering a notification. @@ -3861,197 +3303,6 @@ } TEST_F(RemoteSuggestionsProviderImplTest, - ShouldNotStartListeningForBreakingNewsIfSuggestionsDisabledAtStartup) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProviderWithoutInitialization( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/true); - - FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener(); - EXPECT_FALSE(fake_listener->IsListening()); - - WaitForSuggestionsProviderInitialization(); - EXPECT_FALSE(fake_listener->IsListening()); - - // Notify the provider about status change (simulating startup). The provider - // should not start listening, because the suggestions are disabled. - ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::EXPLICITLY_DISABLED, - RemoteSuggestionsStatus::EXPLICITLY_DISABLED); - EXPECT_FALSE(fake_listener->IsListening()); -} - -TEST_F(RemoteSuggestionsProviderImplTest, - ShouldNotStartListeningForBreakingNewsIfSignedOutAndDisabled) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/false); - - MakeSuggestionsProviderWithoutInitialization( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/true); - - FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener(); - EXPECT_FALSE(fake_listener->IsListening()); - - WaitForSuggestionsProviderInitialization(); - EXPECT_FALSE(fake_listener->IsListening()); - - // Notify the provider about status change (simulating startup). The provider - // should not start listening, because the user is signed out and such - // subscription is disabled via feature params. - ChangeRemoteSuggestionsStatus( - RemoteSuggestionsStatus::EXPLICITLY_DISABLED, - RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT); - EXPECT_FALSE(fake_listener->IsListening()); -} - -TEST_F(RemoteSuggestionsProviderImplTest, - ShouldStartListeningForBreakingNewsIfSuggestionsEnabledAtStartup) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/false, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/true); - - FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener(); - ASSERT_FALSE(fake_listener->IsListening()); - - // Notify the provider about status change (simulating startup). The provider - // should start listening, because the suggestions are enabled. - ChangeRemoteSuggestionsStatus( - RemoteSuggestionsStatus::EXPLICITLY_DISABLED, - RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT); - EXPECT_TRUE(fake_listener->IsListening()); -} - -TEST_F(RemoteSuggestionsProviderImplTest, - ShouldStartListeningForBreakingNewsIfSuggestionsEnabled) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/false); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/true); - - FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener(); - - // Notify the provider about status change (simulating startup). - ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::EXPLICITLY_DISABLED, - RemoteSuggestionsStatus::EXPLICITLY_DISABLED); - ASSERT_FALSE(fake_listener->IsListening()); - - // Simulate the user enabling suggestions by notifying the status change. The - // provider should start listening. - ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::EXPLICITLY_DISABLED, - RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN); - EXPECT_TRUE(fake_listener->IsListening()); -} - -TEST_F(RemoteSuggestionsProviderImplTest, - ShouldStopListeningForBreakingNewsIfSuggestionsDisabled) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/true); - - FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener(); - - // Notify the provider about status change (simulating startup). - ChangeRemoteSuggestionsStatus( - RemoteSuggestionsStatus::EXPLICITLY_DISABLED, - RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT); - ASSERT_TRUE(fake_listener->IsListening()); - - // Simulate the user disabling suggestions by notifying the status change. The - // provider should stop listening. - ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT, - RemoteSuggestionsStatus::EXPLICITLY_DISABLED); - EXPECT_FALSE(fake_listener->IsListening()); -} - -TEST_F(RemoteSuggestionsProviderImplTest, - ShouldStopListeningForBreakingNewsAfterSignOutIfDisabled) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/true, - /*subscribe_signed_out=*/false); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/true); - - FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener(); - - // Notify the provider about status change (simulating startup). - ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::EXPLICITLY_DISABLED, - RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN); - ASSERT_TRUE(fake_listener->IsListening()); - - // Simulate the user signing out by notifying the status change. The provider - // should stop listening, because signed out subscription is disabled via - // feature params. - ChangeRemoteSuggestionsStatus( - RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN, - RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT); - EXPECT_FALSE(fake_listener->IsListening()); -} - -TEST_F(RemoteSuggestionsProviderImplTest, - ShouldStopListeningForBreakingNewsAfterSignInIfDisabled) { - SetTriggeringNotificationsAndSubscriptionParams( - /*fetched_notifications_enabled=*/false, - /*pushed_notifications_enabled=*/false, - /*subscribe_signed_in=*/false, - /*subscribe_signed_out=*/true); - - MakeSuggestionsProvider( - /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/true, - /*use_mock_remote_suggestions_status_service=*/true); - - FakeBreakingNewsListener* fake_listener = fake_breaking_news_listener(); - - // Notify the provider about status change (simulating startup). - ChangeRemoteSuggestionsStatus( - RemoteSuggestionsStatus::EXPLICITLY_DISABLED, - RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT); - ASSERT_TRUE(fake_listener->IsListening()); - - // Simulate the user signing in by notifying the status change. The provider - // should stop listening, because signed in subscription is disabled via - // feature params. - ChangeRemoteSuggestionsStatus(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT, - RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN); - EXPECT_FALSE(fake_listener->IsListening()); -} - -TEST_F(RemoteSuggestionsProviderImplTest, ShouldForceFetchedSuggestionsNotificationsWhenEnabled) { SetFetchedNotificationsParams( /*enabled=*/true, /*force=*/true); @@ -4060,7 +3311,6 @@ // notification and one - without. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -4096,7 +3346,6 @@ // Initialize the provider with an article suggestions without a notification. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -4123,7 +3372,6 @@ // Initialize the provider with two categories. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; const FetchedCategoryBuilder articles_category_builder = @@ -4164,7 +3412,6 @@ // Initialize the provider with two categories. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; const FetchedCategoryBuilder articles_category_builder = @@ -4205,7 +3452,6 @@ // Initialize the provider with two categories. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; fetched_categories.push_back( @@ -4245,7 +3491,6 @@ // Initialize the provider with two categories. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Set up state with present suggestions. @@ -4293,7 +3538,6 @@ // Initialize the provider with two categories. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Set up state with present suggestions. @@ -4336,7 +3580,6 @@ // Initialize the provider with two categories. MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); // Set up state with present suggestions. @@ -4375,7 +3618,6 @@ ShouldNotSetExclusiveCategoryWhenFetchingSuggestions) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); RequestParams params; @@ -4395,7 +3637,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); RequestParams params; @@ -4420,7 +3661,6 @@ ShouldToggleStatusIfRefetchWhileDisplayingSucceeds) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; const FetchedCategoryBuilder articles_category_builder = @@ -4460,7 +3700,6 @@ ShouldToggleStatusIfRefetchWhileDisplayingFails) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; const FetchedCategoryBuilder articles_category_builder = @@ -4496,7 +3735,6 @@ ShouldToggleStatusIfRefetchWhileDisplayingTimeouts) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; const FetchedCategoryBuilder articles_category_builder = @@ -4537,7 +3775,6 @@ ShouldHandleCategoryDisabledBeforeTimeout) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; const FetchedCategoryBuilder articles_category_builder = @@ -4579,7 +3816,6 @@ ShouldNotUpdateTimeoutIfRefetchWhileDisplayingCalledAgain) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); std::vector<FetchedCategory> fetched_categories; const FetchedCategoryBuilder articles_category_builder = @@ -4623,7 +3859,6 @@ MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/true, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); StrictMock<MockPrefetchedPagesTracker>* mock_tracker = mock_prefetched_pages_tracker(); @@ -4671,7 +3906,6 @@ ShouldToggleStatusIfReloadSuggestionsFails) { MakeSuggestionsProvider( /*use_mock_prefetched_pages_tracker=*/false, - /*use_fake_breaking_news_listener=*/false, /*use_mock_remote_suggestions_status_service=*/false); ASSERT_EQ(CategoryStatus::AVAILABLE,
diff --git a/components/omnibox/browser/history_url_provider.cc b/components/omnibox/browser/history_url_provider.cc index 6618330..3c74a8e7 100644 --- a/components/omnibox/browser/history_url_provider.cc +++ b/components/omnibox/browser/history_url_provider.cc
@@ -1244,36 +1244,23 @@ (!params.prevent_inline_autocomplete || (inline_autocomplete_offset >= match.fill_into_edit.length())); - // Get the adjusted (for match contents) match start and end offsets. - std::vector<size_t> offsets = { - history_match.input_location, - history_match.input_location + params.input.text().length()}; - const auto format_types = AutocompleteMatch::GetFormatTypes( params.input.parts().scheme.len > 0 || !params.trim_http || history_match.match_in_scheme, history_match.match_in_subdomain); - match.contents = url_formatter::FormatUrlWithOffsets( - info.url(), format_types, net::UnescapeRule::SPACES, nullptr, nullptr, - &offsets); + match.contents = url_formatter::FormatUrl(info.url(), format_types, + net::UnescapeRule::SPACES, nullptr, + nullptr, nullptr); + auto term_matches = FindTermMatches(params.input.text(), match.contents); + match.contents_class = ClassifyTermMatches( + term_matches, match.contents.size(), + ACMatchClassification::URL | ACMatchClassification::MATCH, + ACMatchClassification::URL); - size_t match_start = offsets[0]; - size_t match_end = offsets[1]; - - if (match_start != base::string16::npos && - match_end != base::string16::npos && match_end != match_start) { - DCHECK_GT(match_end, match_start); - AutocompleteMatch::ClassifyLocationInString( - match_start, match_end - match_start, match.contents.length(), - ACMatchClassification::URL, &match.contents_class); - } else { - AutocompleteMatch::ClassifyLocationInString(base::string16::npos, 0, - match.contents.length(), ACMatchClassification::URL, - &match.contents_class); - } match.description = info.title(); match.description_class = ClassifyDescription(params.input.text(), match.description); + RecordAdditionalInfoFromUrlRow(info, &match); return match; }
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc index 633cce6..0a190ab 100644 --- a/components/payments/content/payment_request.cc +++ b/components/payments/content/payment_request.cc
@@ -420,6 +420,7 @@ if (methods_supported) { if (SatisfiesSkipUIConstraints()) { skipped_payment_request_ui_ = true; + journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SKIPPED_SHOW); Pay(); } } else {
diff --git a/components/previews/content/hint_cache.cc b/components/previews/content/hint_cache.cc index 29ad4cfc..83e68dc 100644 --- a/components/previews/content/hint_cache.cc +++ b/components/previews/content/hint_cache.cc
@@ -87,9 +87,9 @@ } std::unique_ptr<HintCacheStore::ComponentUpdateData> -HintCache::CreateUpdateDataForFetchedHints() const { +HintCache::CreateUpdateDataForFetchedHints(base::Time update_time) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return hint_store_->CreateUpdateDataForFetchedHints(); + return hint_store_->CreateUpdateDataForFetchedHints(update_time); } void HintCache::UpdateComponentData( @@ -108,16 +108,18 @@ bool HintCache::StoreFetchedHints( std::unique_ptr<optimization_guide::proto::GetHintsResponse> - get_hints_response) { + get_hints_response, + base::Time update_time, + base::OnceClosure callback) { std::unique_ptr<HintCacheStore::ComponentUpdateData> - fetched_hints_update_data = CreateUpdateDataForFetchedHints(); - if (!ProcessGetHintsResponse(get_hints_response.get(), - fetched_hints_update_data.get())) { - return false; + fetched_hints_update_data = CreateUpdateDataForFetchedHints(update_time); + if (ProcessGetHintsResponse(get_hints_response.get(), + fetched_hints_update_data.get())) { + hint_store_->UpdateFetchedHintsData(std::move(fetched_hints_update_data), + std::move(callback)); + return true; } - - // TODO(mcrouse): Provide the |hint_store_| with UpdateData to stored. - return true; + return false; } bool HintCache::HasHint(const std::string& host) const { @@ -171,6 +173,13 @@ return nullptr; } +base::Time HintCache::FetchedHintsUpdateTime() const { + if (!hint_store_) { + return base::Time(); + } + return hint_store_->FetchedHintsUpdateTime(); +} + void HintCache::OnStoreInitialized(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::move(callback).Run();
diff --git a/components/previews/content/hint_cache.h b/components/previews/content/hint_cache.h index b21749b9..55f1ed2 100644 --- a/components/previews/content/hint_cache.h +++ b/components/previews/content/hint_cache.h
@@ -56,9 +56,10 @@ // hints. No version is needed nor applicable for fetched hints. During // processing of the GetHintsResponse, hints are moved into the update data. // After processing is complete, the update data is provided to the backing - // store to update hints. + // store to update hints. |update_time| specifies when the hints within the + // created update data will be scheduled to be updated. std::unique_ptr<HintCacheStore::ComponentUpdateData> - CreateUpdateDataForFetchedHints() const; + CreateUpdateDataForFetchedHints(base::Time update_time) const; // Updates the store's component data using the provided ComponentUpdateData // and asynchronously runs the provided callback after the update finishes. @@ -66,13 +67,18 @@ std::unique_ptr<HintCacheStore::ComponentUpdateData> component_data, base::OnceClosure callback); - // Process |get_hints_response| to be stored in the hint cache store. - // Returns true if processing get_hints_response is successful and applicable - // hints can be stored. Returns false if there are no applicable hints in - // |get_hints_response| or it cannot be processed. + // Process |get_hints_response| to be stored in the hint cache store. Returns + // true if processing |get_hints_response| is successful and applicable hints + // can be stored. Returns false if there are no applicable hints in + // |get_hints_response| or it cannot be processed. |callback| is + // asynchronously run when the hints are successfully stored or if the store + // is not available. |update_time| specifies when the hints within + // |get_hints_response| will need to be updated next. bool StoreFetchedHints( std::unique_ptr<optimization_guide::proto::GetHintsResponse> - get_hints_response); + get_hints_response, + base::Time update_time, + base::OnceClosure callback); // Returns whether the cache has a hint data for |host| locally (whether // in memory or persisted on disk). @@ -82,6 +88,11 @@ // |callback| if/when loaded. void LoadHint(const std::string& host, HintLoadedCallback callback); + // Returns the update time provided by |hint_store_|, which specifies when the + // fetched hints within the store are ready to be updated. If |hint_store_| is + // not initialized, base::Time() is returned. + base::Time FetchedHintsUpdateTime() const; + // Returns the hint data for |host| if found in memory, otherwise nullptr. const optimization_guide::proto::Hint* GetHintIfLoaded( const std::string& host);
diff --git a/components/previews/content/hint_cache_store.cc b/components/previews/content/hint_cache_store.cc index d5283d3d..6b78079e 100644 --- a/components/previews/content/hint_cache_store.cc +++ b/components/previews/content/hint_cache_store.cc
@@ -6,6 +6,8 @@ #include "base/bind.h" #include "base/metrics/histogram_macros.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "components/leveldb_proto/public/proto_database_provider.h" #include "components/previews/content/proto/hint_cache.pb.h" @@ -42,7 +44,9 @@ kSchemaMetadataMissing = 2, kSchemaMetadataWrongVersion = 3, kComponentMetadataMissing = 4, - kMaxValue = kComponentMetadataMissing, + kFetchedMetadataMissing = 5, + kComponentAndFetchedMetadataMissing = 6, + kMaxValue = kComponentAndFetchedMetadataMissing, }; // Util class for recording the result of loading the metadata. The result is @@ -68,6 +72,12 @@ UMA_HISTOGRAM_ENUMERATION("Previews.HintCacheLevelDBStore.Status", status); } +// Returns true if |key_prefix| is a prefix of |key|. +bool DatabasePrefixFilter(const std::string& key_prefix, + const std::string& key) { + return base::StartsWith(key, key_prefix, base::CompareCase::SENSITIVE); +} + } // namespace HintCacheStore::HintCacheStore( @@ -142,11 +152,11 @@ } std::unique_ptr<HintCacheStore::ComponentUpdateData> -HintCacheStore::CreateUpdateDataForFetchedHints() const { +HintCacheStore::CreateUpdateDataForFetchedHints(base::Time update_time) const { // TODO(mcrouse): Currently returns a LevelDBComponentUpdateData, future - // refactor will create a LevelDBFetchedHintsData that will take a cache - // expiry time. The version for this object will be ignored. - return std::make_unique<LevelDBComponentUpdateData>(base::Version("0.0.1")); + // refactor will enable the construction of UpdateData with the settings + // necessary for the type of hint being updated, fetched or component. + return std::make_unique<LevelDBComponentUpdateData>(update_time); } void HintCacheStore::UpdateComponentData( @@ -209,6 +219,37 @@ weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } +void HintCacheStore::UpdateFetchedHintsData( + std::unique_ptr<ComponentUpdateData> fetched_hints_data, + base::OnceClosure callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(fetched_hints_data); + DCHECK(!component_data_update_in_flight_); + + if (!IsAvailable()) { + std::move(callback).Run(); + return; + } + + fetched_update_time_ = fetched_hints_data->update_time(); + + component_data_update_in_flight_ = true; + + hint_entry_keys_.reset(); + + LevelDBComponentUpdateData* leveldb_fetched_hints_data = + static_cast<LevelDBComponentUpdateData*>(fetched_hints_data.get()); + + // This will remove the fetched metadata entry and insert all the entries + // currently in |leveldb_fetched_hints_data|. + database_->UpdateEntriesWithRemoveFilter( + std::move(leveldb_fetched_hints_data->entries_to_save_), + base::BindRepeating(&DatabasePrefixFilter, + GetMetadataTypeEntryKey(MetadataType::kFetched)), + base::BindOnce(&HintCacheStore::OnUpdateComponentData, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + bool HintCacheStore::FindHintEntryKey(const std::string& host_suffix, EntryKey* out_hint_entry_key) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -240,6 +281,14 @@ hint_entry_key, std::move(callback))); } +base::Time HintCacheStore::FetchedHintsUpdateTime() const { + // If the store is not available, the metadata entries have not been loaded + // so there are no fetched hints. + if (!IsAvailable()) + return base::Time(); + return fetched_update_time_; +} + HintCacheStore::LevelDBComponentUpdateData::LevelDBComponentUpdateData( const base::Version& version) : ComponentUpdateData(version), @@ -254,6 +303,21 @@ std::move(metadata_component_entry)); } +HintCacheStore::LevelDBComponentUpdateData::LevelDBComponentUpdateData( + base::Time update_time) + : ComponentUpdateData(update_time), + component_hint_entry_key_prefix_(GetFetchedHintEntryKeyPrefix()), + entries_to_save_(std::make_unique<EntryVector>()) { + // Add fetched metadata entry + previews::proto::StoreEntry metadata_fetched_entry; + metadata_fetched_entry.set_update_time_secs( + update_time.ToDeltaSinceWindowsEpoch().InSeconds()); + + entries_to_save_->emplace_back( + GetMetadataTypeEntryKey(MetadataType::kFetched), + std::move(metadata_fetched_entry)); +} + HintCacheStore::LevelDBComponentUpdateData::~LevelDBComponentUpdateData() = default; @@ -299,6 +363,12 @@ component_version.GetString() + kKeySectionDelimiter; } +// static +HintCacheStore::EntryKeyPrefix HintCacheStore::GetFetchedHintEntryKeyPrefix() { + return base::NumberToString(static_cast<int>(EntryType::kFetchedHint)) + + kKeySectionDelimiter; +} + void HintCacheStore::UpdateStatus(Status new_status) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -483,6 +553,7 @@ // If the component metadata entry exists, then use it to set the component // version. + bool component_metadata_missing = false; auto component_entry = metadata_entries->find(GetMetadataTypeEntryKey(MetadataType::kComponent)); if (component_entry != metadata_entries->end()) { @@ -491,6 +562,26 @@ } else { result_recorder.set_result(PreviewsHintCacheLevelDBStoreLoadMetadataResult:: kComponentMetadataMissing); + component_metadata_missing = true; + } + + auto fetched_entry = + metadata_entries->find(GetMetadataTypeEntryKey(MetadataType::kFetched)); + if (fetched_entry != metadata_entries->end()) { + DCHECK(fetched_entry->second.has_update_time_secs()); + fetched_update_time_ = base::Time::FromDeltaSinceWindowsEpoch( + base::TimeDelta::FromSeconds(fetched_entry->second.update_time_secs())); + } else { + if (component_metadata_missing) { + result_recorder.set_result( + PreviewsHintCacheLevelDBStoreLoadMetadataResult:: + kComponentAndFetchedMetadataMissing); + } else { + result_recorder.set_result( + PreviewsHintCacheLevelDBStoreLoadMetadataResult:: + kFetchedMetadataMissing); + } + fetched_update_time_ = base::Time(); } UpdateStatus(Status::kAvailable);
diff --git a/components/previews/content/hint_cache_store.h b/components/previews/content/hint_cache_store.h index c5310dd5..224d315 100644 --- a/components/previews/content/hint_cache_store.h +++ b/components/previews/content/hint_cache_store.h
@@ -71,9 +71,12 @@ : version_(version) { DCHECK(version_.IsValid()); } + explicit ComponentUpdateData(base::Time update_time) + : update_time_(update_time) {} virtual ~ComponentUpdateData() = default; const base::Version& version() const { return version_; } + base::Time update_time() const { return update_time_; } // Pure virtual function for moving a hint into ComponentUpdateData. After // MoveHintIntoUpdateData() is called, |hint| is no longer valid. @@ -83,6 +86,9 @@ private: // The component version of the update data. base::Version version_; + + // The time when hints in the update data need to be updated. + base::Time update_time_; }; HintCacheStore(const base::FilePath& database_dir, @@ -114,7 +120,7 @@ // Service so the store can expire old hints, remove hints specified by the // server, and store the fresh hints. std::unique_ptr<HintCacheStore::ComponentUpdateData> - CreateUpdateDataForFetchedHints() const; + CreateUpdateDataForFetchedHints(base::Time update_time) const; // Updates the component data (both version and hints) contained within the // store. When this is called, all pre-existing component data within the @@ -124,6 +130,18 @@ void UpdateComponentData(std::unique_ptr<ComponentUpdateData> component_data, base::OnceClosure callback); + // Updates the fetched hints data contained in the store, including the + // metadata entry. The callback is run asynchronously after the database + // stores the hints. + // + // TODO(mcrouse): When called, fetched hint data in the store that has expired + // specified by |expiry_time_secs| will be purged and only the new hints and + // non-expired hints are retained. + + void UpdateFetchedHintsData( + std::unique_ptr<ComponentUpdateData> fetched_hints_data, + base::OnceClosure callback); + // Finds a hint entry key associated with the specified host suffix. Returns // true if a hint entry key is found, in which case |out_hint_entry_key| is // populated with the key. @@ -137,6 +155,10 @@ // asynchronous. void LoadHint(const EntryKey& hint_entry_key, HintLoadedCallback callback); + // Returns the time that the fetched hints in the store can be updated. If + // |this| is not available, base::Time() is returned. + base::Time FetchedHintsUpdateTime() const; + private: friend class HintCacheStoreTest; friend class HintUpdateData; @@ -165,6 +187,7 @@ enum class EntryType { kMetadata = 1, kComponentHint = 2, + kFetchedHint = 3, }; // Metadata types within the store. The metadata type appears at the end of @@ -178,17 +201,23 @@ enum class MetadataType { kSchema = 1, kComponent = 2, + kFetched = 3, }; // HintCacheStore's concrete implementation of ComponentUpdateData. - // LevelDBComponentUpdateData is private within HintCacheStore. All - // classes outside of HintCacheStore can only interact with the - // ComponentUpdateData base class. LevelDBComponentUpdateData is created by - // HintCacheStore when MaybeCreateComponentUpdateData() is called and - // used to update the store's component data during UpdateComponentData(). + // LevelDBComponentUpdateData is private within HintCacheStore. All classes + // outside of HintCacheStore can only interact with the ComponentUpdateData + // base class. LevelDBComponentUpdateData is created by HintCacheStore when + // MaybeCreateComponentUpdateData() is called and used to update the store's + // component data during UpdateComponentData(). + // + // TODO(mcrouse): Bug: 932707. + // This class should be refactored so that there is a single constructor and + // the base class removed. The class will also be moved out of |this|. class LevelDBComponentUpdateData : public ComponentUpdateData { public: explicit LevelDBComponentUpdateData(const base::Version& version); + explicit LevelDBComponentUpdateData(base::Time update_time); ~LevelDBComponentUpdateData() override; // ComponentUpdateData overrides: @@ -227,6 +256,9 @@ static EntryKeyPrefix GetComponentHintEntryKeyPrefix( const base::Version& component_version); + // Returns prefix of the key of every fetched hint entry: "3_". + static EntryKeyPrefix GetFetchedHintEntryKeyPrefix(); + // Updates the status of the store to the specified value, validates the // transition, and destroys the database in the case where the status // transitions to Status::kFailed. @@ -331,6 +363,10 @@ // is true, keys and hints will not be returned by the store. bool component_data_update_in_flight_; + // The next update time for the fetched hints that are currently in the + // store. + base::Time fetched_update_time_; + // The keys of the hints available within the store. std::unique_ptr<EntryKeySet> hint_entry_keys_;
diff --git a/components/previews/content/hint_cache_store_unittest.cc b/components/previews/content/hint_cache_store_unittest.cc index 3dc531ba..0541e5d4 100644 --- a/components/previews/content/hint_cache_store_unittest.cc +++ b/components/previews/content/hint_cache_store_unittest.cc
@@ -57,7 +57,9 @@ // Initializes the entries contained within the database on startup. void SeedInitialData( MetadataSchemaState state, - base::Optional<size_t> component_hint_count = base::Optional<size_t>()) { + base::Optional<size_t> component_hint_count = base::Optional<size_t>(), + base::Optional<base::Time> fetched_hints_update = + base::Optional<base::Time>()) { db_store_.clear(); // Add a metadata schema entry if its state isn't kMissing. The version @@ -76,7 +78,9 @@ // If the database is being seeded with component hints, it is indicated // with a provided count. Add the component metadata with the default // component version and then add the indicated number of component hints. - if (component_hint_count) { + // if (component_hint_count && component_hint_count > + // static_cast<size_t>(0)) { + if (component_hint_count && component_hint_count > 0u) { db_store_[HintCacheStore::GetMetadataTypeEntryKey( HintCacheStore::MetadataType::kComponent)] .set_version(kDefaultComponentVersion); @@ -93,6 +97,12 @@ page_hint->set_page_pattern("page pattern " + std::to_string(i)); } } + if (fetched_hints_update) { + db_store_[HintCacheStore::GetMetadataTypeEntryKey( + HintCacheStore::MetadataType::kFetched)] + .set_update_time_secs( + fetched_hints_update->ToDeltaSinceWindowsEpoch().InSeconds()); + } } // Moves the specified number of component hints into the update data. @@ -173,6 +183,23 @@ HintCacheStore::MetadataType::kSchema)); } + // Verifies that the fetched metadata has the expected next update time. + void ExpectFetchedMetadata(base::Time update_time) const { + const auto& metadata_entry = + db_store_.find(HintCacheStore::GetMetadataTypeEntryKey( + HintCacheStore::MetadataType::kFetched)); + if (metadata_entry != db_store_.end()) { + // The next update time should have same time up to the second as the + // metadata entry is stored in seconds. + EXPECT_TRUE( + base::Time::FromDeltaSinceWindowsEpoch(base::TimeDelta::FromSeconds( + metadata_entry->second.update_time_secs())) - + update_time < + base::TimeDelta::FromSeconds(1)); + } else { + FAIL() << "No fetched metadata found"; + } + } // Verifies that the component metadata has the expected version and all // expected component hints are present. void ExpectComponentHintsPresent(const std::string& version, @@ -437,7 +464,7 @@ TEST_F(HintCacheStoreTest, InitializeFailedOnLoadHintEntryKeysWithInitialData) { base::HistogramTester histogram_tester; - SeedInitialData(MetadataSchemaState::kValid, 10); + SeedInitialData(MetadataSchemaState::kValid, 10, base::Time().Now()); CreateDatabase(); InitializeDatabase(true /*=success*/); @@ -535,7 +562,13 @@ histogram_tester.ExpectBucketCount( "Previews.HintCacheLevelDBStore.LoadMetadataResult", - 4 /* kComponentMetadataMissing */, 1); + 4 /* kComponentMetadataMissing*/, 0); + histogram_tester.ExpectBucketCount( + "Previews.HintCacheLevelDBStore.LoadMetadataResult", + 5 /* kFetchedMetadataMissing*/, 0); + histogram_tester.ExpectBucketCount( + "Previews.HintCacheLevelDBStore.LoadMetadataResult", + 6 /* kComponentAndFetchedMetadataMissing*/, 1); histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", 0 /* kUninitialized */, 1); @@ -610,6 +643,38 @@ MetadataSchemaState schema_state = MetadataSchemaState::kValid; size_t component_hint_count = 10; + SeedInitialData(schema_state, component_hint_count, base::Time().Now()); + CreateDatabase(); + InitializeStore(schema_state); + + // The store should contain the schema metadata entry, the component metadata + // entry, and all of the initial component hints. + EXPECT_EQ(GetDBStoreEntryCount(), + static_cast<size_t>(component_hint_count + 3)); + EXPECT_EQ(GetStoreHintEntryKeyCount(), component_hint_count); + + EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); + ExpectComponentHintsPresent(kDefaultComponentVersion, component_hint_count); + + histogram_tester.ExpectBucketCount( + "Previews.HintCacheLevelDBStore.LoadMetadataResult", 0 /* kSuccess */, 1); + + histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", + 0 /* kUninitialized */, 1); + histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", + 1 /* kInitializing */, 1); + histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", + 2 /* kAvailable */, 1); + histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", + 3 /* kFailed */, 0); +} + +TEST_F(HintCacheStoreTest, + InitializeSucceededWithValidSchemaEntryAndComponentDataOnly) { + base::HistogramTester histogram_tester; + + MetadataSchemaState schema_state = MetadataSchemaState::kValid; + size_t component_hint_count = 10; SeedInitialData(schema_state, component_hint_count); CreateDatabase(); InitializeStore(schema_state); @@ -624,7 +689,46 @@ ExpectComponentHintsPresent(kDefaultComponentVersion, component_hint_count); histogram_tester.ExpectBucketCount( - "Previews.HintCacheLevelDBStore.LoadMetadataResult", 0 /* kSuccess */, 1); + "Previews.HintCacheLevelDBStore.LoadMetadataResult", + 4 /* kComponentMetadataMissing*/, 0); + histogram_tester.ExpectBucketCount( + "Previews.HintCacheLevelDBStore.LoadMetadataResult", + 5 /* kFetchedMetadataMissing*/, 1); + histogram_tester.ExpectBucketCount( + "Previews.HintCacheLevelDBStore.LoadMetadataResult", + 6 /* kComponentAndFetchedMetadataMissing*/, 0); + + histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", + 0 /* kUninitialized */, 1); + histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", + 1 /* kInitializing */, 1); + histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", + 2 /* kAvailable */, 1); + histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", + 3 /* kFailed */, 0); +} + +TEST_F(HintCacheStoreTest, + InitializeSucceededWithValidSchemaEntryAndFetchedMetaData) { + base::HistogramTester histogram_tester; + + MetadataSchemaState schema_state = MetadataSchemaState::kValid; + size_t component_hint_count = 0; + SeedInitialData(schema_state, component_hint_count, base::Time().Now()); + CreateDatabase(); + InitializeStore(schema_state); + + // The store should contain the schema metadata entry, the component metadata + // entry, and all of the initial component hints. + EXPECT_EQ(GetDBStoreEntryCount(), + static_cast<size_t>(component_hint_count + 2)); + EXPECT_EQ(GetStoreHintEntryKeyCount(), component_hint_count); + + EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); + + histogram_tester.ExpectBucketCount( + "Previews.HintCacheLevelDBStore.LoadMetadataResult", + 4 /* kComponentMetadataMissing*/, 1); histogram_tester.ExpectBucketCount("Previews.HintCacheLevelDBStore.Status", 0 /* kUninitialized */, 1); @@ -1010,4 +1114,13 @@ } } +TEST_F(HintCacheStoreTest, FetchedHintsMetadataStored) { + MetadataSchemaState schema_state = MetadataSchemaState::kValid; + base::Time update_time = base::Time().Now(); + SeedInitialData(schema_state, 10, update_time); + CreateDatabase(); + InitializeStore(schema_state); + + ExpectFetchedMetadata(update_time); +} } // namespace previews
diff --git a/components/previews/content/hint_cache_unittest.cc b/components/previews/content/hint_cache_unittest.cc index 8415412..fa28b9c 100644 --- a/components/previews/content/hint_cache_unittest.cc +++ b/components/previews/content/hint_cache_unittest.cc
@@ -59,13 +59,16 @@ loaded_hint_ = nullptr; is_store_initialized_ = false; is_component_data_updated_ = false; - on_load_hint_callback_called = false; + on_load_hint_callback_called_ = false; + is_fetched_data_stored_ = false; RunUntilIdle(); } HintCache* hint_cache() { return hint_cache_.get(); } + bool is_fetched_data_stored() { return is_fetched_data_stored_; } + // Updates the cache with |component_data| and waits for callback indicating // that the update is complete. void UpdateComponentData( @@ -82,21 +85,27 @@ bool StoreFetchedHints( std::unique_ptr<optimization_guide::proto::GetHintsResponse> - get_hints_response) { - bool result = hint_cache_->StoreFetchedHints(std::move(get_hints_response)); + get_hints_response, + base::Time stored_time) { + is_fetched_data_stored_ = false; + bool result = hint_cache_->StoreFetchedHints( + std::move(get_hints_response), stored_time, + base::BindOnce(&HintCacheTest::OnHintStored, base::Unretained(this))); RunUntilIdle(); return result; } + void OnHintStored() { is_fetched_data_stored_ = true; } + // Loads hint for the specified host from the cache and waits for callback // indicating that loading the hint is complete. void LoadHint(const std::string& host) { - on_load_hint_callback_called = false; + on_load_hint_callback_called_ = false; loaded_hint_ = nullptr; hint_cache_->LoadHint(host, base::BindOnce(&HintCacheTest::OnLoadHint, base::Unretained(this))); - while (!on_load_hint_callback_called) { + while (!on_load_hint_callback_called_) { RunUntilIdle(); } } @@ -114,7 +123,7 @@ void OnStoreInitialized() { is_store_initialized_ = true; } void OnUpdateComponentData() { is_component_data_updated_ = true; } void OnLoadHint(const optimization_guide::proto::Hint* hint) { - on_load_hint_callback_called = true; + on_load_hint_callback_called_ = true; loaded_hint_ = hint; } @@ -126,7 +135,8 @@ bool is_store_initialized_; bool is_component_data_updated_; - bool on_load_hint_callback_called; + bool on_load_hint_callback_called_; + bool is_fetched_data_stored_; DISALLOW_COPY_AND_ASSIGN(HintCacheTest); }; @@ -486,10 +496,13 @@ EXPECT_EQ(hint_key, GetLoadedHint()->key()); } -TEST_F(HintCacheTest, ParseValidFetchedHints) { +TEST_F(HintCacheTest, StoreValidFetchedHints) { const int kMemoryCacheSize = 5; CreateAndInitializeHintCache(kMemoryCacheSize); + // Default update time for empty hint cache store is base::Time(). + EXPECT_EQ(hint_cache()->FetchedHintsUpdateTime(), base::Time()); + std::unique_ptr<optimization_guide::proto::GetHintsResponse> get_hints_response = std::make_unique<optimization_guide::proto::GetHintsResponse>(); @@ -500,7 +513,12 @@ optimization_guide::proto::PageHint* page_hint = hint->add_page_hints(); page_hint->set_page_pattern("page pattern"); - EXPECT_TRUE(StoreFetchedHints(std::move(get_hints_response))); + base::Time stored_time = base::Time().Now(); + EXPECT_TRUE(StoreFetchedHints(std::move(get_hints_response), stored_time)); + EXPECT_TRUE(is_fetched_data_stored()); + + // Next update time for hints should be updated. + EXPECT_EQ(hint_cache()->FetchedHintsUpdateTime(), stored_time); } TEST_F(HintCacheTest, ParseEmptyFetchedHints) { @@ -511,7 +529,9 @@ get_hints_response = std::make_unique<optimization_guide::proto::GetHintsResponse>(); - EXPECT_FALSE(StoreFetchedHints(std::move(get_hints_response))); + EXPECT_FALSE( + StoreFetchedHints(std::move(get_hints_response), base::Time().Now())); + EXPECT_FALSE(is_fetched_data_stored()); } } // namespace
diff --git a/components/previews/content/hints_fetcher.cc b/components/previews/content/hints_fetcher.cc index fe5f2e36..c6b54ba 100644 --- a/components/previews/content/hints_fetcher.cc +++ b/components/previews/content/hints_fetcher.cc
@@ -144,6 +144,8 @@ if (net_status == net::OK && response_code == net::HTTP_OK && get_hints_response->ParseFromString(get_hints_response_data)) { std::move(hints_fetched_callback_).Run(std::move(get_hints_response)); + } else { + std::move(hints_fetched_callback_).Run(base::nullopt); } }
diff --git a/components/previews/content/hints_fetcher.h b/components/previews/content/hints_fetcher.h index 9a8258e..1df02b5 100644 --- a/components/previews/content/hints_fetcher.h +++ b/components/previews/content/hints_fetcher.h
@@ -12,6 +12,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/scoped_refptr.h" +#include "base/optional.h" #include "base/sequence_checker.h" #include "components/optimization_guide/proto/hints.pb.h" #include "components/previews/core/previews_experiments.h" @@ -35,19 +36,21 @@ // to pass back the fetched hints response from the remote Optimization Guide // Service. using HintsFetchedCallback = base::OnceCallback<void( - std::unique_ptr<optimization_guide::proto::GetHintsResponse>)>; + base::Optional< + std::unique_ptr<optimization_guide::proto::GetHintsResponse>>)>; public: HintsFetcher( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, GURL optimization_guide_service_url); - ~HintsFetcher(); + virtual ~HintsFetcher(); - // Requests hints from the Optimization Guide Service if a request for - // them is not already in progress. Returns whether a new request was - // issued. |hints_fetched_callback| is only run if a fetch was successful - // and GetHintsResponse can be returned. - bool FetchOptimizationGuideServiceHints( + // Requests hints from the Optimization Guide Service if a request for them is + // not already in progress. Returns whether a new request was issued. + // |hints_fetched_callback| is run, passing a GetHintsResponse object, if a + // fetch was successful or passes nullopt if the fetch fails. Virtualized for + // testing. + virtual bool FetchOptimizationGuideServiceHints( const std::vector<std::string>& hosts, HintsFetchedCallback hints_fetched_callback);
diff --git a/components/previews/content/hints_fetcher_unittest.cc b/components/previews/content/hints_fetcher_unittest.cc index b1dd3dd7..71042934 100644 --- a/components/previews/content/hints_fetcher_unittest.cc +++ b/components/previews/content/hints_fetcher_unittest.cc
@@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/scoped_refptr.h" +#include "base/optional.h" #include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" @@ -42,12 +43,14 @@ ~HintsFetcherTest() override {} void OnHintsFetched( - std::unique_ptr<optimization_guide::proto::GetHintsResponse> + base::Optional< + std::unique_ptr<optimization_guide::proto::GetHintsResponse>> get_hints_response) { - hints_fetched_ = true; + if (get_hints_response) + hints_fetched_ = true; } - bool HintsFetched() { return hints_fetched_; } + bool hints_fetched() { return hints_fetched_; } protected: bool FetchHints(const std::vector<std::string>& hosts) { @@ -99,7 +102,7 @@ EXPECT_TRUE(FetchHints(std::vector<std::string>())); VerifyHasPendingFetchRequests(); EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK)); - EXPECT_TRUE(HintsFetched()); + EXPECT_TRUE(hints_fetched()); } // Tests to ensure that multiple hint fetches by the same object cannot be in @@ -124,7 +127,7 @@ // Send a 404 to HintsFetcher. SimulateResponse(response_content, net::HTTP_NOT_FOUND); - EXPECT_FALSE(HintsFetched()); + EXPECT_FALSE(hints_fetched()); } TEST_F(HintsFetcherTest, FetchReturnBadResponse) { @@ -132,7 +135,7 @@ EXPECT_TRUE(FetchHints(std::vector<std::string>())); VerifyHasPendingFetchRequests(); EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK)); - EXPECT_FALSE(HintsFetched()); + EXPECT_FALSE(hints_fetched()); } } // namespace previews
diff --git a/components/previews/content/previews_decider_impl_unittest.cc b/components/previews/content/previews_decider_impl_unittest.cc index 2612a1d..0d2cd87 100644 --- a/components/previews/content/previews_decider_impl_unittest.cc +++ b/components/previews/content/previews_decider_impl_unittest.cc
@@ -22,6 +22,7 @@ #include "base/metrics/field_trial_params.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/task/post_task.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_command_line.h" #include "base/test/scoped_feature_list.h" @@ -151,11 +152,13 @@ TestPreviewsOptimizationGuide( optimization_guide::OptimizationGuideService* optimization_guide_service, const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, + const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, const base::FilePath& test_path, PreviewsTopHostProvider* previews_top_host_provider, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) : PreviewsOptimizationGuide(optimization_guide_service, ui_task_runner, + background_task_runner, test_path, previews_top_host_provider, url_loader_factory) {} @@ -402,6 +405,8 @@ std::make_unique<TestPreviewsOptimizationGuide>( &optimization_guide_service_, scoped_task_environment_.GetMainThreadTaskRunner(), + base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT}), temp_dir_.GetPath(), &previews_top_host_provider_, url_loader_factory_), base::BindRepeating(&IsPreviewFieldTrialEnabled),
diff --git a/components/previews/content/previews_optimization_guide.cc b/components/previews/content/previews_optimization_guide.cc index 8e32ca6..98369b9 100644 --- a/components/previews/content/previews_optimization_guide.cc +++ b/components/previews/content/previews_optimization_guide.cc
@@ -9,8 +9,10 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/metrics/histogram_macros.h" +#include "base/rand_util.h" #include "base/task/post_task.h" #include "base/task_runner_util.h" +#include "base/time/default_clock.h" #include "components/optimization_guide/hints_component_info.h" #include "components/optimization_guide/optimization_guide_service.h" #include "components/optimization_guide/proto/hints.pb.h" @@ -34,6 +36,15 @@ // will have a newer version than it. constexpr char kManualConfigComponentVersion[] = "0.0.0"; +// Delay between retries on failed fetch and store of hints from the remote +// Optimization Guide Service. +constexpr base::TimeDelta kFetchRetryDelay = base::TimeDelta::FromMinutes(15); + +// Delay until successfully fetched hints should be updated by requesting from +// the remote Optimization Guide Service. +constexpr base::TimeDelta kUpdateFetchedHintsDelay = + base::TimeDelta::FromHours(24); + // Hints are purged during startup if the explicit purge switch exists or if // a proto override is being used--in which case the hints need to come from the // override instead. @@ -79,25 +90,60 @@ return proto_configuration; } +// Parses a list of hosts to have hints fetched for. This overrides scheduling +// of the first hints fetch and forces it to occur immediately. If no hosts are +// provided, nullopt is returned. +base::Optional<std::vector<std::string>> +ParseHintsFetchOverrideFromCommandLine() { + base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + if (!cmd_line->HasSwitch(switches::kFetchHintsOverride)) + return base::nullopt; + + std::string override_hosts_value = + cmd_line->GetSwitchValueASCII(switches::kFetchHintsOverride); + + std::vector<std::string> hosts = + base::SplitString(override_hosts_value, ",", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + + if (hosts.size() == 0) + return base::nullopt; + + return hosts; +} + +// Provides a random time delta in seconds between |kFetchRandomMinDelay| and +// |kFetchRandomMaxDelay|. +base::TimeDelta RandomFetchDelay() { + constexpr int kFetchRandomMinDelaySecs = 30; + constexpr int kFetchRandomMaxDelaySecs = 60; + return base::TimeDelta::FromSeconds( + base::RandInt(kFetchRandomMinDelaySecs, kFetchRandomMaxDelaySecs)); +} + } // namespace PreviewsOptimizationGuide::PreviewsOptimizationGuide( optimization_guide::OptimizationGuideService* optimization_guide_service, const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, + const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, const base::FilePath& profile_path, PreviewsTopHostProvider* previews_top_host_provider, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) : optimization_guide_service_(optimization_guide_service), ui_task_runner_(ui_task_runner), - background_task_runner_(base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT})), + background_task_runner_(background_task_runner), hint_cache_(std::make_unique<HintCache>( std::make_unique<HintCacheStore>(profile_path, background_task_runner_))), previews_top_host_provider_(previews_top_host_provider), + time_clock_(base::DefaultClock::GetInstance()), url_loader_factory_(url_loader_factory), ui_weak_ptr_factory_(this) { DCHECK(optimization_guide_service_); + // TODO(mcrouse): This needs to be a pref to persist the last fetch attempt + // time and prevent crash loops. + last_fetch_attempt_ = base::Time(); hint_cache_->Initialize( ShouldPurgeHintCacheStoreOnStartup(), base::BindOnce(&PreviewsOptimizationGuide::OnHintCacheInitialized, @@ -259,30 +305,53 @@ } void PreviewsOptimizationGuide::FetchHints() { - std::vector<std::string> top_hosts = previews_top_host_provider_->GetTopHosts( - previews::params::MaxHostsForOptimizationGuideServiceHintsFetch()); + base::Optional<std::vector<std::string>> top_hosts = + ParseHintsFetchOverrideFromCommandLine(); + if (!top_hosts) { + top_hosts = previews_top_host_provider_->GetTopHosts( + previews::params::MaxHostsForOptimizationGuideServiceHintsFetch()); + } DCHECK_GE(previews::params::MaxHostsForOptimizationGuideServiceHintsFetch(), - top_hosts.size()); + top_hosts->size()); + if (!hints_fetcher_) { hints_fetcher_ = std::make_unique<HintsFetcher>( url_loader_factory_, params::GetOptimizationGuideServiceURL()); } - hints_fetcher_->FetchOptimizationGuideServiceHints( - top_hosts, base::BindOnce(&PreviewsOptimizationGuide::OnHintsFetched, - ui_weak_ptr_factory_.GetWeakPtr())); + if (top_hosts->size() > 0) { + hints_fetcher_->FetchOptimizationGuideServiceHints( + *top_hosts, base::BindOnce(&PreviewsOptimizationGuide::OnHintsFetched, + ui_weak_ptr_factory_.GetWeakPtr())); + } } void PreviewsOptimizationGuide::OnHintsFetched( - std::unique_ptr<optimization_guide::proto::GetHintsResponse> + base::Optional<std::unique_ptr<optimization_guide::proto::GetHintsResponse>> get_hints_response) { - DCHECK(get_hints_response); - // TODO(mcrouse): this will be dropped into a backgroundtask as it will likely // be intensive/slow storing hints. - // The callback will be UpdateHints(). + if (get_hints_response) { + hint_cache_->StoreFetchedHints( + std::move(*get_hints_response), + time_clock_->Now() + kUpdateFetchedHintsDelay, + base::BindOnce(&PreviewsOptimizationGuide::OnFetchedHintsStored, + ui_weak_ptr_factory_.GetWeakPtr())); + } else { + // The fetch did not succeed so we will schedule to retry the fetch in + // after delaying for |kFetchRetryDelay| + // TODO(mcrouse): When the store is refactored from closures, the timer will + // be scheduled on failure of the store instead. + hints_fetch_timer_.Start(FROM_HERE, kFetchRetryDelay, this, + &PreviewsOptimizationGuide::ScheduleHintsFetch); + } +} - hint_cache_->StoreFetchedHints(std::move(get_hints_response)); +void PreviewsOptimizationGuide::OnFetchedHintsStored() { + hints_fetch_timer_.Stop(); + hints_fetch_timer_.Start( + FROM_HERE, hint_cache_->FetchedHintsUpdateTime() - time_clock_->Now(), + this, &PreviewsOptimizationGuide::ScheduleHintsFetch); } void PreviewsOptimizationGuide::UpdateHints( @@ -322,12 +391,62 @@ // notification needs to be shown to the user. if (previews::params::IsHintsFetchingEnabled()) { - // TODO(mcrouse): On initialize, we should check if hints have been fetched - // recently. We will also schedule this to be called on a timer. - FetchHints(); + if (ParseHintsFetchOverrideFromCommandLine()) { + // Skip the fetch scheduling logic and perform a hints fetch immediately + // after initialization. + last_fetch_attempt_ = time_clock_->Now(); + FetchHints(); + } else { + ScheduleHintsFetch(); + } } } +void PreviewsOptimizationGuide::ScheduleHintsFetch() { + DCHECK(!hints_fetch_timer_.IsRunning()); + + const base::TimeDelta time_until_update_time = + hint_cache_->FetchedHintsUpdateTime() - time_clock_->Now(); + const base::TimeDelta time_until_retry = + last_fetch_attempt_ + kFetchRetryDelay - time_clock_->Now(); + base::TimeDelta fetcher_delay; + if (time_until_update_time <= base::TimeDelta() && + time_until_retry <= base::TimeDelta()) { + // Fetched hints in the store should be updated and an attempt has not been + // made in last |kFetchRetryDelay|. + last_fetch_attempt_ = time_clock_->Now(); + hints_fetch_timer_.Start(FROM_HERE, RandomFetchDelay(), this, + &PreviewsOptimizationGuide::FetchHints); + } else { + if (time_until_update_time >= base::TimeDelta()) { + // If the fetched hints in the store are still up-to-date, set a timer for + // when the hints need to be updated. + fetcher_delay = time_until_update_time; + } else { + // Otherwise, hints need to be updated but an attempt was made in last + // |kFetchRetryDelay|. Schedule the timer for after the retry + // delay. + fetcher_delay = time_until_retry; + } + hints_fetch_timer_.Start(FROM_HERE, fetcher_delay, this, + &PreviewsOptimizationGuide::ScheduleHintsFetch); + } +} + +void PreviewsOptimizationGuide::SetTimeClockForTesting( + const base::Clock* time_clock) { + time_clock_ = time_clock; +} + +void PreviewsOptimizationGuide::SetHintsFetcherForTesting( + std::unique_ptr<previews::HintsFetcher> hints_fetcher) { + hints_fetcher_ = std::move(hints_fetcher); +} + +HintsFetcher* PreviewsOptimizationGuide::GetHintsFetcherForTesting() { + return hints_fetcher_.get(); +} + void PreviewsOptimizationGuide::ListenForNextUpdateForTesting( base::OnceClosure next_update_closure) { DCHECK(next_update_closure_.is_null())
diff --git a/components/previews/content/previews_optimization_guide.h b/components/previews/content/previews_optimization_guide.h index 5a2d763..44fde91 100644 --- a/components/previews/content/previews_optimization_guide.h +++ b/components/previews/content/previews_optimization_guide.h
@@ -16,6 +16,8 @@ #include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner.h" #include "base/single_thread_task_runner.h" +#include "base/time/clock.h" +#include "base/timer/timer.h" #include "components/optimization_guide/optimization_guide_service_observer.h" #include "components/previews/content/hint_cache.h" #include "components/previews/core/previews_experiments.h" @@ -34,6 +36,7 @@ class Hint; } // namespace proto } // namespace optimization_guide + namespace previews { class HintsFetcher; @@ -51,6 +54,7 @@ PreviewsOptimizationGuide( optimization_guide::OptimizationGuideService* optimization_guide_service, const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, + const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, const base::FilePath& profile_path, PreviewsTopHostProvider* previews_top_host_provider, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); @@ -110,19 +114,42 @@ bool has_hints() const { return !!hints_; } + // Set |time_clock_| for testing. + void SetTimeClockForTesting(const base::Clock* time_clock); + + // Set |hints_fetcher_| for testing. + void SetHintsFetcherForTesting( + std::unique_ptr<previews::HintsFetcher> hints_fetcher); + + HintsFetcher* GetHintsFetcherForTesting(); + + // Called when the hints store is initialized to determine when hints + // should be fetched and schedules the |hints_fetch_timer_| to fire based on: + // 1. The update time for the fetched hints in the store and + // 2. The last time a fetch attempt was made, |last_fetch_attempt_|. + // TODONOW(mcrouse) : confirm is this is ok or not. + void ScheduleHintsFetch(); + + protected: + // Callback executed after remote hints have been fetched and returned from + // the remote Optimization Guide Service. At this point, the hints response + // is ready to be processed and stored for use. Virtual to be mocked in + // testing. + virtual void OnHintsFetched( + base::Optional< + std::unique_ptr<optimization_guide::proto::GetHintsResponse>> + get_hints_response); + + // Callback executed after the Hints have been successfully stored in the + // store. Virtual to be mocked in tests. + virtual void OnFetchedHintsStored(); + private: // Callback run after the hint cache is fully initialized. At this point, the // PreviewsOptimizationGuide is ready to process components from the // OptimizationGuideService and registers as an observer with it. void OnHintCacheInitialized(); - // Callback executed after remote hints have been fetched and returned from - // the remote Optimization Guide Service. At this point, the hints response - // is ready to be processed and stored for use. - void OnHintsFetched( - std::unique_ptr<optimization_guide::proto::GetHintsResponse> - get_hints_response); - // Called when the hints have been fully updated with the latest hints from // the Component Updater. This is used as a signal during tests. // |update_closure| is called immediately if not null. @@ -162,9 +189,18 @@ // Optimization Guide Service. std::unique_ptr<HintsFetcher> hints_fetcher_; + // Timer to schedule when to fetch hints from the remote Optimization Guide + // Service. + base::OneShotTimer hints_fetch_timer_; + // TopHostProvider that this guide can query. Not owned. PreviewsTopHostProvider* previews_top_host_provider_ = nullptr; + // Clock used for scheduling the |hints_fetch_timer_|. + const base::Clock* time_clock_; + + base::Time last_fetch_attempt_; + // Used for fetching Hints by the Hints Fetcher. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
diff --git a/components/previews/content/previews_optimization_guide_unittest.cc b/components/previews/content/previews_optimization_guide_unittest.cc index 1b7fbda..11d21eae 100644 --- a/components/previews/content/previews_optimization_guide_unittest.cc +++ b/components/previews/content/previews_optimization_guide_unittest.cc
@@ -21,9 +21,11 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" +#include "base/test/simple_test_clock.h" #include "components/optimization_guide/hints_component_info.h" #include "components/optimization_guide/optimization_guide_service.h" #include "components/optimization_guide/proto/hints.pb.h" +#include "components/previews/content/hints_fetcher.h" #include "components/previews/content/previews_hints.h" #include "components/previews/content/previews_top_host_provider.h" #include "components/previews/content/previews_user_data.h" @@ -43,6 +45,19 @@ namespace { // A fake default page_id for testing. const uint64_t kDefaultPageId = 123456; + +enum class HintsFetcherEndState { + kFetchFailed = 0, + kFetchSuccessWithHints = 1, + kFetchSuccessWithNoHints = 2, +}; + +// Retry delay is 16 minutes to allow for kFetchRetryDelaySecs + +// kFetchRandomMaxDelaySecs to pass. +constexpr int kTestFetchRetryDelaySecs = 60 * 16; + +constexpr int kUpdateFetchHintsTimeSecs = 24 * 60 * 60; // 24 hours. + } // namespace class TestOptimizationGuideService @@ -78,9 +93,106 @@ MOCK_CONST_METHOD1(GetTopHosts, std::vector<std::string>(size_t max_sites)); }; +std::unique_ptr<optimization_guide::proto::GetHintsResponse> BuildHintsResponse( + std::vector<std::string> hosts) { + std::unique_ptr<optimization_guide::proto::GetHintsResponse> + get_hints_response = + std::make_unique<optimization_guide::proto::GetHintsResponse>(); + + for (const auto& host : hosts) { + optimization_guide::proto::Hint* hint = get_hints_response->add_hints(); + hint->set_key_representation(optimization_guide::proto::HOST_SUFFIX); + hint->set_key(host); + optimization_guide::proto::PageHint* page_hint = hint->add_page_hints(); + page_hint->set_page_pattern("page pattern"); + } + return get_hints_response; +} + +// A mock class implementation of HintsFetcher for unittesting +// previews_optimization_guide. +class TestHintsFetcher : public HintsFetcher { + using HintsFetchedCallback = base::OnceCallback<void( + base::Optional< + std::unique_ptr<optimization_guide::proto::GetHintsResponse>>)>; + using HintsFetcher::FetchOptimizationGuideServiceHints; + + public: + TestHintsFetcher( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + GURL optimization_guide_service_url, + HintsFetcherEndState fetch_state) + : HintsFetcher(url_loader_factory, optimization_guide_service_url), + fetch_state_(fetch_state) {} + + bool FetchOptimizationGuideServiceHints( + const std::vector<std::string>& hosts, + HintsFetchedCallback hints_fetched_callback) override { + switch (fetch_state_) { + case HintsFetcherEndState::kFetchFailed: + std::move(hints_fetched_callback).Run(base::nullopt); + return false; + case HintsFetcherEndState::kFetchSuccessWithHints: + hints_fetched_ = true; + std::move(hints_fetched_callback).Run(BuildHintsResponse({"host.com"})); + return true; + case HintsFetcherEndState::kFetchSuccessWithNoHints: + hints_fetched_ = true; + std::move(hints_fetched_callback).Run(BuildHintsResponse({})); + return true; + } + return true; + } + + bool hints_fetched() { return hints_fetched_; } + + private: + bool hints_fetched_ = false; + HintsFetcherEndState fetch_state_; +}; + +// A Test PreviewsOptimizationGuide to observe and record when callbacks +// from hints fetching and storing occur. +class TestPreviewsOptimizationGuide : public PreviewsOptimizationGuide { + public: + TestPreviewsOptimizationGuide( + optimization_guide::OptimizationGuideService* optimization_guide_service, + const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner, + const scoped_refptr<base::SequencedTaskRunner>& background_task_runner, + const base::FilePath& profile_path, + PreviewsTopHostProvider* previews_top_host_provider, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) + : PreviewsOptimizationGuide(optimization_guide_service, + ui_task_runner, + background_task_runner, + profile_path, + previews_top_host_provider, + url_loader_factory) {} + + bool fetched_hints_stored() { return fetched_hints_stored_; } + + private: + void OnHintsFetched( + base::Optional< + std::unique_ptr<optimization_guide::proto::GetHintsResponse>> + get_hints_response) override { + fetched_hints_stored_ = false; + PreviewsOptimizationGuide::OnHintsFetched(std::move(get_hints_response)); + } + + void OnFetchedHintsStored() override { + fetched_hints_stored_ = true; + PreviewsOptimizationGuide::OnFetchedHintsStored(); + } + + bool fetched_hints_stored_ = false; +}; + class PreviewsOptimizationGuideTest : public testing::Test { public: - PreviewsOptimizationGuideTest() {} + PreviewsOptimizationGuideTest() + : scoped_task_environment_( + base::test::ScopedTaskEnvironment::MainThreadType::UI_MOCK_TIME) {} ~PreviewsOptimizationGuideTest() override {} @@ -102,6 +214,14 @@ return optimization_guide_service_.get(); } + network::SharedURLLoaderFactory* url_loader_factory() { + return url_loader_factory_.get(); + } + + TestHintsFetcher* hints_fetcher() { + return static_cast<TestHintsFetcher*>(guide_->GetHintsFetcherForTesting()); + } + void ProcessHints(const optimization_guide::proto::Configuration& config, const std::string& version) { optimization_guide::HintsComponentInfo info( @@ -126,11 +246,17 @@ optimization_guide_service_ = std::make_unique<TestOptimizationGuideService>( scoped_task_environment_.GetMainThreadTaskRunner()); - guide_ = std::make_unique<PreviewsOptimizationGuide>( + guide_ = std::make_unique<TestPreviewsOptimizationGuide>( optimization_guide_service_.get(), + scoped_task_environment_.GetMainThreadTaskRunner(), scoped_task_environment_.GetMainThreadTaskRunner(), temp_dir(), previews_top_host_provider_.get(), url_loader_factory_); + guide_->SetTimeClockForTesting(scoped_task_environment_.GetMockClock()); + + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature(features::kOptimizationHintsFetching); + // Add observer is called after the HintCache is fully initialized, // indicating that the PreviewsOptimizationGuide is ready to process hints. while (!optimization_guide_service_->AddObserverCalled()) { @@ -143,9 +269,24 @@ RunUntilIdle(); } + std::unique_ptr<TestHintsFetcher> BuildTestHintsFetcher( + HintsFetcherEndState end_state) { + std::unique_ptr<TestHintsFetcher> hints_fetcher = + std::make_unique<TestHintsFetcher>( + url_loader_factory_, GURL("https://hintsserver.com"), end_state); + return hints_fetcher; + } + base::FilePath temp_dir() const { return temp_dir_.GetPath(); } protected: + base::test::ScopedTaskEnvironment scoped_task_environment_; + + void MoveClockForwardBy(base::TimeDelta time_delta) { + scoped_task_environment_.FastForwardBy(time_delta); + base::RunLoop().RunUntilIdle(); + } + void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); base::RunLoop().RunUntilIdle(); @@ -183,6 +324,11 @@ PreviewsType type, net::EffectiveConnectionType* out_ect_threshold); + void RunUntilFetchedHintsStored() { + while (!guide_->fetched_hints_stored()) { + } + } + private: void WriteConfigToFile(const optimization_guide::proto::Configuration& config, const base::FilePath& filePath) { @@ -193,14 +339,19 @@ serialized_config.length())); } + void TestOnHintsFetched( + std::unique_ptr<optimization_guide::proto::GetHintsResponse> + get_hints_response) {} + + std::unique_ptr<TestHintsFetcher> test_fetcher_; // Callback used to indicate that the asynchronous call to // MaybeLoadOptimizationHints() has completed its processing. void OnLoadOptimizationHints(); - base::test::ScopedTaskEnvironment scoped_task_environment_; base::ScopedTempDir temp_dir_; - std::unique_ptr<PreviewsOptimizationGuide> guide_; + // std::unique_ptr<PreviewsOptimizationGuide> guide_; + std::unique_ptr<TestPreviewsOptimizationGuide> guide_; std::unique_ptr<TestOptimizationGuideService> optimization_guide_service_; std::unique_ptr<MockPreviewsTopHostProvider> previews_top_host_provider_; @@ -213,6 +364,7 @@ GURL loaded_hints_document_gurl_; std::vector<std::string> loaded_hints_resource_patterns_; + // const base::SimpleTestClock* test_clock_; DISALLOW_COPY_AND_ASSIGN(PreviewsOptimizationGuideTest); }; @@ -1575,18 +1727,110 @@ EXPECT_TRUE(optimization_guide_service()->RemoveObserverCalled()); } -TEST_F(PreviewsOptimizationGuideTest, HintsFetcherEnabled) { +TEST_F(PreviewsOptimizationGuideTest, HintsFetcherEnabledNoHosts) { + base::HistogramTester histogram_tester; base::test::ScopedFeatureList scoped_list; scoped_list.InitAndEnableFeature(features::kOptimizationHintsFetching); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); command_line->AppendSwitchASCII("optimization_guide_service_url", "https://hintsserver.com"); - EXPECT_CALL(*top_host_provider(), GetTopHosts(testing::_)); - CreateServiceAndGuide(); + guide()->SetHintsFetcherForTesting( + BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints)); + + EXPECT_CALL(*top_host_provider(), GetTopHosts(testing::_)).Times(1); + // Load hints so that OnHintsUpdated is called. This will force FetchHints to // be triggered if OptimizationHintsFetching is enabled. InitializeFixedCountResourceLoadingHints(); + // Cause the timer to fire the fetch event. + MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs)); + EXPECT_FALSE(hints_fetcher()->hints_fetched()); +} + +TEST_F(PreviewsOptimizationGuideTest, HintsFetcherEnabledWithHosts) { + base::HistogramTester histogram_tester; + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature(features::kOptimizationHintsFetching); + std::string opt_guide_url = "https://hintsserver.com"; + + guide()->SetHintsFetcherForTesting( + BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints)); + + std::vector<std::string> hosts = {"example1.com", "example2.com"}; + EXPECT_CALL(*top_host_provider(), GetTopHosts(testing::_)) + .Times(1) + .WillRepeatedly(testing::Return(hosts)); + + // Load hints so that OnHintsUpdated is called. This will force FetchHints to + // be triggered if OptimizationHintsFetching is enabled. + InitializeFixedCountResourceLoadingHints(); + + // Force timer to expire and schedule a hints fetch. + MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs)); + EXPECT_TRUE(hints_fetcher()->hints_fetched()); +} + +TEST_F(PreviewsOptimizationGuideTest, HintsFetcherTimerRetryDelay) { + base::HistogramTester histogram_tester; + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature(features::kOptimizationHintsFetching); + std::string opt_guide_url = "https://hintsserver.com"; + + guide()->SetHintsFetcherForTesting( + BuildTestHintsFetcher(HintsFetcherEndState::kFetchFailed)); + + std::vector<std::string> hosts = {"example1.com", "example2.com"}; + EXPECT_CALL(*top_host_provider(), GetTopHosts(testing::_)) + .Times(2) + .WillRepeatedly(testing::Return(hosts)); + + // Force hints fetch scheduling. + guide()->ScheduleHintsFetch(); + + // Force timer to expire and schedule a hints fetch - first time. + MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs)); + EXPECT_FALSE(hints_fetcher()->hints_fetched()); + + // Force speculative timer to expire after fetch fails first time, update + // hints fetcher so it succeeds this time. + guide()->SetHintsFetcherForTesting( + BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints)); + MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs)); + EXPECT_TRUE(hints_fetcher()->hints_fetched()); +} + +TEST_F(PreviewsOptimizationGuideTest, HintsFetcherTimerFetchSucceeds) { + base::HistogramTester histogram_tester; + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature(features::kOptimizationHintsFetching); + std::string opt_guide_url = "https://hintsserver.com"; + + guide()->SetHintsFetcherForTesting( + BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints)); + + std::vector<std::string> hosts = {"example1.com", "example2.com"}; + EXPECT_CALL(*top_host_provider(), GetTopHosts(testing::_)) + .WillRepeatedly(testing::Return(hosts)); + + // Force hints fetch scheduling. + guide()->ScheduleHintsFetch(); + + // Force timer to expire and schedule a hints fetch that succeeds. + MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs)); + EXPECT_TRUE(hints_fetcher()->hints_fetched()); + + // TODO(mcrouse): Make sure timer is triggered by metadata entry, + // |hint_cache| control needed. + guide()->SetHintsFetcherForTesting( + BuildTestHintsFetcher(HintsFetcherEndState::kFetchSuccessWithHints)); + + MoveClockForwardBy(base::TimeDelta::FromSeconds(kTestFetchRetryDelaySecs)); + EXPECT_FALSE(hints_fetcher()->hints_fetched()); + MoveClockForwardBy(base::TimeDelta::FromSeconds(kUpdateFetchHintsTimeSecs)); + + RunUntilFetchedHintsStored(); + EXPECT_TRUE(hints_fetcher()->hints_fetched()); } TEST_F(PreviewsOptimizationGuideTest, HintsFetcherDisabled) {
diff --git a/components/previews/content/proto/hint_cache.proto b/components/previews/content/proto/hint_cache.proto index 9f795aa8..b04fc3c 100644 --- a/components/previews/content/proto/hint_cache.proto +++ b/components/previews/content/proto/hint_cache.proto
@@ -19,4 +19,7 @@ optional string version = 1; // The actual hint data. optional optimization_guide.proto.Hint hint = 2; + // Time when top host fetched hints are still usable but update should + // be requested. This is set on the fetched metadata entry. + optional int64 update_time_secs = 3; }
diff --git a/components/previews/core/previews_switches.cc b/components/previews/core/previews_switches.cc index 676be59..3906dd8 100644 --- a/components/previews/core/previews_switches.cc +++ b/components/previews/core/previews_switches.cc
@@ -33,6 +33,11 @@ // valid value to this switch causes Chrome startup to block on hints parsing. const char kHintsProtoOverride[] = "optimization_guide_hints_override"; +// Overrides scheduling and time delays for fetching hints and causes a hints +// fetch immediately on start up using the provided comma separate lists of +// hosts. +const char kFetchHintsOverride[] = "optimization-guide-fetch-hints-override"; + // Overrides the Optimization Guide Service URL that the HintsFetcher will // request remote hints from. const char kOptimizationGuideServiceURL[] = "optimization_guide_service_url";
diff --git a/components/previews/core/previews_switches.h b/components/previews/core/previews_switches.h index 4fa8f396..9fa115f 100644 --- a/components/previews/core/previews_switches.h +++ b/components/previews/core/previews_switches.h
@@ -14,6 +14,7 @@ extern const char kIgnoreLitePageRedirectOptimizationBlacklist[]; extern const char kClearLitePageRedirectLocalBlacklist[]; extern const char kHintsProtoOverride[]; +extern const char kFetchHintsOverride[]; extern const char kOptimizationGuideServiceURL[]; extern const char kOptimizationGuideServiceAPIKey[]; extern const char kPurgeHintCacheStore[];
diff --git a/components/translate/core/browser/mock_translate_client.h b/components/translate/core/browser/mock_translate_client.h index 899a248..ff8fef9 100644 --- a/components/translate/core/browser/mock_translate_client.h +++ b/components/translate/core/browser/mock_translate_client.h
@@ -38,7 +38,6 @@ MOCK_METHOD0(GetTranslateAcceptLanguages, TranslateAcceptLanguages*()); MOCK_CONST_METHOD0(GetInfobarIconID, int()); - MOCK_METHOD1(RecordTranslateEvent, void(const metrics::TranslateEventProto&)); #if !defined(USE_AURA) MOCK_CONST_METHOD1(CreateInfoBarMock, @@ -49,9 +48,6 @@ } #endif - MOCK_CONST_METHOD1(RecordLanguageDetectionEvent, - void(const LanguageDetectionDetails&)); - MOCK_METHOD5(ShowTranslateUI, bool(translate::TranslateStep, const std::string&,
diff --git a/components/translate/core/browser/translate_client.h b/components/translate/core/browser/translate_client.h index 6798639..54ea538 100644 --- a/components/translate/core/browser/translate_client.h +++ b/components/translate/core/browser/translate_client.h
@@ -21,18 +21,12 @@ class InfoBar; } // namespace infobars -namespace metrics { -class TranslateEventProto; -} // namespace metrics - namespace translate { class TranslateAcceptLanguages; class TranslateDriver; class TranslateInfoBarDelegate; -struct LanguageDetectionDetails; - // A client interface that needs to be supplied to TranslateManager by the // embedder. // @@ -54,16 +48,6 @@ // Returns the associated TranslateAcceptLanguages. virtual TranslateAcceptLanguages* GetTranslateAcceptLanguages() = 0; - // Record language detection event. - virtual void RecordLanguageDetectionEvent( - const LanguageDetectionDetails& details) const = 0; - - // Record translate event. - // This is for user ID keyed event logging. - // This function will take metrics::TranslateEventProto and log the evnet that - // we care about. - virtual void RecordTranslateEvent(const metrics::TranslateEventProto&) = 0; - #if defined(OS_ANDROID) || defined(OS_IOS) // Returns a translate infobar that owns |delegate|. virtual std::unique_ptr<infobars::InfoBar> CreateInfoBar(
diff --git a/components/translate/core/browser/translate_manager.cc b/components/translate/core/browser/translate_manager.cc index 8585df47..b3a5382 100644 --- a/components/translate/core/browser/translate_manager.cc +++ b/components/translate/core/browser/translate_manager.cc
@@ -526,7 +526,6 @@ void TranslateManager::RecordTranslateEvent(int event_type) { translate_ranker_->RecordTranslateEvent( event_type, translate_driver_->GetUkmSourceId(), translate_event_.get()); - translate_client_->RecordTranslateEvent(*translate_event_); } bool TranslateManager::ShouldOverrideDecision(int event_type) {
diff --git a/components/translate/core/browser/translate_ui_delegate_unittest.cc b/components/translate/core/browser/translate_ui_delegate_unittest.cc index 1e48ee8..42f8d54 100644 --- a/components/translate/core/browser/translate_ui_delegate_unittest.cc +++ b/components/translate/core/browser/translate_ui_delegate_unittest.cc
@@ -93,7 +93,6 @@ EXPECT_CALL(*ranker_, RecordTranslateEvent( metrics::TranslateEventProto::USER_IGNORE, _, _)) .Times(1); - EXPECT_CALL(*client_, RecordTranslateEvent(_)).Times(1); std::unique_ptr<TranslatePrefs> prefs(client_->GetTranslatePrefs()); for (int i = 0; i < 10; i++) { @@ -117,7 +116,6 @@ EXPECT_CALL(*ranker_, RecordTranslateEvent( metrics::TranslateEventProto::USER_DECLINE, _, _)) .Times(1); - EXPECT_CALL(*client_, RecordTranslateEvent(_)).Times(1); std::unique_ptr<TranslatePrefs> prefs(client_->GetTranslatePrefs()); for (int i = 0; i < 10; i++) { @@ -141,7 +139,6 @@ RecordTranslateEvent( metrics::TranslateEventProto::USER_NEVER_TRANSLATE_LANGUAGE, _, _)) .Times(1); - EXPECT_CALL(*client_, RecordTranslateEvent(_)).Times(1); std::unique_ptr<TranslatePrefs> prefs(client_->GetTranslatePrefs()); manager_->GetLanguageState().SetTranslateEnabled(true);
diff --git a/components/translate/ios/browser/ios_translate_driver.mm b/components/translate/ios/browser/ios_translate_driver.mm index 3ee105b..57f381a 100644 --- a/components/translate/ios/browser/ios_translate_driver.mm +++ b/components/translate/ios/browser/ios_translate_driver.mm
@@ -94,8 +94,6 @@ translate_manager_->GetLanguageState().LanguageDetermined( details.adopted_language, true); - translate_manager_->translate_client()->RecordLanguageDetectionEvent(details); - if (web_state_) translate_manager_->InitiateTranslation(details.adopted_language); }
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn index 89d1184..3069ef5 100644 --- a/components/viz/common/BUILD.gn +++ b/components/viz/common/BUILD.gn
@@ -86,6 +86,7 @@ "display/overlay_strategy.h", "display/renderer_settings.cc", "display/renderer_settings.h", + "display/update_vsync_parameters_callback.h", "features.cc", "features.h", "frame_sinks/begin_frame_args.cc",
diff --git a/components/viz/common/display/update_vsync_parameters_callback.h b/components/viz/common/display/update_vsync_parameters_callback.h new file mode 100644 index 0000000..bd2f3095 --- /dev/null +++ b/components/viz/common/display/update_vsync_parameters_callback.h
@@ -0,0 +1,19 @@ +// 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. + +#ifndef COMPONENTS_VIZ_COMMON_DISPLAY_UPDATE_VSYNC_PARAMETERS_CALLBACK_H_ +#define COMPONENTS_VIZ_COMMON_DISPLAY_UPDATE_VSYNC_PARAMETERS_CALLBACK_H_ + +#include "base/callback.h" +#include "base/time/time.h" + +namespace viz { + +using UpdateVSyncParametersCallback = + base::RepeatingCallback<void(base::TimeTicks timebase, + base::TimeDelta interval)>; + +} // namespace viz + +#endif // COMPONENTS_VIZ_COMMON_DISPLAY_UPDATE_VSYNC_PARAMETERS_CALLBACK_H_
diff --git a/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.cc b/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.cc index cf6dc6d..db2ef8e 100644 --- a/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.cc +++ b/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.cc
@@ -90,8 +90,8 @@ gpu::SurfaceHandle surface_handle, bool gpu_compositing, mojom::DisplayClient* display_client, - ExternalBeginFrameSource* external_begin_frame_source, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + BeginFrameSource* begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, const RendererSettings& renderer_settings, bool send_swap_size_notifications) { auto task_runner = base::ThreadTaskRunnerHandle::Get(); @@ -102,7 +102,7 @@ : std::make_unique<SoftwareOutputDevice>(); auto output_surface = std::make_unique<SoftwareOutputSurface>( - std::move(software_output_device), synthetic_begin_frame_source); + std::move(software_output_device), std::move(update_vsync_callback)); auto scheduler = std::make_unique<DisplayScheduler>( begin_frame_source_.get(), task_runner.get(),
diff --git a/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.h b/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.h index 0eb98213..da3d7db 100644 --- a/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.h +++ b/components/viz/service/compositor_frame_fuzzer/fuzzer_software_display_provider.h
@@ -33,8 +33,8 @@ gpu::SurfaceHandle surface_handle, bool gpu_compositing, mojom::DisplayClient* display_client, - ExternalBeginFrameSource* external_begin_frame_source, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + BeginFrameSource* begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, const RendererSettings& renderer_settings, bool send_swap_size_notifications) override; uint32_t GetRestartId() const override;
diff --git a/components/viz/service/display_embedder/display_provider.h b/components/viz/service/display_embedder/display_provider.h index 11cc9ef..854fe48 100644 --- a/components/viz/service/display_embedder/display_provider.h +++ b/components/viz/service/display_embedder/display_provider.h
@@ -7,32 +7,31 @@ #include <memory> +#include "components/viz/common/display/update_vsync_parameters_callback.h" #include "gpu/ipc/common/surface_handle.h" #include "services/viz/privileged/interfaces/compositing/display_private.mojom.h" namespace viz { +class BeginFrameSource; class Display; -class ExternalBeginFrameSource; class FrameSinkId; class RendererSettings; -class SyntheticBeginFrameSource; // Handles creating Display and related classes for FrameSinkManagerImpl. class DisplayProvider { public: virtual ~DisplayProvider() {} - // Creates a new Display for |surface_handle| with |frame_sink_id|. One of - // |external_begin_frame_source| or |synthetic_begin_frame_source| should be - // non-null. If creating a Display fails this function will return null. + // Creates a new Display for |surface_handle| with |frame_sink_id|. If + // creating a Display fails this function will return null. virtual std::unique_ptr<Display> CreateDisplay( const FrameSinkId& frame_sink_id, gpu::SurfaceHandle surface_handle, bool gpu_compositing, mojom::DisplayClient* display_client, - ExternalBeginFrameSource* external_begin_frame_source, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + BeginFrameSource* begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, const RendererSettings& renderer_settings, bool send_swap_size_notifications) = 0;
diff --git a/components/viz/service/display_embedder/gl_output_surface.cc b/components/viz/service/display_embedder/gl_output_surface.cc index 3da59a89..419d8ba 100644 --- a/components/viz/service/display_embedder/gl_output_surface.cc +++ b/components/viz/service/display_embedder/gl_output_surface.cc
@@ -23,9 +23,9 @@ GLOutputSurface::GLOutputSurface( scoped_refptr<VizProcessContextProvider> context_provider, - SyntheticBeginFrameSource* synthetic_begin_frame_source) + UpdateVSyncParametersCallback update_vsync_callback) : OutputSurface(context_provider), - synthetic_begin_frame_source_(synthetic_begin_frame_source), + wants_vsync_parameter_updates_(!update_vsync_callback.is_null()), use_gpu_fence_( context_provider->ContextCapabilities().chromium_gpu_fence && context_provider->ContextCapabilities() @@ -41,8 +41,7 @@ capabilities_.max_frames_pending = context_provider->ContextCapabilities().num_surface_buffers - 1; context_provider->SetUpdateVSyncParametersCallback( - base::BindRepeating(&GLOutputSurface::OnVSyncParametersUpdated, - weak_ptr_factory_.GetWeakPtr())); + std::move(update_vsync_callback)); } GLOutputSurface::~GLOutputSurface() { @@ -97,7 +96,7 @@ DCHECK(context_provider_); uint32_t flags = 0; - if (synthetic_begin_frame_source_) + if (wants_vsync_parameter_updates_) flags |= gpu::SwapBuffersFlags::kVSyncParams; auto swap_callback = base::BindOnce( @@ -181,16 +180,6 @@ client_->DidSwapWithSize(pixel_size); } -void GLOutputSurface::OnVSyncParametersUpdated(base::TimeTicks timebase, - base::TimeDelta interval) { - if (synthetic_begin_frame_source_) { - // TODO(brianderson): We should not be receiving 0 intervals. - synthetic_begin_frame_source_->OnUpdateVSyncParameters( - timebase, - interval.is_zero() ? BeginFrameArgs::DefaultInterval() : interval); - } -} - void GLOutputSurface::OnPresentation( const gfx::PresentationFeedback& feedback) { client_->DidReceivePresentationFeedback(feedback);
diff --git a/components/viz/service/display_embedder/gl_output_surface.h b/components/viz/service/display_embedder/gl_output_surface.h index 0556d3a..3789fdb0 100644 --- a/components/viz/service/display_embedder/gl_output_surface.h +++ b/components/viz/service/display_embedder/gl_output_surface.h
@@ -7,6 +7,7 @@ #include <memory> +#include "components/viz/common/display/update_vsync_parameters_callback.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display_embedder/viz_process_context_provider.h" #include "gpu/command_buffer/client/context_support.h" @@ -14,14 +15,12 @@ namespace viz { -class SyntheticBeginFrameSource; - // An OutputSurface implementation that directly draws and // swaps to an actual GL surface. class GLOutputSurface : public OutputSurface { public: GLOutputSurface(scoped_refptr<VizProcessContextProvider> context_provider, - SyntheticBeginFrameSource* synthetic_begin_frame_source); + UpdateVSyncParametersCallback update_vsync_callback); ~GLOutputSurface() override; // OutputSurface implementation @@ -68,12 +67,10 @@ void OnGpuSwapBuffersCompleted(std::vector<ui::LatencyInfo> latency_info, const gfx::Size& pixel_size, const gpu::SwapBuffersCompleteParams& params); - void OnVSyncParametersUpdated(base::TimeTicks timebase, - base::TimeDelta interval); void OnPresentation(const gfx::PresentationFeedback& feedback); OutputSurfaceClient* client_ = nullptr; - SyntheticBeginFrameSource* const synthetic_begin_frame_source_; + const bool wants_vsync_parameter_updates_; ui::LatencyTracker latency_tracker_; bool set_draw_rectangle_for_frame_ = false;
diff --git a/components/viz/service/display_embedder/gl_output_surface_android.cc b/components/viz/service/display_embedder/gl_output_surface_android.cc index c5bd5a8..68de1f9 100644 --- a/components/viz/service/display_embedder/gl_output_surface_android.cc +++ b/components/viz/service/display_embedder/gl_output_surface_android.cc
@@ -10,8 +10,8 @@ GLOutputSurfaceAndroid::GLOutputSurfaceAndroid( scoped_refptr<VizProcessContextProvider> context_provider, - SyntheticBeginFrameSource* synthetic_begin_frame_source) - : GLOutputSurface(context_provider, synthetic_begin_frame_source), + UpdateVSyncParametersCallback update_vsync_callback) + : GLOutputSurface(context_provider, std::move(update_vsync_callback)), overlay_candidate_validator_( std::make_unique<CompositorOverlayCandidateValidatorAndroid>()) {}
diff --git a/components/viz/service/display_embedder/gl_output_surface_android.h b/components/viz/service/display_embedder/gl_output_surface_android.h index e10c463..334c7743 100644 --- a/components/viz/service/display_embedder/gl_output_surface_android.h +++ b/components/viz/service/display_embedder/gl_output_surface_android.h
@@ -16,7 +16,7 @@ public: GLOutputSurfaceAndroid( scoped_refptr<VizProcessContextProvider> context_provider, - SyntheticBeginFrameSource* synthetic_begin_frame_source); + UpdateVSyncParametersCallback update_vsync_callback); ~GLOutputSurfaceAndroid() override; // GLOutputSurface implementation:
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc index e017557..5b61a39 100644 --- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc +++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
@@ -20,10 +20,10 @@ GLOutputSurfaceBufferQueue::GLOutputSurfaceBufferQueue( scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, gfx::BufferFormat buffer_format) - : GLOutputSurface(context_provider, synthetic_begin_frame_source) { + : GLOutputSurface(context_provider, std::move(update_vsync_callback)) { capabilities_.uses_default_gl_framebuffer = false; capabilities_.flipped_output_surface = true; // Set |max_frames_pending| to 2 for buffer_queue, which aligns scheduling
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h index d46caa8..6843772a4 100644 --- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h +++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h
@@ -24,7 +24,6 @@ namespace viz { class BufferQueue; -class SyntheticBeginFrameSource; // An OutputSurface implementation that directly draws and swap to a GL // "buffer_queue" surface (aka one backed by a buffer managed explicitly in @@ -35,7 +34,7 @@ GLOutputSurfaceBufferQueue( scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, gfx::BufferFormat buffer_format);
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc index 3a3b875..8269aad1 100644 --- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc +++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc
@@ -11,12 +11,12 @@ GLOutputSurfaceBufferQueueAndroid::GLOutputSurfaceBufferQueueAndroid( scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, gfx::BufferFormat buffer_format) : GLOutputSurfaceBufferQueue(context_provider, surface_handle, - synthetic_begin_frame_source, + std::move(update_vsync_callback), gpu_memory_buffer_manager, buffer_format) {}
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h index bf8f72c..879f5c0 100644 --- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h +++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h
@@ -17,7 +17,7 @@ GLOutputSurfaceBufferQueueAndroid( scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, gfx::BufferFormat buffer_format); ~GLOutputSurfaceBufferQueueAndroid() override;
diff --git a/components/viz/service/display_embedder/gl_output_surface_mac.cc b/components/viz/service/display_embedder/gl_output_surface_mac.cc index f05a8db..1c4f94d 100644 --- a/components/viz/service/display_embedder/gl_output_surface_mac.cc +++ b/components/viz/service/display_embedder/gl_output_surface_mac.cc
@@ -11,12 +11,12 @@ GLOutputSurfaceMac::GLOutputSurfaceMac( scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, bool allow_overlays) : GLOutputSurfaceBufferQueue(context_provider, surface_handle, - synthetic_begin_frame_source, + std::move(update_vsync_callback), gpu_memory_buffer_manager, gfx::BufferFormat::RGBA_8888), overlay_validator_(
diff --git a/components/viz/service/display_embedder/gl_output_surface_mac.h b/components/viz/service/display_embedder/gl_output_surface_mac.h index 5e2e8b2..093b1ad5 100644 --- a/components/viz/service/display_embedder/gl_output_surface_mac.h +++ b/components/viz/service/display_embedder/gl_output_surface_mac.h
@@ -14,7 +14,7 @@ public: GLOutputSurfaceMac(scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, bool allow_overlays); ~GLOutputSurfaceMac() override;
diff --git a/components/viz/service/display_embedder/gl_output_surface_offscreen.cc b/components/viz/service/display_embedder/gl_output_surface_offscreen.cc index 3981b2db..5cd270a 100644 --- a/components/viz/service/display_embedder/gl_output_surface_offscreen.cc +++ b/components/viz/service/display_embedder/gl_output_surface_offscreen.cc
@@ -25,8 +25,8 @@ GLOutputSurfaceOffscreen::GLOutputSurfaceOffscreen( scoped_refptr<VizProcessContextProvider> context_provider, - SyntheticBeginFrameSource* synthetic_begin_frame_source) - : GLOutputSurface(context_provider, synthetic_begin_frame_source), + UpdateVSyncParametersCallback update_vsync_callback) + : GLOutputSurface(context_provider, std::move(update_vsync_callback)), weak_ptr_factory_(this) {} GLOutputSurfaceOffscreen::~GLOutputSurfaceOffscreen() {}
diff --git a/components/viz/service/display_embedder/gl_output_surface_offscreen.h b/components/viz/service/display_embedder/gl_output_surface_offscreen.h index 4295afaa..c39018b 100644 --- a/components/viz/service/display_embedder/gl_output_surface_offscreen.h +++ b/components/viz/service/display_embedder/gl_output_surface_offscreen.h
@@ -20,7 +20,7 @@ public: GLOutputSurfaceOffscreen( scoped_refptr<VizProcessContextProvider> context_provider, - SyntheticBeginFrameSource* synthetic_begin_frame_source); + UpdateVSyncParametersCallback update_vsync_callback); ~GLOutputSurfaceOffscreen() override; // OutputSurface implementation.
diff --git a/components/viz/service/display_embedder/gl_output_surface_ozone.cc b/components/viz/service/display_embedder/gl_output_surface_ozone.cc index 2c34702..cd217c8 100644 --- a/components/viz/service/display_embedder/gl_output_surface_ozone.cc +++ b/components/viz/service/display_embedder/gl_output_surface_ozone.cc
@@ -17,12 +17,12 @@ GLOutputSurfaceOzone::GLOutputSurfaceOzone( scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, std::vector<OverlayStrategy> strategies) : GLOutputSurfaceBufferQueue(context_provider, surface_handle, - synthetic_begin_frame_source, + std::move(update_vsync_callback), gpu_memory_buffer_manager, display::DisplaySnapshot::PrimaryFormat()) { if (!strategies.empty()) {
diff --git a/components/viz/service/display_embedder/gl_output_surface_ozone.h b/components/viz/service/display_embedder/gl_output_surface_ozone.h index ce0f932..1676c49 100644 --- a/components/viz/service/display_embedder/gl_output_surface_ozone.h +++ b/components/viz/service/display_embedder/gl_output_surface_ozone.h
@@ -20,7 +20,7 @@ GLOutputSurfaceOzone( scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, std::vector<OverlayStrategy> strategies); ~GLOutputSurfaceOzone() override;
diff --git a/components/viz/service/display_embedder/gl_output_surface_win.cc b/components/viz/service/display_embedder/gl_output_surface_win.cc index 5e79df4..117d9c8 100644 --- a/components/viz/service/display_embedder/gl_output_surface_win.cc +++ b/components/viz/service/display_embedder/gl_output_surface_win.cc
@@ -10,9 +10,9 @@ GLOutputSurfaceWin::GLOutputSurfaceWin( scoped_refptr<VizProcessContextProvider> context_provider, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, bool use_overlays) - : GLOutputSurface(context_provider, synthetic_begin_frame_source) { + : GLOutputSurface(context_provider, std::move(update_vsync_callback)) { if (use_overlays) { overlay_validator_ = std::make_unique<CompositorOverlayCandidateValidatorWin>();
diff --git a/components/viz/service/display_embedder/gl_output_surface_win.h b/components/viz/service/display_embedder/gl_output_surface_win.h index e71a7b0b..67ef72d3 100644 --- a/components/viz/service/display_embedder/gl_output_surface_win.h +++ b/components/viz/service/display_embedder/gl_output_surface_win.h
@@ -17,7 +17,7 @@ class GLOutputSurfaceWin : public GLOutputSurface { public: GLOutputSurfaceWin(scoped_refptr<VizProcessContextProvider> context_provider, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, bool use_overlays); ~GLOutputSurfaceWin() override;
diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc index 7cf787f..b2dc18e 100644 --- a/components/viz/service/display_embedder/gpu_display_provider.cc +++ b/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -110,15 +110,10 @@ gpu::SurfaceHandle surface_handle, bool gpu_compositing, mojom::DisplayClient* display_client, - ExternalBeginFrameSource* external_begin_frame_source, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + BeginFrameSource* begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, const RendererSettings& renderer_settings, bool send_swap_size_notifications) { - BeginFrameSource* begin_frame_source = - synthetic_begin_frame_source - ? static_cast<BeginFrameSource*>(synthetic_begin_frame_source) - : static_cast<BeginFrameSource*>(external_begin_frame_source); - // TODO(penghuang): Merge two output surfaces into one when GLRenderer and // software compositor is removed. std::unique_ptr<OutputSurface> output_surface; @@ -127,7 +122,7 @@ if (!gpu_compositing) { output_surface = std::make_unique<SoftwareOutputSurface>( CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client), - synthetic_begin_frame_source); + std::move(update_vsync_callback)); } else if (renderer_settings.use_skia_renderer || renderer_settings.use_skia_renderer_non_ddl) { #if defined(OS_MACOSX) || defined(OS_WIN) @@ -163,7 +158,7 @@ } else { output_surface = std::make_unique<SkiaOutputSurfaceImpl>( - gpu_service_impl_, surface_handle, synthetic_begin_frame_source, + gpu_service_impl_, surface_handle, std::move(update_vsync_callback), renderer_settings); } skia_output_surface = static_cast<SkiaOutputSurface*>(output_surface.get()); @@ -207,17 +202,17 @@ if (surface_handle == gpu::kNullSurfaceHandle) { output_surface = std::make_unique<GLOutputSurfaceOffscreen>( - std::move(context_provider), synthetic_begin_frame_source); + std::move(context_provider), std::move(update_vsync_callback)); } else if (context_provider->ContextCapabilities().surfaceless) { #if defined(USE_OZONE) output_surface = std::make_unique<GLOutputSurfaceOzone>( std::move(context_provider), surface_handle, - synthetic_begin_frame_source, gpu_memory_buffer_manager_.get(), + std::move(update_vsync_callback), gpu_memory_buffer_manager_.get(), renderer_settings.overlay_strategies); #elif defined(OS_MACOSX) output_surface = std::make_unique<GLOutputSurfaceMac>( std::move(context_provider), surface_handle, - synthetic_begin_frame_source, gpu_memory_buffer_manager_.get(), + std::move(update_vsync_callback), gpu_memory_buffer_manager_.get(), renderer_settings.allow_overlays); #elif defined(OS_ANDROID) auto buffer_format = context_provider->UseRGB565PixelFormat() @@ -225,7 +220,7 @@ : gfx::BufferFormat::RGBA_8888; output_surface = std::make_unique<GLOutputSurfaceBufferQueueAndroid>( std::move(context_provider), surface_handle, - synthetic_begin_frame_source, gpu_memory_buffer_manager_.get(), + std::move(update_vsync_callback), gpu_memory_buffer_manager_.get(), buffer_format); #else NOTREACHED(); @@ -240,14 +235,14 @@ capabilities.dc_layers && (capabilities.use_dc_overlays_for_video || use_overlays_for_sw_protected_video); output_surface = std::make_unique<GLOutputSurfaceWin>( - std::move(context_provider), synthetic_begin_frame_source, + std::move(context_provider), std::move(update_vsync_callback), use_overlays); #elif defined(OS_ANDROID) output_surface = std::make_unique<GLOutputSurfaceAndroid>( - std::move(context_provider), synthetic_begin_frame_source); + std::move(context_provider), std::move(update_vsync_callback)); #else output_surface = std::make_unique<GLOutputSurface>( - std::move(context_provider), synthetic_begin_frame_source); + std::move(context_provider), std::move(update_vsync_callback)); #endif } }
diff --git a/components/viz/service/display_embedder/gpu_display_provider.h b/components/viz/service/display_embedder/gpu_display_provider.h index b11a62a..c79c7a2 100644 --- a/components/viz/service/display_embedder/gpu_display_provider.h +++ b/components/viz/service/display_embedder/gpu_display_provider.h
@@ -32,7 +32,6 @@ namespace viz { class Display; -class ExternalBeginFrameSource; class GpuServiceImpl; class ServerSharedBitmapManager; class SoftwareOutputDevice; @@ -63,8 +62,8 @@ gpu::SurfaceHandle surface_handle, bool gpu_compositing, mojom::DisplayClient* display_client, - ExternalBeginFrameSource* external_begin_frame_source, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + BeginFrameSource* begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, const RendererSettings& renderer_settings, bool send_swap_size_notifications) override; uint32_t GetRestartId() const override;
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 54b2c14..0dffe29 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -277,12 +277,12 @@ SkiaOutputSurfaceImpl::SkiaOutputSurfaceImpl( GpuServiceImpl* gpu_service, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, const RendererSettings& renderer_settings) : gpu_service_(gpu_service), is_using_vulkan_(gpu_service->is_using_vulkan()), surface_handle_(surface_handle), - synthetic_begin_frame_source_(synthetic_begin_frame_source), + update_vsync_callback_(std::move(update_vsync_callback)), renderer_settings_(renderer_settings), weak_ptr_factory_(this) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -729,13 +729,13 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(client_); client_->DidReceivePresentationFeedback(feedback); - if (synthetic_begin_frame_source_ && + if (update_vsync_callback_ && feedback.flags & gfx::PresentationFeedback::kVSync) { // TODO(brianderson): We should not be receiving 0 intervals. - synthetic_begin_frame_source_->OnUpdateVSyncParameters( - feedback.timestamp, feedback.interval.is_zero() - ? BeginFrameArgs::DefaultInterval() - : feedback.interval); + update_vsync_callback_.Run(feedback.timestamp, + feedback.interval.is_zero() + ? BeginFrameArgs::DefaultInterval() + : feedback.interval); } }
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.h b/components/viz/service/display_embedder/skia_output_surface_impl.h index 7334d12..c946cc9d 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl.h +++ b/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -13,6 +13,7 @@ #include "base/optional.h" #include "base/threading/thread_checker.h" #include "components/viz/common/display/renderer_settings.h" +#include "components/viz/common/display/update_vsync_parameters_callback.h" #include "components/viz/service/display/skia_output_surface.h" #include "components/viz/service/viz_service_export.h" #include "gpu/command_buffer/common/sync_token.h" @@ -30,7 +31,6 @@ class GpuServiceImpl; class SkiaOutputSurfaceImplOnGpu; -class SyntheticBeginFrameSource; // The SkiaOutputSurface implementation. It is the output surface for // SkiaRenderer. It lives on the compositor thread, but it will post tasks @@ -46,7 +46,7 @@ public: SkiaOutputSurfaceImpl(GpuServiceImpl* gpu_service, gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, const RendererSettings& renderer_settings); ~SkiaOutputSurfaceImpl() override; @@ -136,7 +136,7 @@ const bool is_using_vulkan_; const gpu::SurfaceHandle surface_handle_; - SyntheticBeginFrameSource* const synthetic_begin_frame_source_; + UpdateVSyncParametersCallback update_vsync_callback_; OutputSurfaceClient* client_ = nullptr; std::unique_ptr<base::WaitableEvent> initialize_waitable_event_;
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc index 7416ad1..8bf2ff5 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -757,7 +757,22 @@ auto surface = SkSurface::MakeRenderTarget( gr_context(), SkBudgeted::kNo, image_info, 0 /* sampleCount */, kTopLeft_GrSurfaceOrigin, nullptr /* surfaceProps */); - DCHECK(!!surface); + + // We don't have driver support for that particular color_type. Try again with + // well supported SkColorType. Reads from this may have unusual colors due to + // interpreting RGBA as |color_type|, but that's better than completely + // undefined. + if (!surface) { + image_info = SkImageInfo::Make(1 /* width */, 1 /* height */, + kRGBA_8888_SkColorType, kOpaque_SkAlphaType); + surface = SkSurface::MakeRenderTarget( + gr_context(), SkBudgeted::kNo, image_info, 0 /* sampleCount */, + kTopLeft_GrSurfaceOrigin, nullptr /* surfaceProps */); + + if (!surface) + return; + } + auto* canvas = surface->getCanvas(); #if DCHECK_IS_ON() canvas->clear(SK_ColorRED);
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc b/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc index 8e1c36c..22d3b35 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
@@ -16,6 +16,7 @@ #include "cc/test/fake_output_surface_client.h" #include "cc/test/pixel_test_utils.h" #include "components/viz/common/display/renderer_settings.h" +#include "components/viz/common/display/update_vsync_parameters_callback.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/common/frame_sinks/copy_output_result.h" #include "components/viz/common/frame_sinks/copy_output_util.h" @@ -210,8 +211,8 @@ #endif } output_surface_ = std::make_unique<SkiaOutputSurfaceImpl>( - gpu_service_.get(), surface_handle_, - nullptr /* synthetic_begin_frame_source */, RendererSettings()); + gpu_service_.get(), surface_handle_, UpdateVSyncParametersCallback(), + RendererSettings()); output_surface_->BindToClient(output_surface_client_.get()); }
diff --git a/components/viz/service/display_embedder/software_output_surface.cc b/components/viz/service/display_embedder/software_output_surface.cc index 5c1c96ff..fe5cd0f 100644 --- a/components/viz/service/display_embedder/software_output_surface.cc +++ b/components/viz/service/display_embedder/software_output_surface.cc
@@ -23,10 +23,9 @@ SoftwareOutputSurface::SoftwareOutputSurface( std::unique_ptr<SoftwareOutputDevice> software_device, - SyntheticBeginFrameSource* synthetic_begin_frame_source) + UpdateVSyncParametersCallback update_vsync_callback) : OutputSurface(std::move(software_device)), - synthetic_begin_frame_source_(synthetic_begin_frame_source), - weak_factory_(this) {} + update_vsync_callback_(std::move(update_vsync_callback)) {} SoftwareOutputSurface::~SoftwareOutputSurface() = default; @@ -78,9 +77,9 @@ &SoftwareOutputSurface::SwapBuffersCallback, weak_factory_.GetWeakPtr())); gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider(); - if (vsync_provider && synthetic_begin_frame_source_) { + if (vsync_provider && update_vsync_callback_) { vsync_provider->GetVSyncParameters( - base::BindOnce(&SoftwareOutputSurface::UpdateVSyncParametersCallback, + base::BindOnce(&SoftwareOutputSurface::UpdateVSyncParameters, weak_factory_.GetWeakPtr())); } } @@ -129,13 +128,12 @@ gfx::PresentationFeedback(now, interval_to_next_refresh, 0u)); } -void SoftwareOutputSurface::UpdateVSyncParametersCallback( - base::TimeTicks timebase, - base::TimeDelta interval) { - DCHECK(synthetic_begin_frame_source_); +void SoftwareOutputSurface::UpdateVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) { + DCHECK(update_vsync_callback_); refresh_timebase_ = timebase; refresh_interval_ = interval; - synthetic_begin_frame_source_->OnUpdateVSyncParameters(timebase, interval); + update_vsync_callback_.Run(timebase, interval); } unsigned SoftwareOutputSurface::UpdateGpuFence() {
diff --git a/components/viz/service/display_embedder/software_output_surface.h b/components/viz/service/display_embedder/software_output_surface.h index f7111f1..04593bf 100644 --- a/components/viz/service/display_embedder/software_output_surface.h +++ b/components/viz/service/display_embedder/software_output_surface.h
@@ -5,7 +5,10 @@ #ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_SURFACE_H_ #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_SURFACE_H_ +#include <memory> + #include "base/memory/weak_ptr.h" +#include "components/viz/common/display/update_vsync_parameters_callback.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/viz_service_export.h" @@ -14,13 +17,11 @@ namespace viz { class SoftwareOutputDevice; -class SyntheticBeginFrameSource; class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface { public: - SoftwareOutputSurface( - std::unique_ptr<SoftwareOutputDevice> software_device, - SyntheticBeginFrameSource* synthetic_begin_frame_source); + SoftwareOutputSurface(std::unique_ptr<SoftwareOutputDevice> software_device, + UpdateVSyncParametersCallback update_vsync_callback); ~SoftwareOutputSurface() override; // OutputSurface implementation. @@ -46,19 +47,19 @@ private: void SwapBuffersCallback(); - void UpdateVSyncParametersCallback(base::TimeTicks timebase, - base::TimeDelta interval); + void UpdateVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval); OutputSurfaceClient* client_ = nullptr; - SyntheticBeginFrameSource* const synthetic_begin_frame_source_; + UpdateVSyncParametersCallback update_vsync_callback_; base::TimeTicks refresh_timebase_; base::TimeDelta refresh_interval_ = BeginFrameArgs::DefaultInterval(); std::vector<ui::LatencyInfo> stored_latency_info_; ui::LatencyTracker latency_tracker_; - base::WeakPtrFactory<SoftwareOutputSurface> weak_factory_; + base::WeakPtrFactory<SoftwareOutputSurface> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(SoftwareOutputSurface); };
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc index 2c1e82aa..980b661 100644 --- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc +++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -82,10 +82,21 @@ std::move(synthetic_begin_frame_source), std::move(external_begin_frame_source))); + UpdateVSyncParametersCallback update_vsync_callback; + if (impl->synthetic_begin_frame_source_) { + // |impl| owns the display and will outlive it so unretained is safe. + update_vsync_callback = base::BindRepeating( + &RootCompositorFrameSinkImpl::SetDisplayVSyncParameters, + base::Unretained(impl.get())); + } + // TODO(kylechar): For the cases where we expect browser to providing vsync + // parameter updates over mojo we shouldn't create |update_vsync_callback|. + // I think this is always the case on mac. + auto display = display_provider->CreateDisplay( params->frame_sink_id, params->widget, params->gpu_compositing, - impl->display_client_.get(), impl->external_begin_frame_source_.get(), - impl->synthetic_begin_frame_source_.get(), params->renderer_settings, + impl->display_client_.get(), impl->begin_frame_source(), + std::move(update_vsync_callback), params->renderer_settings, params->send_swap_size_notifications); // Creating a display failed. Destroy |impl| which will close the message
diff --git a/components/viz/test/test_display_provider.cc b/components/viz/test/test_display_provider.cc index 13632e6..ef3c1f2 100644 --- a/components/viz/test/test_display_provider.cc +++ b/components/viz/test/test_display_provider.cc
@@ -21,18 +21,13 @@ gpu::SurfaceHandle surface_handle, bool gpu_compositing, mojom::DisplayClient* display_client, - ExternalBeginFrameSource* external_begin_frame_source, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + BeginFrameSource* begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, const RendererSettings& renderer_settings, bool send_swap_size_notifications) { auto task_runner = base::ThreadTaskRunnerHandle::Get(); DCHECK(task_runner); - BeginFrameSource* begin_frame_source = - synthetic_begin_frame_source - ? static_cast<BeginFrameSource*>(synthetic_begin_frame_source) - : static_cast<BeginFrameSource*>(external_begin_frame_source); - std::unique_ptr<OutputSurface> output_surface; if (gpu_compositing) { output_surface = FakeOutputSurface::Create3d();
diff --git a/components/viz/test/test_display_provider.h b/components/viz/test/test_display_provider.h index 23d2737..92a9e52 100644 --- a/components/viz/test/test_display_provider.h +++ b/components/viz/test/test_display_provider.h
@@ -25,8 +25,8 @@ gpu::SurfaceHandle surface_handle, bool gpu_compositing, mojom::DisplayClient* display_client, - ExternalBeginFrameSource* external_begin_frame_source, - SyntheticBeginFrameSource* synthetic_begin_frame_source, + BeginFrameSource* begin_frame_source, + UpdateVSyncParametersCallback update_vsync_callback, const RendererSettings& renderer_settings, bool send_swap_size_notifications) override; uint32_t GetRestartId() const override;
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.cc b/content/browser/accessibility/browser_accessibility_state_impl.cc index 01b8057d..cbb9640 100644 --- a/content/browser/accessibility/browser_accessibility_state_impl.cc +++ b/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -71,22 +71,25 @@ // Let each platform do its own initialization. PlatformInitialize(); -#if defined(OS_WIN) || defined(OS_ANDROID) + // Schedule calls to update histograms after a delay. + // // The delay is necessary because assistive technology sometimes isn't // detected until after the user interacts in some way, so a reasonable delay // gives us better numbers. + + // Some things can be done on another thread safely. base::PostDelayedTaskWithTraits( FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&BrowserAccessibilityStateImpl::UpdateHistograms, this), + base::BindOnce( + &BrowserAccessibilityStateImpl::UpdateHistogramsOnOtherThread, this), base::TimeDelta::FromSeconds(ACCESSIBILITY_HISTOGRAM_DELAY_SECS)); -#else - // On MacOS, UpdateHistograms should be called on the UI thread because it - // needs to be able to access PrefService. + + // Other things must be done on the UI thread (e.g. to access PrefService). base::PostDelayedTaskWithTraits( FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&BrowserAccessibilityStateImpl::UpdateHistograms, this), + base::BindOnce(&BrowserAccessibilityStateImpl::UpdateHistogramsOnUIThread, + this), base::TimeDelta::FromSeconds(ACCESSIBILITY_HISTOGRAM_DELAY_SECS)); -#endif } BrowserAccessibilityStateImpl::~BrowserAccessibilityStateImpl() { @@ -136,20 +139,27 @@ return accessibility_mode_ == ui::kAXModeComplete; } -void BrowserAccessibilityStateImpl::AddHistogramCallback( - base::Closure callback) { - histogram_callbacks_.push_back(std::move(callback)); +void BrowserAccessibilityStateImpl::AddUIThreadHistogramCallback( + base::OnceClosure callback) { + ui_thread_histogram_callbacks_.push_back(std::move(callback)); +} + +void BrowserAccessibilityStateImpl::AddOtherThreadHistogramCallback( + base::OnceClosure callback) { + other_thread_histogram_callbacks_.push_back(std::move(callback)); } void BrowserAccessibilityStateImpl::UpdateHistogramsForTesting() { - UpdateHistograms(); + UpdateHistogramsOnUIThread(); + UpdateHistogramsOnOtherThread(); } -void BrowserAccessibilityStateImpl::UpdateHistograms() { - UpdatePlatformSpecificHistograms(); +void BrowserAccessibilityStateImpl::UpdateHistogramsOnUIThread() { + UpdatePlatformSpecificHistogramsOnUIThread(); - for (size_t i = 0; i < histogram_callbacks_.size(); ++i) - histogram_callbacks_[i].Run(); + for (auto& callback : ui_thread_histogram_callbacks_) + std::move(callback).Run(); + ui_thread_histogram_callbacks_.clear(); // TODO(dmazzoni): remove this in M59 since Accessibility.ModeFlag // supercedes it. http://crbug.com/672205 @@ -162,6 +172,14 @@ switches::kForceRendererAccessibility)); } +void BrowserAccessibilityStateImpl::UpdateHistogramsOnOtherThread() { + UpdatePlatformSpecificHistogramsOnOtherThread(); + + for (auto& callback : other_thread_histogram_callbacks_) + std::move(callback).Run(); + other_thread_histogram_callbacks_.clear(); +} + void BrowserAccessibilityStateImpl::OnAXModeAdded(ui::AXMode mode) { AddAccessibilityModeFlags(mode); } @@ -173,7 +191,10 @@ #if !defined(OS_ANDROID) && !defined(OS_WIN) && !defined(OS_MACOSX) void BrowserAccessibilityStateImpl::PlatformInitialize() {} -void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {} +void BrowserAccessibilityStateImpl:: + UpdatePlatformSpecificHistogramsOnUIThread() {} +void BrowserAccessibilityStateImpl:: + UpdatePlatformSpecificHistogramsOnOtherThread() {} #endif void BrowserAccessibilityStateImpl::AddAccessibilityModeFlags(ui::AXMode mode) {
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.h b/content/browser/accessibility/browser_accessibility_state_impl.h index 30dd3485..2af968c 100644 --- a/content/browser/accessibility/browser_accessibility_state_impl.h +++ b/content/browser/accessibility/browser_accessibility_state_impl.h
@@ -57,7 +57,8 @@ void ResetAccessibilityMode() override; void OnScreenReaderDetected() override; bool IsAccessibleBrowser() override; - void AddHistogramCallback(base::Closure callback) override; + void AddUIThreadHistogramCallback(base::OnceClosure callback) override; + void AddOtherThreadHistogramCallback(base::OnceClosure callback) override; void UpdateHistogramsForTesting() override; @@ -85,17 +86,22 @@ // Called a short while after startup to allow time for the accessibility // state to be determined. Updates histograms with the current state. - void UpdateHistograms(); + // Two variants - one for things that must be run on the UI thread, and + // another that can be run on another thread. + void UpdateHistogramsOnUIThread(); + void UpdateHistogramsOnOtherThread(); // Leaky singleton, destructor generally won't be called. ~BrowserAccessibilityStateImpl() override; void PlatformInitialize(); - void UpdatePlatformSpecificHistograms(); + void UpdatePlatformSpecificHistogramsOnUIThread(); + void UpdatePlatformSpecificHistogramsOnOtherThread(); ui::AXMode accessibility_mode_; - std::vector<base::Closure> histogram_callbacks_; + std::vector<base::OnceClosure> ui_thread_histogram_callbacks_; + std::vector<base::OnceClosure> other_thread_histogram_callbacks_; bool disable_hot_tracking_;
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_android.cc b/content/browser/accessibility/browser_accessibility_state_impl_android.cc index 7622a81..1cc7b7a 100644 --- a/content/browser/accessibility/browser_accessibility_state_impl_android.cc +++ b/content/browser/accessibility/browser_accessibility_state_impl_android.cc
@@ -21,8 +21,12 @@ Java_BrowserAccessibilityState_registerAnimatorDurationScaleObserver(env); } -void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() { - // NOTE: this method is run from the file thread to reduce jank, since +void BrowserAccessibilityStateImpl:: + UpdatePlatformSpecificHistogramsOnUIThread() {} + +void BrowserAccessibilityStateImpl:: + UpdatePlatformSpecificHistogramsOnOtherThread() { + // NOTE: this method is run from another thread to reduce jank, since // there's no guarantee these system calls will return quickly. Be careful // not to add any code that isn't safe to run from a non-main thread! DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_mac.mm b/content/browser/accessibility/browser_accessibility_state_impl_mac.mm index fde90e81..e91b463 100644 --- a/content/browser/accessibility/browser_accessibility_state_impl_mac.mm +++ b/content/browser/accessibility/browser_accessibility_state_impl_mac.mm
@@ -59,8 +59,8 @@ base::BindOnce(&SetupAccessibilityDisplayOptionsNotifier)); } -void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() { - // NOTE: This function is running on the file thread. +void BrowserAccessibilityStateImpl:: + UpdatePlatformSpecificHistogramsOnUIThread() { NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; SEL sel = @selector(accessibilityDisplayShouldIncreaseContrast); @@ -86,4 +86,7 @@ } } +void BrowserAccessibilityStateImpl:: + UpdatePlatformSpecificHistogramsOnOtherThread() {} + } // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_win.cc b/content/browser/accessibility/browser_accessibility_state_impl_win.cc index 641f4068..2c66497 100644 --- a/content/browser/accessibility/browser_accessibility_state_impl_win.cc +++ b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
@@ -89,10 +89,15 @@ new gfx::SingletonHwndObserver(base::BindRepeating(&OnWndProc))); } -void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() { - // NOTE: this method is run from the file thread to reduce jank, since - // there's no guarantee these system calls will return quickly. Be careful - // not to add any code that isn't safe to run from a non-main thread! +void BrowserAccessibilityStateImpl:: + UpdatePlatformSpecificHistogramsOnUIThread() {} + +void BrowserAccessibilityStateImpl:: + UpdatePlatformSpecificHistogramsOnOtherThread() { + // NOTE: this method is run from another thread to reduce jank, since + // there's no guarantee these system calls will return quickly. Code that + // needs to run in the UI thread can be run in + // UpdatePlatformSpecificHistogramsOnUIThread instead. AUDIODESCRIPTION audio_description = {0}; audio_description.cbSize = sizeof(AUDIODESCRIPTION);
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc index 5867d47..c7225b59 100644 --- a/content/browser/background_sync/background_sync_manager.cc +++ b/content/browser/background_sync/background_sync_manager.cc
@@ -111,7 +111,9 @@ void NotifyBackgroundSyncRegisteredOnUIThread( scoped_refptr<ServiceWorkerContextWrapper> sw_context_wrapper, - const url::Origin& origin) { + const url::Origin& origin, + bool can_fire, + bool is_reregistered) { DCHECK_CURRENTLY_ON(BrowserThread::UI); BackgroundSyncController* background_sync_controller = @@ -120,7 +122,26 @@ if (!background_sync_controller) return; - background_sync_controller->NotifyBackgroundSyncRegistered(origin); + background_sync_controller->NotifyBackgroundSyncRegistered(origin, can_fire, + is_reregistered); +} + +void NotifyBackgroundSyncCompletedOnUIThread( + scoped_refptr<ServiceWorkerContextWrapper> sw_context_wrapper, + const url::Origin& origin, + blink::ServiceWorkerStatusCode status_code, + int num_attempts, + int max_attempts) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + BackgroundSyncController* background_sync_controller = + GetBackgroundSyncControllerOnUIThread(std::move(sw_context_wrapper)); + + if (!background_sync_controller) + return; + + background_sync_controller->NotifyBackgroundSyncCompleted( + origin, status_code, num_attempts, max_attempts); } void RunInBackgroundOnUIThread( @@ -599,17 +620,25 @@ return; } - // TODO(crbug.com/925297): Record Periodic Sync metrics. - url::Origin origin = - url::Origin::Create(sw_registration->scope().GetOrigin()); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&NotifyBackgroundSyncRegisteredOnUIThread, - service_worker_context_, origin)); - BackgroundSyncRegistration* existing_registration = LookupActiveRegistration(blink::mojom::BackgroundSyncRegistrationInfo( sw_registration_id, options.tag, GetBackgroundSyncType(options))); + + url::Origin origin = + url::Origin::Create(sw_registration->scope().GetOrigin()); + + // TODO(crbug.com/925297): Record Periodic Sync metrics. + if (GetBackgroundSyncType(options) == + blink::mojom::BackgroundSyncType::ONE_SHOT) { + bool is_reregistered = + existing_registration && existing_registration->IsFiring(); + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce( + &NotifyBackgroundSyncRegisteredOnUIThread, service_worker_context_, + origin, /* can_fire= */ AreOptionConditionsMet(), is_reregistered)); + } + if (existing_registration) { DCHECK(existing_registration->options()->Equals(options)); @@ -1406,6 +1435,16 @@ {{"status", GetEventStatusString(status_code)}}); } + if (registration_info->sync_type == + blink::mojom::BackgroundSyncType::ONE_SHOT) { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&NotifyBackgroundSyncCompletedOnUIThread, + service_worker_context_, origin, status_code, + registration->num_attempts(), + parameters_->max_sync_attempts)); + } + RemoveActiveRegistration(*registration_info); }
diff --git a/content/browser/compositor/browser_compositor_output_surface.cc b/content/browser/compositor/browser_compositor_output_surface.cc index 0a1231d..24cfe2fb 100644 --- a/content/browser/compositor/browser_compositor_output_surface.cc +++ b/content/browser/compositor/browser_compositor_output_surface.cc
@@ -20,7 +20,7 @@ BrowserCompositorOutputSurface::BrowserCompositorOutputSurface( scoped_refptr<viz::ContextProvider> context_provider, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, + const viz::UpdateVSyncParametersCallback& update_vsync_parameters_callback, std::unique_ptr<viz::CompositorOverlayCandidateValidator> overlay_candidate_validator) : OutputSurface(std::move(context_provider)), @@ -31,7 +31,7 @@ BrowserCompositorOutputSurface::BrowserCompositorOutputSurface( std::unique_ptr<viz::SoftwareOutputDevice> software_device, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback) + const viz::UpdateVSyncParametersCallback& update_vsync_parameters_callback) : OutputSurface(std::move(software_device)), update_vsync_parameters_callback_(update_vsync_parameters_callback), reflector_(nullptr) {}
diff --git a/content/browser/compositor/browser_compositor_output_surface.h b/content/browser/compositor/browser_compositor_output_surface.h index 3c4d448..dda4ac0 100644 --- a/content/browser/compositor/browser_compositor_output_surface.h +++ b/content/browser/compositor/browser_compositor_output_surface.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "build/build_config.h" +#include "components/viz/common/display/update_vsync_parameters_callback.h" #include "components/viz/service/display/output_surface.h" #include "content/common/content_export.h" @@ -28,9 +29,6 @@ class CONTENT_EXPORT BrowserCompositorOutputSurface : public viz::OutputSurface { public: - using UpdateVSyncParametersCallback = - base::Callback<void(base::TimeTicks timebase, base::TimeDelta interval)>; - ~BrowserCompositorOutputSurface() override; // viz::OutputSurface implementation. @@ -47,16 +45,18 @@ // Constructor used by the accelerated implementation. BrowserCompositorOutputSurface( scoped_refptr<viz::ContextProvider> context, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, + const viz::UpdateVSyncParametersCallback& + update_vsync_parameters_callback, std::unique_ptr<viz::CompositorOverlayCandidateValidator> overlay_candidate_validator); // Constructor used by the software implementation. BrowserCompositorOutputSurface( std::unique_ptr<viz::SoftwareOutputDevice> software_device, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback); + const viz::UpdateVSyncParametersCallback& + update_vsync_parameters_callback); - const UpdateVSyncParametersCallback update_vsync_parameters_callback_; + const viz::UpdateVSyncParametersCallback update_vsync_parameters_callback_; ReflectorImpl* reflector_; private:
diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_browser_compositor_output_surface.cc index 1cc27ce..84907b72 100644 --- a/content/browser/compositor/gpu_browser_compositor_output_surface.cc +++ b/content/browser/compositor/gpu_browser_compositor_output_surface.cc
@@ -26,7 +26,7 @@ GpuBrowserCompositorOutputSurface::GpuBrowserCompositorOutputSurface( scoped_refptr<ws::ContextProviderCommandBuffer> context, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, + const viz::UpdateVSyncParametersCallback& update_vsync_parameters_callback, std::unique_ptr<viz::CompositorOverlayCandidateValidator> overlay_candidate_validator) : BrowserCompositorOutputSurface(std::move(context),
diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.h b/content/browser/compositor/gpu_browser_compositor_output_surface.h index 5d502d1..8c728be 100644 --- a/content/browser/compositor/gpu_browser_compositor_output_surface.h +++ b/content/browser/compositor/gpu_browser_compositor_output_surface.h
@@ -41,7 +41,8 @@ public: GpuBrowserCompositorOutputSurface( scoped_refptr<ws::ContextProviderCommandBuffer> context, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, + const viz::UpdateVSyncParametersCallback& + update_vsync_parameters_callback, std::unique_ptr<viz::CompositorOverlayCandidateValidator> overlay_candidate_validator);
diff --git a/content/browser/compositor/gpu_output_surface_mac.cc b/content/browser/compositor/gpu_output_surface_mac.cc index f6024e3e..91ebbee 100644 --- a/content/browser/compositor/gpu_output_surface_mac.cc +++ b/content/browser/compositor/gpu_output_surface_mac.cc
@@ -15,7 +15,7 @@ GpuOutputSurfaceMac::GpuOutputSurfaceMac( scoped_refptr<ws::ContextProviderCommandBuffer> context, gpu::SurfaceHandle surface_handle, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, + const viz::UpdateVSyncParametersCallback& update_vsync_parameters_callback, std::unique_ptr<viz::CompositorOverlayCandidateValidator> overlay_candidate_validator, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager)
diff --git a/content/browser/compositor/gpu_output_surface_mac.h b/content/browser/compositor/gpu_output_surface_mac.h index 0fe8986a..573358a 100644 --- a/content/browser/compositor/gpu_output_surface_mac.h +++ b/content/browser/compositor/gpu_output_surface_mac.h
@@ -14,13 +14,13 @@ class GpuOutputSurfaceMac : public GpuSurfacelessBrowserCompositorOutputSurface { public: - GpuOutputSurfaceMac( - scoped_refptr<ws::ContextProviderCommandBuffer> context, - gpu::SurfaceHandle surface_handle, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, - std::unique_ptr<viz::CompositorOverlayCandidateValidator> - overlay_candidate_validator, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager); + GpuOutputSurfaceMac(scoped_refptr<ws::ContextProviderCommandBuffer> context, + gpu::SurfaceHandle surface_handle, + const viz::UpdateVSyncParametersCallback& + update_vsync_parameters_callback, + std::unique_ptr<viz::CompositorOverlayCandidateValidator> + overlay_candidate_validator, + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager); ~GpuOutputSurfaceMac() override; private:
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index 519ea20..99c703a1 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -437,8 +437,8 @@ } } - BrowserCompositorOutputSurface::UpdateVSyncParametersCallback vsync_callback = - base::Bind(&ui::Compositor::SetDisplayVSyncParameters, compositor); + auto vsync_callback = base::BindRepeating( + &ui::Compositor::SetDisplayVSyncParameters, compositor); std::unique_ptr<BrowserCompositorOutputSurface> display_output_surface; if (!use_gpu_compositing) { if (!is_gpu_compositing_disabled_ &&
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc index ad0a788..4d4f7136 100644 --- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc +++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -22,7 +22,8 @@ GpuSurfacelessBrowserCompositorOutputSurface( scoped_refptr<ws::ContextProviderCommandBuffer> context, gpu::SurfaceHandle surface_handle, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, + const viz::UpdateVSyncParametersCallback& + update_vsync_parameters_callback, std::unique_ptr<viz::CompositorOverlayCandidateValidator> overlay_candidate_validator, gfx::BufferFormat format,
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h index b29ee9ef..af364ef 100644 --- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h +++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
@@ -27,7 +27,8 @@ GpuSurfacelessBrowserCompositorOutputSurface( scoped_refptr<ws::ContextProviderCommandBuffer> context, gpu::SurfaceHandle surface_handle, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, + const viz::UpdateVSyncParametersCallback& + update_vsync_parameters_callback, std::unique_ptr<viz::CompositorOverlayCandidateValidator> overlay_candidate_validator, gfx::BufferFormat format,
diff --git a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc index e719683c..dfedf6a 100644 --- a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc +++ b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
@@ -32,7 +32,8 @@ OffscreenBrowserCompositorOutputSurface:: OffscreenBrowserCompositorOutputSurface( scoped_refptr<ws::ContextProviderCommandBuffer> context, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, + const viz::UpdateVSyncParametersCallback& + update_vsync_parameters_callback, std::unique_ptr<viz::CompositorOverlayCandidateValidator> overlay_candidate_validator) : BrowserCompositorOutputSurface(std::move(context),
diff --git a/content/browser/compositor/offscreen_browser_compositor_output_surface.h b/content/browser/compositor/offscreen_browser_compositor_output_surface.h index 71830777..9751f1e 100644 --- a/content/browser/compositor/offscreen_browser_compositor_output_surface.h +++ b/content/browser/compositor/offscreen_browser_compositor_output_surface.h
@@ -29,7 +29,8 @@ public: OffscreenBrowserCompositorOutputSurface( scoped_refptr<ws::ContextProviderCommandBuffer> context, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback, + const viz::UpdateVSyncParametersCallback& + update_vsync_parameters_callback, std::unique_ptr<viz::CompositorOverlayCandidateValidator> overlay_candidate_validator);
diff --git a/content/browser/compositor/reflector_impl_unittest.cc b/content/browser/compositor/reflector_impl_unittest.cc index 2287823..d3fc3f8 100644 --- a/content/browser/compositor/reflector_impl_unittest.cc +++ b/content/browser/compositor/reflector_impl_unittest.cc
@@ -80,7 +80,7 @@ public: TestOutputSurface(scoped_refptr<viz::ContextProvider> context_provider) : BrowserCompositorOutputSurface(std::move(context_provider), - UpdateVSyncParametersCallback(), + viz::UpdateVSyncParametersCallback(), CreateTestValidatorOzone()) {} void SetFlip(bool flip) { capabilities_.flipped_output_surface = flip; }
diff --git a/content/browser/compositor/software_browser_compositor_output_surface.cc b/content/browser/compositor/software_browser_compositor_output_surface.cc index f119a78..0f13e98 100644 --- a/content/browser/compositor/software_browser_compositor_output_surface.cc +++ b/content/browser/compositor/software_browser_compositor_output_surface.cc
@@ -22,7 +22,7 @@ SoftwareBrowserCompositorOutputSurface::SoftwareBrowserCompositorOutputSurface( std::unique_ptr<viz::SoftwareOutputDevice> software_device, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback) + const viz::UpdateVSyncParametersCallback& update_vsync_parameters_callback) : BrowserCompositorOutputSurface(std::move(software_device), update_vsync_parameters_callback), weak_factory_(this) {}
diff --git a/content/browser/compositor/software_browser_compositor_output_surface.h b/content/browser/compositor/software_browser_compositor_output_surface.h index 83ad7ba..fa54dcb 100644 --- a/content/browser/compositor/software_browser_compositor_output_surface.h +++ b/content/browser/compositor/software_browser_compositor_output_surface.h
@@ -19,7 +19,8 @@ public: SoftwareBrowserCompositorOutputSurface( std::unique_ptr<viz::SoftwareOutputDevice> software_device, - const UpdateVSyncParametersCallback& update_vsync_parameters_callback); + const viz::UpdateVSyncParametersCallback& + update_vsync_parameters_callback); ~SoftwareBrowserCompositorOutputSurface() override;
diff --git a/content/browser/devtools/devtools_pipe_handler.cc b/content/browser/devtools/devtools_pipe_handler.cc index dd9ea0b..c03af15 100644 --- a/content/browser/devtools/devtools_pipe_handler.cc +++ b/content/browser/devtools/devtools_pipe_handler.cc
@@ -32,12 +32,24 @@ #include "content/public/browser/devtools_agent_host.h" #include "content/public/common/content_switches.h" #include "net/server/http_connection.h" +#include "third_party/inspector_protocol/encoding/encoding.h" const size_t kReceiveBufferSizeForDevTools = 100 * 1024 * 1024; // 100Mb const size_t kWritePacketSize = 1 << 16; const int kReadFD = 3; const int kWriteFD = 4; +// Our CBOR (RFC 7049) based format starts with a tag 24 indicating +// an envelope, that is, a byte string which as payload carries the +// entire remaining message. Thereby, the length of the byte string +// also tells us the message size on the wire. +// The details of the encoding are implemented in +// third_party/inspector_protocol/encoding/encoding.h. +using inspector_protocol_encoding::SpanFrom; +using inspector_protocol_encoding::cbor::InitialByteFor32BitLengthByteString; +using inspector_protocol_encoding::cbor::InitialByteForEnvelope; +using inspector_protocol_encoding::cbor::IsCBORMessage; + namespace content { class PipeReaderBase { @@ -113,29 +125,6 @@ const char kDevToolsPipeHandlerWriteThreadName[] = "DevToolsPipeHandlerWriteThread"; -// Our CBOR (RFC 7049) based format starts with a tag 24 indicating -// an envelope, that is, a byte string which as payload carries the -// entire remaining message. Thereby, the length of the byte string -// also tells us the message size on the wire. -// Envelope is encoded as TAG with minor info 24. -// Our byte strings always have their length encoded as a 32 bit -// unsigned value. - -constexpr uint8_t kCBOR_MAJOR_BYTE_STRING = 2; -constexpr uint8_t kCBOR_MAJOR_TAG = 6; - -constexpr uint8_t kCBOR_MINOR_ENVELOPE = 24; -constexpr uint8_t kCBOR_MINOR_32BIT = 26; - -constexpr uint8_t cbor_first_byte(uint8_t major, uint8_t minor) { - return major << 5 | minor; -} - -constexpr uint8_t kCBOR_ENVELOPE_TAG = - cbor_first_byte(kCBOR_MAJOR_TAG, kCBOR_MINOR_ENVELOPE); -constexpr uint8_t kCBOR_BYTESTR_32B_LEN = - cbor_first_byte(kCBOR_MAJOR_BYTE_STRING, kCBOR_MINOR_32BIT); - void WriteBytes(int write_fd, const char* bytes, size_t size) { #if defined(OS_WIN) HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(write_fd)); @@ -171,8 +160,7 @@ } void WriteIntoPipeCBOR(int write_fd, const std::string& message) { - DCHECK(!message.empty() && - static_cast<uint8_t>(message[0]) == kCBOR_ENVELOPE_TAG); + DCHECK(IsCBORMessage(SpanFrom(message))); WriteBytes(write_fd, message.data(), message.size()); } @@ -237,8 +225,8 @@ if (!ReadBytes(&buffer.front(), kHeaderSize, true)) break; const uint8_t* prefix = reinterpret_cast<const uint8_t*>(buffer.data()); - if (prefix[0] != kCBOR_ENVELOPE_TAG || - prefix[1] != kCBOR_BYTESTR_32B_LEN) { + if (prefix[0] != InitialByteForEnvelope() || + prefix[1] != InitialByteFor32BitLengthByteString()) { LOG(ERROR) << "Unexpected start of CBOR envelope " << prefix[0] << "," << prefix[1]; return;
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc index 35a4ebf..3ed425d 100644 --- a/content/browser/frame_host/navigation_controller_impl.cc +++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -3447,9 +3447,9 @@ bool replace_entry, bool previous_document_was_activated, bool is_renderer_initiated) { - // Note that for a subframe navigation, previous_document_was_activated is - // false if there has been any user gesture on an ancestor frame but not on - // the subframe doing the navigation. + // Note that for a subframe, previous_document_was_activated is true if the + // gesture happened in any subframe (propagated to main frame) or in the main + // frame itself. if (replace_entry || previous_document_was_activated || !is_renderer_initiated) { if (last_committed_entry_index_ != -1) {
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc index 387584c1..2e64e2d 100644 --- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc +++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -9298,14 +9298,6 @@ EXPECT_FALSE(root->HasBeenActivated()); EXPECT_FALSE(root->HasTransientUserActivation()); - // Simulate user gesture in the main frame. Cross origin subframes creating - // entries without user gesture will still lead to the last committed entry - // being marked as skippable. - root->UpdateUserActivationState( - blink::UserActivationUpdateType::kNotifyActivation); - EXPECT_TRUE(root->HasBeenActivated()); - EXPECT_TRUE(root->HasTransientUserActivation()); - // Invoke pushstate from a subframe. std::string script = "history.pushState({}, 'page 1', 'simple_page_1.html')"; EXPECT_TRUE(ExecuteScriptWithoutUserGesture(root->child_at(0), script)); @@ -9338,10 +9330,8 @@ controller.GoToIndex(2); load_observer.Wait(); - // A user gesture even in the main frame now will lead to all same document - // entries to be marked as non-skippable. This is an inconsistency but the - // other option of tracking which entries to reset based on which frame was - // activated seems unnecessarily complex. + // A user gesture in the main frame now will lead to all same document + // entries to be marked as non-skippable. root->UpdateUserActivationState( blink::UserActivationUpdateType::kNotifyActivation); EXPECT_TRUE(root->HasBeenActivated()); @@ -9351,6 +9341,53 @@ EXPECT_FALSE(controller.GetEntryAtIndex(2)->should_skip_on_back_forward_ui()); } +// Tests that the navigation entry is not marked as skippable on back/forward +// button if a subframe does a push state without ever getting a user +// activation on itself but there was a user gesture on the main frame. +IN_PROC_BROWSER_TEST_F( + NavigationControllerHistoryInterventionBrowserTest, + UserActivationMainFrameDoNotSetSkipOnBackForwardSubframe) { + base::HistogramTester histograms; + + GURL non_skippable_url(embedded_test_server()->GetURL("/title1.html")); + EXPECT_TRUE(NavigateToURL(shell(), non_skippable_url)); + + // It is safe to obtain the root frame tree node here, as it doesn't change. + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + + GURL url_with_frames( + embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html")); + EXPECT_TRUE(NavigateToURL(shell(), url_with_frames)); + + EXPECT_FALSE(root->HasBeenActivated()); + EXPECT_FALSE(root->HasTransientUserActivation()); + + // Simulate user gesture in the main frame. Subframes creating entries without + // user gesture will not lead to the last committed entry being marked as + // skippable. + root->UpdateUserActivationState( + blink::UserActivationUpdateType::kNotifyActivation); + EXPECT_TRUE(root->HasBeenActivated()); + EXPECT_TRUE(root->HasTransientUserActivation()); + + // Invoke pushstate from a subframe. + std::string script = "history.pushState({}, 'page 1', 'simple_page_1.html')"; + EXPECT_TRUE(ExecuteScriptWithoutUserGesture(root->child_at(0), script)); + + NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>( + shell()->web_contents()->GetController()); + EXPECT_EQ(2, controller.GetCurrentEntryIndex()); + EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); + + EXPECT_FALSE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui()); + EXPECT_FALSE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui()); + EXPECT_FALSE(controller.GetEntryAtIndex(2)->should_skip_on_back_forward_ui()); + histograms.ExpectBucketCount( + "Navigation.BackForward.SetShouldSkipOnBackForwardUI", true, 0); +} + // Tests that a same document navigation followed by a client redirect // do not add any more session history entries and going to previous entry // works.
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc index af289a0..b16bcd8 100644 --- a/content/browser/frame_host/navigator_impl.cc +++ b/content/browser/frame_host/navigator_impl.cc
@@ -221,7 +221,7 @@ // Save the activation status of the previous page here before it gets reset // in FrameTreeNode::ResetForNavigation. - bool previous_document_was_activated = frame_tree_node->HasBeenActivated(); + bool previous_document_was_activated = frame_tree->root()->HasBeenActivated(); // Navigating to a new location means a new, fresh set of http headers and/or // <meta> elements - we need to reset CSP and Feature Policy.
diff --git a/content/browser/indexed_db/database_impl.cc b/content/browser/indexed_db/database_impl.cc index 39f7264..a0b478f 100644 --- a/content/browser/indexed_db/database_impl.cc +++ b/content/browser/indexed_db/database_impl.cc
@@ -71,6 +71,13 @@ if (!transaction) return; + if (transaction->mode() != blink::mojom::IDBTransactionMode::VersionChange) { + mojo::ReportBadMessage( + "RenameObjectStore must be called from a version change transaction."); + } + + // Note: This doesn't schedule a task on the transaction because version + // change transactions pre-start in the OpenRequest inside IndexedDBDatabase. connection_->database()->RenameObjectStore(transaction, object_store_id, new_name); } @@ -209,6 +216,11 @@ if (!transaction) return; + if (transaction->mode() != blink::mojom::IDBTransactionMode::VersionChange) { + mojo::ReportBadMessage( + "SetIndexKeys must be called from a version change transaction."); + } + connection_->database()->SetIndexKeys( transaction, object_store_id, std::make_unique<IndexedDBKey>(primary_key), index_keys); @@ -226,6 +238,11 @@ if (!transaction) return; + if (transaction->mode() != blink::mojom::IDBTransactionMode::VersionChange) { + mojo::ReportBadMessage( + "SetIndexesReady must be called from a version change transaction."); + } + connection_->database()->SetIndexesReady(transaction, object_store_id, index_ids); } @@ -251,6 +268,13 @@ if (!transaction) return; + if (transaction->mode() != blink::mojom::IDBTransactionMode::VersionChange && + task_type == blink::mojom::IDBTaskType::Preemptive) { + mojo::ReportBadMessage( + "OpenCursor with |Preemptive| task type must be called from a version " + "change transaction."); + } + connection_->database()->OpenCursor( transaction, object_store_id, index_id, std::make_unique<IndexedDBKeyRange>(key_range), direction, key_only, @@ -357,6 +381,11 @@ if (!transaction) return; + if (transaction->mode() != blink::mojom::IDBTransactionMode::VersionChange) { + mojo::ReportBadMessage( + "CreateIndex must be called from a version change transaction."); + } + connection_->database()->CreateIndex(transaction, object_store_id, index_id, name, key_path, unique, multi_entry); } @@ -373,6 +402,11 @@ if (!transaction) return; + if (transaction->mode() != blink::mojom::IDBTransactionMode::VersionChange) { + mojo::ReportBadMessage( + "DeleteIndex must be called from a version change transaction."); + } + connection_->database()->DeleteIndex(transaction, object_store_id, index_id); } @@ -389,6 +423,11 @@ if (!transaction) return; + if (transaction->mode() != blink::mojom::IDBTransactionMode::VersionChange) { + mojo::ReportBadMessage( + "RenameIndex must be called from a version change transaction."); + } + connection_->database()->RenameIndex(transaction, object_store_id, index_id, new_name); }
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc index 22702e6..5cec6415 100644 --- a/content/browser/indexed_db/indexed_db_database.cc +++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -271,7 +271,6 @@ blink::mojom::IDBTransactionMode::VersionChange, new IndexedDBBackingStore::Transaction(db_->backing_store())); - // Create transaction binding. std::move(pending_->create_transaction_callback) .Run(transaction->AsWeakPtr()); @@ -609,6 +608,11 @@ // Store creation is done synchronously, as it may be followed by // index creation (also sync) since preemptive OpenCursor/SetIndexKeys // may follow. + + // TODO(dmurph): Remove this call once this method is asynchronous (scheduled + // on the transaction). + transaction->EnsureBackingStoreTransactionBegun(); + IndexedDBObjectStoreMetadata object_store_metadata; Status s = metadata_coding_->CreateObjectStore( transaction->BackingStoreTransaction()->transaction(), @@ -698,10 +702,14 @@ UMA_HISTOGRAM_BOOLEAN("WebCore.IndexedDB.Schema.Index.MultiEntry", multi_entry); + // TODO(dmurph): Remove this call once this method is asynchronous (scheduled + // on the transaction). + transaction->EnsureBackingStoreTransactionBegun(); + // Index creation is done synchronously since preemptive // OpenCursor/SetIndexKeys may follow. + // TODO(dmurph): Make this asynchronous. IndexedDBIndexMetadata index_metadata; - Status s = metadata_coding_->CreateIndex( transaction->BackingStoreTransaction()->transaction(), transaction->database()->id(), object_store_id, index_id, name, key_path, @@ -748,8 +756,8 @@ int64_t object_store_id, int64_t index_id, IndexedDBTransaction* transaction) { - IDB_TRACE1( - "IndexedDBDatabase::DeleteIndexOperation", "txn.id", transaction->id()); + IDB_TRACE1("IndexedDBDatabase::DeleteIndexOperation", "txn.id", + transaction->id()); IndexedDBIndexMetadata index_metadata = RemoveIndex(object_store_id, index_id); @@ -796,9 +804,13 @@ if (!ValidateObjectStoreIdAndIndexId(object_store_id, index_id)) return; + // TODO(dmurph): Remove this call once this method is asynchronous (scheduled + // on the transaction). + transaction->EnsureBackingStoreTransactionBegun(); + // Index renaming is done synchronously since preemptive // OpenCursor/SetIndexKeys may follow. - + // TODO(dmurph): Make this asynchronous. IndexedDBIndexMetadata& index_metadata = metadata_.object_stores[object_store_id].indexes[index_id]; @@ -1001,15 +1013,11 @@ key = &backing_store_cursor->key(); } - std::unique_ptr<IndexedDBKey> primary_key; if (index_id == IndexedDBIndexMetadata::kInvalidId) { // Object Store Retrieval Operation IndexedDBReturnValue value; - s = backing_store_->GetRecord(transaction->BackingStoreTransaction(), - id(), - object_store_id, - *key, - &value); + s = backing_store_->GetRecord(transaction->BackingStoreTransaction(), id(), + object_store_id, *key, &value); if (!s.ok()) return s; @@ -1034,13 +1042,10 @@ } // From here we are dealing only with indexes. + std::unique_ptr<IndexedDBKey> primary_key; s = backing_store_->GetPrimaryKeyViaIndex( - transaction->BackingStoreTransaction(), - id(), - object_store_id, - index_id, - *key, - &primary_key); + transaction->BackingStoreTransaction(), id(), object_store_id, index_id, + *key, &primary_key); if (!s.ok()) return s; @@ -1056,11 +1061,8 @@ // Index Referenced Value Retrieval Operation IndexedDBReturnValue value; - s = backing_store_->GetRecord(transaction->BackingStoreTransaction(), - id(), - object_store_id, - *primary_key, - &value); + s = backing_store_->GetRecord(transaction->BackingStoreTransaction(), id(), + object_store_id, *primary_key, &value); if (!s.ok()) return s; @@ -1342,16 +1344,10 @@ std::vector<std::unique_ptr<IndexWriter>> index_writers; base::string16 error_message; bool obeys_constraints = false; - bool backing_store_success = MakeIndexWriters(transaction, - backing_store_.get(), - id(), - object_store, - *key, - key_was_generated, - params->index_keys, - &index_writers, - &error_message, - &obeys_constraints); + bool backing_store_success = + MakeIndexWriters(transaction, backing_store_.get(), id(), object_store, + *key, key_was_generated, params->index_keys, + &index_writers, &error_message, &obeys_constraints); if (!backing_store_success) { params->callbacks->OnError( CreateError(blink::kWebIDBDatabaseExceptionUnknownError, @@ -1420,8 +1416,12 @@ DCHECK_EQ(transaction->mode(), blink::mojom::IDBTransactionMode::VersionChange); - // TODO(alecflett): This method could be asynchronous, but we need to - // evaluate if it's worth the extra complexity. + // TODO(dmurph): Remove this call once this method is asynchronous (scheduled + // on the transaction). + transaction->EnsureBackingStoreTransactionBegun(); + + // TODO(dmurph): This methods should be turned asynchronous, and not rely on + // the renderer to have matching calls to OpenCursor and SetIndexedsReady. IndexedDBBackingStore::RecordIdentifier record_identifier; bool found = false; Status s = backing_store_->KeyExistsInObjectStore( @@ -1445,16 +1445,10 @@ metadata_.object_stores.end()); const IndexedDBObjectStoreMetadata& object_store_metadata = metadata_.object_stores[object_store_id]; - bool backing_store_success = MakeIndexWriters(transaction, - backing_store_.get(), - id(), - object_store_metadata, - *primary_key, - false, - index_keys, - &index_writers, - &error_message, - &obeys_constraints); + bool backing_store_success = + MakeIndexWriters(transaction, backing_store_.get(), id(), + object_store_metadata, *primary_key, false, index_keys, + &index_writers, &error_message, &obeys_constraints); if (!backing_store_success) { transaction->Abort(IndexedDBDatabaseError( blink::kWebIDBDatabaseExceptionUnknownError, @@ -1490,6 +1484,8 @@ Status IndexedDBDatabase::SetIndexesReadyOperation( size_t index_count, IndexedDBTransaction* transaction) { + // TODO(dmurph): This method should be refactored out for something more + // reliable. for (size_t i = 0; i < index_count; ++i) transaction->DidCompletePreemptiveEvent(); return Status::OK(); @@ -1541,8 +1537,8 @@ Status IndexedDBDatabase::OpenCursorOperation( std::unique_ptr<OpenCursorOperationParams> params, IndexedDBTransaction* transaction) { - IDB_TRACE1( - "IndexedDBDatabase::OpenCursorOperation", "txn.id", transaction->id()); + IDB_TRACE1("IndexedDBDatabase::OpenCursorOperation", "txn.id", + transaction->id()); // The frontend has begun indexing, so this pauses the transaction // until the indexing is complete. This can't happen any earlier @@ -1557,41 +1553,23 @@ if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) { DCHECK_EQ(params->task_type, blink::mojom::IDBTaskType::Normal); backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor( - transaction->BackingStoreTransaction(), - id(), - params->object_store_id, - *params->key_range, - params->direction, - &s); + transaction->BackingStoreTransaction(), id(), params->object_store_id, + *params->key_range, params->direction, &s); } else { backing_store_cursor = backing_store_->OpenObjectStoreCursor( - transaction->BackingStoreTransaction(), - id(), - params->object_store_id, - *params->key_range, - params->direction, - &s); + transaction->BackingStoreTransaction(), id(), params->object_store_id, + *params->key_range, params->direction, &s); } } else { DCHECK_EQ(params->task_type, blink::mojom::IDBTaskType::Normal); if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) { backing_store_cursor = backing_store_->OpenIndexKeyCursor( - transaction->BackingStoreTransaction(), - id(), - params->object_store_id, - params->index_id, - *params->key_range, - params->direction, - &s); + transaction->BackingStoreTransaction(), id(), params->object_store_id, + params->index_id, *params->key_range, params->direction, &s); } else { backing_store_cursor = backing_store_->OpenIndexCursor( - transaction->BackingStoreTransaction(), - id(), - params->object_store_id, - params->index_id, - *params->key_range, - params->direction, - &s); + transaction->BackingStoreTransaction(), id(), params->object_store_id, + params->index_id, *params->key_range, params->direction, &s); } } @@ -1777,8 +1755,7 @@ Status IndexedDBDatabase::DeleteObjectStoreOperation( int64_t object_store_id, IndexedDBTransaction* transaction) { - IDB_TRACE1("IndexedDBDatabase::DeleteObjectStoreOperation", - "txn.id", + IDB_TRACE1("IndexedDBDatabase::DeleteObjectStoreOperation", "txn.id", transaction->id()); IndexedDBObjectStoreMetadata object_store_metadata = @@ -1815,8 +1792,8 @@ int64_t version, scoped_refptr<IndexedDBCallbacks> callbacks, IndexedDBTransaction* transaction) { - IDB_TRACE1( - "IndexedDBDatabase::VersionChangeOperation", "txn.id", transaction->id()); + IDB_TRACE1("IndexedDBDatabase::VersionChangeOperation", "txn.id", + transaction->id()); int64_t old_version = metadata_.version; DCHECK_GT(version, old_version);
diff --git a/content/browser/indexed_db/indexed_db_database.h b/content/browser/indexed_db/indexed_db_database.h index f7f669d..5622190 100644 --- a/content/browser/indexed_db/indexed_db_database.h +++ b/content/browser/indexed_db/indexed_db_database.h
@@ -219,6 +219,7 @@ // Asynchronous tasks scheduled within transactions: void CreateObjectStoreAbortOperation(int64_t object_store_id); + leveldb::Status DeleteObjectStoreOperation(int64_t object_store_id, IndexedDBTransaction* transaction); void DeleteObjectStoreAbortOperation(
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.cc b/content/browser/indexed_db/indexed_db_factory_impl.cc index daec254..416401a4 100644 --- a/content/browser/indexed_db/indexed_db_factory_impl.cc +++ b/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -739,9 +739,9 @@ } for (base::string16& name : db_names) { - const scoped_refptr<IndexedDBDatabase>& db = - database_map_[std::make_pair(origin, name)]; - db->AbortAllTransactionsForConnections(); + auto database_it = database_map_.find(std::make_pair(origin, name)); + if (database_it != database_map_.end()) + database_it->second->AbortAllTransactionsForConnections(); } return leveldb::Status::OK();
diff --git a/content/browser/indexed_db/indexed_db_leveldb_operations.cc b/content/browser/indexed_db/indexed_db_leveldb_operations.cc index fbcde08..e11fb15 100644 --- a/content/browser/indexed_db/indexed_db_leveldb_operations.cc +++ b/content/browser/indexed_db/indexed_db_leveldb_operations.cc
@@ -410,7 +410,7 @@ } if (object_store_id <= max_object_store_id) { - INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_MAX_OBJECT_STORE_ID); + INTERNAL_CONSISTENCY_ERROR(SET_MAX_OBJECT_STORE_ID); return indexed_db::InternalInconsistencyStatus(); } indexed_db::PutInt(transaction, max_object_store_id_key, object_store_id);
diff --git a/content/browser/indexed_db/indexed_db_metadata_coding.cc b/content/browser/indexed_db/indexed_db_metadata_coding.cc index 98371afd..954db45 100644 --- a/content/browser/indexed_db/indexed_db_metadata_coding.cc +++ b/content/browser/indexed_db/indexed_db_metadata_coding.cc
@@ -591,6 +591,7 @@ IndexedDBKeyPath key_path, bool auto_increment, IndexedDBObjectStoreMetadata* metadata) { + DCHECK(transaction); if (!KeyPrefix::ValidIds(database_id, object_store_id)) return InvalidDBKeyStatus(); Status s = indexed_db::SetMaxObjectStoreId(transaction, database_id,
diff --git a/content/browser/indexed_db/indexed_db_transaction.cc b/content/browser/indexed_db/indexed_db_transaction.cc index 3db0dcc..9e010f6 100644 --- a/content/browser/indexed_db/indexed_db_transaction.cc +++ b/content/browser/indexed_db/indexed_db_transaction.cc
@@ -293,6 +293,12 @@ RunTasksIfStarted(); } +void IndexedDBTransaction::EnsureBackingStoreTransactionBegun() { + if (!backing_store_transaction_begun_) { + transaction_->Begin(); + backing_store_transaction_begun_ = true; + } +} class BlobWriteCallbackImpl : public IndexedDBBackingStore::BlobWriteCallback { public: @@ -491,6 +497,8 @@ } callbacks_->OnAbort(*this, error); database_->TransactionFinished(mode_, false); + // RemoveTransaction will delete |this|. + connection_->RemoveTransaction(id_); } return s; } @@ -509,10 +517,7 @@ DCHECK(!IsTaskQueueEmpty()); should_process_queue_ = false; - if (!backing_store_transaction_begun_) { - transaction_->Begin(); - backing_store_transaction_begun_ = true; - } + EnsureBackingStoreTransactionBegun(); TaskQueue* task_queue = pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
diff --git a/content/browser/indexed_db/indexed_db_transaction.h b/content/browser/indexed_db/indexed_db_transaction.h index ae99873..b01ee8c 100644 --- a/content/browser/indexed_db/indexed_db_transaction.h +++ b/content/browser/indexed_db/indexed_db_transaction.h
@@ -99,6 +99,8 @@ void AddObservation(int32_t connection_id, blink::mojom::IDBObservationPtr observation); + void EnsureBackingStoreTransactionBegun(); + blink::mojom::IDBObserverChangesPtr* GetPendingChangesForConnection( int32_t connection_id);
diff --git a/content/browser/indexed_db/transaction_impl.cc b/content/browser/indexed_db/transaction_impl.cc index b65adc9..8ba3fc3f 100644 --- a/content/browser/indexed_db/transaction_impl.cc +++ b/content/browser/indexed_db/transaction_impl.cc
@@ -96,10 +96,17 @@ if (!transaction_) return; + if (transaction_->mode() != blink::mojom::IDBTransactionMode::VersionChange) { + mojo::ReportBadMessage( + "CreateObjectStore must be called from a version change transaction."); + } + IndexedDBConnection* connection = transaction_->connection(); if (!connection->IsConnected()) return; + // Note: This doesn't schedule a task on the transaction because the + // SetIndexKeys call path isn't asynchronous. connection->database()->CreateObjectStore(transaction_.get(), object_store_id, name, key_path, auto_increment); } @@ -109,6 +116,11 @@ if (!transaction_) return; + if (transaction_->mode() != blink::mojom::IDBTransactionMode::VersionChange) { + mojo::ReportBadMessage( + "DeleteObjectStore must be called from a version change transaction."); + } + IndexedDBConnection* connection = transaction_->connection(); if (!connection->IsConnected()) return;
diff --git a/content/public/android/java/src/org/chromium/content/browser/BindingManager.java b/content/public/android/java/src/org/chromium/content/browser/BindingManager.java index 75e5dc7..ea7e4cf 100644 --- a/content/public/android/java/src/org/chromium/content/browser/BindingManager.java +++ b/content/public/android/java/src/org/chromium/content/browser/BindingManager.java
@@ -10,6 +10,7 @@ import android.support.v4.util.ArraySet; import org.chromium.base.Log; +import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.process_launcher.ChildProcessConnection; @@ -144,19 +145,14 @@ LauncherThread.removeCallbacks(mDelayedClearer); } - // Whether this instance is used on testing. - private final boolean mOnTesting; - /** * The constructor is private to hide parameters exposed for testing from the regular consumer. * Use factory methods to create an instance. */ - BindingManager(Context context, int maxSize, Iterable<ChildProcessConnection> ranking, - boolean onTesting) { + BindingManager(Context context, int maxSize, Iterable<ChildProcessConnection> ranking) { assert LauncherThread.runningOnLauncherThread(); Log.i(TAG, "Moderate binding enabled: maxSize=%d", maxSize); - mOnTesting = onTesting; mMaxSize = maxSize; mRanking = ranking; assert mMaxSize > 0; @@ -165,7 +161,9 @@ @Override public void run() { Log.i(TAG, "Release moderate connections: %d", mConnections.size()); - if (!mOnTesting) { + // Tests may not load the native library which is required for + // recording histograms. + if (LibraryLoader.getInstance().isInitialized()) { RecordHistogram.recordCountHistogram( "Android.ModerateBindingCount", mConnections.size()); }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java index e938cae..fc602f5 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelperImpl.java
@@ -273,8 +273,8 @@ public void run() { ChildConnectionAllocator allocator = getConnectionAllocator(context, true /* sandboxed */); - sBindingManager = new BindingManager(context, allocator.getNumberOfServices(), - sSandboxedChildConnectionRanking, false /* onTesting */); + sBindingManager = new BindingManager( + context, allocator.getNumberOfServices(), sSandboxedChildConnectionRanking); } });
diff --git a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerTest.java b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerTest.java index 90574d52..46b9bf2 100644 --- a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerTest.java +++ b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerTest.java
@@ -68,7 +68,7 @@ LauncherThread.setCurrentThreadAsLauncherThread(); mActivity = Robolectric.buildActivity(Activity.class).setup().get(); mIterable = new ArrayList<>(); - mManager = new BindingManager(mActivity, 4, mIterable, true); + mManager = new BindingManager(mActivity, 4, mIterable); } @After
diff --git a/content/public/browser/background_sync_controller.h b/content/public/browser/background_sync_controller.h index aee7dca..4bf2067 100644 --- a/content/public/browser/background_sync_controller.h +++ b/content/public/browser/background_sync_controller.h
@@ -9,11 +9,12 @@ #include "base/time/time.h" #include "content/common/content_export.h" +#include "third_party/blink/public/common/service_worker/service_worker_status_code.h" #include "third_party/blink/public/mojom/background_sync/background_sync.mojom-shared.h" namespace url { class Origin; -} +} // namespace url namespace content { @@ -32,8 +33,21 @@ BackgroundSyncParameters* parameters) const {} // Notification that a service worker registration with origin |origin| just - // registered a background sync event. - virtual void NotifyBackgroundSyncRegistered(const url::Origin& origin) {} + // registered a background sync event. Also includes information about the + // registration. + virtual void NotifyBackgroundSyncRegistered(const url::Origin& origin, + bool can_fire, + bool is_reregistered) {} + + // Notification that a service worker registration with origin |origin| just + // completed a background sync registration. Also include the |status_code| + // the registration finished with, the number of attempts, and the max + // allowed number of attempts. + virtual void NotifyBackgroundSyncCompleted( + const url::Origin& origin, + blink::ServiceWorkerStatusCode status_code, + int num_attempts, + int max_attempts) {} // Calculates the soonest wakeup delta across all storage partitions and // schedules a background task to wake up the browser.
diff --git a/content/public/browser/browser_accessibility_state.h b/content/public/browser/browser_accessibility_state.h index 484214b..389acd3 100644 --- a/content/public/browser/browser_accessibility_state.h +++ b/content/public/browser/browser_accessibility_state.h
@@ -56,7 +56,14 @@ // browser starts up, when accessibility state histograms are updated. // Use this to register a method to update additional accessibility // histograms. - virtual void AddHistogramCallback(base::Closure callback) = 0; + // + // Use this variant for a callback that must be run on the UI thread, + // for example something that needs to access prefs. + virtual void AddUIThreadHistogramCallback(base::OnceClosure callback) = 0; + + // Use this variant for a callback that's better to run on another + // thread, for example something that may block or run slowly. + virtual void AddOtherThreadHistogramCallback(base::OnceClosure callback) = 0; virtual void UpdateHistogramsForTesting() = 0; };
diff --git a/content/shell/browser/shell_browser_context.cc b/content/shell/browser/shell_browser_context.cc index b5d8a834..245c443 100644 --- a/content/shell/browser/shell_browser_context.cc +++ b/content/shell/browser/shell_browser_context.cc
@@ -16,6 +16,8 @@ #include "base/threading/thread.h" #include "build/build_config.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/keyed_service/core/simple_key_map.h" +#include "components/keyed_service/core/test_simple_factory_key.h" #include "components/network_session_configurator/common/network_switches.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -63,6 +65,9 @@ BrowserContextDependencyManager::GetInstance()-> DestroyBrowserContextServices(this); + + SimpleKeyMap::GetInstance()->Dissociate(this); + // Need to destruct the ResourceContext before posting tasks which may delete // the URLRequestContext because ResourceContext's destructor will remove any // outstanding request while URLRequestContext's destructor ensures that there @@ -92,7 +97,7 @@ if (!path_.IsAbsolute()) path_ = base::MakeAbsoluteFilePath(path_); if (!path_.empty()) { - BrowserContext::Initialize(this, path_); + FinishInitWhileIOAllowed(); return; } } else { @@ -125,7 +130,14 @@ if (!base::PathExists(path_)) base::CreateDirectory(path_); + + FinishInitWhileIOAllowed(); +} + +void ShellBrowserContext::FinishInitWhileIOAllowed() { BrowserContext::Initialize(this, path_); + key_ = std::make_unique<TestSimpleFactoryKey>(path_, off_the_record_); + SimpleKeyMap::GetInstance()->Associate(this, key_.get()); } #if !defined(OS_ANDROID)
diff --git a/content/shell/browser/shell_browser_context.h b/content/shell/browser/shell_browser_context.h index d85b99d..f5b44e2 100644 --- a/content/shell/browser/shell_browser_context.h +++ b/content/shell/browser/shell_browser_context.h
@@ -17,6 +17,8 @@ #include "content/shell/browser/shell_url_request_context_getter.h" #include "net/url_request/url_request_job_factory.h" +class SimpleFactoryKey; + namespace net { class NetLog; } @@ -112,6 +114,7 @@ // Performs initialization of the ShellBrowserContext while IO is still // allowed on the current thread. void InitWhileIOAllowed(); + void FinishInitWhileIOAllowed(); bool ignore_certificate_errors_; bool off_the_record_; @@ -121,6 +124,7 @@ scoped_refptr<ShellURLRequestContextGetter> url_request_getter_; std::map<base::FilePath, scoped_refptr<ShellURLRequestContextGetter>> isolated_url_request_getters_; + std::unique_ptr<SimpleFactoryKey> key_; DISALLOW_COPY_AND_ASSIGN(ShellBrowserContext); };
diff --git a/content/shell/browser/web_test/web_test_background_fetch_delegate.cc b/content/shell/browser/web_test/web_test_background_fetch_delegate.cc index 931aec6..f994de3 100644 --- a/content/shell/browser/web_test/web_test_background_fetch_delegate.cc +++ b/content/shell/browser/web_test/web_test_background_fetch_delegate.cc
@@ -17,6 +17,7 @@ #include "components/download/public/background_service/download_params.h" #include "components/download/public/background_service/download_service.h" #include "components/download/public/background_service/features.h" +#include "components/keyed_service/core/simple_key_map.h" #include "components/keyed_service/core/test_simple_factory_key.h" #include "content/public/browser/background_fetch_description.h" #include "content/public/browser/background_fetch_response.h" @@ -251,12 +252,12 @@ BrowserContext::GetDefaultStoragePartition(browser_context_) ->GetURLLoaderFactoryForBrowserProcess() .get(); - simple_factory_key_ = std::make_unique<TestSimpleFactoryKey>( - browser_context_->GetPath(), browser_context_->IsOffTheRecord()); + SimpleFactoryKey* simple_key = + SimpleKeyMap::GetInstance()->GetForBrowserContext(browser_context_); download_service_ = base::WrapUnique(download::BuildInMemoryDownloadService( - simple_factory_key_.get(), std::move(clients), - GetNetworkConnectionTracker(), base::FilePath(), + simple_key, std::move(clients), GetNetworkConnectionTracker(), + base::FilePath(), BrowserContext::GetBlobStorageContext(browser_context_), base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}), url_loader_factory));
diff --git a/content/test/data/gpu/webgl2_conformance_tests_output.json b/content/test/data/gpu/webgl2_conformance_tests_output.json index 148393f..9bed7b2 100644 --- a/content/test/data/gpu/webgl2_conformance_tests_output.json +++ b/content/test/data/gpu/webgl2_conformance_tests_output.json
@@ -1,2725 +1,2759 @@ { "times": { - "WebglConformance_conformance2_attribs_gl_vertex_attrib": 1.2771, - "WebglConformance_conformance2_attribs_gl_vertex_attrib_i_render": 1.2651, - "WebglConformance_conformance2_attribs_gl_vertex_attrib_normalized_int": 1.3045, - "WebglConformance_conformance2_attribs_gl_vertexattribipointer": 2.1507, - "WebglConformance_conformance2_attribs_gl_vertexattribipointer_offsets": 3.4749, - "WebglConformance_conformance2_buffers_bound_buffer_size_change_test": 0.9629, - "WebglConformance_conformance2_buffers_buffer_copying_contents": 0.193, - "WebglConformance_conformance2_buffers_buffer_copying_restrictions": 0.1279, - "WebglConformance_conformance2_buffers_buffer_data_and_buffer_sub_data_sub_source": 1.115, - "WebglConformance_conformance2_buffers_buffer_overflow_test": 0.0562, - "WebglConformance_conformance2_buffers_buffer_type_restrictions": 0.2218, - "WebglConformance_conformance2_buffers_get_buffer_sub_data": 1.3289, - "WebglConformance_conformance2_buffers_one_large_uniform_buffer": 0.1274, - "WebglConformance_conformance2_buffers_uniform_buffers": 1.4102, - "WebglConformance_conformance2_buffers_uniform_buffers_second_compile": 0.0576, - "WebglConformance_conformance2_buffers_uniform_buffers_state_restoration": 0.1626, - "WebglConformance_conformance2_canvas_to_data_url_with_pack_params": 1.1473, - "WebglConformance_conformance2_context_constants_and_properties_2": 1.0001, - "WebglConformance_conformance2_context_context_attributes_depth_stencil_antialias_obeyed": 0.1599, - "WebglConformance_conformance2_context_context_resize_changes_buffer_binding_bug": 0.0723, - "WebglConformance_conformance2_context_context_type_test_2": 1.3136, - "WebglConformance_conformance2_context_methods_2": 0.0798, - "WebglConformance_conformance2_context_no_experimental_webgl2": 0.9074, - "WebglConformance_conformance2_extensions_ext_color_buffer_float": 1.1959, - "WebglConformance_conformance2_extensions_ext_disjoint_timer_query_webgl2": 4.3499, - "WebglConformance_conformance2_extensions_promoted_extensions": 0.0576, - "WebglConformance_conformance2_extensions_promoted_extensions_in_shaders": 0.2679, - "WebglConformance_conformance2_glsl3_array_as_return_value": 0.2149, - "WebglConformance_conformance2_glsl3_array_assign": 0.2059, - "WebglConformance_conformance2_glsl3_array_assign_constructor": 0.1988, - "WebglConformance_conformance2_glsl3_array_complex_indexing": 0.2026, - "WebglConformance_conformance2_glsl3_array_element_increment": 0.203, - "WebglConformance_conformance2_glsl3_array_equality": 0.2363, - "WebglConformance_conformance2_glsl3_array_in_complex_expression": 0.2313, - "WebglConformance_conformance2_glsl3_array_initialize_with_same_name_array": 0.0603, - "WebglConformance_conformance2_glsl3_array_length_side_effects": 0.213, - "WebglConformance_conformance2_glsl3_attrib_location_length_limits": 1.0087, - "WebglConformance_conformance2_glsl3_bool_type_cast_bug_uint_ivec_uvec": 0.1677, - "WebglConformance_conformance2_glsl3_compare_structs_containing_arrays": 0.2009, - "WebglConformance_conformance2_glsl3_compound_assignment_type_combination": 2.6949, - "WebglConformance_conformance2_glsl3_const_array_init": 0.1652, - "WebglConformance_conformance2_glsl3_float_parsing": 0.2218, - "WebglConformance_conformance2_glsl3_forbidden_operators": 0.1509, - "WebglConformance_conformance2_glsl3_frag_depth": 0.0644, - "WebglConformance_conformance2_glsl3_gradient_in_discontinuous_loop": 0.0561, - "WebglConformance_conformance2_glsl3_input_with_interpotaion_as_lvalue": 0.1482, - "WebglConformance_conformance2_glsl3_invalid_default_precision": 0.1475, - "WebglConformance_conformance2_glsl3_invalid_invariant": 0.0709, - "WebglConformance_conformance2_glsl3_loops_with_side_effects": 0.1893, - "WebglConformance_conformance2_glsl3_misplaced_version_directive": 0.1751, - "WebglConformance_conformance2_glsl3_no_attribute_vertex_shader": 0.0609, - "WebglConformance_conformance2_glsl3_sampler_no_precision": 0.2561, - "WebglConformance_conformance2_glsl3_sequence_operator_returns_non_constant": 0.0521, - "WebglConformance_conformance2_glsl3_shader_linking": 0.1507, - "WebglConformance_conformance2_glsl3_shader_with_1024_character_define": 0.0673, - "WebglConformance_conformance2_glsl3_shader_with_1024_character_identifier_frag": 0.1583, - "WebglConformance_conformance2_glsl3_shader_with_1025_character_define": 0.0468, - "WebglConformance_conformance2_glsl3_shader_with_1025_character_identifier_frag": 0.047, - "WebglConformance_conformance2_glsl3_shader_with_invalid_characters": 0.0543, - "WebglConformance_conformance2_glsl3_shader_with_mis_matching_uniform_block": 0.047, - "WebglConformance_conformance2_glsl3_short_circuiting_in_loop_condition": 0.2193, - "WebglConformance_conformance2_glsl3_texture_offset_out_of_range": 0.1624, - "WebglConformance_conformance2_glsl3_texture_offset_uniform_texture_coordinate": 0.1685, - "WebglConformance_conformance2_glsl3_tricky_loop_conditions": 6.6889, - "WebglConformance_conformance2_glsl3_unary_minus_operator_in_dynamic_loop": 0.201, - "WebglConformance_conformance2_glsl3_uniform_block_layout_match": 0.0525, - "WebglConformance_conformance2_glsl3_uniform_block_layouts": 0.9754, - "WebglConformance_conformance2_glsl3_uniform_location_length_limits": 0.0621, - "WebglConformance_conformance2_glsl3_uniform_struct_with_non_square_matrix": 0.103, - "WebglConformance_conformance2_glsl3_uninitialized_local_global_variables": 0.0905, - "WebglConformance_conformance2_glsl3_valid_invariant": 0.1645, - "WebglConformance_conformance2_glsl3_vector_dynamic_indexing": 0.3382, - "WebglConformance_conformance2_glsl3_vector_dynamic_indexing_nv_driver_bug": 5.9845, - "WebglConformance_conformance2_glsl3_vector_dynamic_indexing_swizzled_lvalue": 7.3692, - "WebglConformance_conformance2_misc_expando_loss_2": 0.2508, - "WebglConformance_conformance2_misc_getextension_while_pbo_bound_stability": 0.0787, - "WebglConformance_conformance2_misc_instanceof_test": 0.088, - "WebglConformance_conformance2_misc_object_deletion_behaviour_2": 0.0881, - "WebglConformance_conformance2_misc_uninitialized_test_2": 9.4902, - "WebglConformance_conformance2_misc_views_with_offsets": 0.2256, - "WebglConformance_conformance2_offscreencanvas_context_creation": 0.0501, - "WebglConformance_conformance2_offscreencanvas_context_creation_worker": 0.1414, - "WebglConformance_conformance2_offscreencanvas_methods_2": 0.0429, - "WebglConformance_conformance2_offscreencanvas_methods_2_worker": 0.1562, - "WebglConformance_conformance2_offscreencanvas_offscreencanvas_transfer_image_bitmap": 0.1382, - "WebglConformance_conformance2_programs_active_built_in_attribs": 0.121, - "WebglConformance_conformance2_programs_gl_get_frag_data_location": 0.153, - "WebglConformance_conformance2_programs_sampler_uniforms": 0.0897, - "WebglConformance_conformance2_query_occlusion_query": 2.2758, - "WebglConformance_conformance2_query_query": 0.0519, - "WebglConformance_conformance2_reading_format_r11f_g11f_b10f": 16.0263, - "WebglConformance_conformance2_reading_read_pixels_from_fbo_test": 0.1879, - "WebglConformance_conformance2_reading_read_pixels_from_rgb8_into_pbo_bug": 0.0758, - "WebglConformance_conformance2_reading_read_pixels_into_pixel_pack_buffer": 0.1207, - "WebglConformance_conformance2_reading_read_pixels_pack_parameters": 0.244, - "WebglConformance_conformance2_renderbuffers_framebuffer_object_attachment": 0.0916, - "WebglConformance_conformance2_renderbuffers_framebuffer_test": 0.0567, - "WebglConformance_conformance2_renderbuffers_framebuffer_texture_layer": 0.0494, - "WebglConformance_conformance2_renderbuffers_invalidate_framebuffer": 0.0563, - "WebglConformance_conformance2_renderbuffers_multisample_with_full_sample_counts": 0.1437, - "WebglConformance_conformance2_renderbuffers_multisampled_depth_renderbuffer_initialization": 0.1534, - "WebglConformance_conformance2_renderbuffers_multisampled_renderbuffer_initialization": 0.1667, - "WebglConformance_conformance2_renderbuffers_readbuffer": 0.0547, - "WebglConformance_conformance2_rendering_attrib_type_match": 0.2, - "WebglConformance_conformance2_rendering_blitframebuffer_filter_outofbounds": 0.2066, - "WebglConformance_conformance2_rendering_blitframebuffer_filter_srgb": 0.0798, - "WebglConformance_conformance2_rendering_blitframebuffer_multisampled_readbuffer": 0.0547, - "WebglConformance_conformance2_rendering_blitframebuffer_outside_readbuffer": 0.0702, - "WebglConformance_conformance2_rendering_blitframebuffer_r11f_g11f_b10f": 0.1603, - "WebglConformance_conformance2_rendering_blitframebuffer_resolve_to_back_buffer": 0.1998, - "WebglConformance_conformance2_rendering_blitframebuffer_scissor_enabled": 0.1118, - "WebglConformance_conformance2_rendering_blitframebuffer_size_overflow": 0.0624, - "WebglConformance_conformance2_rendering_blitframebuffer_srgb_and_linear_drawbuffers": 0.1438, - "WebglConformance_conformance2_rendering_blitframebuffer_stencil_only": 0.048, - "WebglConformance_conformance2_rendering_blitframebuffer_test": 0.1165, - "WebglConformance_conformance2_rendering_canvas_resizing_with_pbo_bound": 0.29, - "WebglConformance_conformance2_rendering_clear_func_buffer_type_match": 0.0897, - "WebglConformance_conformance2_rendering_clear_srgb_color_buffer": 0.0523, - "WebglConformance_conformance2_rendering_clearbuffer_sub_source": 0.0545, - "WebglConformance_conformance2_rendering_clearbufferfv_with_alpha_false": 0.0832, - "WebglConformance_conformance2_rendering_clipping_wide_points": 0.0522, - "WebglConformance_conformance2_rendering_depth_stencil_feedback_loop": 6.0372, - "WebglConformance_conformance2_rendering_draw_buffers": 0.2019, - "WebglConformance_conformance2_rendering_draw_buffers_dirty_state_bug": 0.0537, - "WebglConformance_conformance2_rendering_draw_buffers_driver_hang": 0.1523, - "WebglConformance_conformance2_rendering_draw_with_integer_texture_base_level": 0.0659, - "WebglConformance_conformance2_rendering_element_index_uint": 0.1337, - "WebglConformance_conformance2_rendering_framebuffer_completeness_unaffected": 0.0456, - "WebglConformance_conformance2_rendering_framebuffer_texture_level1": 0.0693, - "WebglConformance_conformance2_rendering_framebuffer_unsupported": 0.053, - "WebglConformance_conformance2_rendering_fs_color_type_mismatch_color_buffer_type": 0.063, - "WebglConformance_conformance2_rendering_instanced_arrays": 0.1336, - "WebglConformance_conformance2_rendering_instanced_rendering_bug": 0.1367, - "WebglConformance_conformance2_rendering_multisampling_fragment_evaluation": 6.0613, - "WebglConformance_conformance2_rendering_out_of_bounds_index_buffers_after_copying": 0.1049, - "WebglConformance_conformance2_rendering_read_draw_when_missing_image": 0.0869, - "WebglConformance_conformance2_rendering_rendering_sampling_feedback_loop": 6.0428, - "WebglConformance_conformance2_rendering_rgb_format_support": 0.0627, - "WebglConformance_conformance2_rendering_texture_switch_performance": 0.0008, - "WebglConformance_conformance2_rendering_uniform_block_buffer_size": 0.171, - "WebglConformance_conformance2_samplers_multi_context_sampler_test": 0.1326, - "WebglConformance_conformance2_samplers_sampler_drawing_test": 0.8882, - "WebglConformance_conformance2_samplers_samplers": 0.1499, - "WebglConformance_conformance2_state_gl_enum_tests": 0.0788, - "WebglConformance_conformance2_state_gl_get_calls": 0.0876, - "WebglConformance_conformance2_state_gl_getstring": 0.0503, - "WebglConformance_conformance2_state_gl_object_get_calls": 18.025, - "WebglConformance_conformance2_sync_sync_webgl_specific": 0.0711, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_r11f_g11f_b10f_rgb_float": 0.6866, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_r11f_g11f_b10f_rgb_half_float": 0.7004, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.6887, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_r16f_red_float": 0.6778, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_r16f_red_half_float": 0.6667, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_r32f_red_float": 1.0895, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_r8_red_unsigned_byte": 0.6879, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_r8ui_red_integer_unsigned_byte": 1.2957, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rg16f_rg_float": 0.6383, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rg16f_rg_half_float": 0.7699, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rg32f_rg_float": 0.7517, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rg8_rg_unsigned_byte": 2.4407, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rg8ui_rg_integer_unsigned_byte": 0.451, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.7678, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb16f_rgb_float": 1.0506, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb16f_rgb_half_float": 2.1093, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb32f_rgb_float": 1.1926, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb565_rgb_unsigned_byte": 0.588, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 0.5631, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb5_a1_rgba_unsigned_byte": 0.7155, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.7321, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb8_rgb_unsigned_byte": 0.7367, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 0.5116, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb9_e5_rgb_float": 2.1477, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgb9_e5_rgb_half_float": 1.7073, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgba16f_rgba_float": 0.7476, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgba16f_rgba_half_float": 0.7706, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgba32f_rgba_float": 0.7372, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgba4_rgba_unsigned_byte": 0.7541, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 0.6231, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgba8_rgba_unsigned_byte": 1.2204, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 0.4981, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 1.1873, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_2d_srgb8_rgb_unsigned_byte": 0.8987, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_r11f_g11f_b10f_rgb_float": 1.0093, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_r11f_g11f_b10f_rgb_half_float": 0.9421, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.8369, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_r16f_red_float": 0.7869, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_r16f_red_half_float": 0.9325, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_r32f_red_float": 0.7813, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_r8_red_unsigned_byte": 0.9061, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_r8ui_red_integer_unsigned_byte": 0.7379, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rg16f_rg_float": 0.9833, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rg16f_rg_half_float": 0.8366, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rg32f_rg_float": 0.8514, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rg8_rg_unsigned_byte": 0.7849, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rg8ui_rg_integer_unsigned_byte": 0.7181, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.8802, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb16f_rgb_float": 0.8512, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb16f_rgb_half_float": 0.935, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb32f_rgb_float": 0.9292, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb565_rgb_unsigned_byte": 0.8164, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 0.8004, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb5_a1_rgba_unsigned_byte": 0.8517, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.82, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb8_rgb_unsigned_byte": 0.8999, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 0.9669, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb9_e5_rgb_float": 0.8991, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgb9_e5_rgb_half_float": 0.9224, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgba16f_rgba_float": 0.9016, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgba16f_rgba_half_float": 0.7585, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgba32f_rgba_float": 0.9331, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgba4_rgba_unsigned_byte": 0.7972, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 0.6991, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgba8_rgba_unsigned_byte": 0.8009, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 0.8352, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 0.8322, - "WebglConformance_conformance2_textures_canvas_sub_rectangle_tex_3d_srgb8_rgb_unsigned_byte": 0.8929, - "WebglConformance_conformance2_textures_canvas_tex_2d_r11f_g11f_b10f_rgb_float": 3.5631, - "WebglConformance_conformance2_textures_canvas_tex_2d_r11f_g11f_b10f_rgb_half_float": 3.3226, - "WebglConformance_conformance2_textures_canvas_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 3.5999, - "WebglConformance_conformance2_textures_canvas_tex_2d_r16f_red_float": 3.2862, - "WebglConformance_conformance2_textures_canvas_tex_2d_r16f_red_half_float": 3.3203, - "WebglConformance_conformance2_textures_canvas_tex_2d_r32f_red_float": 3.3207, - "WebglConformance_conformance2_textures_canvas_tex_2d_r8_red_unsigned_byte": 3.4569, - "WebglConformance_conformance2_textures_canvas_tex_2d_r8ui_red_integer_unsigned_byte": 3.3223, - "WebglConformance_conformance2_textures_canvas_tex_2d_rg16f_rg_float": 3.2481, - "WebglConformance_conformance2_textures_canvas_tex_2d_rg16f_rg_half_float": 3.2913, - "WebglConformance_conformance2_textures_canvas_tex_2d_rg32f_rg_float": 3.3196, - "WebglConformance_conformance2_textures_canvas_tex_2d_rg8_rg_unsigned_byte": 3.3174, - "WebglConformance_conformance2_textures_canvas_tex_2d_rg8ui_rg_integer_unsigned_byte": 3.4278, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 3.5001, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb16f_rgb_float": 3.3168, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb16f_rgb_half_float": 3.3, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb32f_rgb_float": 3.611, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb565_rgb_unsigned_byte": 3.2775, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 3.2944, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb5_a1_rgba_unsigned_byte": 3.4081, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 3.4487, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb8_rgb_unsigned_byte": 3.3144, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 3.3422, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb9_e5_rgb_float": 3.6635, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgb9_e5_rgb_half_float": 3.5347, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgba16f_rgba_float": 3.5257, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgba16f_rgba_half_float": 3.3199, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgba32f_rgba_float": 3.6815, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgba4_rgba_unsigned_byte": 3.4688, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 3.3993, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgba8_rgba_unsigned_byte": 3.3613, - "WebglConformance_conformance2_textures_canvas_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 3.3097, - "WebglConformance_conformance2_textures_canvas_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 3.2337, - "WebglConformance_conformance2_textures_canvas_tex_2d_srgb8_rgb_unsigned_byte": 3.3176, - "WebglConformance_conformance2_textures_canvas_tex_3d_r11f_g11f_b10f_rgb_float": 4.0325, - "WebglConformance_conformance2_textures_canvas_tex_3d_r11f_g11f_b10f_rgb_half_float": 3.9435, - "WebglConformance_conformance2_textures_canvas_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 3.9842, - "WebglConformance_conformance2_textures_canvas_tex_3d_r16f_red_float": 4.046, - "WebglConformance_conformance2_textures_canvas_tex_3d_r16f_red_half_float": 4.2542, - "WebglConformance_conformance2_textures_canvas_tex_3d_r32f_red_float": 4.0578, - "WebglConformance_conformance2_textures_canvas_tex_3d_r8_red_unsigned_byte": 3.9851, - "WebglConformance_conformance2_textures_canvas_tex_3d_r8ui_red_integer_unsigned_byte": 3.9061, - "WebglConformance_conformance2_textures_canvas_tex_3d_rg16f_rg_float": 4.0492, - "WebglConformance_conformance2_textures_canvas_tex_3d_rg16f_rg_half_float": 4.0347, - "WebglConformance_conformance2_textures_canvas_tex_3d_rg32f_rg_float": 4.1517, - "WebglConformance_conformance2_textures_canvas_tex_3d_rg8_rg_unsigned_byte": 4.0532, - "WebglConformance_conformance2_textures_canvas_tex_3d_rg8ui_rg_integer_unsigned_byte": 3.9581, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 3.9556, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb16f_rgb_float": 4.0331, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb16f_rgb_half_float": 4.0833, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb32f_rgb_float": 4.0049, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb565_rgb_unsigned_byte": 4.1216, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 4.162, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb5_a1_rgba_unsigned_byte": 4.0461, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 3.9081, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb8_rgb_unsigned_byte": 4.0409, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 4.1574, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb9_e5_rgb_float": 4.0362, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgb9_e5_rgb_half_float": 4.2182, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgba16f_rgba_float": 4.0394, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgba16f_rgba_half_float": 3.9535, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgba32f_rgba_float": 4.0409, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgba4_rgba_unsigned_byte": 4.1089, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 4.1626, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgba8_rgba_unsigned_byte": 4.214, - "WebglConformance_conformance2_textures_canvas_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 4.0512, - "WebglConformance_conformance2_textures_canvas_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 4.1489, - "WebglConformance_conformance2_textures_canvas_tex_3d_srgb8_rgb_unsigned_byte": 4.0428, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_r11f_g11f_b10f_rgb_float": 0.2045, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_r11f_g11f_b10f_rgb_half_float": 0.2229, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.2226, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_r16f_red_float": 0.221, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_r16f_red_half_float": 0.2148, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_r32f_red_float": 0.2903, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_r8_red_unsigned_byte": 0.6649, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_r8ui_red_integer_unsigned_byte": 0.2749, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rg16f_rg_float": 0.1544, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rg16f_rg_half_float": 0.1934, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rg32f_rg_float": 0.2654, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rg8_rg_unsigned_byte": 0.2002, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rg8ui_rg_integer_unsigned_byte": 0.2027, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.1725, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb16f_rgb_float": 0.2154, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb16f_rgb_half_float": 0.2449, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb32f_rgb_float": 0.2327, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb565_rgb_unsigned_byte": 0.2309, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 0.2845, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb5_a1_rgba_unsigned_byte": 0.2026, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.1325, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb8_rgb_unsigned_byte": 0.1658, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 0.2186, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb9_e5_rgb_float": 0.2256, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgb9_e5_rgb_half_float": 0.1983, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgba16f_rgba_float": 0.2924, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgba16f_rgba_half_float": 0.2683, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgba32f_rgba_float": 0.2024, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgba4_rgba_unsigned_byte": 0.1985, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 0.1969, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgba8_rgba_unsigned_byte": 0.2046, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 0.2603, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 0.2225, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_2d_srgb8_rgb_unsigned_byte": 0.2771, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_r11f_g11f_b10f_rgb_float": 0.2296, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_r11f_g11f_b10f_rgb_half_float": 0.1517, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.2236, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_r16f_red_float": 0.1775, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_r16f_red_half_float": 0.1814, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_r32f_red_float": 0.1852, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_r8_red_unsigned_byte": 0.1796, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_r8ui_red_integer_unsigned_byte": 0.1882, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rg16f_rg_float": 0.2141, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rg16f_rg_half_float": 0.1127, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rg32f_rg_float": 0.1799, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rg8_rg_unsigned_byte": 0.2182, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rg8ui_rg_integer_unsigned_byte": 0.1481, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.2145, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb16f_rgb_float": 0.1915, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb16f_rgb_half_float": 0.1832, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb32f_rgb_float": 0.2214, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb565_rgb_unsigned_byte": 0.1977, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 0.1801, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb5_a1_rgba_unsigned_byte": 0.2667, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.2002, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb8_rgb_unsigned_byte": 0.074, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 0.189, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb9_e5_rgb_float": 0.1785, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgb9_e5_rgb_half_float": 0.1898, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgba16f_rgba_float": 0.2098, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgba16f_rgba_half_float": 0.2151, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgba32f_rgba_float": 0.184, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgba4_rgba_unsigned_byte": 0.1886, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 0.2141, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgba8_rgba_unsigned_byte": 0.0964, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 0.2234, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 0.2285, - "WebglConformance_conformance2_textures_image_bitmap_from_blob_tex_3d_srgb8_rgb_unsigned_byte": 0.15, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_r11f_g11f_b10f_rgb_float": 0.2952, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_r11f_g11f_b10f_rgb_half_float": 0.4035, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.5648, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_r16f_red_float": 0.2069, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_r16f_red_half_float": 0.1897, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_r32f_red_float": 0.2303, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_r8_red_unsigned_byte": 0.1783, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_r8ui_red_integer_unsigned_byte": 0.3328, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rg16f_rg_float": 0.3793, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rg16f_rg_half_float": 0.3657, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rg32f_rg_float": 0.2327, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rg8_rg_unsigned_byte": 0.2971, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rg8ui_rg_integer_unsigned_byte": 0.2952, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.3174, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb16f_rgb_float": 0.3254, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb16f_rgb_half_float": 0.4151, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb32f_rgb_float": 0.3585, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb565_rgb_unsigned_byte": 0.3216, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 0.4321, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb5_a1_rgba_unsigned_byte": 0.1902, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.4115, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb8_rgb_unsigned_byte": 0.3183, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 0.3753, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb9_e5_rgb_float": 0.4159, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgb9_e5_rgb_half_float": 0.3938, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgba16f_rgba_float": 0.4297, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgba16f_rgba_half_float": 0.2739, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgba32f_rgba_float": 0.2543, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgba4_rgba_unsigned_byte": 0.2016, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 0.2211, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgba8_rgba_unsigned_byte": 0.3656, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 0.2447, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 0.314, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_2d_srgb8_rgb_unsigned_byte": 0.3999, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_r11f_g11f_b10f_rgb_float": 0.2151, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_r11f_g11f_b10f_rgb_half_float": 0.1651, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.1847, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_r16f_red_float": 0.2189, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_r16f_red_half_float": 0.2174, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_r32f_red_float": 0.2209, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_r8_red_unsigned_byte": 0.2161, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_r8ui_red_integer_unsigned_byte": 0.1324, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rg16f_rg_float": 0.2836, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rg16f_rg_half_float": 0.2676, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rg32f_rg_float": 0.1579, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rg8_rg_unsigned_byte": 0.2146, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rg8ui_rg_integer_unsigned_byte": 0.1983, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.2619, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb16f_rgb_float": 0.2059, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb16f_rgb_half_float": 0.2649, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb32f_rgb_float": 0.2398, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb565_rgb_unsigned_byte": 0.1284, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 0.1188, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb5_a1_rgba_unsigned_byte": 0.1497, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.1371, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb8_rgb_unsigned_byte": 0.1486, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 0.3144, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb9_e5_rgb_float": 0.2646, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgb9_e5_rgb_half_float": 0.1788, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgba16f_rgba_float": 0.1827, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgba16f_rgba_half_float": 0.1461, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgba32f_rgba_float": 0.217, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgba4_rgba_unsigned_byte": 0.2201, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 0.2148, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgba8_rgba_unsigned_byte": 0.1667, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 0.1788, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 0.1484, - "WebglConformance_conformance2_textures_image_bitmap_from_canvas_tex_3d_srgb8_rgb_unsigned_byte": 0.185, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_r11f_g11f_b10f_rgb_float": 0.1332, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_r11f_g11f_b10f_rgb_half_float": 0.2433, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.1562, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_r16f_red_float": 0.207, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_r16f_red_half_float": 0.1399, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_r32f_red_float": 0.1082, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_r8_red_unsigned_byte": 0.1776, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_r8ui_red_integer_unsigned_byte": 0.1432, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rg16f_rg_float": 0.165, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rg16f_rg_half_float": 0.108, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rg32f_rg_float": 0.0992, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rg8_rg_unsigned_byte": 0.1252, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rg8ui_rg_integer_unsigned_byte": 0.1203, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.102, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb16f_rgb_float": 0.1972, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb16f_rgb_half_float": 0.1369, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb32f_rgb_float": 0.1008, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb565_rgb_unsigned_byte": 0.1047, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 0.1981, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb5_a1_rgba_unsigned_byte": 0.1883, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.1538, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb8_rgb_unsigned_byte": 0.1028, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 0.1621, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb9_e5_rgb_float": 0.1979, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgb9_e5_rgb_half_float": 0.2003, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgba16f_rgba_float": 0.1975, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgba16f_rgba_half_float": 0.1677, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgba32f_rgba_float": 0.1819, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgba4_rgba_unsigned_byte": 0.1036, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 0.168, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgba8_rgba_unsigned_byte": 0.1305, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 0.1317, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 0.099, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_2d_srgb8_rgb_unsigned_byte": 0.1329, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_r11f_g11f_b10f_rgb_float": 0.1522, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_r11f_g11f_b10f_rgb_half_float": 0.0904, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.1006, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_r16f_red_float": 0.082, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_r16f_red_half_float": 0.125, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_r32f_red_float": 0.0681, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_r8_red_unsigned_byte": 0.1865, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_r8ui_red_integer_unsigned_byte": 0.0845, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rg16f_rg_float": 0.1322, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rg16f_rg_half_float": 0.0712, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rg32f_rg_float": 0.1341, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rg8_rg_unsigned_byte": 0.0822, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rg8ui_rg_integer_unsigned_byte": 0.1208, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.1531, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb16f_rgb_float": 0.0831, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb16f_rgb_half_float": 0.0829, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb32f_rgb_float": 0.1046, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb565_rgb_unsigned_byte": 0.0765, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 0.144, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb5_a1_rgba_unsigned_byte": 0.0825, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.0825, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb8_rgb_unsigned_byte": 0.103, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 0.1327, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb9_e5_rgb_float": 0.083, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgb9_e5_rgb_half_float": 0.0831, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgba16f_rgba_float": 0.0807, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgba16f_rgba_half_float": 0.1842, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgba32f_rgba_float": 0.1494, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgba4_rgba_unsigned_byte": 0.1476, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 0.1816, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgba8_rgba_unsigned_byte": 0.1008, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 0.1198, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 0.1166, - "WebglConformance_conformance2_textures_image_bitmap_from_image_bitmap_tex_3d_srgb8_rgb_unsigned_byte": 0.2069, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_r11f_g11f_b10f_rgb_float": 0.0986, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_r11f_g11f_b10f_rgb_half_float": 0.167, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.1189, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_r16f_red_float": 0.1798, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_r16f_red_half_float": 0.117, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_r32f_red_float": 0.2067, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_r8_red_unsigned_byte": 0.166, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_r8ui_red_integer_unsigned_byte": 0.1829, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rg16f_rg_float": 0.0986, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rg16f_rg_half_float": 0.167, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rg32f_rg_float": 0.1018, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rg8_rg_unsigned_byte": 0.1011, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rg8ui_rg_integer_unsigned_byte": 0.1166, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.115, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb16f_rgb_float": 0.1281, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb16f_rgb_half_float": 0.1499, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb32f_rgb_float": 0.1018, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb565_rgb_unsigned_byte": 0.1634, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 0.118, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb5_a1_rgba_unsigned_byte": 0.1335, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.1801, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb8_rgb_unsigned_byte": 0.1169, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 0.1751, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb9_e5_rgb_float": 0.2033, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgb9_e5_rgb_half_float": 0.2186, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgba16f_rgba_float": 0.1165, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgba16f_rgba_half_float": 0.1747, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgba32f_rgba_float": 0.1089, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgba4_rgba_unsigned_byte": 0.1214, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 0.1799, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgba8_rgba_unsigned_byte": 0.1721, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 0.1802, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 0.131, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_2d_srgb8_rgb_unsigned_byte": 0.2014, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_r11f_g11f_b10f_rgb_float": 0.1179, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_r11f_g11f_b10f_rgb_half_float": 0.0821, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.1669, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_r16f_red_float": 0.1512, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_r16f_red_half_float": 0.1632, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_r32f_red_float": 0.1017, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_r8_red_unsigned_byte": 0.0973, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_r8ui_red_integer_unsigned_byte": 0.1517, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rg16f_rg_float": 0.13, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rg16f_rg_half_float": 0.1438, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rg32f_rg_float": 0.1819, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rg8_rg_unsigned_byte": 0.165, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rg8ui_rg_integer_unsigned_byte": 0.1478, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.1185, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb16f_rgb_float": 0.0688, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb16f_rgb_half_float": 0.0834, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb32f_rgb_float": 0.0706, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb565_rgb_unsigned_byte": 0.1001, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 0.0664, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb5_a1_rgba_unsigned_byte": 0.0794, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.1063, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb8_rgb_unsigned_byte": 0.1363, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 0.1224, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb9_e5_rgb_float": 0.183, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgb9_e5_rgb_half_float": 0.1605, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgba16f_rgba_float": 0.1506, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgba16f_rgba_half_float": 0.135, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgba32f_rgba_float": 0.184, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgba4_rgba_unsigned_byte": 0.0722, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 0.1621, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgba8_rgba_unsigned_byte": 0.1491, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 0.1995, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 0.1502, - "WebglConformance_conformance2_textures_image_bitmap_from_image_data_tex_3d_srgb8_rgb_unsigned_byte": 0.1453, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_r11f_g11f_b10f_rgb_float": 0.1969, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_r11f_g11f_b10f_rgb_half_float": 0.1091, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.209, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_r16f_red_float": 0.3038, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_r16f_red_half_float": 0.1567, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_r32f_red_float": 0.1576, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_r8_red_unsigned_byte": 0.2737, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_r8ui_red_integer_unsigned_byte": 0.2304, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rg16f_rg_float": 0.2577, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rg16f_rg_half_float": 0.1355, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rg32f_rg_float": 0.1149, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rg8_rg_unsigned_byte": 0.1183, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rg8ui_rg_integer_unsigned_byte": 0.114, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.1921, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb16f_rgb_float": 0.3812, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb16f_rgb_half_float": 0.1233, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb32f_rgb_float": 0.2063, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb565_rgb_unsigned_byte": 0.2403, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 0.2811, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb5_a1_rgba_unsigned_byte": 0.2317, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.119, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb8_rgb_unsigned_byte": 0.1967, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 0.1054, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb9_e5_rgb_float": 0.1633, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgb9_e5_rgb_half_float": 0.2096, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgba16f_rgba_float": 0.1623, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgba16f_rgba_half_float": 0.2126, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgba32f_rgba_float": 0.2081, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgba4_rgba_unsigned_byte": 0.1563, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 0.1145, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgba8_rgba_unsigned_byte": 0.2714, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 0.1367, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 0.115, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_2d_srgb8_rgb_unsigned_byte": 0.1977, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_r11f_g11f_b10f_rgb_float": 0.0715, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_r11f_g11f_b10f_rgb_half_float": 0.2509, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.1149, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_r16f_red_float": 0.1184, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_r16f_red_half_float": 0.0842, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_r32f_red_float": 0.2113, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_r8_red_unsigned_byte": 0.2761, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_r8ui_red_integer_unsigned_byte": 0.1806, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rg16f_rg_float": 0.1814, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rg16f_rg_half_float": 0.1187, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rg32f_rg_float": 0.2666, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rg8_rg_unsigned_byte": 0.1799, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rg8ui_rg_integer_unsigned_byte": 0.0714, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.216, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb16f_rgb_float": 0.1472, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb16f_rgb_half_float": 0.1908, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb32f_rgb_float": 0.1826, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb565_rgb_unsigned_byte": 0.0962, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 0.0778, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb5_a1_rgba_unsigned_byte": 0.3267, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.2447, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb8_rgb_unsigned_byte": 0.1338, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 0.079, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb9_e5_rgb_float": 0.1449, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgb9_e5_rgb_half_float": 0.1475, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgba16f_rgba_float": 0.1172, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgba16f_rgba_half_float": 0.2013, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgba32f_rgba_float": 0.1973, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgba4_rgba_unsigned_byte": 0.141, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 0.1168, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgba8_rgba_unsigned_byte": 0.0795, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 0.1327, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 0.1158, - "WebglConformance_conformance2_textures_image_bitmap_from_image_tex_3d_srgb8_rgb_unsigned_byte": 0.0855, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_r11f_g11f_b10f_rgb_float": 1.4195, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_r11f_g11f_b10f_rgb_half_float": 1.294, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 1.4287, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_r16f_red_float": 1.385, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_r16f_red_half_float": 1.2915, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_r32f_red_float": 1.4221, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_r8_red_unsigned_byte": 1.294, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_r8ui_red_integer_unsigned_byte": 1.3614, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rg16f_rg_float": 1.3447, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rg16f_rg_half_float": 1.3861, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rg32f_rg_float": 1.315, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rg8_rg_unsigned_byte": 1.3315, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rg8ui_rg_integer_unsigned_byte": 1.2981, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 1.3189, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb16f_rgb_float": 1.3185, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb16f_rgb_half_float": 1.3023, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb32f_rgb_float": 1.4145, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb565_rgb_unsigned_byte": 1.3493, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 1.7255, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb5_a1_rgba_unsigned_byte": 1.2841, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 1.3901, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb8_rgb_unsigned_byte": 1.4117, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 1.2809, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb9_e5_rgb_float": 1.3019, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgb9_e5_rgb_half_float": 1.3931, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgba16f_rgba_float": 1.2782, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgba16f_rgba_half_float": 1.3763, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgba32f_rgba_float": 1.5946, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgba4_rgba_unsigned_byte": 1.3706, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 1.3739, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgba8_rgba_unsigned_byte": 1.3053, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 1.3375, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 1.3085, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_2d_srgb8_rgb_unsigned_byte": 1.2911, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_r11f_g11f_b10f_rgb_float": 1.3058, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_r11f_g11f_b10f_rgb_half_float": 1.3006, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 1.3352, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_r16f_red_float": 1.2961, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_r16f_red_half_float": 1.2931, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_r32f_red_float": 1.2814, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_r8_red_unsigned_byte": 1.3055, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_r8ui_red_integer_unsigned_byte": 1.3755, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rg16f_rg_float": 2.089, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rg16f_rg_half_float": 1.3029, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rg32f_rg_float": 1.3272, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rg8_rg_unsigned_byte": 1.4057, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rg8ui_rg_integer_unsigned_byte": 1.2943, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 1.2803, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb16f_rgb_float": 1.4152, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb16f_rgb_half_float": 1.2777, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb32f_rgb_float": 1.2992, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb565_rgb_unsigned_byte": 1.2733, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 1.2785, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb5_a1_rgba_unsigned_byte": 1.3005, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 1.3364, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb8_rgb_unsigned_byte": 1.2759, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 1.2985, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb9_e5_rgb_float": 1.4122, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgb9_e5_rgb_half_float": 1.3016, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgba16f_rgba_float": 1.2806, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgba16f_rgba_half_float": 1.278, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgba32f_rgba_float": 1.2747, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgba4_rgba_unsigned_byte": 1.3034, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 1.2847, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgba8_rgba_unsigned_byte": 1.3013, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 1.4028, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 1.2913, - "WebglConformance_conformance2_textures_image_bitmap_from_video_tex_3d_srgb8_rgb_unsigned_byte": 1.2744, - "WebglConformance_conformance2_textures_image_data_tex_2d_r11f_g11f_b10f_rgb_float": 0.4145, - "WebglConformance_conformance2_textures_image_data_tex_2d_r11f_g11f_b10f_rgb_half_float": 0.3868, - "WebglConformance_conformance2_textures_image_data_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.254, - "WebglConformance_conformance2_textures_image_data_tex_2d_r16f_red_float": 0.2563, - "WebglConformance_conformance2_textures_image_data_tex_2d_r16f_red_half_float": 0.4527, - "WebglConformance_conformance2_textures_image_data_tex_2d_r32f_red_float": 0.4573, - "WebglConformance_conformance2_textures_image_data_tex_2d_r8_red_unsigned_byte": 0.4137, - "WebglConformance_conformance2_textures_image_data_tex_2d_r8ui_red_integer_unsigned_byte": 0.1648, - "WebglConformance_conformance2_textures_image_data_tex_2d_rg16f_rg_float": 0.2651, - "WebglConformance_conformance2_textures_image_data_tex_2d_rg16f_rg_half_float": 0.3073, - "WebglConformance_conformance2_textures_image_data_tex_2d_rg32f_rg_float": 0.4413, - "WebglConformance_conformance2_textures_image_data_tex_2d_rg8_rg_unsigned_byte": 0.2413, - "WebglConformance_conformance2_textures_image_data_tex_2d_rg8ui_rg_integer_unsigned_byte": 0.2048, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.3269, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb16f_rgb_float": 0.4182, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb16f_rgb_half_float": 0.1936, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb32f_rgb_float": 0.1836, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb565_rgb_unsigned_byte": 0.3624, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 0.2798, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb5_a1_rgba_unsigned_byte": 0.1867, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.3195, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb8_rgb_unsigned_byte": 0.3641, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 0.2492, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb9_e5_rgb_float": 0.3641, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgb9_e5_rgb_half_float": 0.4558, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgba16f_rgba_float": 0.1746, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgba16f_rgba_half_float": 0.3179, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgba32f_rgba_float": 0.1873, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgba4_rgba_unsigned_byte": 0.3499, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 0.1923, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgba8_rgba_unsigned_byte": 0.2149, - "WebglConformance_conformance2_textures_image_data_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 0.2984, - "WebglConformance_conformance2_textures_image_data_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 0.2882, - "WebglConformance_conformance2_textures_image_data_tex_2d_srgb8_rgb_unsigned_byte": 0.3834, - "WebglConformance_conformance2_textures_image_data_tex_3d_r11f_g11f_b10f_rgb_float": 0.5797, - "WebglConformance_conformance2_textures_image_data_tex_3d_r11f_g11f_b10f_rgb_half_float": 0.2665, - "WebglConformance_conformance2_textures_image_data_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.3936, - "WebglConformance_conformance2_textures_image_data_tex_3d_r16f_red_float": 0.1865, - "WebglConformance_conformance2_textures_image_data_tex_3d_r16f_red_half_float": 0.3163, - "WebglConformance_conformance2_textures_image_data_tex_3d_r32f_red_float": 0.3158, - "WebglConformance_conformance2_textures_image_data_tex_3d_r8_red_unsigned_byte": 0.3519, - "WebglConformance_conformance2_textures_image_data_tex_3d_r8ui_red_integer_unsigned_byte": 0.1969, - "WebglConformance_conformance2_textures_image_data_tex_3d_rg16f_rg_float": 0.3609, - "WebglConformance_conformance2_textures_image_data_tex_3d_rg16f_rg_half_float": 0.3331, - "WebglConformance_conformance2_textures_image_data_tex_3d_rg32f_rg_float": 0.2588, - "WebglConformance_conformance2_textures_image_data_tex_3d_rg8_rg_unsigned_byte": 0.2351, - "WebglConformance_conformance2_textures_image_data_tex_3d_rg8ui_rg_integer_unsigned_byte": 0.3839, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.3199, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb16f_rgb_float": 0.2156, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb16f_rgb_half_float": 0.3296, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb32f_rgb_float": 0.1836, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb565_rgb_unsigned_byte": 0.1838, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 0.1658, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb5_a1_rgba_unsigned_byte": 0.2847, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.3486, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb8_rgb_unsigned_byte": 0.2354, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 0.2332, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb9_e5_rgb_float": 0.2359, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgb9_e5_rgb_half_float": 0.3595, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgba16f_rgba_float": 0.3141, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgba16f_rgba_half_float": 0.235, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgba32f_rgba_float": 0.3815, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgba4_rgba_unsigned_byte": 0.1509, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 0.2858, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgba8_rgba_unsigned_byte": 0.3729, - "WebglConformance_conformance2_textures_image_data_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 0.4079, - "WebglConformance_conformance2_textures_image_data_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 0.165, - "WebglConformance_conformance2_textures_image_data_tex_3d_srgb8_rgb_unsigned_byte": 0.1731, - "WebglConformance_conformance2_textures_image_tex_2d_r11f_g11f_b10f_rgb_float": 0.1903, - "WebglConformance_conformance2_textures_image_tex_2d_r11f_g11f_b10f_rgb_half_float": 0.3265, - "WebglConformance_conformance2_textures_image_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.258, - "WebglConformance_conformance2_textures_image_tex_2d_r16f_red_float": 0.3368, - "WebglConformance_conformance2_textures_image_tex_2d_r16f_red_half_float": 0.407, - "WebglConformance_conformance2_textures_image_tex_2d_r32f_red_float": 0.3382, - "WebglConformance_conformance2_textures_image_tex_2d_r8_red_unsigned_byte": 0.3134, - "WebglConformance_conformance2_textures_image_tex_2d_r8ui_red_integer_unsigned_byte": 0.1904, - "WebglConformance_conformance2_textures_image_tex_2d_rg16f_rg_float": 0.1882, - "WebglConformance_conformance2_textures_image_tex_2d_rg16f_rg_half_float": 0.3128, - "WebglConformance_conformance2_textures_image_tex_2d_rg32f_rg_float": 0.1916, - "WebglConformance_conformance2_textures_image_tex_2d_rg8_rg_unsigned_byte": 0.3583, - "WebglConformance_conformance2_textures_image_tex_2d_rg8ui_rg_integer_unsigned_byte": 0.2324, - "WebglConformance_conformance2_textures_image_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.1951, - "WebglConformance_conformance2_textures_image_tex_2d_rgb16f_rgb_float": 0.3244, - "WebglConformance_conformance2_textures_image_tex_2d_rgb16f_rgb_half_float": 0.3168, - "WebglConformance_conformance2_textures_image_tex_2d_rgb32f_rgb_float": 0.3474, - "WebglConformance_conformance2_textures_image_tex_2d_rgb565_rgb_unsigned_byte": 0.1839, - "WebglConformance_conformance2_textures_image_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 0.3827, - "WebglConformance_conformance2_textures_image_tex_2d_rgb5_a1_rgba_unsigned_byte": 0.349, - "WebglConformance_conformance2_textures_image_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.1893, - "WebglConformance_conformance2_textures_image_tex_2d_rgb8_rgb_unsigned_byte": 0.2461, - "WebglConformance_conformance2_textures_image_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 0.2663, - "WebglConformance_conformance2_textures_image_tex_2d_rgb9_e5_rgb_float": 0.1998, - "WebglConformance_conformance2_textures_image_tex_2d_rgb9_e5_rgb_half_float": 0.1543, - "WebglConformance_conformance2_textures_image_tex_2d_rgba16f_rgba_float": 0.2938, - "WebglConformance_conformance2_textures_image_tex_2d_rgba16f_rgba_half_float": 0.2665, - "WebglConformance_conformance2_textures_image_tex_2d_rgba32f_rgba_float": 0.2422, - "WebglConformance_conformance2_textures_image_tex_2d_rgba4_rgba_unsigned_byte": 0.3524, - "WebglConformance_conformance2_textures_image_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 0.3549, - "WebglConformance_conformance2_textures_image_tex_2d_rgba8_rgba_unsigned_byte": 0.2602, - "WebglConformance_conformance2_textures_image_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 0.3633, - "WebglConformance_conformance2_textures_image_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 0.184, - "WebglConformance_conformance2_textures_image_tex_2d_srgb8_rgb_unsigned_byte": 0.2321, - "WebglConformance_conformance2_textures_image_tex_3d_r11f_g11f_b10f_rgb_float": 0.2437, - "WebglConformance_conformance2_textures_image_tex_3d_r11f_g11f_b10f_rgb_half_float": 0.2121, - "WebglConformance_conformance2_textures_image_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.2063, - "WebglConformance_conformance2_textures_image_tex_3d_r16f_red_float": 0.2701, - "WebglConformance_conformance2_textures_image_tex_3d_r16f_red_half_float": 0.2485, - "WebglConformance_conformance2_textures_image_tex_3d_r32f_red_float": 0.294, - "WebglConformance_conformance2_textures_image_tex_3d_r8_red_unsigned_byte": 0.1216, - "WebglConformance_conformance2_textures_image_tex_3d_r8ui_red_integer_unsigned_byte": 0.3074, - "WebglConformance_conformance2_textures_image_tex_3d_rg16f_rg_float": 0.2634, - "WebglConformance_conformance2_textures_image_tex_3d_rg16f_rg_half_float": 0.2455, - "WebglConformance_conformance2_textures_image_tex_3d_rg32f_rg_float": 0.1648, - "WebglConformance_conformance2_textures_image_tex_3d_rg8_rg_unsigned_byte": 0.2216, - "WebglConformance_conformance2_textures_image_tex_3d_rg8ui_rg_integer_unsigned_byte": 0.1142, - "WebglConformance_conformance2_textures_image_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.1895, - "WebglConformance_conformance2_textures_image_tex_3d_rgb16f_rgb_float": 0.2575, - "WebglConformance_conformance2_textures_image_tex_3d_rgb16f_rgb_half_float": 0.3057, - "WebglConformance_conformance2_textures_image_tex_3d_rgb32f_rgb_float": 0.1237, - "WebglConformance_conformance2_textures_image_tex_3d_rgb565_rgb_unsigned_byte": 0.2208, - "WebglConformance_conformance2_textures_image_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 0.2113, - "WebglConformance_conformance2_textures_image_tex_3d_rgb5_a1_rgba_unsigned_byte": 0.1198, - "WebglConformance_conformance2_textures_image_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.3217, - "WebglConformance_conformance2_textures_image_tex_3d_rgb8_rgb_unsigned_byte": 0.1121, - "WebglConformance_conformance2_textures_image_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 0.1253, - "WebglConformance_conformance2_textures_image_tex_3d_rgb9_e5_rgb_float": 0.1322, - "WebglConformance_conformance2_textures_image_tex_3d_rgb9_e5_rgb_half_float": 0.3352, - "WebglConformance_conformance2_textures_image_tex_3d_rgba16f_rgba_float": 0.3511, - "WebglConformance_conformance2_textures_image_tex_3d_rgba16f_rgba_half_float": 0.1935, - "WebglConformance_conformance2_textures_image_tex_3d_rgba32f_rgba_float": 0.227, - "WebglConformance_conformance2_textures_image_tex_3d_rgba4_rgba_unsigned_byte": 0.0985, - "WebglConformance_conformance2_textures_image_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 0.1131, - "WebglConformance_conformance2_textures_image_tex_3d_rgba8_rgba_unsigned_byte": 0.2177, - "WebglConformance_conformance2_textures_image_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 0.2243, - "WebglConformance_conformance2_textures_image_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 0.1681, - "WebglConformance_conformance2_textures_image_tex_3d_srgb8_rgb_unsigned_byte": 0.153, - "WebglConformance_conformance2_textures_misc_active_3d_texture_bug": 0.1066, - "WebglConformance_conformance2_textures_misc_angle_stuck_depth_textures": 0.1214, - "WebglConformance_conformance2_textures_misc_canvas_remains_unchanged_after_used_in_webgl_texture": 0.0828, - "WebglConformance_conformance2_textures_misc_compressed_tex_from_pbo_crash": 0.067, - "WebglConformance_conformance2_textures_misc_copy_texture_cube_map_AMD_bug": 0.0682, - "WebglConformance_conformance2_textures_misc_copy_texture_image": 0.1672, - "WebglConformance_conformance2_textures_misc_copy_texture_image_luma_format": 1.1854, - "WebglConformance_conformance2_textures_misc_copy_texture_image_webgl_specific": 0.1249, - "WebglConformance_conformance2_textures_misc_gl_get_tex_parameter": 0.1151, - "WebglConformance_conformance2_textures_misc_integer_cubemap_specification_order_bug": 6.0379, - "WebglConformance_conformance2_textures_misc_integer_cubemap_texture_sampling": 0.713, - "WebglConformance_conformance2_textures_misc_mipmap_fbo": 0.0914, - "WebglConformance_conformance2_textures_misc_npot_video_sizing": 0.3953, - "WebglConformance_conformance2_textures_misc_origin_clean_conformance_offscreencanvas": 0.0574, - "WebglConformance_conformance2_textures_misc_tex_3d_mipmap_levels_intel_bug": 0.075, - "WebglConformance_conformance2_textures_misc_tex_3d_size_limit": 0.0991, - "WebglConformance_conformance2_textures_misc_tex_base_level_bug": 0.1165, - "WebglConformance_conformance2_textures_misc_tex_image_and_sub_image_with_array_buffer_view_sub_source": 0.2582, - "WebglConformance_conformance2_textures_misc_tex_image_with_bad_args": 0.0452, - "WebglConformance_conformance2_textures_misc_tex_image_with_bad_args_from_dom_elements": 1.1922, - "WebglConformance_conformance2_textures_misc_tex_image_with_different_data_source": 0.0907, - "WebglConformance_conformance2_textures_misc_tex_input_validation": 0.2154, - "WebglConformance_conformance2_textures_misc_tex_mipmap_levels": 0.1041, - "WebglConformance_conformance2_textures_misc_tex_new_formats": 0.2147, - "WebglConformance_conformance2_textures_misc_tex_srgb_mipmap": 0.1501, - "WebglConformance_conformance2_textures_misc_tex_storage_2d": 0.1398, - "WebglConformance_conformance2_textures_misc_tex_storage_and_subimage_3d": 0.1026, - "WebglConformance_conformance2_textures_misc_tex_storage_compressed_formats": 0.0839, - "WebglConformance_conformance2_textures_misc_tex_subimage3d_pixel_buffer_bug": 0.1042, - "WebglConformance_conformance2_textures_misc_tex_unpack_params": 0.4862, - "WebglConformance_conformance2_textures_misc_texel_fetch_undefined": 0.1705, - "WebglConformance_conformance2_textures_misc_texture_npot": 0.1673, - "WebglConformance_conformance2_textures_svg_image_tex_2d_r11f_g11f_b10f_rgb_float": 0.2245, - "WebglConformance_conformance2_textures_svg_image_tex_2d_r11f_g11f_b10f_rgb_half_float": 0.914, - "WebglConformance_conformance2_textures_svg_image_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.2361, - "WebglConformance_conformance2_textures_svg_image_tex_2d_r16f_red_float": 0.24, - "WebglConformance_conformance2_textures_svg_image_tex_2d_r16f_red_half_float": 0.1609, - "WebglConformance_conformance2_textures_svg_image_tex_2d_r32f_red_float": 0.2062, - "WebglConformance_conformance2_textures_svg_image_tex_2d_r8_red_unsigned_byte": 0.2018, - "WebglConformance_conformance2_textures_svg_image_tex_2d_r8ui_red_integer_unsigned_byte": 0.234, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rg16f_rg_float": 0.2404, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rg16f_rg_half_float": 0.1584, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rg32f_rg_float": 0.1043, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rg8_rg_unsigned_byte": 0.1888, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rg8ui_rg_integer_unsigned_byte": 0.1916, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.0923, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb16f_rgb_float": 0.241, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb16f_rgb_half_float": 0.0875, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb32f_rgb_float": 0.1575, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb565_rgb_unsigned_byte": 0.1258, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 0.2861, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb5_a1_rgba_unsigned_byte": 0.1739, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.2337, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb8_rgb_unsigned_byte": 0.2197, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 0.0803, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb9_e5_rgb_float": 0.0865, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgb9_e5_rgb_half_float": 0.1211, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgba16f_rgba_float": 0.1366, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgba16f_rgba_half_float": 0.2198, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgba32f_rgba_float": 0.1467, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgba4_rgba_unsigned_byte": 0.1388, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 0.2245, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgba8_rgba_unsigned_byte": 0.1819, - "WebglConformance_conformance2_textures_svg_image_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 0.0827, - "WebglConformance_conformance2_textures_svg_image_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 0.0813, - "WebglConformance_conformance2_textures_svg_image_tex_2d_srgb8_rgb_unsigned_byte": 0.0964, - "WebglConformance_conformance2_textures_svg_image_tex_3d_r11f_g11f_b10f_rgb_float": 0.1178, - "WebglConformance_conformance2_textures_svg_image_tex_3d_r11f_g11f_b10f_rgb_half_float": 0.075, - "WebglConformance_conformance2_textures_svg_image_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 0.0603, - "WebglConformance_conformance2_textures_svg_image_tex_3d_r16f_red_float": 0.1368, - "WebglConformance_conformance2_textures_svg_image_tex_3d_r16f_red_half_float": 0.0951, - "WebglConformance_conformance2_textures_svg_image_tex_3d_r32f_red_float": 0.1, - "WebglConformance_conformance2_textures_svg_image_tex_3d_r8_red_unsigned_byte": 0.1111, - "WebglConformance_conformance2_textures_svg_image_tex_3d_r8ui_red_integer_unsigned_byte": 0.272, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rg16f_rg_float": 0.0656, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rg16f_rg_half_float": 0.1857, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rg32f_rg_float": 0.1058, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rg8_rg_unsigned_byte": 0.0644, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rg8ui_rg_integer_unsigned_byte": 0.0989, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 0.0673, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb16f_rgb_float": 0.0882, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb16f_rgb_half_float": 0.0686, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb32f_rgb_float": 0.0679, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb565_rgb_unsigned_byte": 0.1049, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 0.1397, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb5_a1_rgba_unsigned_byte": 0.1361, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 0.1624, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb8_rgb_unsigned_byte": 0.1013, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 0.2173, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb9_e5_rgb_float": 0.1001, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgb9_e5_rgb_half_float": 0.0646, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgba16f_rgba_float": 0.0996, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgba16f_rgba_half_float": 0.0996, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgba32f_rgba_float": 0.0588, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgba4_rgba_unsigned_byte": 0.1462, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 0.0842, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgba8_rgba_unsigned_byte": 0.1579, - "WebglConformance_conformance2_textures_svg_image_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 0.0994, - "WebglConformance_conformance2_textures_svg_image_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 0.0688, - "WebglConformance_conformance2_textures_svg_image_tex_3d_srgb8_rgb_unsigned_byte": 0.0539, - "WebglConformance_conformance2_textures_video_tex_2d_r11f_g11f_b10f_rgb_float": 2.5985, - "WebglConformance_conformance2_textures_video_tex_2d_r11f_g11f_b10f_rgb_half_float": 2.2622, - "WebglConformance_conformance2_textures_video_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 2.3308, - "WebglConformance_conformance2_textures_video_tex_2d_r16f_red_float": 2.5034, - "WebglConformance_conformance2_textures_video_tex_2d_r16f_red_half_float": 2.3098, - "WebglConformance_conformance2_textures_video_tex_2d_r32f_red_float": 2.2719, - "WebglConformance_conformance2_textures_video_tex_2d_r8_red_unsigned_byte": 2.3021, - "WebglConformance_conformance2_textures_video_tex_2d_r8ui_red_integer_unsigned_byte": 2.2446, - "WebglConformance_conformance2_textures_video_tex_2d_rg16f_rg_float": 2.2953, - "WebglConformance_conformance2_textures_video_tex_2d_rg16f_rg_half_float": 2.2859, - "WebglConformance_conformance2_textures_video_tex_2d_rg32f_rg_float": 2.2412, - "WebglConformance_conformance2_textures_video_tex_2d_rg8_rg_unsigned_byte": 2.3932, - "WebglConformance_conformance2_textures_video_tex_2d_rg8ui_rg_integer_unsigned_byte": 2.6177, - "WebglConformance_conformance2_textures_video_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 2.2874, - "WebglConformance_conformance2_textures_video_tex_2d_rgb16f_rgb_float": 2.6235, - "WebglConformance_conformance2_textures_video_tex_2d_rgb16f_rgb_half_float": 2.2313, - "WebglConformance_conformance2_textures_video_tex_2d_rgb32f_rgb_float": 2.6085, - "WebglConformance_conformance2_textures_video_tex_2d_rgb565_rgb_unsigned_byte": 2.2352, - "WebglConformance_conformance2_textures_video_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 2.3268, - "WebglConformance_conformance2_textures_video_tex_2d_rgb5_a1_rgba_unsigned_byte": 2.2862, - "WebglConformance_conformance2_textures_video_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 2.5908, - "WebglConformance_conformance2_textures_video_tex_2d_rgb8_rgb_unsigned_byte": 2.6031, - "WebglConformance_conformance2_textures_video_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 2.6144, - "WebglConformance_conformance2_textures_video_tex_2d_rgb9_e5_rgb_float": 2.4225, - "WebglConformance_conformance2_textures_video_tex_2d_rgb9_e5_rgb_half_float": 2.4696, - "WebglConformance_conformance2_textures_video_tex_2d_rgba16f_rgba_float": 2.2275, - "WebglConformance_conformance2_textures_video_tex_2d_rgba16f_rgba_half_float": 2.2523, - "WebglConformance_conformance2_textures_video_tex_2d_rgba32f_rgba_float": 2.2588, - "WebglConformance_conformance2_textures_video_tex_2d_rgba4_rgba_unsigned_byte": 2.2723, - "WebglConformance_conformance2_textures_video_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 2.3323, - "WebglConformance_conformance2_textures_video_tex_2d_rgba8_rgba_unsigned_byte": 2.2889, - "WebglConformance_conformance2_textures_video_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 2.2815, - "WebglConformance_conformance2_textures_video_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 2.275, - "WebglConformance_conformance2_textures_video_tex_2d_srgb8_rgb_unsigned_byte": 2.3152, - "WebglConformance_conformance2_textures_video_tex_3d_r11f_g11f_b10f_rgb_float": 2.5289, - "WebglConformance_conformance2_textures_video_tex_3d_r11f_g11f_b10f_rgb_half_float": 2.5909, - "WebglConformance_conformance2_textures_video_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 2.4879, - "WebglConformance_conformance2_textures_video_tex_3d_r16f_red_float": 2.4965, - "WebglConformance_conformance2_textures_video_tex_3d_r16f_red_half_float": 2.6222, - "WebglConformance_conformance2_textures_video_tex_3d_r32f_red_float": 2.4683, - "WebglConformance_conformance2_textures_video_tex_3d_r8_red_unsigned_byte": 2.6728, - "WebglConformance_conformance2_textures_video_tex_3d_r8ui_red_integer_unsigned_byte": 2.4681, - "WebglConformance_conformance2_textures_video_tex_3d_rg16f_rg_float": 2.4682, - "WebglConformance_conformance2_textures_video_tex_3d_rg16f_rg_half_float": 2.504, - "WebglConformance_conformance2_textures_video_tex_3d_rg32f_rg_float": 2.7051, - "WebglConformance_conformance2_textures_video_tex_3d_rg8_rg_unsigned_byte": 2.4675, - "WebglConformance_conformance2_textures_video_tex_3d_rg8ui_rg_integer_unsigned_byte": 2.6524, - "WebglConformance_conformance2_textures_video_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 2.6095, - "WebglConformance_conformance2_textures_video_tex_3d_rgb16f_rgb_float": 2.4519, - "WebglConformance_conformance2_textures_video_tex_3d_rgb16f_rgb_half_float": 2.4609, - "WebglConformance_conformance2_textures_video_tex_3d_rgb32f_rgb_float": 2.646, - "WebglConformance_conformance2_textures_video_tex_3d_rgb565_rgb_unsigned_byte": 2.3074, - "WebglConformance_conformance2_textures_video_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 2.496, - "WebglConformance_conformance2_textures_video_tex_3d_rgb5_a1_rgba_unsigned_byte": 2.7494, - "WebglConformance_conformance2_textures_video_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 2.6739, - "WebglConformance_conformance2_textures_video_tex_3d_rgb8_rgb_unsigned_byte": 2.2756, - "WebglConformance_conformance2_textures_video_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 2.4531, - "WebglConformance_conformance2_textures_video_tex_3d_rgb9_e5_rgb_float": 2.4733, - "WebglConformance_conformance2_textures_video_tex_3d_rgb9_e5_rgb_half_float": 2.5389, - "WebglConformance_conformance2_textures_video_tex_3d_rgba16f_rgba_float": 2.5005, - "WebglConformance_conformance2_textures_video_tex_3d_rgba16f_rgba_half_float": 2.7688, - "WebglConformance_conformance2_textures_video_tex_3d_rgba32f_rgba_float": 2.4782, - "WebglConformance_conformance2_textures_video_tex_3d_rgba4_rgba_unsigned_byte": 2.2809, - "WebglConformance_conformance2_textures_video_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 2.6706, - "WebglConformance_conformance2_textures_video_tex_3d_rgba8_rgba_unsigned_byte": 2.5199, - "WebglConformance_conformance2_textures_video_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 2.4733, - "WebglConformance_conformance2_textures_video_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 2.4637, - "WebglConformance_conformance2_textures_video_tex_3d_srgb8_rgb_unsigned_byte": 2.2998, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_r11f_g11f_b10f_rgb_float": 2.1271, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_r11f_g11f_b10f_rgb_half_float": 1.9786, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 2.1817, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_r16f_red_float": 1.9583, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_r16f_red_half_float": 2.0261, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_r32f_red_float": 2.1028, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_r8_red_unsigned_byte": 1.9372, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_r8ui_red_integer_unsigned_byte": 1.9373, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rg16f_rg_float": 2.1054, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rg16f_rg_half_float": 2.0165, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rg32f_rg_float": 1.9615, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rg8_rg_unsigned_byte": 1.9843, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rg8ui_rg_integer_unsigned_byte": 2.0889, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 1.9118, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb16f_rgb_float": 2.2226, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb16f_rgb_half_float": 2.0158, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb32f_rgb_float": 2.175, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb565_rgb_unsigned_byte": 2.1262, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb565_rgb_unsigned_short_5_6_5": 1.9188, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb5_a1_rgba_unsigned_byte": 2.0992, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 2.0969, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb8_rgb_unsigned_byte": 2.1288, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb8ui_rgb_integer_unsigned_byte": 1.9389, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb9_e5_rgb_float": 2.203, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgb9_e5_rgb_half_float": 2.3149, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgba16f_rgba_float": 1.9984, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgba16f_rgba_half_float": 2.0797, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgba32f_rgba_float": 2.0407, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgba4_rgba_unsigned_byte": 2.1512, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgba4_rgba_unsigned_short_4_4_4_4": 2.1331, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgba8_rgba_unsigned_byte": 2.1317, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_rgba8ui_rgba_integer_unsigned_byte": 2.244, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_srgb8_alpha8_rgba_unsigned_byte": 2.0217, - "WebglConformance_conformance2_textures_webgl_canvas_tex_2d_srgb8_rgb_unsigned_byte": 1.9593, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_r11f_g11f_b10f_rgb_float": 4.3125, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_r11f_g11f_b10f_rgb_half_float": 4.2417, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_r11f_g11f_b10f_rgb_unsigned_int_10f_11f_11f_rev": 3.9549, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_r16f_red_float": 4.034, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_r16f_red_half_float": 4.0032, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_r32f_red_float": 4.0219, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_r8_red_unsigned_byte": 4.1662, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_r8ui_red_integer_unsigned_byte": 4.3024, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rg16f_rg_float": 4.316, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rg16f_rg_half_float": 3.9941, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rg32f_rg_float": 4.0344, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rg8_rg_unsigned_byte": 4.0377, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rg8ui_rg_integer_unsigned_byte": 4.0071, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb10_a2_rgba_unsigned_int_2_10_10_10_rev": 4.2612, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb16f_rgb_float": 4.1513, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb16f_rgb_half_float": 4.0476, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb32f_rgb_float": 4.1843, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb565_rgb_unsigned_byte": 4.1506, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb565_rgb_unsigned_short_5_6_5": 4.1173, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb5_a1_rgba_unsigned_byte": 4.1675, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb5_a1_rgba_unsigned_short_5_5_5_1": 4.1105, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb8_rgb_unsigned_byte": 4.1765, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb8ui_rgb_integer_unsigned_byte": 4.1369, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb9_e5_rgb_float": 4.2005, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgb9_e5_rgb_half_float": 4.0695, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgba16f_rgba_float": 4.0226, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgba16f_rgba_half_float": 4.2943, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgba32f_rgba_float": 4.2343, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgba4_rgba_unsigned_byte": 3.9946, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgba4_rgba_unsigned_short_4_4_4_4": 4.3059, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgba8_rgba_unsigned_byte": 4.0783, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_rgba8ui_rgba_integer_unsigned_byte": 4.1543, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_srgb8_alpha8_rgba_unsigned_byte": 4.1886, - "WebglConformance_conformance2_textures_webgl_canvas_tex_3d_srgb8_rgb_unsigned_byte": 4.1456, - "WebglConformance_conformance2_transform_feedback_non_existent_varying": 0.0805, - "WebglConformance_conformance2_transform_feedback_transform_feedback": 0.8567, - "WebglConformance_conformance2_transform_feedback_two_unreferenced_varyings": 0.0866, - "WebglConformance_conformance2_transform_feedback_unwritten_output_defaults_to_zero": 0.1402, - "WebglConformance_conformance2_uniforms_gl_uniform_arrays_sub_source": 0.333, - "WebglConformance_conformance2_uniforms_query_uniform_blocks_after_shader_detach": 0.0719, - "WebglConformance_conformance2_uniforms_uniform_blocks_with_arrays": 0.1643, - "WebglConformance_conformance2_vertex_arrays_vertex_array_object": 6.2691, - "WebglConformance_conformance_attribs_gl_bindAttribLocation_aliasing": 0.1162, - "WebglConformance_conformance_attribs_gl_bindAttribLocation_matrix": 0.2258, - "WebglConformance_conformance_attribs_gl_bindAttribLocation_nonexistent_attribute": 0.0867, - "WebglConformance_conformance_attribs_gl_bindAttribLocation_repeated": 0.0496, - "WebglConformance_conformance_attribs_gl_disabled_vertex_attrib": 0.2489, - "WebglConformance_conformance_attribs_gl_enable_vertex_attrib": 0.0508, - "WebglConformance_conformance_attribs_gl_matrix_attributes": 0.2165, - "WebglConformance_conformance_attribs_gl_vertex_attrib_render": 0.1061, - "WebglConformance_conformance_attribs_gl_vertex_attrib_unconsumed_out_of_bounds": 0.1057, - "WebglConformance_conformance_attribs_gl_vertex_attrib_zero_issues": 0.6185, - "WebglConformance_conformance_attribs_gl_vertexattribpointer": 0.8946, - "WebglConformance_conformance_attribs_gl_vertexattribpointer_offsets": 0.4436, - "WebglConformance_conformance_buffers_buffer_bind_test": 0.0674, - "WebglConformance_conformance_buffers_buffer_data_and_buffer_sub_data": 0.091, - "WebglConformance_conformance_buffers_buffer_data_array_buffer_delete": 2.123, - "WebglConformance_conformance_buffers_buffer_uninitialized": 0.2038, - "WebglConformance_conformance_buffers_element_array_buffer_delete_recreate": 0.0786, - "WebglConformance_conformance_buffers_index_validation": 0.1572, - "WebglConformance_conformance_buffers_index_validation_copies_indices": 0.1143, - "WebglConformance_conformance_buffers_index_validation_crash_with_buffer_sub_data": 0.049, - "WebglConformance_conformance_buffers_index_validation_large_buffer": 0.1274, - "WebglConformance_conformance_buffers_index_validation_verifies_too_many_indices": 0.0857, - "WebglConformance_conformance_buffers_index_validation_with_resized_buffer": 0.0496, - "WebglConformance_conformance_canvas_buffer_offscreen_test": 0.1889, - "WebglConformance_conformance_canvas_buffer_preserve_test": 0.1496, - "WebglConformance_conformance_canvas_canvas_test": 0.2113, - "WebglConformance_conformance_canvas_canvas_zero_size": 0.0494, - "WebglConformance_conformance_canvas_draw_static_webgl_to_multiple_canvas_test": 0.59, - "WebglConformance_conformance_canvas_draw_webgl_to_canvas_test": 0.4433, - "WebglConformance_conformance_canvas_drawingbuffer_hd_dpi_test": 0.2647, - "WebglConformance_conformance_canvas_drawingbuffer_static_canvas_test": 0.1839, - "WebglConformance_conformance_canvas_drawingbuffer_test": 0.1184, - "WebglConformance_conformance_canvas_framebuffer_bindings_affected_by_to_data_url": 0.1522, - "WebglConformance_conformance_canvas_framebuffer_bindings_unaffected_on_resize": 0.2218, - "WebglConformance_conformance_canvas_rapid_resizing": 2.2804, - "WebglConformance_conformance_canvas_texture_bindings_unaffected_on_resize": 0.2332, - "WebglConformance_conformance_canvas_to_data_url_test": 0.6278, - "WebglConformance_conformance_canvas_viewport_unchanged_upon_resize": 0.104, - "WebglConformance_conformance_context_context_attribute_preserve_drawing_buffer": 0.2841, - "WebglConformance_conformance_context_context_attributes_alpha_depth_stencil_antialias": 0.2774, - "WebglConformance_conformance_context_context_creation": 4.5242, - "WebglConformance_conformance_context_context_creation_and_destruction": 5.4453, - "WebglConformance_conformance_context_context_eviction_with_garbage_collection": 0.9847, - "WebglConformance_conformance_context_context_hidden_alpha": 0.1653, - "WebglConformance_conformance_context_context_lost": 0.1101, - "WebglConformance_conformance_context_context_lost_restored": 0.2374, - "WebglConformance_conformance_context_context_no_alpha_fbo_with_alpha": 0.217, - "WebglConformance_conformance_context_context_release_upon_reload": 1.9419, - "WebglConformance_conformance_context_context_release_with_workers": 1.9225, - "WebglConformance_conformance_context_context_size_change": 0.1539, - "WebglConformance_conformance_context_incorrect_context_object_behaviour": 0.0841, - "WebglConformance_conformance_context_premultiplyalpha_test": 0.4361, - "WebglConformance_conformance_context_resource_sharing_test": 0.0662, - "WebglConformance_conformance_context_user_defined_properties_on_context": 0.0912, - "WebglConformance_conformance_extensions_ext_disjoint_timer_query": 0.0736, - "WebglConformance_conformance_extensions_ext_texture_filter_anisotropic": 0.0656, - "WebglConformance_conformance_extensions_get_extension": 0.1672, - "WebglConformance_conformance_extensions_oes_texture_float_linear": 0.0574, - "WebglConformance_conformance_extensions_webgl_compressed_texture_astc": 0.059, - "WebglConformance_conformance_extensions_webgl_compressed_texture_etc": 0.0523, - "WebglConformance_conformance_extensions_webgl_compressed_texture_pvrtc": 0.0694, - "WebglConformance_conformance_extensions_webgl_compressed_texture_s3tc": 0.7971, - "WebglConformance_conformance_extensions_webgl_compressed_texture_s3tc_srgb": 0.775, - "WebglConformance_conformance_extensions_webgl_compressed_texture_size_limit": 2.774, - "WebglConformance_conformance_extensions_webgl_debug_renderer_info": 0.0497, - "WebglConformance_conformance_extensions_webgl_debug_shaders": 0.077, - "WebglConformance_conformance_extensions_webgl_shared_resources": 0.0945, - "WebglConformance_conformance_glsl_bugs_angle_ambiguous_function_call": 0.213, - "WebglConformance_conformance_glsl_bugs_angle_constructor_invalid_parameters": 0.0769, - "WebglConformance_conformance_glsl_bugs_angle_d3d11_compiler_error": 0.0665, - "WebglConformance_conformance_glsl_bugs_angle_dx_variable_bug": 0.0721, - "WebglConformance_conformance_glsl_bugs_array_of_struct_with_int_first_position": 0.1083, - "WebglConformance_conformance_glsl_bugs_bool_type_cast_bug_int_float": 0.212, - "WebglConformance_conformance_glsl_bugs_compare_loop_index_to_uniform": 0.1169, - "WebglConformance_conformance_glsl_bugs_complex_glsl_does_not_crash": 1.3276, - "WebglConformance_conformance_glsl_bugs_compound_assignment_type_combination": 2.4201, - "WebglConformance_conformance_glsl_bugs_conditional_discard_in_loop": 0.1766, - "WebglConformance_conformance_glsl_bugs_conditional_discard_optimization": 0.1718, - "WebglConformance_conformance_glsl_bugs_constant_precision_qualifier": 0.1173, - "WebglConformance_conformance_glsl_bugs_floor_div_cos_should_not_truncate": 0.1081, - "WebglConformance_conformance_glsl_bugs_floored_division_accuracy": 0.1524, - "WebglConformance_conformance_glsl_bugs_fragcoord_linking_bug": 0.0783, - "WebglConformance_conformance_glsl_bugs_gl_fragcoord_multisampling_bug": 0.157, - "WebglConformance_conformance_glsl_bugs_global_invariant_does_not_leak_across_shaders": 0.1856, - "WebglConformance_conformance_glsl_bugs_invariant_does_not_leak_across_shaders": 0.1868, - "WebglConformance_conformance_glsl_bugs_logic_inside_block_without_braces": 0.2676, - "WebglConformance_conformance_glsl_bugs_long_expressions_should_not_crash": 0.6524, - "WebglConformance_conformance_glsl_bugs_loop_if_loop_gradient": 0.1011, - "WebglConformance_conformance_glsl_bugs_modulo_arithmetic_accuracy": 0.0895, - "WebglConformance_conformance_glsl_bugs_multiplication_assignment": 0.0544, - "WebglConformance_conformance_glsl_bugs_nested_functions_should_not_crash": 0.2426, - "WebglConformance_conformance_glsl_bugs_nested_loops_with_break_and_continue": 0.5607, - "WebglConformance_conformance_glsl_bugs_nested_sequence_operator": 0.1411, - "WebglConformance_conformance_glsl_bugs_pow_of_small_constant_in_user_defined_function": 0.0975, - "WebglConformance_conformance_glsl_bugs_pow_with_constant_exponent_should_not_crash": 0.1698, - "WebglConformance_conformance_glsl_bugs_qualcomm_crash": 0.1135, - "WebglConformance_conformance_glsl_bugs_qualcomm_loop_with_continue_crash": 0.0653, - "WebglConformance_conformance_glsl_bugs_sampler_array_struct_function_arg": 0.0007, - "WebglConformance_conformance_glsl_bugs_sampler_array_using_loop_index": 0.1223, - "WebglConformance_conformance_glsl_bugs_sampler_struct_function_arg": 0.1077, - "WebglConformance_conformance_glsl_bugs_sequence_operator_evaluation_order": 0.2577, - "WebglConformance_conformance_glsl_bugs_sketchfab_lighting_shader_crash": 0.1508, - "WebglConformance_conformance_glsl_bugs_struct_constructor_highp_bug": 0.107, - "WebglConformance_conformance_glsl_bugs_temp_expressions_should_not_crash": 0.6486, - "WebglConformance_conformance_glsl_bugs_unary_minus_operator_float_bug": 6.1952, - "WebglConformance_conformance_glsl_bugs_undefined_index_should_not_crash": 0.1808, - "WebglConformance_conformance_glsl_bugs_uniforms_should_not_lose_values": 0.1079, - "WebglConformance_conformance_glsl_bugs_varying_arrays_should_not_be_reversed": 0.1204, - "WebglConformance_conformance_glsl_constructors_glsl_construct_bvec2": 1.3041, - "WebglConformance_conformance_glsl_constructors_glsl_construct_bvec3": 0.8954, - "WebglConformance_conformance_glsl_constructors_glsl_construct_bvec4": 1.1256, - "WebglConformance_conformance_glsl_constructors_glsl_construct_ivec2": 0.7311, - "WebglConformance_conformance_glsl_constructors_glsl_construct_ivec3": 0.9181, - "WebglConformance_conformance_glsl_constructors_glsl_construct_ivec4": 1.2931, - "WebglConformance_conformance_glsl_constructors_glsl_construct_mat2": 0.8777, - "WebglConformance_conformance_glsl_constructors_glsl_construct_mat3": 0.7439, - "WebglConformance_conformance_glsl_constructors_glsl_construct_mat4": 0.5712, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec2": 0.7112, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec3": 1.0902, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec4": 1.2655, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec_mat_corner_cases": 0.1708, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec_mat_index": 0.1192, - "WebglConformance_conformance_glsl_functions_glsl_function": 0.3066, - "WebglConformance_conformance_glsl_functions_glsl_function_abs": 0.4447, - "WebglConformance_conformance_glsl_functions_glsl_function_acos": 0.2612, - "WebglConformance_conformance_glsl_functions_glsl_function_asin": 0.4871, - "WebglConformance_conformance_glsl_functions_glsl_function_atan": 0.2722, - "WebglConformance_conformance_glsl_functions_glsl_function_atan_xy": 0.2961, - "WebglConformance_conformance_glsl_functions_glsl_function_ceil": 0.4628, - "WebglConformance_conformance_glsl_functions_glsl_function_clamp_float": 0.4618, - "WebglConformance_conformance_glsl_functions_glsl_function_clamp_gentype": 0.3227, - "WebglConformance_conformance_glsl_functions_glsl_function_cos": 0.321, - "WebglConformance_conformance_glsl_functions_glsl_function_cross": 0.1256, - "WebglConformance_conformance_glsl_functions_glsl_function_distance": 0.2992, - "WebglConformance_conformance_glsl_functions_glsl_function_dot": 0.1827, - "WebglConformance_conformance_glsl_functions_glsl_function_faceforward": 0.4325, - "WebglConformance_conformance_glsl_functions_glsl_function_floor": 0.305, - "WebglConformance_conformance_glsl_functions_glsl_function_fract": 0.1956, - "WebglConformance_conformance_glsl_functions_glsl_function_length": 0.2907, - "WebglConformance_conformance_glsl_functions_glsl_function_max_float": 0.2911, - "WebglConformance_conformance_glsl_functions_glsl_function_max_gentype": 0.4601, - "WebglConformance_conformance_glsl_functions_glsl_function_min_float": 0.2649, - "WebglConformance_conformance_glsl_functions_glsl_function_min_gentype": 0.4486, - "WebglConformance_conformance_glsl_functions_glsl_function_mix_float": 0.3265, - "WebglConformance_conformance_glsl_functions_glsl_function_mix_gentype": 0.4349, - "WebglConformance_conformance_glsl_functions_glsl_function_mod_float": 0.2605, - "WebglConformance_conformance_glsl_functions_glsl_function_mod_gentype": 0.2396, - "WebglConformance_conformance_glsl_functions_glsl_function_normalize": 0.3675, - "WebglConformance_conformance_glsl_functions_glsl_function_reflect": 0.2391, - "WebglConformance_conformance_glsl_functions_glsl_function_sign": 0.272, - "WebglConformance_conformance_glsl_functions_glsl_function_sin": 0.3017, - "WebglConformance_conformance_glsl_functions_glsl_function_smoothstep_float": 0.17, - "WebglConformance_conformance_glsl_functions_glsl_function_smoothstep_gentype": 0.2954, - "WebglConformance_conformance_glsl_functions_glsl_function_step_float": 0.1811, - "WebglConformance_conformance_glsl_functions_glsl_function_step_gentype": 0.2792, - "WebglConformance_conformance_glsl_implicit_add_int_float_vert": 0.0543, - "WebglConformance_conformance_glsl_implicit_add_int_mat2_vert": 0.058, - "WebglConformance_conformance_glsl_implicit_add_int_mat3_vert": 0.086, - "WebglConformance_conformance_glsl_implicit_add_int_mat4_vert": 0.0658, - "WebglConformance_conformance_glsl_implicit_add_int_vec2_vert": 0.1054, - "WebglConformance_conformance_glsl_implicit_add_int_vec3_vert": 0.0526, - "WebglConformance_conformance_glsl_implicit_add_int_vec4_vert": 0.0494, - "WebglConformance_conformance_glsl_implicit_add_ivec2_vec2_vert": 0.0605, - "WebglConformance_conformance_glsl_implicit_add_ivec3_vec3_vert": 0.0468, - "WebglConformance_conformance_glsl_implicit_add_ivec4_vec4_vert": 0.0806, - "WebglConformance_conformance_glsl_implicit_assign_int_to_float_vert": 0.0741, - "WebglConformance_conformance_glsl_implicit_assign_ivec2_to_vec2_vert": 0.0637, - "WebglConformance_conformance_glsl_implicit_assign_ivec3_to_vec3_vert": 0.065, - "WebglConformance_conformance_glsl_implicit_assign_ivec4_to_vec4_vert": 0.0528, - "WebglConformance_conformance_glsl_implicit_construct_struct_vert": 0.0866, - "WebglConformance_conformance_glsl_implicit_divide_int_float_vert": 0.0553, - "WebglConformance_conformance_glsl_implicit_divide_int_mat2_vert": 0.0811, - "WebglConformance_conformance_glsl_implicit_divide_int_mat3_vert": 0.1723, - "WebglConformance_conformance_glsl_implicit_divide_int_mat4_vert": 0.0635, - "WebglConformance_conformance_glsl_implicit_divide_int_vec2_vert": 0.0606, - "WebglConformance_conformance_glsl_implicit_divide_int_vec3_vert": 0.0601, - "WebglConformance_conformance_glsl_implicit_divide_int_vec4_vert": 0.0873, - "WebglConformance_conformance_glsl_implicit_divide_ivec2_vec2_vert": 0.0556, - "WebglConformance_conformance_glsl_implicit_divide_ivec3_vec3_vert": 0.0897, - "WebglConformance_conformance_glsl_implicit_divide_ivec4_vec4_vert": 0.0534, - "WebglConformance_conformance_glsl_implicit_equal_int_float_vert": 0.0544, - "WebglConformance_conformance_glsl_implicit_equal_ivec2_vec2_vert": 0.0927, - "WebglConformance_conformance_glsl_implicit_equal_ivec3_vec3_vert": 0.0765, - "WebglConformance_conformance_glsl_implicit_equal_ivec4_vec4_vert": 0.0764, - "WebglConformance_conformance_glsl_implicit_function_int_float_vert": 0.0677, - "WebglConformance_conformance_glsl_implicit_function_ivec2_vec2_vert": 0.0812, - "WebglConformance_conformance_glsl_implicit_function_ivec3_vec3_vert": 0.0992, - "WebglConformance_conformance_glsl_implicit_function_ivec4_vec4_vert": 0.0567, - "WebglConformance_conformance_glsl_implicit_greater_than_equal_vert": 0.0492, - "WebglConformance_conformance_glsl_implicit_greater_than_vert": 0.0671, - "WebglConformance_conformance_glsl_implicit_less_than_equal_vert": 0.0578, - "WebglConformance_conformance_glsl_implicit_less_than_vert": 0.0679, - "WebglConformance_conformance_glsl_implicit_multiply_int_float_vert": 0.0767, - "WebglConformance_conformance_glsl_implicit_multiply_int_mat2_vert": 0.0676, - "WebglConformance_conformance_glsl_implicit_multiply_int_mat3_vert": 0.0501, - "WebglConformance_conformance_glsl_implicit_multiply_int_mat4_vert": 0.0688, - "WebglConformance_conformance_glsl_implicit_multiply_int_vec2_vert": 0.08, - "WebglConformance_conformance_glsl_implicit_multiply_int_vec3_vert": 0.0494, - "WebglConformance_conformance_glsl_implicit_multiply_int_vec4_vert": 0.0712, - "WebglConformance_conformance_glsl_implicit_multiply_ivec2_vec2_vert": 0.0833, - "WebglConformance_conformance_glsl_implicit_multiply_ivec3_vec3_vert": 0.0805, - "WebglConformance_conformance_glsl_implicit_multiply_ivec4_vec4_vert": 0.0825, - "WebglConformance_conformance_glsl_implicit_not_equal_int_float_vert": 0.0628, - "WebglConformance_conformance_glsl_implicit_not_equal_ivec2_vec2_vert": 0.0478, - "WebglConformance_conformance_glsl_implicit_not_equal_ivec3_vec3_vert": 0.0871, - "WebglConformance_conformance_glsl_implicit_not_equal_ivec4_vec4_vert": 0.0933, - "WebglConformance_conformance_glsl_implicit_subtract_int_float_vert": 0.0963, - "WebglConformance_conformance_glsl_implicit_subtract_int_mat2_vert": 0.0843, - "WebglConformance_conformance_glsl_implicit_subtract_int_mat3_vert": 0.088, - "WebglConformance_conformance_glsl_implicit_subtract_int_mat4_vert": 0.0886, - "WebglConformance_conformance_glsl_implicit_subtract_int_vec2_vert": 0.0834, - "WebglConformance_conformance_glsl_implicit_subtract_int_vec3_vert": 0.0923, - "WebglConformance_conformance_glsl_implicit_subtract_int_vec4_vert": 0.0525, - "WebglConformance_conformance_glsl_implicit_subtract_ivec2_vec2_vert": 0.0507, - "WebglConformance_conformance_glsl_implicit_subtract_ivec3_vec3_vert": 0.0901, - "WebglConformance_conformance_glsl_implicit_subtract_ivec4_vec4_vert": 0.0437, - "WebglConformance_conformance_glsl_implicit_ternary_int_float_vert": 0.0822, - "WebglConformance_conformance_glsl_implicit_ternary_ivec2_vec2_vert": 0.0542, - "WebglConformance_conformance_glsl_implicit_ternary_ivec3_vec3_vert": 0.082, - "WebglConformance_conformance_glsl_implicit_ternary_ivec4_vec4_vert": 0.0498, - "WebglConformance_conformance_glsl_literals_float_literal_vert": 0.053, - "WebglConformance_conformance_glsl_literals_literal_precision": 0.0833, - "WebglConformance_conformance_glsl_literals_overflow_leak_vert": 0.1143, - "WebglConformance_conformance_glsl_matrices_glsl_mat3_construction": 0.1491, - "WebglConformance_conformance_glsl_matrices_glsl_mat4_to_mat3": 0.1789, - "WebglConformance_conformance_glsl_matrices_matrix_compound_multiply": 0.1093, - "WebglConformance_conformance_glsl_misc_boolean_precision": 0.1935, - "WebglConformance_conformance_glsl_misc_const_variable_initialization": 2.1562, - "WebglConformance_conformance_glsl_misc_embedded_struct_definitions_forbidden": 0.0838, - "WebglConformance_conformance_glsl_misc_empty_declaration": 0.1648, - "WebglConformance_conformance_glsl_misc_empty_main_vert": 0.0587, - "WebglConformance_conformance_glsl_misc_expression_list_in_declarator_initializer": 0.7654, - "WebglConformance_conformance_glsl_misc_gl_position_unset_vert": 0.0873, - "WebglConformance_conformance_glsl_misc_global_variable_init": 0.2661, - "WebglConformance_conformance_glsl_misc_glsl_function_nodes": 0.0764, - "WebglConformance_conformance_glsl_misc_glsl_long_variable_names": 0.0861, - "WebglConformance_conformance_glsl_misc_glsl_vertex_branch": 0.1082, - "WebglConformance_conformance_glsl_misc_large_loop_compile": 0.6143, - "WebglConformance_conformance_glsl_misc_local_variable_shadowing_outer_function": 0.0512, - "WebglConformance_conformance_glsl_misc_non_ascii_comments_vert": 0.072, - "WebglConformance_conformance_glsl_misc_non_ascii_vert": 0.0792, - "WebglConformance_conformance_glsl_misc_re_compile_re_link": 0.1595, - "WebglConformance_conformance_glsl_misc_sampler_operand": 0.0748, - "WebglConformance_conformance_glsl_misc_sequence_operator_returns_constant": 0.0998, - "WebglConformance_conformance_glsl_misc_shader_precision_format_obeyed": 0.1854, - "WebglConformance_conformance_glsl_misc_shader_struct_scope": 0.2137, - "WebglConformance_conformance_glsl_misc_shader_uniform_packing_restrictions": 1.8976, - "WebglConformance_conformance_glsl_misc_shader_varying_packing_restrictions": 0.4135, - "WebglConformance_conformance_glsl_misc_shader_with_256_character_define": 0.0469, - "WebglConformance_conformance_glsl_misc_shader_with_256_character_identifier_frag": 0.1658, - "WebglConformance_conformance_glsl_misc_shader_with__webgl_identifier_vert": 0.062, - "WebglConformance_conformance_glsl_misc_shader_with_arbitrary_indexing_frag": 0.0637, - "WebglConformance_conformance_glsl_misc_shader_with_arbitrary_indexing_vert": 0.0428, - "WebglConformance_conformance_glsl_misc_shader_with_array_of_structs_containing_arrays": 0.1047, - "WebglConformance_conformance_glsl_misc_shader_with_array_of_structs_uniform": 0.1425, - "WebglConformance_conformance_glsl_misc_shader_with_attrib_array_vert": 0.0995, - "WebglConformance_conformance_glsl_misc_shader_with_attrib_struct_vert": 0.045, - "WebglConformance_conformance_glsl_misc_shader_with_clipvertex_vert": 0.0694, - "WebglConformance_conformance_glsl_misc_shader_with_comma_assignment": 0.0565, - "WebglConformance_conformance_glsl_misc_shader_with_comma_conditional_assignment": 0.2945, - "WebglConformance_conformance_glsl_misc_shader_with_comma_separated_variable_declarations": 0.0723, - "WebglConformance_conformance_glsl_misc_shader_with_conditional_scoping": 0.0454, - "WebglConformance_conformance_glsl_misc_shader_with_conditional_scoping_negative": 0.0761, - "WebglConformance_conformance_glsl_misc_shader_with_default_precision_frag": 0.0494, - "WebglConformance_conformance_glsl_misc_shader_with_default_precision_vert": 0.0801, - "WebglConformance_conformance_glsl_misc_shader_with_dfdx_frag": 0.058, - "WebglConformance_conformance_glsl_misc_shader_with_dfdx_no_ext_frag": 0.0861, - "WebglConformance_conformance_glsl_misc_shader_with_do_loop": 0.074, - "WebglConformance_conformance_glsl_misc_shader_with_error_directive": 0.0525, - "WebglConformance_conformance_glsl_misc_shader_with_explicit_int_cast_vert": 0.0651, - "WebglConformance_conformance_glsl_misc_shader_with_float_return_value_frag": 0.09, - "WebglConformance_conformance_glsl_misc_shader_with_for_loop": 0.0749, - "WebglConformance_conformance_glsl_misc_shader_with_for_scoping": 0.1072, - "WebglConformance_conformance_glsl_misc_shader_with_frag_depth_frag": 0.045, - "WebglConformance_conformance_glsl_misc_shader_with_function_recursion_frag": 0.1094, - "WebglConformance_conformance_glsl_misc_shader_with_function_scoped_struct": 0.0766, - "WebglConformance_conformance_glsl_misc_shader_with_functional_scoping": 0.0674, - "WebglConformance_conformance_glsl_misc_shader_with_glcolor_vert": 0.0849, - "WebglConformance_conformance_glsl_misc_shader_with_gles_1_frag": 0.0597, - "WebglConformance_conformance_glsl_misc_shader_with_gles_symbol_frag": 0.09, - "WebglConformance_conformance_glsl_misc_shader_with_global_variable_precision_mismatch": 0.1787, - "WebglConformance_conformance_glsl_misc_shader_with_glprojectionmatrix_vert": 0.109, - "WebglConformance_conformance_glsl_misc_shader_with_hex_int_constant_macro": 0.0647, - "WebglConformance_conformance_glsl_misc_shader_with_implicit_vec3_to_vec4_cast_vert": 0.077, - "WebglConformance_conformance_glsl_misc_shader_with_include_vert": 0.0471, - "WebglConformance_conformance_glsl_misc_shader_with_int_return_value_frag": 0.0723, - "WebglConformance_conformance_glsl_misc_shader_with_invalid_identifier_frag": 0.092, - "WebglConformance_conformance_glsl_misc_shader_with_ivec2_return_value_frag": 0.0633, - "WebglConformance_conformance_glsl_misc_shader_with_ivec3_return_value_frag": 0.0468, - "WebglConformance_conformance_glsl_misc_shader_with_ivec4_return_value_frag": 0.0546, - "WebglConformance_conformance_glsl_misc_shader_with_limited_indexing_frag": 0.0655, - "WebglConformance_conformance_glsl_misc_shader_with_long_line": 0.1226, - "WebglConformance_conformance_glsl_misc_shader_with_non_ascii_error_frag": 0.0481, - "WebglConformance_conformance_glsl_misc_shader_with_non_reserved_words": 13.1436, - "WebglConformance_conformance_glsl_misc_shader_with_precision_frag": 0.1352, - "WebglConformance_conformance_glsl_misc_shader_with_preprocessor_whitespace": 0.0954, - "WebglConformance_conformance_glsl_misc_shader_with_quoted_error_frag": 0.0833, - "WebglConformance_conformance_glsl_misc_shader_with_reserved_words": 2.4404, - "WebglConformance_conformance_glsl_misc_shader_with_short_circuiting_operators": 0.4345, - "WebglConformance_conformance_glsl_misc_shader_with_similar_uniform_array_names": 0.2052, - "WebglConformance_conformance_glsl_misc_shader_with_too_many_uniforms": 0.2027, - "WebglConformance_conformance_glsl_misc_shader_with_two_initializer_types": 0.0696, - "WebglConformance_conformance_glsl_misc_shader_with_undefined_preprocessor_symbol_frag": 0.0493, - "WebglConformance_conformance_glsl_misc_shader_with_uniform_in_loop_condition_vert": 0.0442, - "WebglConformance_conformance_glsl_misc_shader_with_vec2_return_value_frag": 0.0929, - "WebglConformance_conformance_glsl_misc_shader_with_vec3_return_value_frag": 0.1062, - "WebglConformance_conformance_glsl_misc_shader_with_vec4_return_value_frag": 0.0892, - "WebglConformance_conformance_glsl_misc_shader_with_vec4_vec3_vec4_conditional": 0.0591, - "WebglConformance_conformance_glsl_misc_shader_with_version_100_frag": 0.0945, - "WebglConformance_conformance_glsl_misc_shader_with_version_100_vert": 0.0681, - "WebglConformance_conformance_glsl_misc_shader_with_version_120_vert": 0.0807, - "WebglConformance_conformance_glsl_misc_shader_with_version_130_vert": 0.0542, - "WebglConformance_conformance_glsl_misc_shader_with_webgl_identifier_vert": 0.0751, - "WebglConformance_conformance_glsl_misc_shader_with_while_loop": 0.0901, - "WebglConformance_conformance_glsl_misc_shader_without_precision_frag": 0.0693, - "WebglConformance_conformance_glsl_misc_shaders_with_constant_expression_loop_conditions": 0.1916, - "WebglConformance_conformance_glsl_misc_shaders_with_invariance": 0.3221, - "WebglConformance_conformance_glsl_misc_shaders_with_mis_matching_uniforms": 0.7104, - "WebglConformance_conformance_glsl_misc_shaders_with_mis_matching_varyings": 0.3001, - "WebglConformance_conformance_glsl_misc_shaders_with_missing_varyings": 0.1765, - "WebglConformance_conformance_glsl_misc_shaders_with_name_conflicts": 0.0803, - "WebglConformance_conformance_glsl_misc_shaders_with_uniform_structs": 0.2135, - "WebglConformance_conformance_glsl_misc_shaders_with_varyings": 0.1696, - "WebglConformance_conformance_glsl_misc_shared": 0.1961, - "WebglConformance_conformance_glsl_misc_struct_assign": 0.1899, - "WebglConformance_conformance_glsl_misc_struct_equals": 0.1806, - "WebglConformance_conformance_glsl_misc_struct_mixed_array_declarators": 0.7767, - "WebglConformance_conformance_glsl_misc_struct_nesting_exceeds_maximum": 0.0474, - "WebglConformance_conformance_glsl_misc_struct_nesting_of_variable_names": 2.6988, - "WebglConformance_conformance_glsl_misc_struct_nesting_under_maximum": 0.063, - "WebglConformance_conformance_glsl_misc_struct_specifiers_in_uniforms": 0.3495, - "WebglConformance_conformance_glsl_misc_struct_unary_operators": 0.4721, - "WebglConformance_conformance_glsl_misc_ternary_operator_on_arrays": 0.0817, - "WebglConformance_conformance_glsl_misc_ternary_operators_in_global_initializers": 0.3605, - "WebglConformance_conformance_glsl_misc_ternary_operators_in_initializers": 0.3554, - "WebglConformance_conformance_glsl_misc_uninitialized_local_global_variables": 0.1852, - "WebglConformance_conformance_glsl_preprocessor_macro_expansion_tricky": 0.0501, - "WebglConformance_conformance_glsl_reserved__webgl_field_vert": 0.0583, - "WebglConformance_conformance_glsl_reserved__webgl_function_vert": 0.0919, - "WebglConformance_conformance_glsl_reserved__webgl_struct_vert": 0.0517, - "WebglConformance_conformance_glsl_reserved__webgl_variable_vert": 0.051, - "WebglConformance_conformance_glsl_reserved_webgl_field_vert": 0.0902, - "WebglConformance_conformance_glsl_reserved_webgl_function_vert": 0.0498, - "WebglConformance_conformance_glsl_reserved_webgl_struct_vert": 0.0847, - "WebglConformance_conformance_glsl_reserved_webgl_variable_vert": 0.0917, - "WebglConformance_conformance_glsl_samplers_glsl_function_texture2d_bias": 0.1648, - "WebglConformance_conformance_glsl_samplers_glsl_function_texture2dlod": 0.2161, - "WebglConformance_conformance_glsl_samplers_glsl_function_texture2dproj": 0.1657, - "WebglConformance_conformance_glsl_samplers_glsl_function_texture2dprojlod": 0.3893, - "WebglConformance_conformance_glsl_variables_gl_fragcoord": 0.1462, - "WebglConformance_conformance_glsl_variables_gl_fragcoord_xy_values": 0.0814, - "WebglConformance_conformance_glsl_variables_gl_fragdata_and_fragcolor": 0.0596, - "WebglConformance_conformance_glsl_variables_gl_frontfacing": 0.159, - "WebglConformance_conformance_glsl_variables_gl_pointcoord": 0.1074, - "WebglConformance_conformance_glsl_variables_glsl_built_ins": 0.2039, - "WebglConformance_conformance_limits_gl_line_width": 0.0863, - "WebglConformance_conformance_limits_gl_max_texture_dimensions": 0.0889, - "WebglConformance_conformance_limits_gl_min_attribs": 0.1156, - "WebglConformance_conformance_limits_gl_min_textures": 0.0608, - "WebglConformance_conformance_limits_gl_min_uniforms": 0.1117, - "WebglConformance_conformance_misc_bad_arguments_test": 0.1601, - "WebglConformance_conformance_misc_boolean_argument_conversion": 0.0603, - "WebglConformance_conformance_misc_delayed_drawing": 1.0664, - "WebglConformance_conformance_misc_error_reporting": 0.0837, - "WebglConformance_conformance_misc_expando_loss": 0.2255, - "WebglConformance_conformance_misc_functions_returning_strings": 0.0426, - "WebglConformance_conformance_misc_invalid_passed_params": 0.069, - "WebglConformance_conformance_misc_is_object": 0.0591, - "WebglConformance_conformance_misc_null_object_behaviour": 0.1145, - "WebglConformance_conformance_misc_object_deletion_behaviour": 0.1999, - "WebglConformance_conformance_misc_shader_precision_format": 0.0806, - "WebglConformance_conformance_misc_type_conversion_test": 0.1606, - "WebglConformance_conformance_misc_uninitialized_test": 0.2832, - "WebglConformance_conformance_misc_webgl_specific": 0.0547, - "WebglConformance_conformance_more_conformance_constants": 0.1369, - "WebglConformance_conformance_more_conformance_getContext": 0.1779, - "WebglConformance_conformance_more_conformance_methods": 0.265, - "WebglConformance_conformance_more_conformance_quickCheckAPI_A": 0.2935, - "WebglConformance_conformance_more_conformance_quickCheckAPI_B1": 0.237, - "WebglConformance_conformance_more_conformance_quickCheckAPI_B2": 0.1953, - "WebglConformance_conformance_more_conformance_quickCheckAPI_B3": 0.1461, - "WebglConformance_conformance_more_conformance_quickCheckAPI_B4": 0.2889, - "WebglConformance_conformance_more_conformance_quickCheckAPI_C": 0.1886, - "WebglConformance_conformance_more_conformance_quickCheckAPI_D_G": 0.1672, - "WebglConformance_conformance_more_conformance_quickCheckAPI_G_I": 0.1664, - "WebglConformance_conformance_more_conformance_quickCheckAPI_L_S": 0.2174, - "WebglConformance_conformance_more_conformance_quickCheckAPI_S_V": 0.2364, - "WebglConformance_conformance_more_conformance_webGLArrays": 0.1601, - "WebglConformance_conformance_more_functions_bindBuffer": 0.1145, - "WebglConformance_conformance_more_functions_bindBufferBadArgs": 0.1639, - "WebglConformance_conformance_more_functions_bindFramebufferLeaveNonZero": 0.1464, - "WebglConformance_conformance_more_functions_bufferData": 0.1403, - "WebglConformance_conformance_more_functions_bufferDataBadArgs": 0.1308, - "WebglConformance_conformance_more_functions_bufferSubData": 0.1585, - "WebglConformance_conformance_more_functions_bufferSubDataBadArgs": 0.1932, - "WebglConformance_conformance_more_functions_copyTexImage2D": 0.1879, - "WebglConformance_conformance_more_functions_copyTexImage2DBadArgs": 0.1134, - "WebglConformance_conformance_more_functions_copyTexSubImage2D": 0.1899, - "WebglConformance_conformance_more_functions_copyTexSubImage2DBadArgs": 0.1491, - "WebglConformance_conformance_more_functions_deleteBufferBadArgs": 0.1664, - "WebglConformance_conformance_more_functions_drawArrays": 0.1423, - "WebglConformance_conformance_more_functions_drawArraysOutOfBounds": 0.1358, - "WebglConformance_conformance_more_functions_drawElements": 0.1184, - "WebglConformance_conformance_more_functions_isTests": 0.1504, - "WebglConformance_conformance_more_functions_isTestsBadArgs": 0.0562, - "WebglConformance_conformance_more_functions_readPixels": 0.0993, - "WebglConformance_conformance_more_functions_readPixelsBadArgs": 0.2621, - "WebglConformance_conformance_more_functions_texImage2D": 0.1637, - "WebglConformance_conformance_more_functions_texImage2DBadArgs": 0.1669, - "WebglConformance_conformance_more_functions_texImage2DHTML": 0.2901, - "WebglConformance_conformance_more_functions_texImage2DHTMLBadArgs": 0.1034, - "WebglConformance_conformance_more_functions_texSubImage2D": 0.1697, - "WebglConformance_conformance_more_functions_texSubImage2DBadArgs": 0.1691, - "WebglConformance_conformance_more_functions_texSubImage2DHTML": 0.193, - "WebglConformance_conformance_more_functions_texSubImage2DHTMLBadArgs": 0.1063, - "WebglConformance_conformance_more_functions_uniformMatrix": 0.1577, - "WebglConformance_conformance_more_functions_uniformMatrixBadArgs": 0.1056, - "WebglConformance_conformance_more_functions_uniformf": 0.104, - "WebglConformance_conformance_more_functions_uniformfArrayLen1": 0.1097, - "WebglConformance_conformance_more_functions_uniformfBadArgs": 0.1889, - "WebglConformance_conformance_more_functions_uniformi": 0.1583, - "WebglConformance_conformance_more_functions_uniformiBadArgs": 0.1997, - "WebglConformance_conformance_more_functions_vertexAttrib": 0.1537, - "WebglConformance_conformance_more_functions_vertexAttribBadArgs": 0.1681, - "WebglConformance_conformance_more_functions_vertexAttribPointer": 0.157, - "WebglConformance_conformance_more_functions_vertexAttribPointerBadArgs": 0.1923, - "WebglConformance_conformance_more_glsl_arrayOutOfBounds": 0.1671, - "WebglConformance_conformance_more_glsl_uniformOutOfBounds": 0.1243, - "WebglConformance_conformance_offscreencanvas_context_attribute_preserve_drawing_buffer": 0.17, - "WebglConformance_conformance_offscreencanvas_context_creation": 0.0879, - "WebglConformance_conformance_offscreencanvas_context_creation_worker": 0.1662, - "WebglConformance_conformance_offscreencanvas_context_lost": 0.123, - "WebglConformance_conformance_offscreencanvas_context_lost_restored": 0.2773, - "WebglConformance_conformance_offscreencanvas_context_lost_restored_worker": 0.1293, - "WebglConformance_conformance_offscreencanvas_context_lost_worker": 0.1616, - "WebglConformance_conformance_offscreencanvas_methods": 0.0759, - "WebglConformance_conformance_offscreencanvas_methods_worker": 0.1712, - "WebglConformance_conformance_offscreencanvas_offscreencanvas_resize": 0.2874, - "WebglConformance_conformance_offscreencanvas_offscreencanvas_transfer_image_bitmap": 0.1316, - "WebglConformance_conformance_ogles_GL_abs_abs_001_to_006": 0.8148, - "WebglConformance_conformance_ogles_GL_acos_acos_001_to_006": 0.7618, - "WebglConformance_conformance_ogles_GL_all_all_001_to_004": 0.5223, - "WebglConformance_conformance_ogles_GL_any_any_001_to_004": 0.492, - "WebglConformance_conformance_ogles_GL_array_array_001_to_006": 0.5327, - "WebglConformance_conformance_ogles_GL_asin_asin_001_to_006": 0.6891, - "WebglConformance_conformance_ogles_GL_atan_atan_001_to_008": 0.8125, - "WebglConformance_conformance_ogles_GL_atan_atan_009_to_012": 1.0414, - "WebglConformance_conformance_ogles_GL_biConstants_biConstants_001_to_008": 0.5593, - "WebglConformance_conformance_ogles_GL_biConstants_biConstants_009_to_016": 0.5659, - "WebglConformance_conformance_ogles_GL_biuDepthRange_biuDepthRange_001_to_002": 0.3517, - "WebglConformance_conformance_ogles_GL_build_build_001_to_008": 0.2657, - "WebglConformance_conformance_ogles_GL_build_build_009_to_016": 0.1837, - "WebglConformance_conformance_ogles_GL_build_build_017_to_024": 0.1898, - "WebglConformance_conformance_ogles_GL_build_build_025_to_032": 0.1898, - "WebglConformance_conformance_ogles_GL_build_build_033_to_040": 0.1648, - "WebglConformance_conformance_ogles_GL_build_build_041_to_048": 0.1824, - "WebglConformance_conformance_ogles_GL_build_build_049_to_056": 0.163, - "WebglConformance_conformance_ogles_GL_build_build_057_to_064": 0.1526, - "WebglConformance_conformance_ogles_GL_build_build_065_to_072": 0.1599, - "WebglConformance_conformance_ogles_GL_build_build_073_to_080": 0.1605, - "WebglConformance_conformance_ogles_GL_build_build_081_to_088": 0.1841, - "WebglConformance_conformance_ogles_GL_build_build_089_to_096": 0.1863, - "WebglConformance_conformance_ogles_GL_build_build_097_to_104": 0.1797, - "WebglConformance_conformance_ogles_GL_build_build_105_to_112": 0.1664, - "WebglConformance_conformance_ogles_GL_build_build_113_to_120": 0.1622, - "WebglConformance_conformance_ogles_GL_build_build_121_to_128": 0.1822, - "WebglConformance_conformance_ogles_GL_build_build_129_to_136": 0.1996, - "WebglConformance_conformance_ogles_GL_build_build_137_to_144": 0.1677, - "WebglConformance_conformance_ogles_GL_build_build_145_to_152": 0.1823, - "WebglConformance_conformance_ogles_GL_build_build_153_to_160": 0.1661, - "WebglConformance_conformance_ogles_GL_build_build_161_to_168": 0.1764, - "WebglConformance_conformance_ogles_GL_build_build_169_to_176": 0.205, - "WebglConformance_conformance_ogles_GL_build_build_177_to_178": 0.1786, - "WebglConformance_conformance_ogles_GL_built_in_varying_array_out_of_bounds_built_in_varying_array_out_of_bounds_001_to_001": 0.0778, - "WebglConformance_conformance_ogles_GL_ceil_ceil_001_to_006": 0.5293, - "WebglConformance_conformance_ogles_GL_clamp_clamp_001_to_006": 0.7175, - "WebglConformance_conformance_ogles_GL_control_flow_control_flow_001_to_008": 0.8215, - "WebglConformance_conformance_ogles_GL_control_flow_control_flow_009_to_010": 0.1886, - "WebglConformance_conformance_ogles_GL_cos_cos_001_to_006": 0.6581, - "WebglConformance_conformance_ogles_GL_cross_cross_001_to_002": 0.3032, - "WebglConformance_conformance_ogles_GL_default_default_001_to_001": 0.2139, - "WebglConformance_conformance_ogles_GL_degrees_degrees_001_to_006": 0.7559, - "WebglConformance_conformance_ogles_GL_discard_discard_001_to_002": 0.2448, - "WebglConformance_conformance_ogles_GL_distance_distance_001_to_006": 0.6038, - "WebglConformance_conformance_ogles_GL_dot_dot_001_to_006": 0.6981, - "WebglConformance_conformance_ogles_GL_equal_equal_001_to_008": 0.6319, - "WebglConformance_conformance_ogles_GL_equal_equal_009_to_012": 0.454, - "WebglConformance_conformance_ogles_GL_exp2_exp2_001_to_008": 0.7954, - "WebglConformance_conformance_ogles_GL_exp2_exp2_009_to_012": 0.7949, - "WebglConformance_conformance_ogles_GL_exp_exp_001_to_008": 0.7845, - "WebglConformance_conformance_ogles_GL_exp_exp_009_to_012": 1.1245, - "WebglConformance_conformance_ogles_GL_faceforward_faceforward_001_to_006": 0.6698, - "WebglConformance_conformance_ogles_GL_floor_floor_001_to_006": 0.7365, - "WebglConformance_conformance_ogles_GL_fract_fract_001_to_006": 0.6441, - "WebglConformance_conformance_ogles_GL_functions_functions_001_to_008": 0.6121, - "WebglConformance_conformance_ogles_GL_functions_functions_009_to_016": 0.5249, - "WebglConformance_conformance_ogles_GL_functions_functions_017_to_024": 0.5815, - "WebglConformance_conformance_ogles_GL_functions_functions_025_to_032": 0.5893, - "WebglConformance_conformance_ogles_GL_functions_functions_033_to_040": 0.5638, - "WebglConformance_conformance_ogles_GL_functions_functions_041_to_048": 0.5432, - "WebglConformance_conformance_ogles_GL_functions_functions_049_to_056": 0.4787, - "WebglConformance_conformance_ogles_GL_functions_functions_057_to_064": 0.5652, - "WebglConformance_conformance_ogles_GL_functions_functions_065_to_072": 0.5133, - "WebglConformance_conformance_ogles_GL_functions_functions_073_to_080": 0.5467, - "WebglConformance_conformance_ogles_GL_functions_functions_081_to_088": 0.5845, - "WebglConformance_conformance_ogles_GL_functions_functions_089_to_096": 0.548, - "WebglConformance_conformance_ogles_GL_functions_functions_097_to_104": 0.5458, - "WebglConformance_conformance_ogles_GL_functions_functions_105_to_112": 0.5041, - "WebglConformance_conformance_ogles_GL_functions_functions_113_to_120": 0.607, - "WebglConformance_conformance_ogles_GL_functions_functions_121_to_126": 0.3578, - "WebglConformance_conformance_ogles_GL_gl_FragCoord_gl_FragCoord_001_to_003": 0.2693, - "WebglConformance_conformance_ogles_GL_gl_FrontFacing_gl_FrontFacing_001_to_001": 0.1287, - "WebglConformance_conformance_ogles_GL_greaterThanEqual_greaterThanEqual_001_to_008": 0.8175, - "WebglConformance_conformance_ogles_GL_greaterThan_greaterThan_001_to_008": 0.7698, - "WebglConformance_conformance_ogles_GL_inversesqrt_inversesqrt_001_to_006": 0.6362, - "WebglConformance_conformance_ogles_GL_length_length_001_to_006": 0.6893, - "WebglConformance_conformance_ogles_GL_lessThanEqual_lessThanEqual_001_to_008": 0.8141, - "WebglConformance_conformance_ogles_GL_lessThan_lessThan_001_to_008": 0.8023, - "WebglConformance_conformance_ogles_GL_log2_log2_001_to_008": 0.7801, - "WebglConformance_conformance_ogles_GL_log2_log2_009_to_012": 1.1009, - "WebglConformance_conformance_ogles_GL_log_log_001_to_008": 0.6934, - "WebglConformance_conformance_ogles_GL_log_log_009_to_012": 1.1254, - "WebglConformance_conformance_ogles_GL_mat3_mat3_001_to_006": 0.352, - "WebglConformance_conformance_ogles_GL_mat_mat_001_to_008": 0.4641, - "WebglConformance_conformance_ogles_GL_mat_mat_009_to_016": 0.6216, - "WebglConformance_conformance_ogles_GL_mat_mat_017_to_024": 0.5082, - "WebglConformance_conformance_ogles_GL_mat_mat_025_to_032": 1.1196, - "WebglConformance_conformance_ogles_GL_mat_mat_033_to_040": 0.6489, - "WebglConformance_conformance_ogles_GL_mat_mat_041_to_046": 0.3488, - "WebglConformance_conformance_ogles_GL_matrixCompMult_matrixCompMult_001_to_004": 0.6173, - "WebglConformance_conformance_ogles_GL_max_max_001_to_006": 0.5182, - "WebglConformance_conformance_ogles_GL_min_min_001_to_006": 0.6078, - "WebglConformance_conformance_ogles_GL_mix_mix_001_to_006": 0.5705, - "WebglConformance_conformance_ogles_GL_mod_mod_001_to_008": 0.7213, - "WebglConformance_conformance_ogles_GL_normalize_normalize_001_to_006": 0.675, - "WebglConformance_conformance_ogles_GL_notEqual_notEqual_001_to_008": 0.6113, - "WebglConformance_conformance_ogles_GL_notEqual_notEqual_009_to_012": 0.4848, - "WebglConformance_conformance_ogles_GL_not_not_001_to_004": 0.5241, - "WebglConformance_conformance_ogles_GL_operators_operators_001_to_008": 0.6529, - "WebglConformance_conformance_ogles_GL_operators_operators_009_to_016": 0.5803, - "WebglConformance_conformance_ogles_GL_operators_operators_017_to_024": 0.5221, - "WebglConformance_conformance_ogles_GL_operators_operators_025_to_026": 0.2934, - "WebglConformance_conformance_ogles_GL_pow_pow_001_to_008": 0.5548, - "WebglConformance_conformance_ogles_GL_pow_pow_009_to_016": 1.0834, - "WebglConformance_conformance_ogles_GL_pow_pow_017_to_024": 0.9511, - "WebglConformance_conformance_ogles_GL_radians_radians_001_to_006": 0.6021, - "WebglConformance_conformance_ogles_GL_reflect_reflect_001_to_006": 0.6893, - "WebglConformance_conformance_ogles_GL_refract_refract_001_to_006": 0.6617, - "WebglConformance_conformance_ogles_GL_sign_sign_001_to_006": 0.5933, - "WebglConformance_conformance_ogles_GL_sin_sin_001_to_006": 0.9673, - "WebglConformance_conformance_ogles_GL_smoothstep_smoothstep_001_to_006": 0.8993, - "WebglConformance_conformance_ogles_GL_sqrt_sqrt_001_to_006": 0.6217, - "WebglConformance_conformance_ogles_GL_step_step_001_to_006": 0.5308, - "WebglConformance_conformance_ogles_GL_struct_struct_001_to_008": 0.7864, - "WebglConformance_conformance_ogles_GL_struct_struct_009_to_016": 0.7945, - "WebglConformance_conformance_ogles_GL_struct_struct_017_to_024": 0.6127, - "WebglConformance_conformance_ogles_GL_struct_struct_025_to_032": 0.7474, - "WebglConformance_conformance_ogles_GL_struct_struct_033_to_040": 0.6425, - "WebglConformance_conformance_ogles_GL_struct_struct_041_to_048": 0.5666, - "WebglConformance_conformance_ogles_GL_struct_struct_049_to_056": 0.5823, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_001_to_008": 0.8179, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_009_to_016": 0.7736, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_017_to_024": 0.7121, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_025_to_032": 0.8386, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_033_to_040": 0.7152, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_041_to_048": 0.8142, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_049_to_056": 0.8073, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_057_to_064": 0.6974, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_065_to_072": 0.6287, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_073_to_080": 0.7537, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_081_to_088": 0.7189, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_089_to_096": 0.7752, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_097_to_104": 0.7001, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_105_to_112": 0.7188, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_113_to_120": 0.8981, - "WebglConformance_conformance_ogles_GL_tan_tan_001_to_006": 0.8477, - "WebglConformance_conformance_ogles_GL_vec3_vec3_001_to_008": 0.5682, - "WebglConformance_conformance_ogles_GL_vec_vec_001_to_008": 0.5556, - "WebglConformance_conformance_ogles_GL_vec_vec_009_to_016": 0.5347, - "WebglConformance_conformance_ogles_GL_vec_vec_017_to_018": 0.2282, - "WebglConformance_conformance_programs_get_active_test": 0.0776, - "WebglConformance_conformance_programs_gl_bind_attrib_location_long_names_test": 0.124, - "WebglConformance_conformance_programs_gl_bind_attrib_location_test": 0.0619, - "WebglConformance_conformance_programs_gl_get_active_attribute": 0.0944, - "WebglConformance_conformance_programs_gl_get_active_uniform": 0.163, - "WebglConformance_conformance_programs_gl_getshadersource": 0.0671, - "WebglConformance_conformance_programs_gl_shader_test": 0.1403, - "WebglConformance_conformance_programs_invalid_UTF_16": 0.048, - "WebglConformance_conformance_programs_program_infolog": 0.0512, - "WebglConformance_conformance_programs_program_test": 0.1327, - "WebglConformance_conformance_programs_use_program_crash_with_discard_in_fragment_shader": 0.0456, - "WebglConformance_conformance_reading_fbo_remains_unchanged_after_read_pixels": 0.0464, - "WebglConformance_conformance_reading_read_pixels_pack_alignment": 0.0977, - "WebglConformance_conformance_reading_read_pixels_test": 0.9123, - "WebglConformance_conformance_renderbuffers_feedback_loop": 0.0504, - "WebglConformance_conformance_renderbuffers_framebuffer_state_restoration": 0.4373, - "WebglConformance_conformance_renderbuffers_renderbuffer_initialization": 0.2167, - "WebglConformance_conformance_rendering_clear_after_copyTexImage2D": 0.1549, - "WebglConformance_conformance_rendering_culling": 0.1404, - "WebglConformance_conformance_rendering_default_texture_draw_bug": 0.1819, - "WebglConformance_conformance_rendering_draw_arrays_out_of_bounds": 0.0804, - "WebglConformance_conformance_rendering_draw_elements_out_of_bounds": 0.1043, - "WebglConformance_conformance_rendering_draw_with_changing_start_vertex_bug": 0.1194, - "WebglConformance_conformance_rendering_framebuffer_switch": 0.1031, - "WebglConformance_conformance_rendering_framebuffer_texture_clear": 0.1481, - "WebglConformance_conformance_rendering_framebuffer_texture_switch": 0.0615, - "WebglConformance_conformance_rendering_gl_clear": 0.1253, - "WebglConformance_conformance_rendering_gl_drawarrays": 0.1511, - "WebglConformance_conformance_rendering_gl_drawelements": 0.0653, - "WebglConformance_conformance_rendering_gl_scissor_canvas_dimensions": 0.1579, - "WebglConformance_conformance_rendering_gl_scissor_fbo_test": 0.1355, - "WebglConformance_conformance_rendering_gl_scissor_test": 0.17, - "WebglConformance_conformance_rendering_gl_viewport_test": 0.2774, - "WebglConformance_conformance_rendering_line_loop_tri_fan": 0.0527, - "WebglConformance_conformance_rendering_many_draw_calls": 1.8664, - "WebglConformance_conformance_rendering_more_than_65536_indices": 0.2456, - "WebglConformance_conformance_rendering_multisample_corruption": 7.018, - "WebglConformance_conformance_rendering_negative_one_index": 0.0819, - "WebglConformance_conformance_rendering_out_of_bounds_index_buffers": 0.0697, - "WebglConformance_conformance_rendering_point_no_attributes": 0.1242, - "WebglConformance_conformance_rendering_point_size": 0.1559, - "WebglConformance_conformance_rendering_point_specific_shader_variables": 0.0672, - "WebglConformance_conformance_rendering_point_with_gl_pointcoord_in_fragment_shader": 0.0831, - "WebglConformance_conformance_rendering_polygon_offset": 0.0515, - "WebglConformance_conformance_rendering_simple": 0.1072, - "WebglConformance_conformance_rendering_texture_switch_performance": 0.0011, - "WebglConformance_conformance_rendering_triangle": 0.1446, - "WebglConformance_conformance_state_gl_enable_enum_test": 0.1953, - "WebglConformance_conformance_state_gl_get_calls": 0.0702, - "WebglConformance_conformance_state_gl_geterror": 0.1543, - "WebglConformance_conformance_state_gl_initial_state": 0.0631, - "WebglConformance_conformance_state_state_uneffected_after_compositing": 0.1849, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_alpha_alpha_unsigned_byte": 0.8327, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.7319, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_luminance_luminance_unsigned_byte": 0.7166, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgb_rgb_unsigned_byte": 1.1354, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgb_rgb_unsigned_short_5_6_5": 1.192, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgba_rgba_unsigned_byte": 1.3535, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.733, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 1.2111, - "WebglConformance_conformance_textures_canvas_tex_2d_alpha_alpha_unsigned_byte": 2.9287, - "WebglConformance_conformance_textures_canvas_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 3.3439, - "WebglConformance_conformance_textures_canvas_tex_2d_luminance_luminance_unsigned_byte": 3.2342, - "WebglConformance_conformance_textures_canvas_tex_2d_rgb_rgb_unsigned_byte": 13.7904, - "WebglConformance_conformance_textures_canvas_tex_2d_rgb_rgb_unsigned_short_5_6_5": 3.5115, - "WebglConformance_conformance_textures_canvas_tex_2d_rgba_rgba_unsigned_byte": 14.2866, - "WebglConformance_conformance_textures_canvas_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 3.2352, - "WebglConformance_conformance_textures_canvas_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 3.5279, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_alpha_alpha_unsigned_byte": 0.2263, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.2112, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_luminance_luminance_unsigned_byte": 0.1534, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgb_rgb_unsigned_byte": 0.226, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.2464, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgba_rgba_unsigned_byte": 0.162, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.1328, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.2248, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_alpha_alpha_unsigned_byte": 0.3226, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.3237, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_luminance_luminance_unsigned_byte": 0.3023, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgb_rgb_unsigned_byte": 0.3625, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.347, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgba_rgba_unsigned_byte": 0.3075, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.2964, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.3881, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_alpha_alpha_unsigned_byte": 0.2009, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.1623, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_luminance_luminance_unsigned_byte": 0.1813, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgb_rgb_unsigned_byte": 0.1916, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.1835, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgba_rgba_unsigned_byte": 0.1672, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.2001, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.1505, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_alpha_alpha_unsigned_byte": 0.1998, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.1794, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_luminance_luminance_unsigned_byte": 0.1655, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgb_rgb_unsigned_byte": 0.1289, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.1941, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgba_rgba_unsigned_byte": 0.1071, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.2141, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.1159, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_alpha_alpha_unsigned_byte": 0.248, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.2695, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_luminance_luminance_unsigned_byte": 0.2569, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgb_rgb_unsigned_byte": 0.211, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.1029, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgba_rgba_unsigned_byte": 0.3197, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.3032, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.1567, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_alpha_alpha_unsigned_byte": 1.2998, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 1.3587, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_luminance_luminance_unsigned_byte": 1.4284, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgb_rgb_unsigned_byte": 1.2788, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgb_rgb_unsigned_short_5_6_5": 1.3356, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgba_rgba_unsigned_byte": 1.3695, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 1.3052, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 1.3514, - "WebglConformance_conformance_textures_image_data_tex_2d_alpha_alpha_unsigned_byte": 0.2546, - "WebglConformance_conformance_textures_image_data_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.265, - "WebglConformance_conformance_textures_image_data_tex_2d_luminance_luminance_unsigned_byte": 0.1923, - "WebglConformance_conformance_textures_image_data_tex_2d_rgb_rgb_unsigned_byte": 0.3506, - "WebglConformance_conformance_textures_image_data_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.3805, - "WebglConformance_conformance_textures_image_data_tex_2d_rgba_rgba_unsigned_byte": 0.1859, - "WebglConformance_conformance_textures_image_data_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.4427, - "WebglConformance_conformance_textures_image_data_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.3861, - "WebglConformance_conformance_textures_image_tex_2d_alpha_alpha_unsigned_byte": 0.381, - "WebglConformance_conformance_textures_image_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.2253, - "WebglConformance_conformance_textures_image_tex_2d_luminance_luminance_unsigned_byte": 0.2937, - "WebglConformance_conformance_textures_image_tex_2d_rgb_rgb_unsigned_byte": 0.3899, - "WebglConformance_conformance_textures_image_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.2236, - "WebglConformance_conformance_textures_image_tex_2d_rgba_rgba_unsigned_byte": 0.4098, - "WebglConformance_conformance_textures_image_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.2442, - "WebglConformance_conformance_textures_image_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.1584, - "WebglConformance_conformance_textures_misc_copy_tex_image_2d_formats": 0.1633, - "WebglConformance_conformance_textures_misc_copy_tex_image_and_sub_image_2d": 0.2521, - "WebglConformance_conformance_textures_misc_copy_tex_image_crash": 0.0724, - "WebglConformance_conformance_textures_misc_copytexsubimage2d_large_partial_copy_corruption": 0.2085, - "WebglConformance_conformance_textures_misc_copytexsubimage2d_subrects": 0.1372, - "WebglConformance_conformance_textures_misc_cube_incomplete_fbo": 0.0568, - "WebglConformance_conformance_textures_misc_cube_map_uploads_out_of_order": 1.0564, - "WebglConformance_conformance_textures_misc_default_texture": 0.0856, - "WebglConformance_conformance_textures_misc_gl_pixelstorei": 0.1467, - "WebglConformance_conformance_textures_misc_gl_teximage": 0.2408, - "WebglConformance_conformance_textures_misc_mipmap_fbo": 0.1375, - "WebglConformance_conformance_textures_misc_origin_clean_conformance": 0.0644, - "WebglConformance_conformance_textures_misc_origin_clean_conformance_offscreencanvas": 0.0647, - "WebglConformance_conformance_textures_misc_tex_image_and_sub_image_2d_with_array_buffer_view": 0.7225, - "WebglConformance_conformance_textures_misc_tex_image_and_uniform_binding_bugs": 0.0944, - "WebglConformance_conformance_textures_misc_tex_image_canvas_corruption": 0.1014, - "WebglConformance_conformance_textures_misc_tex_image_webgl": 0.1273, - "WebglConformance_conformance_textures_misc_tex_image_with_format_and_type": 0.1812, - "WebglConformance_conformance_textures_misc_tex_image_with_invalid_data": 0.0669, - "WebglConformance_conformance_textures_misc_tex_sub_image_2d": 0.0744, - "WebglConformance_conformance_textures_misc_tex_sub_image_2d_bad_args": 6.0224, - "WebglConformance_conformance_textures_misc_tex_video_using_tex_unit_non_zero": 1.2823, - "WebglConformance_conformance_textures_misc_texparameter_test": 0.1082, - "WebglConformance_conformance_textures_misc_texture_active_bind": 0.1361, - "WebglConformance_conformance_textures_misc_texture_active_bind_2": 0.1017, - "WebglConformance_conformance_textures_misc_texture_attachment_formats": 0.1495, - "WebglConformance_conformance_textures_misc_texture_clear": 0.0616, - "WebglConformance_conformance_textures_misc_texture_complete": 0.093, - "WebglConformance_conformance_textures_misc_texture_copying_feedback_loops": 0.051, - "WebglConformance_conformance_textures_misc_texture_corner_case_videos": 1.3067, - "WebglConformance_conformance_textures_misc_texture_cube_as_fbo_attachment": 0.0457, - "WebglConformance_conformance_textures_misc_texture_draw_with_2d_and_cube": 0.0616, - "WebglConformance_conformance_textures_misc_texture_hd_dpi": 0.1253, - "WebglConformance_conformance_textures_misc_texture_mips": 0.1101, - "WebglConformance_conformance_textures_misc_texture_size": 0.6764, - "WebglConformance_conformance_textures_misc_texture_size_cube_maps": 0.5105, - "WebglConformance_conformance_textures_misc_texture_size_limit": 1.7159, - "WebglConformance_conformance_textures_misc_texture_sub_image_cube_maps": 0.1407, - "WebglConformance_conformance_textures_misc_texture_transparent_pixels_initialized": 0.1496, - "WebglConformance_conformance_textures_misc_texture_upload_cube_maps": 0.0657, - "WebglConformance_conformance_textures_misc_texture_upload_size": 1.1963, - "WebglConformance_conformance_textures_svg_image_tex_2d_alpha_alpha_unsigned_byte": 0.2355, - "WebglConformance_conformance_textures_svg_image_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.2265, - "WebglConformance_conformance_textures_svg_image_tex_2d_luminance_luminance_unsigned_byte": 0.1512, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgb_rgb_unsigned_byte": 0.2533, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.1426, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgba_rgba_unsigned_byte": 0.1423, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.263, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.1074, - "WebglConformance_conformance_textures_video_tex_2d_alpha_alpha_unsigned_byte": 2.6139, - "WebglConformance_conformance_textures_video_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 2.2951, - "WebglConformance_conformance_textures_video_tex_2d_luminance_luminance_unsigned_byte": 2.2713, - "WebglConformance_conformance_textures_video_tex_2d_rgb_rgb_unsigned_byte": 2.271, - "WebglConformance_conformance_textures_video_tex_2d_rgb_rgb_unsigned_short_5_6_5": 2.5503, - "WebglConformance_conformance_textures_video_tex_2d_rgba_rgba_unsigned_byte": 2.6049, - "WebglConformance_conformance_textures_video_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 2.2676, - "WebglConformance_conformance_textures_video_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 2.2764, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_alpha_alpha_unsigned_byte": 1.9277, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 1.9048, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_luminance_luminance_unsigned_byte": 1.9002, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgb_rgb_unsigned_byte": 8.437, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgb_rgb_unsigned_short_5_6_5": 2.0977, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgba_rgba_unsigned_byte": 8.5878, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 2.1308, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 1.9359, - "WebglConformance_conformance_typedarrays_array_buffer_crash": 0.0494, - "WebglConformance_conformance_typedarrays_array_buffer_view_crash": 0.0559, - "WebglConformance_conformance_typedarrays_array_large_array_tests": 0.031, - "WebglConformance_conformance_typedarrays_array_unit_tests": 0.0603, - "WebglConformance_conformance_typedarrays_data_view_crash": 0.0564, - "WebglConformance_conformance_typedarrays_data_view_test": 0.085, - "WebglConformance_conformance_typedarrays_typed_arrays_in_workers": 0.1294, - "WebglConformance_conformance_uniforms_gl_uniform_arrays": 0.1237, - "WebglConformance_conformance_uniforms_gl_uniform_bool": 0.0528, - "WebglConformance_conformance_uniforms_gl_uniformmatrix4fv": 0.0924, - "WebglConformance_conformance_uniforms_gl_unknown_uniform": 0.0791, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_00": 0.5972, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_01": 0.697, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_02": 0.661, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_03": 1.0042, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_04": 0.6522, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_05": 0.9898, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_06": 0.7383, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_07": 0.9805, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_08": 0.668, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_09": 0.6158, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_10": 0.618, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_11": 0.6358, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_12": 1.1128, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_13": 0.9786, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_14": 0.7107, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_15": 0.6396, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_16": 0.6507, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_17": 0.5989, - "WebglConformance_conformance_uniforms_null_uniform_location": 0.0875, - "WebglConformance_conformance_uniforms_out_of_bounds_uniform_array_access": 5.3298, - "WebglConformance_conformance_uniforms_uniform_default_values": 1.6313, - "WebglConformance_conformance_uniforms_uniform_location": 0.1116, - "WebglConformance_conformance_uniforms_uniform_samplers_test": 18.4324, - "WebglConformance_conformance_uniforms_uniform_values_per_program": 0.7526, - "WebglConformance_deqp_data_gles3_shaders_arrays": 3.4337, - "WebglConformance_deqp_data_gles3_shaders_conditionals": 1.0705, - "WebglConformance_deqp_data_gles3_shaders_constant_expressions": 0.9855, - "WebglConformance_deqp_data_gles3_shaders_constants": 2.2007, - "WebglConformance_deqp_data_gles3_shaders_conversions": 30.4474, - "WebglConformance_deqp_data_gles3_shaders_declarations": 0.9153, - "WebglConformance_deqp_data_gles3_shaders_fragdata": 0.2319, - "WebglConformance_deqp_data_gles3_shaders_functions": 4.6403, - "WebglConformance_deqp_data_gles3_shaders_invalid_texture_functions": 0.9868, - "WebglConformance_deqp_data_gles3_shaders_keywords": 2.4873, - "WebglConformance_deqp_data_gles3_shaders_linkage": 3.4234, - "WebglConformance_deqp_data_gles3_shaders_negative": 0.3389, - "WebglConformance_deqp_data_gles3_shaders_preprocessor": 9.6751, - "WebglConformance_deqp_data_gles3_shaders_qualification_order": 0.8099, - "WebglConformance_deqp_data_gles3_shaders_scoping": 1.3058, - "WebglConformance_deqp_data_gles3_shaders_switch": 0.7634, - "WebglConformance_deqp_data_gles3_shaders_swizzles": 22.5649, - "WebglConformance_deqp_framework_opengl_simplereference_referencecontext": 1.0872, - "WebglConformance_deqp_functional_gles3_attriblocation": 2.512, - "WebglConformance_deqp_functional_gles3_booleanstatequery": 0.3793, - "WebglConformance_deqp_functional_gles3_buffercopy": 2.996, - "WebglConformance_deqp_functional_gles3_bufferobjectquery": 0.2525, - "WebglConformance_deqp_functional_gles3_builtinprecision_abs": 0.0032, - "WebglConformance_deqp_functional_gles3_builtinprecision_acos": 0.0069, - "WebglConformance_deqp_functional_gles3_builtinprecision_acosh": 0.0031, - "WebglConformance_deqp_functional_gles3_builtinprecision_add": 0.0032, - "WebglConformance_deqp_functional_gles3_builtinprecision_asin": 0.0032, - "WebglConformance_deqp_functional_gles3_builtinprecision_asinh": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_atan": 0.0041, - "WebglConformance_deqp_functional_gles3_builtinprecision_atan2": 0.0032, - "WebglConformance_deqp_functional_gles3_builtinprecision_atanh": 0.0032, - "WebglConformance_deqp_functional_gles3_builtinprecision_ceil": 0.0034, - "WebglConformance_deqp_functional_gles3_builtinprecision_clamp": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_cos": 0.0032, - "WebglConformance_deqp_functional_gles3_builtinprecision_cosh": 0.0031, - "WebglConformance_deqp_functional_gles3_builtinprecision_cross": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_degrees": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_determinant": 0.0032, - "WebglConformance_deqp_functional_gles3_builtinprecision_distance": 0.0032, - "WebglConformance_deqp_functional_gles3_builtinprecision_div": 0.0066, - "WebglConformance_deqp_functional_gles3_builtinprecision_dot": 0.0029, - "WebglConformance_deqp_functional_gles3_builtinprecision_exp": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_exp2": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_faceforward": 0.0048, - "WebglConformance_deqp_functional_gles3_builtinprecision_floor": 0.0035, - "WebglConformance_deqp_functional_gles3_builtinprecision_fract": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_inverse": 0.0029, - "WebglConformance_deqp_functional_gles3_builtinprecision_inversesqrt": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_length": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_log": 0.0027, - "WebglConformance_deqp_functional_gles3_builtinprecision_log2": 0.0076, - "WebglConformance_deqp_functional_gles3_builtinprecision_matrixcompmult": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_max": 0.0029, - "WebglConformance_deqp_functional_gles3_builtinprecision_min": 0.003, - "WebglConformance_deqp_functional_gles3_builtinprecision_mix": 0.0051, - "WebglConformance_deqp_functional_gles3_builtinprecision_mod": 0.0073, - "WebglConformance_deqp_functional_gles3_builtinprecision_modf": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_mul": 0.0031, - "WebglConformance_deqp_functional_gles3_builtinprecision_normalize": 0.0029, - "WebglConformance_deqp_functional_gles3_builtinprecision_outerproduct": 0.0029, - "WebglConformance_deqp_functional_gles3_builtinprecision_pow": 0.0044, - "WebglConformance_deqp_functional_gles3_builtinprecision_radians": 0.0027, - "WebglConformance_deqp_functional_gles3_builtinprecision_reflect": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_refract": 0.0029, - "WebglConformance_deqp_functional_gles3_builtinprecision_round": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_roundeven": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_sign": 0.0029, - "WebglConformance_deqp_functional_gles3_builtinprecision_sin": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_sinh": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_smoothstep": 0.0027, - "WebglConformance_deqp_functional_gles3_builtinprecision_sqrt": 0.0029, - "WebglConformance_deqp_functional_gles3_builtinprecision_step": 0.0054, - "WebglConformance_deqp_functional_gles3_builtinprecision_sub": 0.0044, - "WebglConformance_deqp_functional_gles3_builtinprecision_tan": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_tanh": 0.0027, - "WebglConformance_deqp_functional_gles3_builtinprecision_transpose": 0.0028, - "WebglConformance_deqp_functional_gles3_builtinprecision_trunc": 0.0029, - "WebglConformance_deqp_functional_gles3_clipping": 6.5033, - "WebglConformance_deqp_functional_gles3_defaultvertexattribute": 10.2816, - "WebglConformance_deqp_functional_gles3_draw_draw_arrays": 8.2797, - "WebglConformance_deqp_functional_gles3_draw_draw_arrays_instanced": 11.2006, - "WebglConformance_deqp_functional_gles3_draw_draw_elements": 6.2561, - "WebglConformance_deqp_functional_gles3_draw_draw_elements_instanced": 8.0591, - "WebglConformance_deqp_functional_gles3_draw_draw_range_elements": 4.4921, - "WebglConformance_deqp_functional_gles3_draw_instancing": 0.4208, - "WebglConformance_deqp_functional_gles3_draw_random": 7.7433, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_blend": 5.9963, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_clear": 3.2343, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2d_00": 6.4351, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2d_01": 5.3817, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2d_02": 6.1342, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2d_03": 6.2772, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2d_04": 5.9425, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2d_05": 4.9984, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2darray_00": 6.8743, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2darray_01": 7.0084, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2darray_02": 6.231, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2darray_03": 6.5802, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2darray_04": 6.2186, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex2darray_05": 5.1666, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex3d_00": 5.7252, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex3d_01": 5.6934, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex3d_02": 6.0087, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex3d_03": 6.1582, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex3d_04": 6.1301, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_tex3d_05": 4.8943, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_texcube_00": 7.5276, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_texcube_01": 7.8874, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_texcube_02": 7.9163, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_texcube_03": 6.5326, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_texcube_04": 8.8646, - "WebglConformance_deqp_functional_gles3_fbocolorbuffer_texcube_05": 6.9127, - "WebglConformance_deqp_functional_gles3_fbocompleteness": 2.0545, - "WebglConformance_deqp_functional_gles3_fbodepthbuffer": 6.0387, - "WebglConformance_deqp_functional_gles3_fboinvalidate_default": 15.3117, - "WebglConformance_deqp_functional_gles3_fboinvalidate_format_00": 5.839, - "WebglConformance_deqp_functional_gles3_fboinvalidate_format_01": 5.606, - "WebglConformance_deqp_functional_gles3_fboinvalidate_format_02": 5.2942, - "WebglConformance_deqp_functional_gles3_fboinvalidate_sub": 8.0844, - "WebglConformance_deqp_functional_gles3_fboinvalidate_target": 14.0728, - "WebglConformance_deqp_functional_gles3_fboinvalidate_whole": 10.576, - "WebglConformance_deqp_functional_gles3_fbomultisample_2_samples": 13.9878, - "WebglConformance_deqp_functional_gles3_fbomultisample_4_samples": 11.7618, - "WebglConformance_deqp_functional_gles3_fbomultisample_8_samples": 13.2293, - "WebglConformance_deqp_functional_gles3_fborender_recreate_color_00": 5.5693, - "WebglConformance_deqp_functional_gles3_fborender_recreate_color_01": 5.5437, - "WebglConformance_deqp_functional_gles3_fborender_recreate_color_02": 4.6546, - "WebglConformance_deqp_functional_gles3_fborender_recreate_color_03": 5.5737, - "WebglConformance_deqp_functional_gles3_fborender_recreate_color_04": 4.8172, - "WebglConformance_deqp_functional_gles3_fborender_recreate_color_05": 5.2758, - "WebglConformance_deqp_functional_gles3_fborender_recreate_color_06": 5.799, - "WebglConformance_deqp_functional_gles3_fborender_recreate_depth_stencil": 5.5278, - "WebglConformance_deqp_functional_gles3_fborender_resize_00": 4.5919, - "WebglConformance_deqp_functional_gles3_fborender_resize_01": 5.1412, - "WebglConformance_deqp_functional_gles3_fborender_resize_02": 4.4121, - "WebglConformance_deqp_functional_gles3_fborender_resize_03": 8.6669, - "WebglConformance_deqp_functional_gles3_fborender_shared_colorbuffer_00": 6.4687, - "WebglConformance_deqp_functional_gles3_fborender_shared_colorbuffer_01": 8.0698, - "WebglConformance_deqp_functional_gles3_fborender_shared_colorbuffer_02": 7.617, - "WebglConformance_deqp_functional_gles3_fborender_shared_colorbuffer_clear": 3.1344, - "WebglConformance_deqp_functional_gles3_fborender_shared_depth_stencil": 4.1987, - "WebglConformance_deqp_functional_gles3_fborender_stencil_clear": 2.6872, - "WebglConformance_deqp_functional_gles3_fbostatequery": 0.1864, - "WebglConformance_deqp_functional_gles3_fbostencilbuffer": 4.6646, - "WebglConformance_deqp_functional_gles3_floatstatequery": 0.449, - "WebglConformance_deqp_functional_gles3_fragdepth": 2.4864, - "WebglConformance_deqp_functional_gles3_fragmentoutput_array_fixed": 3.2481, - "WebglConformance_deqp_functional_gles3_fragmentoutput_array_float": 6.8456, - "WebglConformance_deqp_functional_gles3_fragmentoutput_array_int": 6.2948, - "WebglConformance_deqp_functional_gles3_fragmentoutput_array_uint": 4.6631, - "WebglConformance_deqp_functional_gles3_fragmentoutput_basic_fixed": 2.7335, - "WebglConformance_deqp_functional_gles3_fragmentoutput_basic_float": 2.7536, - "WebglConformance_deqp_functional_gles3_fragmentoutput_basic_int": 3.1484, - "WebglConformance_deqp_functional_gles3_fragmentoutput_basic_uint": 2.3971, - "WebglConformance_deqp_functional_gles3_fragmentoutput_random_00": 4.4889, - "WebglConformance_deqp_functional_gles3_fragmentoutput_random_01": 5.29, - "WebglConformance_deqp_functional_gles3_fragmentoutput_random_02": 4.8835, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_00": 3.4159, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_01": 2.8153, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_02": 3.3797, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_03": 3.0114, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_04": 4.9273, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_05": 3.2407, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_06": 2.8006, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_07": 4.829, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_08": 4.7944, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_09": 2.8716, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_10": 4.256, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_11": 4.8106, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_12": 5.4511, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_13": 5.1385, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_14": 3.2428, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_15": 3.0827, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_16": 2.5315, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_17": 2.6083, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_18": 4.2653, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_19": 2.2981, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_20": 3.5971, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_21": 3.266, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_22": 3.0378, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_23": 3.1458, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_24": 2.8279, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_25": 4.8875, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_26": 2.8292, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_27": 3.1961, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_28": 5.4832, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_29": 5.8381, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_30": 5.1448, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_31": 4.1322, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_32": 4.5803, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_33": 5.0377, - "WebglConformance_deqp_functional_gles3_framebufferblit_conversion_34": 4.0733, - "WebglConformance_deqp_functional_gles3_framebufferblit_default_framebuffer_00": 5.7497, - "WebglConformance_deqp_functional_gles3_framebufferblit_default_framebuffer_01": 6.4116, - "WebglConformance_deqp_functional_gles3_framebufferblit_default_framebuffer_02": 3.1131, - "WebglConformance_deqp_functional_gles3_framebufferblit_default_framebuffer_03": 5.2164, - "WebglConformance_deqp_functional_gles3_framebufferblit_default_framebuffer_04": 12.4543, - "WebglConformance_deqp_functional_gles3_framebufferblit_default_framebuffer_05": 5.1727, - "WebglConformance_deqp_functional_gles3_framebufferblit_default_framebuffer_06": 6.7483, - "WebglConformance_deqp_functional_gles3_framebufferblit_depth_stencil": 8.7174, - "WebglConformance_deqp_functional_gles3_framebufferblit_rect_00": 4.0136, - "WebglConformance_deqp_functional_gles3_framebufferblit_rect_01": 4.4551, - "WebglConformance_deqp_functional_gles3_framebufferblit_rect_02": 2.8406, - "WebglConformance_deqp_functional_gles3_framebufferblit_rect_03": 1.2204, - "WebglConformance_deqp_functional_gles3_framebufferblit_rect_04": 1.4644, - "WebglConformance_deqp_functional_gles3_framebufferblit_rect_05": 0.2285, - "WebglConformance_deqp_functional_gles3_framebufferblit_rect_06": 0.1625, - "WebglConformance_deqp_functional_gles3_indexedstatequery": 0.1623, - "WebglConformance_deqp_functional_gles3_instancedrendering": 9.4708, - "WebglConformance_deqp_functional_gles3_integerstatequery": 0.894, - "WebglConformance_deqp_functional_gles3_internalformatquery": 0.3055, - "WebglConformance_deqp_functional_gles3_lifetime": 0.6754, - "WebglConformance_deqp_functional_gles3_multisample": 26.6443, - "WebglConformance_deqp_functional_gles3_negativebufferapi": 0.4255, - "WebglConformance_deqp_functional_gles3_negativefragmentapi": 0.2005, - "WebglConformance_deqp_functional_gles3_negativeshaderapi": 0.3933, - "WebglConformance_deqp_functional_gles3_negativestateapi": 0.5542, - "WebglConformance_deqp_functional_gles3_negativetextureapi": 0.5886, - "WebglConformance_deqp_functional_gles3_negativevertexarrayapi": 0.2955, - "WebglConformance_deqp_functional_gles3_occlusionquery_conservative": 15.3166, - "WebglConformance_deqp_functional_gles3_occlusionquery_strict": 14.9064, - "WebglConformance_deqp_functional_gles3_pixelbufferobject": 3.5715, - "WebglConformance_deqp_functional_gles3_primitiverestart_00": 2.6652, - "WebglConformance_deqp_functional_gles3_primitiverestart_01": 3.4102, - "WebglConformance_deqp_functional_gles3_primitiverestart_02": 3.3645, - "WebglConformance_deqp_functional_gles3_primitiverestart_03": 3.3745, - "WebglConformance_deqp_functional_gles3_primitiverestart_04": 2.3187, - "WebglConformance_deqp_functional_gles3_primitiverestart_05": 2.6928, - "WebglConformance_deqp_functional_gles3_primitiverestart_06": 2.3355, - "WebglConformance_deqp_functional_gles3_primitiverestart_07": 2.7312, - "WebglConformance_deqp_functional_gles3_rasterizerdiscard": 3.2458, - "WebglConformance_deqp_functional_gles3_rbostatequery": 0.2425, - "WebglConformance_deqp_functional_gles3_readpixel": 0.8918, - "WebglConformance_deqp_functional_gles3_samplerobject": 2.2027, - "WebglConformance_deqp_functional_gles3_samplerstatequery": 0.2115, - "WebglConformance_deqp_functional_gles3_shaderapi": 0.324, - "WebglConformance_deqp_functional_gles3_shaderbuiltinvar": 3.4959, - "WebglConformance_deqp_functional_gles3_shadercommonfunction": 6.1155, - "WebglConformance_deqp_functional_gles3_shaderderivate_dfdx": 5.0401, - "WebglConformance_deqp_functional_gles3_shaderderivate_dfdy": 8.7798, - "WebglConformance_deqp_functional_gles3_shaderderivate_fwidth": 5.1709, - "WebglConformance_deqp_functional_gles3_shaderindexing_mat_00": 21.2695, - "WebglConformance_deqp_functional_gles3_shaderindexing_mat_01": 19.9371, - "WebglConformance_deqp_functional_gles3_shaderindexing_mat_02": 30.2059, - "WebglConformance_deqp_functional_gles3_shaderindexing_tmp": 26.1704, - "WebglConformance_deqp_functional_gles3_shaderindexing_uniform": 6.4167, - "WebglConformance_deqp_functional_gles3_shaderindexing_varying": 15.8332, - "WebglConformance_deqp_functional_gles3_shaderindexing_vec2": 13.6021, - "WebglConformance_deqp_functional_gles3_shaderindexing_vec3": 17.1894, - "WebglConformance_deqp_functional_gles3_shaderindexing_vec4": 16.2082, - "WebglConformance_deqp_functional_gles3_shaderloop_do_while": 36.6713, - "WebglConformance_deqp_functional_gles3_shaderloop_for": 38.4743, - "WebglConformance_deqp_functional_gles3_shaderloop_while": 42.015, - "WebglConformance_deqp_functional_gles3_shadermatrix_add_assign": 21.3498, - "WebglConformance_deqp_functional_gles3_shadermatrix_add_const": 31.2447, - "WebglConformance_deqp_functional_gles3_shadermatrix_add_dynamic": 35.1966, - "WebglConformance_deqp_functional_gles3_shadermatrix_add_uniform": 32.8574, - "WebglConformance_deqp_functional_gles3_shadermatrix_determinant": 7.1658, - "WebglConformance_deqp_functional_gles3_shadermatrix_div_assign": 18.0596, - "WebglConformance_deqp_functional_gles3_shadermatrix_div_const": 18.3006, - "WebglConformance_deqp_functional_gles3_shadermatrix_div_dynamic": 33.4187, - "WebglConformance_deqp_functional_gles3_shadermatrix_div_uniform": 35.036, - "WebglConformance_deqp_functional_gles3_shadermatrix_inverse": 12.4196, - "WebglConformance_deqp_functional_gles3_shadermatrix_matrixcompmult": 17.4345, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_assign": 6.3289, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_const_highp": 28.6748, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_const_lowp": 30.8609, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_const_mediump": 31.9598, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_dynamic_highp": 38.6587, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_dynamic_lowp": 31.3829, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_dynamic_mediump": 37.089, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_uniform_highp": 33.5054, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_uniform_lowp": 32.4026, - "WebglConformance_deqp_functional_gles3_shadermatrix_mul_uniform_mediump": 30.5766, - "WebglConformance_deqp_functional_gles3_shadermatrix_negation": 18.4866, - "WebglConformance_deqp_functional_gles3_shadermatrix_outerproduct": 17.6339, - "WebglConformance_deqp_functional_gles3_shadermatrix_post_decrement": 16.3863, - "WebglConformance_deqp_functional_gles3_shadermatrix_post_increment": 18.0883, - "WebglConformance_deqp_functional_gles3_shadermatrix_pre_decrement": 21.5258, - "WebglConformance_deqp_functional_gles3_shadermatrix_pre_increment": 21.7068, - "WebglConformance_deqp_functional_gles3_shadermatrix_sub_assign": 18.0845, - "WebglConformance_deqp_functional_gles3_shadermatrix_sub_const": 27.1752, - "WebglConformance_deqp_functional_gles3_shadermatrix_sub_dynamic": 29.4676, - "WebglConformance_deqp_functional_gles3_shadermatrix_sub_uniform": 33.5693, - "WebglConformance_deqp_functional_gles3_shadermatrix_transpose": 16.6529, - "WebglConformance_deqp_functional_gles3_shadermatrix_unary_addition": 15.9791, - "WebglConformance_deqp_functional_gles3_shaderoperator_angle_and_trigonometry_00": 24.0647, - "WebglConformance_deqp_functional_gles3_shaderoperator_angle_and_trigonometry_01": 15.3533, - "WebglConformance_deqp_functional_gles3_shaderoperator_angle_and_trigonometry_02": 16.4254, - "WebglConformance_deqp_functional_gles3_shaderoperator_angle_and_trigonometry_03": 12.9345, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_00": 58.5162, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_01": 60.3718, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_02": 36.8558, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_03": 35.2516, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_04": 56.1237, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_05": 44.0499, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_06": 41.2143, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_07": 24.8599, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_08": 26.2303, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_09": 48.4185, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_10": 50.4109, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_11": 48.2361, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_12": 29.2724, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_13": 25.053, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_14": 58.0559, - "WebglConformance_deqp_functional_gles3_shaderoperator_binary_operator_15": 59.3889, - "WebglConformance_deqp_functional_gles3_shaderoperator_bool_compare": 7.4854, - "WebglConformance_deqp_functional_gles3_shaderoperator_common_functions": 149.8543, - "WebglConformance_deqp_functional_gles3_shaderoperator_exponential": 27.8124, - "WebglConformance_deqp_functional_gles3_shaderoperator_float_compare": 35.6689, - "WebglConformance_deqp_functional_gles3_shaderoperator_geometric": 24.098, - "WebglConformance_deqp_functional_gles3_shaderoperator_int_compare": 26.1962, - "WebglConformance_deqp_functional_gles3_shaderoperator_selection": 22.9018, - "WebglConformance_deqp_functional_gles3_shaderoperator_sequence": 13.7452, - "WebglConformance_deqp_functional_gles3_shaderoperator_unary_operator_00": 32.3367, - "WebglConformance_deqp_functional_gles3_shaderoperator_unary_operator_01": 65.9774, - "WebglConformance_deqp_functional_gles3_shaderoperator_unary_operator_02": 67.6177, - "WebglConformance_deqp_functional_gles3_shaderpackingfunction": 0.4571, - "WebglConformance_deqp_functional_gles3_shaderprecision_float": 14.3504, - "WebglConformance_deqp_functional_gles3_shaderprecision_int": 9.1453, - "WebglConformance_deqp_functional_gles3_shaderprecision_uint": 5.3299, - "WebglConformance_deqp_functional_gles3_shaderstatequery": 0.4731, - "WebglConformance_deqp_functional_gles3_shaderstruct": 19.6815, - "WebglConformance_deqp_functional_gles3_shaderswitch": 25.0165, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_texelfetch": 8.214, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_texelfetchoffset": 9.7353, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_texture": 14.1479, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_texturegrad": 10.233, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_texturegradoffset": 7.7636, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_texturelod": 9.6282, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_texturelodoffset": 5.6257, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_textureoffset": 10.9596, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_textureproj": 13.6322, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_textureprojgrad": 5.6602, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_textureprojgradoffset": 6.3791, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_textureprojlod": 5.0267, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_textureprojlodoffset": 5.2777, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_textureprojoffset": 12.7666, - "WebglConformance_deqp_functional_gles3_shadertexturefunction_texturesize": 19.5724, - "WebglConformance_deqp_functional_gles3_stringquery": 0.2131, - "WebglConformance_deqp_functional_gles3_sync": 1.8453, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_combinations_00": 3.1315, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_combinations_01": 3.3895, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_combinations_02": 2.9293, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_combinations_03": 3.2543, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_combinations_04": 3.3361, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_combinations_05": 4.1574, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_00": 2.0165, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_01": 1.4156, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_02": 1.1631, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_03": 1.2515, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_04": 1.5592, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_05": 0.9926, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_06": 1.1348, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_07": 1.1017, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_08": 1.4357, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_formats_09": 1.1407, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_sizes_00": 0.9036, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_sizes_01": 1.239, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_sizes_02": 1.4375, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_sizes_03": 1.0748, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_array_sizes_04": 4.3795, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_combinations_00": 1.5132, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_combinations_01": 1.5665, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_combinations_02": 1.5548, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_combinations_03": 1.54, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_combinations_04": 1.561, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_combinations_05": 1.5522, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_00": 1.1928, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_01": 0.9257, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_02": 0.97, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_03": 0.8159, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_04": 0.7325, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_05": 0.8025, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_06": 0.7525, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_07": 0.7641, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_08": 0.9875, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_formats_09": 0.8227, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_sizes_00": 0.8353, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_sizes_01": 0.6941, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_sizes_02": 0.777, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_sizes_03": 0.7133, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_sizes_04": 0.7327, - "WebglConformance_deqp_functional_gles3_texturefiltering_2d_sizes_05": 0.7853, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_00": 1.7246, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_01": 1.8029, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_02": 1.7447, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_03": 1.8474, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_04": 1.8654, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_05": 1.8032, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_06": 1.8224, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_07": 1.8489, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_08": 1.8506, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_09": 1.8623, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_10": 1.87, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_11": 2.2839, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_12": 2.1132, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_13": 1.7459, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_14": 1.7738, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_15": 1.8553, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_16": 1.817, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_17": 2.211, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_18": 1.9081, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_19": 1.844, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_20": 1.879, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_21": 1.8603, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_22": 1.8709, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_23": 2.3829, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_24": 9.3533, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_25": 9.3687, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_26": 10.0041, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_27": 9.6053, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_28": 9.676, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_29": 9.5281, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_30": 11.0144, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_31": 9.5306, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_32": 11.3403, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_33": 10.1569, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_34": 9.1454, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_combinations_35": 11.0613, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_00": 5.2626, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_01": 4.6869, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_02": 4.6086, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_03": 4.3758, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_04": 4.3024, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_05": 2.9381, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_06": 4.0622, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_07": 4.5002, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_08": 4.5766, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_formats_09": 4.3158, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_sizes_00": 4.2055, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_sizes_01": 3.8593, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_sizes_02": 4.4203, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_sizes_03": 2.9351, - "WebglConformance_deqp_functional_gles3_texturefiltering_3d_sizes_04": 3.4984, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_combinations_00": 4.1339, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_combinations_01": 7.4524, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_combinations_02": 8.3571, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_combinations_03": 7.8209, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_combinations_04": 10.0546, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_combinations_05": 20.1002, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_00": 5.0793, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_01": 3.8654, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_02": 4.2449, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_03": 3.7092, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_04": 3.794, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_05": 3.4464, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_06": 3.6315, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_07": 4.1719, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_08": 3.7609, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_formats_09": 3.7148, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_no_edges_visible": 1.6779, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_sizes_00": 1.8703, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_sizes_01": 3.5182, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_sizes_02": 5.9222, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_sizes_03": 1.9969, - "WebglConformance_deqp_functional_gles3_texturefiltering_cube_sizes_04": 4.2755, - "WebglConformance_deqp_functional_gles3_textureformat_compressed_2d": 0.1372, - "WebglConformance_deqp_functional_gles3_textureformat_compressed_cube": 0.1188, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_array_npot_00": 2.2171, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_array_npot_01": 2.177, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_array_npot_02": 3.1057, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_array_npot_03": 2.2352, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_array_pot_00": 2.5806, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_array_pot_01": 2.4005, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_array_pot_02": 2.5109, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_array_pot_03": 3.369, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_npot_00": 0.8763, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_npot_01": 0.8539, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_npot_02": 0.897, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_npot_03": 0.9156, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_pot_00": 1.3386, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_pot_01": 1.1528, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_pot_02": 1.1346, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_2d_pot_03": 1.1897, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_3d_npot_00": 2.2101, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_3d_npot_01": 1.7345, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_3d_npot_02": 1.5938, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_3d_npot_03": 1.6566, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_3d_pot_00": 4.3149, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_3d_pot_01": 3.7273, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_3d_pot_02": 3.576, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_3d_pot_03": 4.0017, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_cube_npot_00": 2.1304, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_cube_npot_01": 2.67, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_cube_npot_02": 1.9234, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_cube_npot_03": 2.4145, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_cube_pot_00": 2.2245, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_cube_pot_01": 2.1903, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_cube_pot_02": 2.3981, - "WebglConformance_deqp_functional_gles3_textureformat_sized_color_cube_pot_03": 2.5784, - "WebglConformance_deqp_functional_gles3_textureformat_sized_depth_stencil": 2.6799, - "WebglConformance_deqp_functional_gles3_textureformat_unsized_2d": 4.0011, - "WebglConformance_deqp_functional_gles3_textureformat_unsized_2d_array": 2.7908, - "WebglConformance_deqp_functional_gles3_textureformat_unsized_3d": 3.8379, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_always": 1.1397, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_equal": 1.9977, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_greater": 1.7641, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_greater_or_equal": 1.8175, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_less": 1.8941, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_less_or_equal": 1.6253, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_linear_always": 1.0821, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_linear_equal": 2.2415, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_linear_greater": 2.6757, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_linear_greater_or_equal": 3.0473, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_linear_less": 2.8018, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_linear_less_or_equal": 2.8225, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_linear_never": 1.1511, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_linear_not_equal": 2.3076, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_nearest_always": 1.0307, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_nearest_equal": 2.1713, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_nearest_greater": 2.1444, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_nearest_greater_or_equal": 1.9003, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_nearest_less": 1.8471, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_nearest_less_or_equal": 1.9547, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_nearest_never": 1.0664, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_mipmap_nearest_not_equal": 2.0288, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_never": 1.0703, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_linear_not_equal": 2.0577, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_always": 1.083, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_equal": 1.0497, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_greater": 1.0102, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_greater_or_equal": 1.0137, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_less": 0.9652, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_less_or_equal": 0.9692, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_linear_always": 1.0278, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_linear_equal": 1.7354, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_linear_greater": 1.6662, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_linear_greater_or_equal": 1.517, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_linear_less": 1.2973, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_linear_less_or_equal": 1.3703, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_linear_never": 1.0164, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_linear_not_equal": 1.9033, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_nearest_always": 1.1352, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_nearest_equal": 1.8325, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_nearest_greater": 1.5231, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_nearest_greater_or_equal": 1.431, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_nearest_less": 1.5596, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_nearest_less_or_equal": 1.6277, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_nearest_never": 1.0164, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_mipmap_nearest_not_equal": 1.6664, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_never": 1.1603, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_array_nearest_not_equal": 1.1004, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_always": 1.0178, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_equal": 1.8701, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_greater": 1.5378, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_greater_or_equal": 1.3798, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_less": 1.4839, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_less_or_equal": 1.6842, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_linear_always": 0.9904, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_linear_equal": 2.7437, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_linear_greater": 2.4513, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_linear_greater_or_equal": 2.8869, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_linear_less": 2.8408, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_linear_less_or_equal": 2.5395, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_linear_never": 1.0174, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_linear_not_equal": 2.7492, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_nearest_always": 0.913, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_nearest_equal": 1.6387, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_nearest_greater": 1.6509, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_nearest_greater_or_equal": 1.743, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_nearest_less": 1.6619, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_nearest_less_or_equal": 1.6614, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_nearest_never": 1.0259, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_mipmap_nearest_not_equal": 1.6155, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_never": 0.926, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_linear_not_equal": 1.846, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_always": 0.7778, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_equal": 1.0168, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_greater": 0.7679, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_greater_or_equal": 0.8, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_less": 0.8167, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_less_or_equal": 0.7969, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_linear_always": 0.9456, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_linear_equal": 2.3343, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_linear_greater": 1.3932, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_linear_greater_or_equal": 2.1356, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_linear_less": 1.9215, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_linear_less_or_equal": 1.4048, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_linear_never": 0.8292, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_linear_not_equal": 2.3946, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_nearest_always": 0.9126, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_nearest_equal": 1.6548, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_nearest_greater": 1.7268, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_nearest_greater_or_equal": 1.3653, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_nearest_less": 1.2818, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_nearest_less_or_equal": 1.5302, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_nearest_never": 0.8659, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_mipmap_nearest_not_equal": 1.4457, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_never": 0.8878, - "WebglConformance_deqp_functional_gles3_textureshadow_2d_nearest_not_equal": 0.9787, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_always": 1.8696, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_equal": 3.3654, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_greater": 3.7748, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_greater_or_equal": 3.1528, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_less": 3.1393, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_less_or_equal": 2.841, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_linear_always": 2.1579, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_linear_equal": 5.0931, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_linear_greater": 4.5434, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_linear_greater_or_equal": 4.8859, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_linear_less": 4.5757, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_linear_less_or_equal": 5.3561, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_linear_never": 2.0103, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_linear_not_equal": 5.0601, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_nearest_always": 1.9699, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_nearest_equal": 3.4308, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_nearest_greater": 3.0437, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_nearest_greater_or_equal": 4.3208, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_nearest_less": 4.1832, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_nearest_less_or_equal": 3.2881, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_nearest_never": 2.4681, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_mipmap_nearest_not_equal": 3.6558, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_never": 1.9345, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_linear_not_equal": 4.0192, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_always": 1.6689, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_equal": 2.4084, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_greater": 2.4959, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_greater_or_equal": 1.9781, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_less": 2.0838, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_less_or_equal": 2.3625, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_linear_always": 2.5536, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_linear_equal": 5.2437, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_linear_greater": 3.9088, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_linear_greater_or_equal": 4.159, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_linear_less": 4.1298, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_linear_less_or_equal": 5.466, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_linear_never": 1.9927, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_linear_not_equal": 4.6291, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_nearest_always": 2.0171, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_nearest_equal": 3.7186, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_nearest_greater": 2.8809, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_nearest_greater_or_equal": 3.3137, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_nearest_less": 3.034, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_nearest_less_or_equal": 3.018, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_nearest_never": 1.8814, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_mipmap_nearest_not_equal": 3.1661, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_never": 2.5135, - "WebglConformance_deqp_functional_gles3_textureshadow_cube_nearest_not_equal": 1.836, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_copyteximage2d": 7.3204, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_copytexsubimage2d": 7.6176, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage2d_2d_00": 3.7366, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage2d_2d_01": 3.5363, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage2d_cube_00": 4.8583, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage2d_cube_01": 5.1252, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage2d_cube_02": 4.9941, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage2d_cube_03": 5.5777, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage2d_cube_04": 5.1146, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage3d_2d_array_00": 3.4683, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage3d_2d_array_01": 2.83, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage3d_2d_array_02": 2.8914, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage3d_3d_00": 2.558, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage3d_3d_01": 2.2721, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage3d_3d_02": 3.2673, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage3d_3d_03": 3.1397, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_teximage3d_3d_04": 2.205, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage2d_2d_00": 2.7475, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage2d_2d_01": 2.5083, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage2d_2d_02": 2.6493, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage2d_cube_00": 5.8911, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage2d_cube_01": 5.2494, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage2d_cube_02": 4.8928, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage2d_cube_03": 5.512, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage2d_cube_04": 4.9508, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage3d_00": 2.8841, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage3d_01": 2.3928, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage3d_02": 2.482, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage3d_03": 2.4245, - "WebglConformance_deqp_functional_gles3_texturespecification_basic_texsubimage3d_04": 2.187, - "WebglConformance_deqp_functional_gles3_texturespecification_random_teximage2d_2d": 2.8237, - "WebglConformance_deqp_functional_gles3_texturespecification_random_teximage2d_cube": 6.8586, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_align": 5.803, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_depth": 1.171, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_depth_pbo": 1.0993, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_pbo_2d_00": 1.9139, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_pbo_2d_01": 1.5435, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_pbo_cube_00": 4.4261, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_pbo_cube_01": 4.7131, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_pbo_cube_02": 4.1716, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_pbo_cube_03": 3.6343, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_pbo_cube_04": 3.6618, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_pbo_params": 1.5825, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage2d_unpack_params": 0.6968, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage3d_depth": 1.4982, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage3d_depth_pbo": 1.3445, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage3d_pbo_2d_array_00": 1.5208, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage3d_pbo_2d_array_01": 1.8703, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage3d_pbo_3d_00": 1.5597, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage3d_pbo_3d_01": 1.4899, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage3d_pbo_params": 0.9306, - "WebglConformance_deqp_functional_gles3_texturespecification_teximage3d_unpack_params": 1.1209, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_2d_00": 3.2934, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_2d_01": 3.1532, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_2d_02": 3.5331, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_cube_00": 4.2438, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_cube_01": 4.2974, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_cube_02": 4.0346, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_cube_03": 5.0757, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_cube_04": 3.5549, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_depth_stencil": 3.9528, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage2d_format_size": 2.8877, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage3d_format_2d_array_00": 2.789, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage3d_format_2d_array_01": 2.3218, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage3d_format_2d_array_02": 2.4819, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage3d_format_3d_00": 3.8647, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage3d_format_3d_01": 4.1054, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage3d_format_3d_02": 3.2356, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage3d_format_3d_03": 3.3525, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage3d_format_depth_stencil": 1.0289, - "WebglConformance_deqp_functional_gles3_texturespecification_texstorage3d_format_size": 2.3091, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_align": 8.4151, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_depth": 0.7055, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_empty_tex": 2.0308, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_pbo_2d_00": 2.3813, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_pbo_2d_01": 1.9227, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_pbo_cube_00": 4.2491, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_pbo_cube_01": 4.2268, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_pbo_cube_02": 3.9057, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_pbo_cube_03": 4.7322, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_pbo_cube_04": 4.3877, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_pbo_params": 2.1137, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage2d_unpack_params": 1.3551, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage3d_depth": 1.1654, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage3d_pbo_2d_array_00": 3.0391, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage3d_pbo_2d_array_01": 2.4208, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage3d_pbo_3d_00": 3.7751, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage3d_pbo_3d_01": 2.7685, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage3d_pbo_params": 1.57, - "WebglConformance_deqp_functional_gles3_texturespecification_texsubimage3d_unpack_params": 1.1706, - "WebglConformance_deqp_functional_gles3_texturestatequery": 0.6641, - "WebglConformance_deqp_functional_gles3_texturewrap_eac_r11_npot": 0.2031, - "WebglConformance_deqp_functional_gles3_texturewrap_eac_r11_pot": 0.2254, - "WebglConformance_deqp_functional_gles3_texturewrap_eac_rg11_npot": 0.2061, - "WebglConformance_deqp_functional_gles3_texturewrap_eac_rg11_pot": 0.2036, - "WebglConformance_deqp_functional_gles3_texturewrap_eac_signed_r11_npot": 0.2331, - "WebglConformance_deqp_functional_gles3_texturewrap_eac_signed_r11_pot": 0.0847, - "WebglConformance_deqp_functional_gles3_texturewrap_eac_signed_rg11_npot": 0.1989, - "WebglConformance_deqp_functional_gles3_texturewrap_eac_signed_rg11_pot": 0.2111, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_eac_rgba8_npot": 0.1033, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_eac_rgba8_pot": 0.2296, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_eac_srgb8_alpha8_npot": 0.195, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_eac_srgb8_alpha8_pot": 0.2098, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_rgb8_npot": 0.2392, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_rgb8_pot": 0.1282, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_rgb8_punchthrough_alpha1_npot": 0.2098, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_rgb8_punchthrough_alpha1_pot": 0.1079, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_srgb8_npot": 0.2256, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_srgb8_pot": 0.1087, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_srgb8_punchthrough_alpha1_npot": 0.2099, - "WebglConformance_deqp_functional_gles3_texturewrap_etc2_srgb8_punchthrough_alpha1_pot": 0.0835, - "WebglConformance_deqp_functional_gles3_texturewrap_rgba8_npot": 2.6697, - "WebglConformance_deqp_functional_gles3_texturewrap_rgba8_pot": 2.5963, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_element_interleaved_lines": 1.0437, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_element_interleaved_points": 1.0244, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_element_interleaved_triangles": 0.9021, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_element_separate_lines": 0.6831, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_element_separate_points": 0.9824, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_element_separate_triangles": 1.1757, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_interleaved_lines": 21.4741, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_interleaved_points": 23.4039, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_interleaved_triangles": 21.6903, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_separate_lines": 7.0275, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_separate_points": 7.0206, - "WebglConformance_deqp_functional_gles3_transformfeedback_array_separate_triangles": 6.6633, - "WebglConformance_deqp_functional_gles3_transformfeedback_basic_types_interleaved_lines": 22.187, - "WebglConformance_deqp_functional_gles3_transformfeedback_basic_types_interleaved_points": 23.1019, - "WebglConformance_deqp_functional_gles3_transformfeedback_basic_types_interleaved_triangles": 23.1321, - "WebglConformance_deqp_functional_gles3_transformfeedback_basic_types_separate_lines": 14.5626, - "WebglConformance_deqp_functional_gles3_transformfeedback_basic_types_separate_points": 13.7099, - "WebglConformance_deqp_functional_gles3_transformfeedback_basic_types_separate_triangles": 15.3802, - "WebglConformance_deqp_functional_gles3_transformfeedback_interpolation_centroid": 6.828, - "WebglConformance_deqp_functional_gles3_transformfeedback_interpolation_flat": 6.7793, - "WebglConformance_deqp_functional_gles3_transformfeedback_interpolation_smooth": 6.5448, - "WebglConformance_deqp_functional_gles3_transformfeedback_point_size": 2.4242, - "WebglConformance_deqp_functional_gles3_transformfeedback_position": 2.265, - "WebglConformance_deqp_functional_gles3_transformfeedback_random_interleaved_lines": 3.832, - "WebglConformance_deqp_functional_gles3_transformfeedback_random_interleaved_points": 3.6551, - "WebglConformance_deqp_functional_gles3_transformfeedback_random_interleaved_triangles": 3.9192, - "WebglConformance_deqp_functional_gles3_transformfeedback_random_separate_lines": 3.9257, - "WebglConformance_deqp_functional_gles3_transformfeedback_random_separate_points": 3.6978, - "WebglConformance_deqp_functional_gles3_transformfeedback_random_separate_triangles": 3.8343, - "WebglConformance_deqp_functional_gles3_uniformapi_info_query": 6.112, - "WebglConformance_deqp_functional_gles3_uniformapi_random": 4.0919, - "WebglConformance_deqp_functional_gles3_uniformapi_value_assigned": 14.5482, - "WebglConformance_deqp_functional_gles3_uniformapi_value_initial": 6.8823, - "WebglConformance_deqp_functional_gles3_uniformbuffers_instance_array_basic_type": 3.778, - "WebglConformance_deqp_functional_gles3_uniformbuffers_multi_basic_types": 0.6133, - "WebglConformance_deqp_functional_gles3_uniformbuffers_multi_nested_struct": 1.1384, - "WebglConformance_deqp_functional_gles3_uniformbuffers_random": 15.2619, - "WebglConformance_deqp_functional_gles3_uniformbuffers_single_basic_array": 3.7725, - "WebglConformance_deqp_functional_gles3_uniformbuffers_single_basic_type": 9.8616, - "WebglConformance_deqp_functional_gles3_uniformbuffers_single_nested_struct": 1.8242, - "WebglConformance_deqp_functional_gles3_uniformbuffers_single_nested_struct_array": 1.2154, - "WebglConformance_deqp_functional_gles3_uniformbuffers_single_struct": 0.9916, - "WebglConformance_deqp_functional_gles3_uniformbuffers_single_struct_array": 2.6636, - "WebglConformance_deqp_functional_gles3_vertexarrayobject": 1.0315, - "WebglConformance_deqp_functional_gles3_vertexarrays_multiple_attributes_count": 10.5048, - "WebglConformance_deqp_functional_gles3_vertexarrays_multiple_attributes_output": 39.5225, - "WebglConformance_deqp_functional_gles3_vertexarrays_multiple_attributes_storage": 2.4033, - "WebglConformance_deqp_functional_gles3_vertexarrays_multiple_attributes_stride": 38.8897, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_first": 31.7817, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_normalize": 27.0694, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_offset": 27.2355, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_byte": 17.6212, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_float": 11.1325, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_half": 10.7179, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_int": 14.9896, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_int_2_10_10_10": 5.2107, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_short": 16.3124, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_unsigned_byte": 17.7132, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_unsigned_int": 15.538, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_unsigned_int_2_10_10_10": 3.9775, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_output_type_unsigned_short": 16.3771, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_stride": 24.393, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_usage_dynamic_copy": 11.7612, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_usage_dynamic_draw": 15.3632, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_usage_dynamic_read": 11.8367, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_usage_static_copy": 12.6557, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_usage_static_draw": 12.9455, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_usage_static_read": 14.6844, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_usage_stream_copy": 13.5926, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_usage_stream_draw": 14.2477, - "WebglConformance_deqp_functional_gles3_vertexarrays_single_attribute_usage_stream_read": 11.5545, - "WebglExtension_EXT_color_buffer_float": 0.0736, - "WebglExtension_EXT_disjoint_timer_query_webgl2": 0.0622, - "WebglExtension_EXT_texture_filter_anisotropic": 0.0921, - "WebglExtension_OES_texture_float_linear": 0.0473, - "WebglExtension_TestCoverage": 0.1012, - "WebglExtension_WEBGL_compressed_texture_astc": 0.0008, - "WebglExtension_WEBGL_compressed_texture_etc": 0.0007, - "WebglExtension_WEBGL_compressed_texture_etc1": 0.0009, - "WebglExtension_WEBGL_compressed_texture_pvrtc": 0.0007, - "WebglExtension_WEBGL_compressed_texture_s3tc": 0.0619, - "WebglExtension_WEBGL_compressed_texture_s3tc_srgb": 0.0007, + "WebglExtension_EXT_color_buffer_float": 2.0888, + "WebglExtension_EXT_disjoint_timer_query_webgl2": 0.0703, + "WebglExtension_EXT_float_blend": 10.4939, + "WebglExtension_EXT_texture_filter_anisotropic": 2.5161, + "WebglExtension_KHR_parallel_shader_compile": 0.0121, + "WebglExtension_OES_texture_float_linear": 0.1089, + "WebglExtension_OVR_multiview2": 0.0119, + "WebglExtension_TestCoverage": 0.09, + "WebglExtension_WEBGL_compressed_texture_astc": 0.0133, + "WebglExtension_WEBGL_compressed_texture_etc": 0.0131, + "WebglExtension_WEBGL_compressed_texture_etc1": 0.0121, + "WebglExtension_WEBGL_compressed_texture_pvrtc": 0.0122, + "WebglExtension_WEBGL_compressed_texture_s3tc": 0.0714, + "WebglExtension_WEBGL_compressed_texture_s3tc_srgb": 0.0141, "WebglExtension_WEBGL_debug_renderer_info": 0.0907, - "WebglExtension_WEBGL_debug_shaders": 0.0739, - "WebglExtension_WEBGL_lose_context": 0.0534 + "WebglExtension_WEBGL_debug_shaders": 0.0863, + "WebglExtension_WEBGL_lose_context": 0.0928, + "WebglExtension_WEBGL_multi_draw": 0.0881, + "WebglExtension_WEBGL_multi_draw_instanced": 1.6534, + "WebglExtension_WEBGL_video_texture": 0.0709, + "conformance/attribs/gl-bindAttribLocation-aliasing.html": 0.1817, + "conformance/attribs/gl-bindAttribLocation-matrix.html": 0.4799, + "conformance/attribs/gl-bindAttribLocation-nonexistent-attribute.html": 0.1706, + "conformance/attribs/gl-bindAttribLocation-repeated.html": 0.1981, + "conformance/attribs/gl-disabled-vertex-attrib-update.html": 0.1962, + "conformance/attribs/gl-disabled-vertex-attrib.html": 0.4672, + "conformance/attribs/gl-enable-vertex-attrib.html": 0.173, + "conformance/attribs/gl-matrix-attributes.html": 0.4901, + "conformance/attribs/gl-vertex-attrib-context-switch.html": 7.2368, + "conformance/attribs/gl-vertex-attrib-render.html": 18.3709, + "conformance/attribs/gl-vertex-attrib-unconsumed-out-of-bounds.html": 3.6946, + "conformance/attribs/gl-vertex-attrib-zero-issues.html": 0.3593, + "conformance/attribs/gl-vertexattribpointer-offsets.html": 0.6203, + "conformance/attribs/gl-vertexattribpointer.html": 1.6031, + "conformance/buffers/buffer-bind-test.html": 0.2258, + "conformance/buffers/buffer-data-and-buffer-sub-data.html": 0.1876, + "conformance/buffers/buffer-data-array-buffer-delete.html": 19.1775, + "conformance/buffers/buffer-data-dynamic-delay.html": 12.5865, + "conformance/buffers/buffer-uninitialized.html": 0.2947, + "conformance/buffers/element-array-buffer-delete-recreate.html": 0.174, + "conformance/buffers/index-validation-copies-indices.html": 0.0664, + "conformance/buffers/index-validation-crash-with-buffer-sub-data.html": 0.0704, + "conformance/buffers/index-validation-large-buffer.html": 0.0688, + "conformance/buffers/index-validation-verifies-too-many-indices.html": 0.0937, + "conformance/buffers/index-validation-with-resized-buffer.html": 0.09, + "conformance/buffers/index-validation.html": 0.0894, + "conformance/buffers/vertex-buffer-updated-after-draw.html": 0.0782, + "conformance/canvas/buffer-offscreen-test.html": 0.1661, + "conformance/canvas/buffer-preserve-test.html": 0.1684, + "conformance/canvas/canvas-test.html": 0.1884, + "conformance/canvas/canvas-zero-size.html": 0.0836, + "conformance/canvas/draw-static-webgl-to-multiple-canvas-test.html": 0.4775, + "conformance/canvas/draw-webgl-to-canvas-test.html": 0.3664, + "conformance/canvas/drawingbuffer-hd-dpi-test.html": 0.262, + "conformance/canvas/drawingbuffer-static-canvas-test.html": 0.0928, + "conformance/canvas/drawingbuffer-test.html": 0.1043, + "conformance/canvas/framebuffer-bindings-affected-by-to-data-url.html": 0.1681, + "conformance/canvas/framebuffer-bindings-unaffected-on-resize.html": 0.1581, + "conformance/canvas/rapid-resizing.html": 1.9689, + "conformance/canvas/render-after-resize-test.html": 0.1316, + "conformance/canvas/texture-bindings-unaffected-on-resize.html": 0.1605, + "conformance/canvas/to-data-url-test.html": 0.4387, + "conformance/canvas/viewport-unchanged-upon-resize.html": 0.0688, + "conformance/context/context-attribute-preserve-drawing-buffer.html": 0.294, + "conformance/context/context-attributes-alpha-depth-stencil-antialias.html": 0.4027, + "conformance/context/context-creation-and-destruction.html": 0.92, + "conformance/context/context-creation.html": 1.232, + "conformance/context/context-eviction-with-garbage-collection.html": 1.2097, + "conformance/context/context-hidden-alpha.html": 0.1857, + "conformance/context/context-lost-restored.html": 0.1918, + "conformance/context/context-lost.html": 0.2022, + "conformance/context/context-no-alpha-fbo-with-alpha.html": 0.1558, + "conformance/context/context-release-upon-reload.html": 1.6703, + "conformance/context/context-release-with-workers.html": 2.5503, + "conformance/context/context-size-change.html": 0.0622, + "conformance/context/incorrect-context-object-behaviour.html": 0.1992, + "conformance/context/premultiplyalpha-test.html": 0.5302, + "conformance/context/user-defined-properties-on-context.html": 0.1654, + "conformance/extensions/ext-disjoint-timer-query.html": 0.0481, + "conformance/extensions/ext-texture-compression-bptc.html": 0.0691, + "conformance/extensions/ext-texture-compression-rgtc.html": 0.0645, + "conformance/extensions/ext-texture-filter-anisotropic.html": 0.0968, + "conformance/extensions/get-extension.html": 0.1697, + "conformance/extensions/oes-texture-float-linear.html": 0.3558, + "conformance/extensions/webgl-compressed-texture-astc.html": 0.0898, + "conformance/extensions/webgl-compressed-texture-etc.html": 0.1492, + "conformance/extensions/webgl-compressed-texture-etc1.html": 0.1334, + "conformance/extensions/webgl-compressed-texture-pvrtc.html": 0.1701, + "conformance/extensions/webgl-compressed-texture-s3tc-srgb.html": 1.1233, + "conformance/extensions/webgl-compressed-texture-s3tc.html": 0.6894, + "conformance/extensions/webgl-compressed-texture-size-limit.html": 3.1803, + "conformance/extensions/webgl-debug-renderer-info.html": 0.0896, + "conformance/extensions/webgl-debug-shaders.html": 0.0684, + "conformance/extensions/webgl-multi-draw.html": 0.3654, + "conformance/glsl/bugs/angle-ambiguous-function-call.html": 0.1045, + "conformance/glsl/bugs/angle-constructor-invalid-parameters.html": 0.1582, + "conformance/glsl/bugs/angle-d3d11-compiler-error.html": 0.073, + "conformance/glsl/bugs/angle-dx-variable-bug.html": 0.055, + "conformance/glsl/bugs/array-of-struct-with-int-first-position.html": 0.2092, + "conformance/glsl/bugs/assign-to-swizzled-twice-in-function.html": 0.1244, + "conformance/glsl/bugs/bool-type-cast-bug-int-float.html": 0.1056, + "conformance/glsl/bugs/compare-loop-index-to-uniform.html": 0.1725, + "conformance/glsl/bugs/complex-glsl-does-not-crash.html": 1.4452, + "conformance/glsl/bugs/compound-assignment-type-combination.html": 1.0064, + "conformance/glsl/bugs/conditional-discard-in-loop.html": 0.1986, + "conformance/glsl/bugs/conditional-discard-optimization.html": 0.138, + "conformance/glsl/bugs/conditional-texture-fetch.html": 0.0771, + "conformance/glsl/bugs/constant-precision-qualifier.html": 0.2259, + "conformance/glsl/bugs/floor-div-cos-should-not-truncate.html": 0.1034, + "conformance/glsl/bugs/floored-division-accuracy.html": 0.2258, + "conformance/glsl/bugs/fragcoord-linking-bug.html": 0.0705, + "conformance/glsl/bugs/gl-fragcoord-multisampling-bug.html": 0.305, + "conformance/glsl/bugs/global-invariant-does-not-leak-across-shaders.html": 0.1674, + "conformance/glsl/bugs/if-return-and-elseif.html": 0.1336, + "conformance/glsl/bugs/in-parameter-passed-as-inout-argument-and-global.html": 0.0826, + "conformance/glsl/bugs/init-array-with-loop.html": 0.0811, + "conformance/glsl/bugs/invariant-does-not-leak-across-shaders.html": 0.0868, + "conformance/glsl/bugs/logic-inside-block-without-braces.html": 0.1795, + "conformance/glsl/bugs/long-expressions-should-not-crash.html": 0.5764, + "conformance/glsl/bugs/loop-if-loop-gradient.html": 0.0682, + "conformance/glsl/bugs/modulo-arithmetic-accuracy.html": 0.194, + "conformance/glsl/bugs/multiplication-assignment.html": 0.0829, + "conformance/glsl/bugs/nested-functions-should-not-crash.html": 0.2865, + "conformance/glsl/bugs/nested-loops-with-break-and-continue.html": 0.2463, + "conformance/glsl/bugs/nested-sequence-operator.html": 0.1602, + "conformance/glsl/bugs/pow-of-small-constant-in-user-defined-function.html": 0.0896, + "conformance/glsl/bugs/pow-with-constant-exponent-should-not-crash.html": 0.1106, + "conformance/glsl/bugs/qualcomm-crash.html": 0.0763, + "conformance/glsl/bugs/qualcomm-loop-with-continue-crash.html": 0.0876, + "conformance/glsl/bugs/sampler-array-struct-function-arg.html": 0.0032, + "conformance/glsl/bugs/sampler-array-using-loop-index.html": 0.0664, + "conformance/glsl/bugs/sampler-struct-function-arg.html": 0.0852, + "conformance/glsl/bugs/sequence-operator-evaluation-order.html": 0.1444, + "conformance/glsl/bugs/sketchfab-lighting-shader-crash.html": 0.1559, + "conformance/glsl/bugs/struct-constructor-highp-bug.html": 0.0846, + "conformance/glsl/bugs/struct-with-single-member-constructor.html": 0.085, + "conformance/glsl/bugs/temp-expressions-should-not-crash.html": 1.042, + "conformance/glsl/bugs/unary-minus-operator-float-bug.html": 0.0691, + "conformance/glsl/bugs/undefined-index-should-not-crash.html": 0.0737, + "conformance/glsl/bugs/uniforms-should-not-lose-values.html": 0.1133, + "conformance/glsl/bugs/varying-arrays-should-not-be-reversed.html": 0.143, + "conformance/glsl/bugs/vector-scalar-arithmetic-inside-loop-complex.html": 0.1216, + "conformance/glsl/bugs/vector-scalar-arithmetic-inside-loop.html": 0.1149, + "conformance/glsl/constructors/glsl-construct-bvec2.html": 0.3664, + "conformance/glsl/constructors/glsl-construct-bvec3.html": 0.489, + "conformance/glsl/constructors/glsl-construct-bvec4.html": 0.715, + "conformance/glsl/constructors/glsl-construct-ivec2.html": 0.3358, + "conformance/glsl/constructors/glsl-construct-ivec3.html": 0.4457, + "conformance/glsl/constructors/glsl-construct-ivec4.html": 0.7756, + "conformance/glsl/constructors/glsl-construct-mat2.html": 0.4646, + "conformance/glsl/constructors/glsl-construct-mat3.html": 0.3643, + "conformance/glsl/constructors/glsl-construct-mat4.html": 0.4331, + "conformance/glsl/constructors/glsl-construct-vec-mat-corner-cases.html": 0.1, + "conformance/glsl/constructors/glsl-construct-vec-mat-index.html": 0.1516, + "conformance/glsl/constructors/glsl-construct-vec2.html": 0.5235, + "conformance/glsl/constructors/glsl-construct-vec3.html": 0.5007, + "conformance/glsl/constructors/glsl-construct-vec4.html": 0.6334, + "conformance/glsl/functions/glsl-function-abs.html": 0.4982, + "conformance/glsl/functions/glsl-function-acos.html": 0.3398, + "conformance/glsl/functions/glsl-function-asin.html": 0.3286, + "conformance/glsl/functions/glsl-function-atan-xy.html": 0.4073, + "conformance/glsl/functions/glsl-function-atan.html": 0.429, + "conformance/glsl/functions/glsl-function-ceil.html": 0.4622, + "conformance/glsl/functions/glsl-function-clamp-float.html": 0.5316, + "conformance/glsl/functions/glsl-function-clamp-gentype.html": 0.3463, + "conformance/glsl/functions/glsl-function-cos.html": 0.3683, + "conformance/glsl/functions/glsl-function-cross.html": 0.2473, + "conformance/glsl/functions/glsl-function-distance.html": 0.4815, + "conformance/glsl/functions/glsl-function-dot.html": 0.4628, + "conformance/glsl/functions/glsl-function-faceforward.html": 0.4093, + "conformance/glsl/functions/glsl-function-floor.html": 0.4727, + "conformance/glsl/functions/glsl-function-fract.html": 0.3772, + "conformance/glsl/functions/glsl-function-length.html": 0.3548, + "conformance/glsl/functions/glsl-function-max-float.html": 0.5016, + "conformance/glsl/functions/glsl-function-max-gentype.html": 0.5431, + "conformance/glsl/functions/glsl-function-min-float.html": 0.3451, + "conformance/glsl/functions/glsl-function-min-gentype.html": 0.35, + "conformance/glsl/functions/glsl-function-mix-float.html": 0.3356, + "conformance/glsl/functions/glsl-function-mix-gentype.html": 0.3406, + "conformance/glsl/functions/glsl-function-mod-float.html": 0.2593, + "conformance/glsl/functions/glsl-function-mod-gentype.html": 0.3556, + "conformance/glsl/functions/glsl-function-normalize.html": 0.224, + "conformance/glsl/functions/glsl-function-reflect.html": 0.4592, + "conformance/glsl/functions/glsl-function-sign.html": 0.3847, + "conformance/glsl/functions/glsl-function-sin.html": 0.2388, + "conformance/glsl/functions/glsl-function-smoothstep-float.html": 0.4034, + "conformance/glsl/functions/glsl-function-smoothstep-gentype.html": 0.3616, + "conformance/glsl/functions/glsl-function-step-float.html": 0.2252, + "conformance/glsl/functions/glsl-function-step-gentype.html": 0.2578, + "conformance/glsl/functions/glsl-function.html": 0.2221, + "conformance/glsl/implicit/add_int_float.vert.html": 0.0677, + "conformance/glsl/implicit/add_int_mat2.vert.html": 0.0889, + "conformance/glsl/implicit/add_int_mat3.vert.html": 0.0583, + "conformance/glsl/implicit/add_int_mat4.vert.html": 0.0546, + "conformance/glsl/implicit/add_int_vec2.vert.html": 0.0838, + "conformance/glsl/implicit/add_int_vec3.vert.html": 0.0838, + "conformance/glsl/implicit/add_int_vec4.vert.html": 0.0601, + "conformance/glsl/implicit/add_ivec2_vec2.vert.html": 0.0527, + "conformance/glsl/implicit/add_ivec3_vec3.vert.html": 0.0762, + "conformance/glsl/implicit/add_ivec4_vec4.vert.html": 0.1522, + "conformance/glsl/implicit/assign_int_to_float.vert.html": 0.1519, + "conformance/glsl/implicit/assign_ivec2_to_vec2.vert.html": 0.0827, + "conformance/glsl/implicit/assign_ivec3_to_vec3.vert.html": 0.1619, + "conformance/glsl/implicit/assign_ivec4_to_vec4.vert.html": 0.1054, + "conformance/glsl/implicit/construct_struct.vert.html": 0.0842, + "conformance/glsl/implicit/divide_int_float.vert.html": 0.0643, + "conformance/glsl/implicit/divide_int_mat2.vert.html": 0.0635, + "conformance/glsl/implicit/divide_int_mat3.vert.html": 0.0651, + "conformance/glsl/implicit/divide_int_mat4.vert.html": 0.0786, + "conformance/glsl/implicit/divide_int_vec2.vert.html": 0.0724, + "conformance/glsl/implicit/divide_int_vec3.vert.html": 0.0611, + "conformance/glsl/implicit/divide_int_vec4.vert.html": 0.0756, + "conformance/glsl/implicit/divide_ivec2_vec2.vert.html": 0.076, + "conformance/glsl/implicit/divide_ivec3_vec3.vert.html": 0.0714, + "conformance/glsl/implicit/divide_ivec4_vec4.vert.html": 0.0703, + "conformance/glsl/implicit/equal_int_float.vert.html": 0.0735, + "conformance/glsl/implicit/equal_ivec2_vec2.vert.html": 0.0711, + "conformance/glsl/implicit/equal_ivec3_vec3.vert.html": 0.0795, + "conformance/glsl/implicit/equal_ivec4_vec4.vert.html": 0.0768, + "conformance/glsl/implicit/function_int_float.vert.html": 0.0531, + "conformance/glsl/implicit/function_ivec2_vec2.vert.html": 0.124, + "conformance/glsl/implicit/function_ivec3_vec3.vert.html": 0.0822, + "conformance/glsl/implicit/function_ivec4_vec4.vert.html": 0.0612, + "conformance/glsl/implicit/greater_than.vert.html": 0.0776, + "conformance/glsl/implicit/greater_than_equal.vert.html": 0.081, + "conformance/glsl/implicit/less_than.vert.html": 0.0791, + "conformance/glsl/implicit/less_than_equal.vert.html": 0.1613, + "conformance/glsl/implicit/multiply_int_float.vert.html": 0.0499, + "conformance/glsl/implicit/multiply_int_mat2.vert.html": 0.0664, + "conformance/glsl/implicit/multiply_int_mat3.vert.html": 0.0764, + "conformance/glsl/implicit/multiply_int_mat4.vert.html": 0.0516, + "conformance/glsl/implicit/multiply_int_vec2.vert.html": 0.1747, + "conformance/glsl/implicit/multiply_int_vec3.vert.html": 0.1569, + "conformance/glsl/implicit/multiply_int_vec4.vert.html": 0.0561, + "conformance/glsl/implicit/multiply_ivec2_vec2.vert.html": 0.0664, + "conformance/glsl/implicit/multiply_ivec3_vec3.vert.html": 0.0823, + "conformance/glsl/implicit/multiply_ivec4_vec4.vert.html": 0.0663, + "conformance/glsl/implicit/not_equal_int_float.vert.html": 0.0513, + "conformance/glsl/implicit/not_equal_ivec2_vec2.vert.html": 0.0746, + "conformance/glsl/implicit/not_equal_ivec3_vec3.vert.html": 0.0641, + "conformance/glsl/implicit/not_equal_ivec4_vec4.vert.html": 0.0536, + "conformance/glsl/implicit/subtract_int_float.vert.html": 0.0823, + "conformance/glsl/implicit/subtract_int_mat2.vert.html": 0.0501, + "conformance/glsl/implicit/subtract_int_mat3.vert.html": 0.0784, + "conformance/glsl/implicit/subtract_int_mat4.vert.html": 0.0729, + "conformance/glsl/implicit/subtract_int_vec2.vert.html": 0.0527, + "conformance/glsl/implicit/subtract_int_vec3.vert.html": 0.125, + "conformance/glsl/implicit/subtract_int_vec4.vert.html": 0.069, + "conformance/glsl/implicit/subtract_ivec2_vec2.vert.html": 0.0694, + "conformance/glsl/implicit/subtract_ivec3_vec3.vert.html": 0.0892, + "conformance/glsl/implicit/subtract_ivec4_vec4.vert.html": 0.0537, + "conformance/glsl/implicit/ternary_int_float.vert.html": 0.077, + "conformance/glsl/implicit/ternary_ivec2_vec2.vert.html": 0.0554, + "conformance/glsl/implicit/ternary_ivec3_vec3.vert.html": 0.0598, + "conformance/glsl/implicit/ternary_ivec4_vec4.vert.html": 0.0697, + "conformance/glsl/literals/float_literal.vert.html": 0.0833, + "conformance/glsl/literals/literal_precision.html": 0.0645, + "conformance/glsl/literals/overflow_leak.vert.html": 0.0745, + "conformance/glsl/matrices/glsl-mat3-construction.html": 0.1237, + "conformance/glsl/matrices/glsl-mat4-to-mat3.html": 0.1867, + "conformance/glsl/matrices/matrix-compound-multiply.html": 0.1491, + "conformance/glsl/misc/boolean_precision.html": 0.0816, + "conformance/glsl/misc/const-variable-initialization.html": 0.7126, + "conformance/glsl/misc/embedded-struct-definitions-forbidden.html": 0.0855, + "conformance/glsl/misc/empty-declaration.html": 0.0879, + "conformance/glsl/misc/empty_main.vert.html": 0.0518, + "conformance/glsl/misc/expression-list-in-declarator-initializer.html": 0.3086, + "conformance/glsl/misc/fragcolor-fragdata-invariant.html": 0.0691, + "conformance/glsl/misc/gl_position_unset.vert.html": 0.0678, + "conformance/glsl/misc/global-variable-init.html": 0.2965, + "conformance/glsl/misc/glsl-function-nodes.html": 0.0808, + "conformance/glsl/misc/glsl-long-variable-names.html": 0.0973, + "conformance/glsl/misc/glsl-vertex-branch.html": 0.1052, + "conformance/glsl/misc/large-loop-compile.html": 0.6022, + "conformance/glsl/misc/local-variable-shadowing-outer-function.html": 0.0617, + "conformance/glsl/misc/non-ascii-comments.vert.html": 0.0791, + "conformance/glsl/misc/non-ascii.vert.html": 0.075, + "conformance/glsl/misc/re-compile-re-link.html": 0.1096, + "conformance/glsl/misc/sampler-operand.html": 0.0635, + "conformance/glsl/misc/sequence-operator-returns-constant.html": 0.0747, + "conformance/glsl/misc/shader-precision-format-obeyed.html": 0.1125, + "conformance/glsl/misc/shader-struct-scope.html": 0.0792, + "conformance/glsl/misc/shader-uniform-packing-restrictions.html": 1.7418, + "conformance/glsl/misc/shader-varying-packing-restrictions.html": 0.3134, + "conformance/glsl/misc/shader-with-256-character-define.html": 0.162, + "conformance/glsl/misc/shader-with-256-character-identifier.frag.html": 0.1065, + "conformance/glsl/misc/shader-with-_webgl-identifier.vert.html": 0.0782, + "conformance/glsl/misc/shader-with-arbitrary-indexing.frag.html": 0.0564, + "conformance/glsl/misc/shader-with-arbitrary-indexing.vert.html": 0.0631, + "conformance/glsl/misc/shader-with-array-of-structs-containing-arrays.html": 0.1384, + "conformance/glsl/misc/shader-with-array-of-structs-uniform.html": 0.1562, + "conformance/glsl/misc/shader-with-attrib-array.vert.html": 0.1535, + "conformance/glsl/misc/shader-with-attrib-struct.vert.html": 0.093, + "conformance/glsl/misc/shader-with-clipvertex.vert.html": 0.0708, + "conformance/glsl/misc/shader-with-comma-assignment.html": 0.094, + "conformance/glsl/misc/shader-with-comma-conditional-assignment.html": 0.2102, + "conformance/glsl/misc/shader-with-comma-separated-variable-declarations.html": 0.0685, + "conformance/glsl/misc/shader-with-conditional-scoping-negative.html": 0.051, + "conformance/glsl/misc/shader-with-conditional-scoping.html": 0.0693, + "conformance/glsl/misc/shader-with-default-precision.frag.html": 0.076, + "conformance/glsl/misc/shader-with-default-precision.vert.html": 0.0901, + "conformance/glsl/misc/shader-with-dfdx-no-ext.frag.html": 0.0596, + "conformance/glsl/misc/shader-with-dfdx.frag.html": 0.0662, + "conformance/glsl/misc/shader-with-do-loop.html": 0.0778, + "conformance/glsl/misc/shader-with-error-directive.html": 0.0548, + "conformance/glsl/misc/shader-with-explicit-int-cast.vert.html": 0.1261, + "conformance/glsl/misc/shader-with-float-return-value.frag.html": 0.1764, + "conformance/glsl/misc/shader-with-for-loop.html": 0.086, + "conformance/glsl/misc/shader-with-for-scoping.html": 0.0594, + "conformance/glsl/misc/shader-with-frag-depth.frag.html": 0.0896, + "conformance/glsl/misc/shader-with-function-recursion.frag.html": 0.059, + "conformance/glsl/misc/shader-with-function-scoped-struct.html": 0.0623, + "conformance/glsl/misc/shader-with-functional-scoping.html": 0.1321, + "conformance/glsl/misc/shader-with-glcolor.vert.html": 0.078, + "conformance/glsl/misc/shader-with-gles-1.frag.html": 0.071, + "conformance/glsl/misc/shader-with-gles-symbol.frag.html": 0.155, + "conformance/glsl/misc/shader-with-global-variable-precision-mismatch.html": 0.0792, + "conformance/glsl/misc/shader-with-glprojectionmatrix.vert.html": 0.0803, + "conformance/glsl/misc/shader-with-hex-int-constant-macro.html": 0.0829, + "conformance/glsl/misc/shader-with-implicit-vec3-to-vec4-cast.vert.html": 0.0839, + "conformance/glsl/misc/shader-with-include.vert.html": 0.0522, + "conformance/glsl/misc/shader-with-int-return-value.frag.html": 0.053, + "conformance/glsl/misc/shader-with-invalid-identifier.frag.html": 0.0726, + "conformance/glsl/misc/shader-with-ivec2-return-value.frag.html": 0.0549, + "conformance/glsl/misc/shader-with-ivec3-return-value.frag.html": 0.0561, + "conformance/glsl/misc/shader-with-ivec4-return-value.frag.html": 0.0723, + "conformance/glsl/misc/shader-with-limited-indexing.frag.html": 0.0554, + "conformance/glsl/misc/shader-with-long-line.html": 0.1151, + "conformance/glsl/misc/shader-with-non-ascii-error.frag.html": 0.0589, + "conformance/glsl/misc/shader-with-non-reserved-words.html": 14.6789, + "conformance/glsl/misc/shader-with-precision.frag.html": 0.0633, + "conformance/glsl/misc/shader-with-preprocessor-whitespace.html": 0.175, + "conformance/glsl/misc/shader-with-quoted-error.frag.html": 0.0751, + "conformance/glsl/misc/shader-with-reserved-words.html": 1.6657, + "conformance/glsl/misc/shader-with-short-circuiting-operators.html": 0.3196, + "conformance/glsl/misc/shader-with-similar-uniform-array-names.html": 0.188, + "conformance/glsl/misc/shader-with-too-many-uniforms.html": 0.4992, + "conformance/glsl/misc/shader-with-two-initializer-types.html": 0.0626, + "conformance/glsl/misc/shader-with-undefined-preprocessor-symbol.frag.html": 0.1494, + "conformance/glsl/misc/shader-with-uniform-in-loop-condition.vert.html": 0.0709, + "conformance/glsl/misc/shader-with-vec2-return-value.frag.html": 0.0575, + "conformance/glsl/misc/shader-with-vec3-return-value.frag.html": 0.0606, + "conformance/glsl/misc/shader-with-vec4-return-value.frag.html": 0.0809, + "conformance/glsl/misc/shader-with-vec4-vec3-vec4-conditional.html": 0.0555, + "conformance/glsl/misc/shader-with-version-100.frag.html": 0.06, + "conformance/glsl/misc/shader-with-version-100.vert.html": 0.071, + "conformance/glsl/misc/shader-with-version-120.vert.html": 0.0527, + "conformance/glsl/misc/shader-with-version-130.vert.html": 0.0739, + "conformance/glsl/misc/shader-with-webgl-identifier.vert.html": 0.0741, + "conformance/glsl/misc/shader-with-while-loop.html": 0.05, + "conformance/glsl/misc/shader-without-precision.frag.html": 0.8011, + "conformance/glsl/misc/shaders-with-constant-expression-loop-conditions.html": 0.0614, + "conformance/glsl/misc/shaders-with-invariance.html": 0.153, + "conformance/glsl/misc/shaders-with-mis-matching-uniforms.html": 0.2195, + "conformance/glsl/misc/shaders-with-mis-matching-varyings.html": 0.0994, + "conformance/glsl/misc/shaders-with-missing-varyings.html": 0.1696, + "conformance/glsl/misc/shaders-with-name-conflicts.html": 0.0753, + "conformance/glsl/misc/shaders-with-uniform-structs.html": 0.068, + "conformance/glsl/misc/shaders-with-varyings.html": 0.2076, + "conformance/glsl/misc/shared.html": 0.0994, + "conformance/glsl/misc/struct-as-inout-parameter.html": 0.0992, + "conformance/glsl/misc/struct-as-out-parameter.html": 0.1075, + "conformance/glsl/misc/struct-assign.html": 0.1429, + "conformance/glsl/misc/struct-equals.html": 0.1523, + "conformance/glsl/misc/struct-mixed-array-declarators.html": 0.3922, + "conformance/glsl/misc/struct-nesting-exceeds-maximum.html": 0.074, + "conformance/glsl/misc/struct-nesting-of-variable-names.html": 0.9291, + "conformance/glsl/misc/struct-nesting-under-maximum.html": 0.0736, + "conformance/glsl/misc/struct-specifiers-in-uniforms.html": 0.1702, + "conformance/glsl/misc/struct-unary-operators.html": 0.255, + "conformance/glsl/misc/ternary-operator-on-arrays.html": 0.0811, + "conformance/glsl/misc/ternary-operators-in-global-initializers.html": 0.1601, + "conformance/glsl/misc/ternary-operators-in-initializers.html": 0.1955, + "conformance/glsl/misc/uninitialized-local-global-variables.html": 0.2009, + "conformance/glsl/preprocessor/macro-expansion-tricky.html": 0.0908, + "conformance/glsl/reserved/_webgl_field.vert.html": 0.0956, + "conformance/glsl/reserved/_webgl_function.vert.html": 0.0554, + "conformance/glsl/reserved/_webgl_struct.vert.html": 0.1255, + "conformance/glsl/reserved/_webgl_variable.vert.html": 0.0842, + "conformance/glsl/reserved/webgl_field.vert.html": 0.0638, + "conformance/glsl/reserved/webgl_function.vert.html": 0.059, + "conformance/glsl/reserved/webgl_struct.vert.html": 0.0716, + "conformance/glsl/reserved/webgl_variable.vert.html": 0.0528, + "conformance/glsl/samplers/glsl-function-texture2d-bias.html": 0.2368, + "conformance/glsl/samplers/glsl-function-texture2dlod.html": 0.202, + "conformance/glsl/samplers/glsl-function-texture2dproj.html": 0.1354, + "conformance/glsl/samplers/glsl-function-texture2dprojlod.html": 0.4437, + "conformance/glsl/variables/gl-fragcoord-xy-values.html": 0.1136, + "conformance/glsl/variables/gl-fragcoord.html": 0.0892, + "conformance/glsl/variables/gl-fragdata-and-fragcolor.html": 0.1572, + "conformance/glsl/variables/gl-frontfacing.html": 0.095, + "conformance/glsl/variables/gl-pointcoord.html": 0.0854, + "conformance/glsl/variables/glsl-built-ins.html": 0.1868, + "conformance/limits/gl-line-width.html": 0.0595, + "conformance/limits/gl-max-texture-dimensions.html": 0.1293, + "conformance/limits/gl-min-attribs.html": 0.0856, + "conformance/limits/gl-min-textures.html": 0.0628, + "conformance/limits/gl-min-uniforms.html": 0.0776, + "conformance/misc/bad-arguments-test.html": 0.1738, + "conformance/misc/boolean-argument-conversion.html": 0.1372, + "conformance/misc/delayed-drawing.html": 1.0644, + "conformance/misc/error-reporting.html": 0.1058, + "conformance/misc/expando-loss.html": 0.2246, + "conformance/misc/functions-returning-strings.html": 0.0828, + "conformance/misc/invalid-passed-params.html": 0.1681, + "conformance/misc/is-object.html": 0.0486, + "conformance/misc/null-object-behaviour.html": 0.0854, + "conformance/misc/object-deletion-behaviour.html": 0.18, + "conformance/misc/shader-precision-format.html": 0.07, + "conformance/misc/type-conversion-test.html": 0.1735, + "conformance/misc/uninitialized-test.html": 0.1901, + "conformance/misc/webgl-specific-stencil-settings.html": 0.2, + "conformance/misc/webgl-specific.html": 0.1155, + "conformance/more/conformance/constants.html": 0.1252, + "conformance/more/conformance/getContext.html": 0.1935, + "conformance/more/conformance/methods.html": 0.1486, + "conformance/more/conformance/quickCheckAPI-A.html": 0.1319, + "conformance/more/conformance/quickCheckAPI-B1.html": 0.1892, + "conformance/more/conformance/quickCheckAPI-B2.html": 0.1763, + "conformance/more/conformance/quickCheckAPI-B3.html": 0.163, + "conformance/more/conformance/quickCheckAPI-B4.html": 0.1338, + "conformance/more/conformance/quickCheckAPI-C.html": 0.1896, + "conformance/more/conformance/quickCheckAPI-D_G.html": 0.145, + "conformance/more/conformance/quickCheckAPI-G_I.html": 0.2451, + "conformance/more/conformance/quickCheckAPI-L_S.html": 0.1899, + "conformance/more/conformance/quickCheckAPI-S_V.html": 0.1859, + "conformance/more/conformance/webGLArrays.html": 0.1275, + "conformance/more/functions/bindBuffer.html": 0.1254, + "conformance/more/functions/bindBufferBadArgs.html": 0.1268, + "conformance/more/functions/bindFramebufferLeaveNonZero.html": 0.1563, + "conformance/more/functions/bufferData.html": 0.1274, + "conformance/more/functions/bufferDataBadArgs.html": 0.1476, + "conformance/more/functions/bufferSubData.html": 0.166, + "conformance/more/functions/bufferSubDataBadArgs.html": 0.1053, + "conformance/more/functions/copyTexImage2D.html": 0.1391, + "conformance/more/functions/copyTexImage2DBadArgs.html": 0.1266, + "conformance/more/functions/copyTexSubImage2D.html": 0.1097, + "conformance/more/functions/copyTexSubImage2DBadArgs.html": 0.1182, + "conformance/more/functions/deleteBufferBadArgs.html": 0.0795, + "conformance/more/functions/drawArrays.html": 0.0984, + "conformance/more/functions/drawElements.html": 0.099, + "conformance/more/functions/isTests.html": 0.1133, + "conformance/more/functions/isTestsBadArgs.html": 0.0507, + "conformance/more/functions/readPixels.html": 0.0998, + "conformance/more/functions/readPixelsBadArgs.html": 0.1953, + "conformance/more/functions/texImage2D.html": 0.1015, + "conformance/more/functions/texImage2DBadArgs.html": 0.082, + "conformance/more/functions/texImage2DHTML.html": 0.5874, + "conformance/more/functions/texImage2DHTMLBadArgs.html": 0.112, + "conformance/more/functions/texSubImage2D.html": 0.1207, + "conformance/more/functions/texSubImage2DBadArgs.html": 0.0895, + "conformance/more/functions/texSubImage2DHTML.html": 0.2517, + "conformance/more/functions/texSubImage2DHTMLBadArgs.html": 0.0994, + "conformance/more/functions/uniformMatrix.html": 0.1291, + "conformance/more/functions/uniformMatrixBadArgs.html": 0.1289, + "conformance/more/functions/uniformf.html": 0.0878, + "conformance/more/functions/uniformfArrayLen1.html": 0.1191, + "conformance/more/functions/uniformfBadArgs.html": 0.1226, + "conformance/more/functions/uniformi.html": 0.3108, + "conformance/more/functions/uniformiBadArgs.html": 0.1162, + "conformance/more/functions/vertexAttrib.html": 0.1175, + "conformance/more/functions/vertexAttribBadArgs.html": 0.142, + "conformance/more/functions/vertexAttribPointer.html": 0.1127, + "conformance/more/functions/vertexAttribPointerBadArgs.html": 0.1254, + "conformance/more/glsl/arrayOutOfBounds.html": 0.1416, + "conformance/more/glsl/uniformOutOfBounds.html": 0.1036, + "conformance/offscreencanvas/context-attribute-preserve-drawing-buffer.html": 0.6764, + "conformance/offscreencanvas/context-creation-worker.html": 0.1328, + "conformance/offscreencanvas/context-creation.html": 0.071, + "conformance/offscreencanvas/context-lost-restored-worker.html": 0.2687, + "conformance/offscreencanvas/context-lost-restored.html": 0.1902, + "conformance/offscreencanvas/context-lost-worker.html": 0.2475, + "conformance/offscreencanvas/context-lost.html": 0.1627, + "conformance/offscreencanvas/methods-worker.html": 0.1637, + "conformance/offscreencanvas/methods.html": 0.1557, + "conformance/offscreencanvas/offscreencanvas-resize.html": 0.086, + "conformance/offscreencanvas/offscreencanvas-transfer-image-bitmap.html": 0.2739, + "conformance/ogles/GL/abs/abs_001_to_006.html": 1.5746, + "conformance/ogles/GL/acos/acos_001_to_006.html": 1.8531, + "conformance/ogles/GL/all/all_001_to_004.html": 2.2465, + "conformance/ogles/GL/any/any_001_to_004.html": 1.5218, + "conformance/ogles/GL/array/array_001_to_006.html": 0.262, + "conformance/ogles/GL/asin/asin_001_to_006.html": 1.8685, + "conformance/ogles/GL/atan/atan_001_to_008.html": 1.8396, + "conformance/ogles/GL/atan/atan_009_to_012.html": 1.6849, + "conformance/ogles/GL/biConstants/biConstants_001_to_008.html": 1.8837, + "conformance/ogles/GL/biConstants/biConstants_009_to_016.html": 1.6361, + "conformance/ogles/GL/biuDepthRange/biuDepthRange_001_to_002.html": 0.9187, + "conformance/ogles/GL/build/build_001_to_008.html": 0.3666, + "conformance/ogles/GL/build/build_009_to_016.html": 0.2799, + "conformance/ogles/GL/build/build_017_to_024.html": 0.164, + "conformance/ogles/GL/build/build_025_to_032.html": 0.1589, + "conformance/ogles/GL/build/build_033_to_040.html": 0.1783, + "conformance/ogles/GL/build/build_041_to_048.html": 0.1752, + "conformance/ogles/GL/build/build_049_to_056.html": 0.1525, + "conformance/ogles/GL/build/build_057_to_064.html": 0.2254, + "conformance/ogles/GL/build/build_065_to_072.html": 0.1632, + "conformance/ogles/GL/build/build_073_to_080.html": 0.1673, + "conformance/ogles/GL/build/build_081_to_088.html": 0.2365, + "conformance/ogles/GL/build/build_089_to_096.html": 0.2114, + "conformance/ogles/GL/build/build_097_to_104.html": 0.1533, + "conformance/ogles/GL/build/build_105_to_112.html": 0.1554, + "conformance/ogles/GL/build/build_113_to_120.html": 0.2103, + "conformance/ogles/GL/build/build_121_to_128.html": 0.2303, + "conformance/ogles/GL/build/build_129_to_136.html": 0.1689, + "conformance/ogles/GL/build/build_137_to_144.html": 0.1855, + "conformance/ogles/GL/build/build_145_to_152.html": 0.1286, + "conformance/ogles/GL/build/build_153_to_160.html": 0.1871, + "conformance/ogles/GL/build/build_161_to_168.html": 0.1716, + "conformance/ogles/GL/build/build_169_to_176.html": 0.1553, + "conformance/ogles/GL/build/build_177_to_178.html": 0.1517, + "conformance/ogles/GL/built_in_varying_array_out_of_bounds/built_in_varying_array_out_of_bounds_001_to_001.html": 0.1528, + "conformance/ogles/GL/ceil/ceil_001_to_006.html": 1.7609, + "conformance/ogles/GL/clamp/clamp_001_to_006.html": 1.7617, + "conformance/ogles/GL/control_flow/control_flow_001_to_008.html": 0.503, + "conformance/ogles/GL/control_flow/control_flow_009_to_010.html": 0.2944, + "conformance/ogles/GL/cos/cos_001_to_006.html": 2.7196, + "conformance/ogles/GL/cross/cross_001_to_002.html": 0.8122, + "conformance/ogles/GL/default/default_001_to_001.html": 0.2029, + "conformance/ogles/GL/degrees/degrees_001_to_006.html": 2.2825, + "conformance/ogles/GL/discard/discard_001_to_002.html": 0.1537, + "conformance/ogles/GL/distance/distance_001_to_006.html": 1.5505, + "conformance/ogles/GL/dot/dot_001_to_006.html": 1.7441, + "conformance/ogles/GL/equal/equal_001_to_008.html": 1.6828, + "conformance/ogles/GL/equal/equal_009_to_012.html": 1.4854, + "conformance/ogles/GL/exp/exp_001_to_008.html": 2.0203, + "conformance/ogles/GL/exp/exp_009_to_012.html": 1.5929, + "conformance/ogles/GL/exp2/exp2_001_to_008.html": 2.4991, + "conformance/ogles/GL/exp2/exp2_009_to_012.html": 1.82, + "conformance/ogles/GL/faceforward/faceforward_001_to_006.html": 1.7123, + "conformance/ogles/GL/floor/floor_001_to_006.html": 1.5997, + "conformance/ogles/GL/fract/fract_001_to_006.html": 2.1399, + "conformance/ogles/GL/functions/functions_001_to_008.html": 1.7699, + "conformance/ogles/GL/functions/functions_009_to_016.html": 0.53, + "conformance/ogles/GL/functions/functions_017_to_024.html": 0.3779, + "conformance/ogles/GL/functions/functions_025_to_032.html": 0.5173, + "conformance/ogles/GL/functions/functions_033_to_040.html": 0.3819, + "conformance/ogles/GL/functions/functions_041_to_048.html": 0.381, + "conformance/ogles/GL/functions/functions_049_to_056.html": 0.5545, + "conformance/ogles/GL/functions/functions_057_to_064.html": 0.5242, + "conformance/ogles/GL/functions/functions_065_to_072.html": 0.3836, + "conformance/ogles/GL/functions/functions_073_to_080.html": 0.3791, + "conformance/ogles/GL/functions/functions_081_to_088.html": 0.5232, + "conformance/ogles/GL/functions/functions_089_to_096.html": 0.3411, + "conformance/ogles/GL/functions/functions_097_to_104.html": 0.3584, + "conformance/ogles/GL/functions/functions_105_to_112.html": 0.4035, + "conformance/ogles/GL/functions/functions_113_to_120.html": 0.4483, + "conformance/ogles/GL/functions/functions_121_to_126.html": 0.3799, + "conformance/ogles/GL/gl_FragCoord/gl_FragCoord_001_to_003.html": 0.313, + "conformance/ogles/GL/gl_FrontFacing/gl_FrontFacing_001_to_001.html": 0.1539, + "conformance/ogles/GL/greaterThan/greaterThan_001_to_008.html": 1.6656, + "conformance/ogles/GL/greaterThanEqual/greaterThanEqual_001_to_008.html": 1.6742, + "conformance/ogles/GL/inversesqrt/inversesqrt_001_to_006.html": 1.9241, + "conformance/ogles/GL/length/length_001_to_006.html": 1.7343, + "conformance/ogles/GL/lessThan/lessThan_001_to_008.html": 1.6195, + "conformance/ogles/GL/lessThanEqual/lessThanEqual_001_to_008.html": 1.9445, + "conformance/ogles/GL/log/log_001_to_008.html": 1.757, + "conformance/ogles/GL/log/log_009_to_012.html": 1.6359, + "conformance/ogles/GL/log2/log2_001_to_008.html": 1.9237, + "conformance/ogles/GL/log2/log2_009_to_012.html": 2.396, + "conformance/ogles/GL/mat/mat_001_to_008.html": 0.3725, + "conformance/ogles/GL/mat/mat_009_to_016.html": 0.3917, + "conformance/ogles/GL/mat/mat_017_to_024.html": 0.5881, + "conformance/ogles/GL/mat/mat_025_to_032.html": 1.6467, + "conformance/ogles/GL/mat/mat_033_to_040.html": 1.9736, + "conformance/ogles/GL/mat/mat_041_to_046.html": 0.3854, + "conformance/ogles/GL/mat3/mat3_001_to_006.html": 0.3706, + "conformance/ogles/GL/matrixCompMult/matrixCompMult_001_to_004.html": 2.2453, + "conformance/ogles/GL/max/max_001_to_006.html": 2.263, + "conformance/ogles/GL/min/min_001_to_006.html": 2.0208, + "conformance/ogles/GL/mix/mix_001_to_006.html": 2.9611, + "conformance/ogles/GL/mod/mod_001_to_008.html": 1.6009, + "conformance/ogles/GL/normalize/normalize_001_to_006.html": 1.6712, + "conformance/ogles/GL/not/not_001_to_004.html": 1.6796, + "conformance/ogles/GL/notEqual/notEqual_001_to_008.html": 1.6549, + "conformance/ogles/GL/notEqual/notEqual_009_to_012.html": 1.6995, + "conformance/ogles/GL/operators/operators_001_to_008.html": 0.3589, + "conformance/ogles/GL/operators/operators_009_to_016.html": 0.3772, + "conformance/ogles/GL/operators/operators_017_to_024.html": 0.4969, + "conformance/ogles/GL/operators/operators_025_to_026.html": 0.2991, + "conformance/ogles/GL/pow/pow_001_to_008.html": 0.5157, + "conformance/ogles/GL/pow/pow_009_to_016.html": 1.6469, + "conformance/ogles/GL/pow/pow_017_to_024.html": 2.2309, + "conformance/ogles/GL/radians/radians_001_to_006.html": 1.5362, + "conformance/ogles/GL/reflect/reflect_001_to_006.html": 1.7224, + "conformance/ogles/GL/refract/refract_001_to_006.html": 3.352, + "conformance/ogles/GL/sign/sign_001_to_006.html": 1.5218, + "conformance/ogles/GL/sin/sin_001_to_006.html": 2.4004, + "conformance/ogles/GL/smoothstep/smoothstep_001_to_006.html": 1.7309, + "conformance/ogles/GL/sqrt/sqrt_001_to_006.html": 2.027, + "conformance/ogles/GL/step/step_001_to_006.html": 1.5448, + "conformance/ogles/GL/struct/struct_001_to_008.html": 1.6513, + "conformance/ogles/GL/struct/struct_009_to_016.html": 1.7496, + "conformance/ogles/GL/struct/struct_017_to_024.html": 1.8236, + "conformance/ogles/GL/struct/struct_025_to_032.html": 1.6417, + "conformance/ogles/GL/struct/struct_033_to_040.html": 1.8579, + "conformance/ogles/GL/struct/struct_041_to_048.html": 1.6717, + "conformance/ogles/GL/struct/struct_049_to_056.html": 1.6739, + "conformance/ogles/GL/swizzlers/swizzlers_001_to_008.html": 1.895, + "conformance/ogles/GL/swizzlers/swizzlers_009_to_016.html": 2.471, + "conformance/ogles/GL/swizzlers/swizzlers_017_to_024.html": 1.7106, + "conformance/ogles/GL/swizzlers/swizzlers_025_to_032.html": 1.6801, + "conformance/ogles/GL/swizzlers/swizzlers_033_to_040.html": 1.8725, + "conformance/ogles/GL/swizzlers/swizzlers_041_to_048.html": 1.679, + "conformance/ogles/GL/swizzlers/swizzlers_049_to_056.html": 1.6806, + "conformance/ogles/GL/swizzlers/swizzlers_057_to_064.html": 1.8965, + "conformance/ogles/GL/swizzlers/swizzlers_065_to_072.html": 1.6142, + "conformance/ogles/GL/swizzlers/swizzlers_073_to_080.html": 1.9778, + "conformance/ogles/GL/swizzlers/swizzlers_081_to_088.html": 1.8411, + "conformance/ogles/GL/swizzlers/swizzlers_089_to_096.html": 1.7127, + "conformance/ogles/GL/swizzlers/swizzlers_097_to_104.html": 11.8058, + "conformance/ogles/GL/swizzlers/swizzlers_105_to_112.html": 2.7031, + "conformance/ogles/GL/swizzlers/swizzlers_113_to_120.html": 1.8531, + "conformance/ogles/GL/tan/tan_001_to_006.html": 2.2158, + "conformance/ogles/GL/vec/vec_001_to_008.html": 0.3785, + "conformance/ogles/GL/vec/vec_009_to_016.html": 0.5446, + "conformance/ogles/GL/vec/vec_017_to_018.html": 0.245, + "conformance/ogles/GL/vec3/vec3_001_to_008.html": 0.3785, + "conformance/programs/get-active-test.html": 0.1235, + "conformance/programs/gl-bind-attrib-location-long-names-test.html": 0.1088, + "conformance/programs/gl-bind-attrib-location-test.html": 1.3369, + "conformance/programs/gl-get-active-attribute.html": 0.1418, + "conformance/programs/gl-get-active-uniform.html": 0.1695, + "conformance/programs/gl-getshadersource.html": 0.0521, + "conformance/programs/gl-shader-test.html": 0.1422, + "conformance/programs/invalid-UTF-16.html": 0.0494, + "conformance/programs/program-infolog.html": 0.066, + "conformance/programs/program-test.html": 0.2195, + "conformance/programs/use-program-crash-with-discard-in-fragment-shader.html": 0.1014, + "conformance/reading/fbo-remains-unchanged-after-read-pixels.html": 0.0672, + "conformance/reading/read-pixels-pack-alignment.html": 0.1514, + "conformance/reading/read-pixels-test.html": 0.6886, + "conformance/renderbuffers/depth-renderbuffer-initialization.html": 0.156, + "conformance/renderbuffers/feedback-loop.html": 0.0678, + "conformance/renderbuffers/framebuffer-state-restoration.html": 0.353, + "conformance/renderbuffers/renderbuffer-initialization.html": 0.3474, + "conformance/renderbuffers/stencil-renderbuffer-initialization.html": 0.1786, + "conformance/rendering/blending.html": 0.2838, + "conformance/rendering/canvas-alpha-bug.html": 0.0883, + "conformance/rendering/clear-after-copyTexImage2D.html": 0.1314, + "conformance/rendering/color-mask-preserved-during-implicit-clears.html": 1.2951, + "conformance/rendering/culling.html": 0.066, + "conformance/rendering/default-texture-draw-bug.html": 0.2524, + "conformance/rendering/draw-arrays-out-of-bounds.html": 0.7191, + "conformance/rendering/draw-elements-out-of-bounds.html": 0.0958, + "conformance/rendering/draw-webgl-to-canvas-2d-repeatedly.html": 0.19, + "conformance/rendering/draw-with-changing-start-vertex-bug.html": 0.1164, + "conformance/rendering/framebuffer-switch.html": 0.1194, + "conformance/rendering/framebuffer-texture-clear.html": 0.1205, + "conformance/rendering/framebuffer-texture-switch.html": 0.2406, + "conformance/rendering/gl-clear.html": 0.0773, + "conformance/rendering/gl-drawarrays.html": 0.1259, + "conformance/rendering/gl-drawelements.html": 0.1419, + "conformance/rendering/gl-scissor-canvas-dimensions.html": 0.0937, + "conformance/rendering/gl-scissor-fbo-test.html": 0.092, + "conformance/rendering/gl-scissor-test.html": 0.2266, + "conformance/rendering/gl-viewport-test.html": 0.3293, + "conformance/rendering/line-loop-tri-fan.html": 0.0662, + "conformance/rendering/line-rendering-quality.html": 0.1015, + "conformance/rendering/many-draw-calls.html": 1.4424, + "conformance/rendering/more-than-65536-indices.html": 0.4449, + "conformance/rendering/multisample-corruption.html": 2.6124, + "conformance/rendering/negative-one-index.html": 0.0738, + "conformance/rendering/out-of-bounds-array-buffers.html": 0.0935, + "conformance/rendering/out-of-bounds-index-buffers.html": 0.0876, + "conformance/rendering/point-no-attributes.html": 0.0847, + "conformance/rendering/point-size.html": 0.0633, + "conformance/rendering/point-specific-shader-variables.html": 0.0949, + "conformance/rendering/point-with-gl-pointcoord-in-fragment-shader.html": 0.1008, + "conformance/rendering/polygon-offset.html": 0.0938, + "conformance/rendering/preservedrawingbuffer-leak.html": 0.1789, + "conformance/rendering/rendering-sampling-feedback-loop.html": 0.1026, + "conformance/rendering/rendering-stencil-large-viewport.html": 0.1151, + "conformance/rendering/scissor-rect-repeated-rendering.html": 0.2706, + "conformance/rendering/simple.html": 0.0916, + "conformance/rendering/texture-switch-performance.html": 0.0009, + "conformance/rendering/triangle.html": 0.0756, + "conformance/state/gl-enable-enum-test.html": 0.3136, + "conformance/state/gl-get-calls.html": 0.117, + "conformance/state/gl-geterror.html": 0.1304, + "conformance/state/gl-initial-state.html": 0.0506, + "conformance/state/state-uneffected-after-compositing.html": 0.2785, + "conformance/textures/canvas/tex-2d-alpha-alpha-unsigned_byte.html": 0.3841, + "conformance/textures/canvas/tex-2d-luminance-luminance-unsigned_byte.html": 0.7054, + "conformance/textures/canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.7952, + "conformance/textures/canvas/tex-2d-rgb-rgb-unsigned_byte.html": 2.297, + "conformance/textures/canvas/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 1.0114, + "conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_byte.html": 1.6781, + "conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.705, + "conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.7684, + "conformance/textures/canvas_sub_rectangle/tex-2d-alpha-alpha-unsigned_byte.html": 0.9165, + "conformance/textures/canvas_sub_rectangle/tex-2d-luminance-luminance-unsigned_byte.html": 0.6039, + "conformance/textures/canvas_sub_rectangle/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.7054, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgb-rgb-unsigned_byte.html": 0.5956, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.7613, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_byte.html": 0.8287, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.6154, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.6127, + "conformance/textures/image/tex-2d-alpha-alpha-unsigned_byte.html": 0.2249, + "conformance/textures/image/tex-2d-luminance-luminance-unsigned_byte.html": 0.2842, + "conformance/textures/image/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.2465, + "conformance/textures/image/tex-2d-rgb-rgb-unsigned_byte.html": 0.312, + "conformance/textures/image/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.2931, + "conformance/textures/image/tex-2d-rgba-rgba-unsigned_byte.html": 0.2729, + "conformance/textures/image/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.2721, + "conformance/textures/image/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.2831, + "conformance/textures/image_bitmap_from_blob/tex-2d-alpha-alpha-unsigned_byte.html": 0.3889, + "conformance/textures/image_bitmap_from_blob/tex-2d-luminance-luminance-unsigned_byte.html": 0.5932, + "conformance/textures/image_bitmap_from_blob/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.2782, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgb-rgb-unsigned_byte.html": 0.1399, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.3649, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgba-rgba-unsigned_byte.html": 0.388, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.1659, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.1694, + "conformance/textures/image_bitmap_from_canvas/tex-2d-alpha-alpha-unsigned_byte.html": 0.3749, + "conformance/textures/image_bitmap_from_canvas/tex-2d-luminance-luminance-unsigned_byte.html": 0.344, + "conformance/textures/image_bitmap_from_canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.5119, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgb-rgb-unsigned_byte.html": 0.5215, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.4973, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgba-rgba-unsigned_byte.html": 0.3586, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.8032, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.5085, + "conformance/textures/image_bitmap_from_image/tex-2d-alpha-alpha-unsigned_byte.html": 0.391, + "conformance/textures/image_bitmap_from_image/tex-2d-luminance-luminance-unsigned_byte.html": 0.3548, + "conformance/textures/image_bitmap_from_image/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.147, + "conformance/textures/image_bitmap_from_image/tex-2d-rgb-rgb-unsigned_byte.html": 0.322, + "conformance/textures/image_bitmap_from_image/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.1487, + "conformance/textures/image_bitmap_from_image/tex-2d-rgba-rgba-unsigned_byte.html": 0.1543, + "conformance/textures/image_bitmap_from_image/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.3348, + "conformance/textures/image_bitmap_from_image/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.1525, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-alpha-alpha-unsigned_byte.html": 0.2263, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-luminance-luminance-unsigned_byte.html": 0.307, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.1249, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgb-rgb-unsigned_byte.html": 0.1487, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.577, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgba-rgba-unsigned_byte.html": 0.2443, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.154, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.2784, + "conformance/textures/image_bitmap_from_image_data/tex-2d-alpha-alpha-unsigned_byte.html": 0.2386, + "conformance/textures/image_bitmap_from_image_data/tex-2d-luminance-luminance-unsigned_byte.html": 0.2359, + "conformance/textures/image_bitmap_from_image_data/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.2443, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgb-rgb-unsigned_byte.html": 0.266, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.1779, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgba-rgba-unsigned_byte.html": 0.2337, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.1481, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.2203, + "conformance/textures/image_bitmap_from_video/tex-2d-alpha-alpha-unsigned_byte.html": 0.3774, + "conformance/textures/image_bitmap_from_video/tex-2d-luminance-luminance-unsigned_byte.html": 0.485, + "conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.4059, + "conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_byte.html": 0.3834, + "conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.3855, + "conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_byte.html": 0.6173, + "conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.8654, + "conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.5302, + "conformance/textures/image_data/tex-2d-alpha-alpha-unsigned_byte.html": 0.5127, + "conformance/textures/image_data/tex-2d-luminance-luminance-unsigned_byte.html": 0.5603, + "conformance/textures/image_data/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.2686, + "conformance/textures/image_data/tex-2d-rgb-rgb-unsigned_byte.html": 0.5385, + "conformance/textures/image_data/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.3342, + "conformance/textures/image_data/tex-2d-rgba-rgba-unsigned_byte.html": 0.2723, + "conformance/textures/image_data/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.5674, + "conformance/textures/image_data/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.3429, + "conformance/textures/misc/canvas-teximage-after-multiple-drawimages.html": 0.1429, + "conformance/textures/misc/compressed-tex-image.html": 0.136, + "conformance/textures/misc/copy-tex-image-2d-formats.html": 0.1156, + "conformance/textures/misc/copy-tex-image-and-sub-image-2d.html": 0.3681, + "conformance/textures/misc/copy-tex-image-crash.html": 0.1384, + "conformance/textures/misc/copytexsubimage2d-large-partial-copy-corruption.html": 0.253, + "conformance/textures/misc/copytexsubimage2d-subrects.html": 0.0796, + "conformance/textures/misc/cube-incomplete-fbo.html": 0.0542, + "conformance/textures/misc/cube-map-uploads-out-of-order.html": 1.0528, + "conformance/textures/misc/default-texture.html": 0.1258, + "conformance/textures/misc/gl-pixelstorei.html": 0.0707, + "conformance/textures/misc/gl-teximage.html": 0.3361, + "conformance/textures/misc/mipmap-fbo.html": 0.0837, + "conformance/textures/misc/origin-clean-conformance-offscreencanvas.html": 0.1409, + "conformance/textures/misc/origin-clean-conformance.html": 0.0748, + "conformance/textures/misc/tex-image-and-sub-image-2d-with-array-buffer-view.html": 1.8466, + "conformance/textures/misc/tex-image-and-uniform-binding-bugs.html": 0.0937, + "conformance/textures/misc/tex-image-canvas-corruption.html": 0.2201, + "conformance/textures/misc/tex-image-webgl.html": 0.1239, + "conformance/textures/misc/tex-image-with-format-and-type.html": 0.4521, + "conformance/textures/misc/tex-image-with-invalid-data.html": 0.0862, + "conformance/textures/misc/tex-sub-image-2d-bad-args.html": 0.0878, + "conformance/textures/misc/tex-sub-image-2d.html": 0.0843, + "conformance/textures/misc/tex-video-using-tex-unit-non-zero.html": 0.489, + "conformance/textures/misc/texparameter-test.html": 0.0787, + "conformance/textures/misc/texture-active-bind-2.html": 0.0667, + "conformance/textures/misc/texture-active-bind.html": 0.1046, + "conformance/textures/misc/texture-attachment-formats.html": 0.102, + "conformance/textures/misc/texture-clear.html": 0.0591, + "conformance/textures/misc/texture-complete.html": 0.062, + "conformance/textures/misc/texture-copying-feedback-loops.html": 0.0595, + "conformance/textures/misc/texture-corner-case-videos.html": 0.1606, + "conformance/textures/misc/texture-cube-as-fbo-attachment.html": 0.1518, + "conformance/textures/misc/texture-draw-with-2d-and-cube.html": 0.1783, + "conformance/textures/misc/texture-hd-dpi.html": 0.1799, + "conformance/textures/misc/texture-mips.html": 0.0939, + "conformance/textures/misc/texture-size-cube-maps.html": 0.579, + "conformance/textures/misc/texture-size-limit.html": 0.667, + "conformance/textures/misc/texture-size.html": 0.6285, + "conformance/textures/misc/texture-sub-image-cube-maps.html": 0.1164, + "conformance/textures/misc/texture-transparent-pixels-initialized.html": 0.1541, + "conformance/textures/misc/texture-upload-cube-maps.html": 0.079, + "conformance/textures/misc/texture-upload-size.html": 0.3717, + "conformance/textures/misc/texture-video-transparent.html": 1.7164, + "conformance/textures/misc/texture-with-flip-y-and-premultiply-alpha.html": 0.0493, + "conformance/textures/svg_image/tex-2d-alpha-alpha-unsigned_byte.html": 0.1543, + "conformance/textures/svg_image/tex-2d-luminance-luminance-unsigned_byte.html": 0.1569, + "conformance/textures/svg_image/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.1635, + "conformance/textures/svg_image/tex-2d-rgb-rgb-unsigned_byte.html": 0.1774, + "conformance/textures/svg_image/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.1504, + "conformance/textures/svg_image/tex-2d-rgba-rgba-unsigned_byte.html": 0.1602, + "conformance/textures/svg_image/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.14, + "conformance/textures/svg_image/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.1476, + "conformance/textures/video/tex-2d-alpha-alpha-unsigned_byte.html": 0.6049, + "conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html": 0.5729, + "conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.6784, + "conformance/textures/video/tex-2d-rgb-rgb-unsigned_byte.html": 0.6673, + "conformance/textures/video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.8234, + "conformance/textures/video/tex-2d-rgba-rgba-unsigned_byte.html": 1.4199, + "conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.5658, + "conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 1.0377, + "conformance/textures/webgl_canvas/tex-2d-alpha-alpha-unsigned_byte.html": 0.5897, + "conformance/textures/webgl_canvas/tex-2d-luminance-luminance-unsigned_byte.html": 0.5268, + "conformance/textures/webgl_canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.4956, + "conformance/textures/webgl_canvas/tex-2d-rgb-rgb-unsigned_byte.html": 0.975, + "conformance/textures/webgl_canvas/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.5978, + "conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_byte.html": 2.4175, + "conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.4184, + "conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.4706, + "conformance/typedarrays/array-buffer-crash.html": 0.0662, + "conformance/typedarrays/array-buffer-view-crash.html": 0.1381, + "conformance/typedarrays/array-large-array-tests.html": 0.1551, + "conformance/typedarrays/array-unit-tests.html": 0.1416, + "conformance/typedarrays/data-view-crash.html": 0.155, + "conformance/typedarrays/data-view-test.html": 0.1465, + "conformance/typedarrays/typed-arrays-in-workers.html": 0.1622, + "conformance/uniforms/gl-uniform-arrays.html": 0.1093, + "conformance/uniforms/gl-uniform-bool.html": 0.0897, + "conformance/uniforms/gl-uniformmatrix4fv.html": 0.1255, + "conformance/uniforms/gl-unknown-uniform.html": 0.1695, + "conformance/uniforms/no-over-optimization-on-uniform-array-00.html": 0.7476, + "conformance/uniforms/no-over-optimization-on-uniform-array-01.html": 0.5987, + "conformance/uniforms/no-over-optimization-on-uniform-array-02.html": 0.8511, + "conformance/uniforms/no-over-optimization-on-uniform-array-03.html": 0.5822, + "conformance/uniforms/no-over-optimization-on-uniform-array-04.html": 0.6949, + "conformance/uniforms/no-over-optimization-on-uniform-array-05.html": 1.1017, + "conformance/uniforms/no-over-optimization-on-uniform-array-06.html": 1.06, + "conformance/uniforms/no-over-optimization-on-uniform-array-07.html": 0.74, + "conformance/uniforms/no-over-optimization-on-uniform-array-08.html": 0.7154, + "conformance/uniforms/no-over-optimization-on-uniform-array-09.html": 1.0439, + "conformance/uniforms/no-over-optimization-on-uniform-array-10.html": 0.6871, + "conformance/uniforms/no-over-optimization-on-uniform-array-11.html": 0.6816, + "conformance/uniforms/no-over-optimization-on-uniform-array-12.html": 0.9344, + "conformance/uniforms/no-over-optimization-on-uniform-array-13.html": 0.5815, + "conformance/uniforms/no-over-optimization-on-uniform-array-14.html": 1.0901, + "conformance/uniforms/no-over-optimization-on-uniform-array-15.html": 1.0292, + "conformance/uniforms/no-over-optimization-on-uniform-array-16.html": 0.5892, + "conformance/uniforms/no-over-optimization-on-uniform-array-17.html": 0.6864, + "conformance/uniforms/null-uniform-location.html": 0.0667, + "conformance/uniforms/out-of-bounds-uniform-array-access.html": 3.2105, + "conformance/uniforms/uniform-default-values.html": 1.5061, + "conformance/uniforms/uniform-location.html": 0.1187, + "conformance/uniforms/uniform-samplers-test.html": 13.3713, + "conformance/uniforms/uniform-values-per-program.html": 0.6972, + "conformance2/attribs/gl-bindAttribLocation-aliasing-inactive.html": 0.1631, + "conformance2/attribs/gl-vertex-attrib-i-render.html": 0.6298, + "conformance2/attribs/gl-vertex-attrib-normalized-int.html": 0.0965, + "conformance2/attribs/gl-vertex-attrib.html": 0.7398, + "conformance2/attribs/gl-vertexattribipointer-offsets.html": 0.1832, + "conformance2/attribs/gl-vertexattribipointer.html": 1.2859, + "conformance2/attribs/render-no-enabled-attrib-arrays.html": 0.065, + "conformance2/buffers/bound-buffer-size-change-test.html": 0.0761, + "conformance2/buffers/buffer-copying-contents.html": 0.3792, + "conformance2/buffers/buffer-copying-restrictions.html": 0.3708, + "conformance2/buffers/buffer-data-and-buffer-sub-data-sub-source.html": 0.1171, + "conformance2/buffers/buffer-overflow-test.html": 0.1231, + "conformance2/buffers/buffer-type-restrictions.html": 0.2577, + "conformance2/buffers/delete-buffer.html": 0.0525, + "conformance2/buffers/get-buffer-sub-data-validity.html": 0.2963, + "conformance2/buffers/get-buffer-sub-data.html": 0.082, + "conformance2/buffers/one-large-uniform-buffer.html": 0.162, + "conformance2/buffers/uniform-buffers-second-compile.html": 0.0834, + "conformance2/buffers/uniform-buffers-state-restoration.html": 0.1605, + "conformance2/buffers/uniform-buffers.html": 0.1846, + "conformance2/canvas/to-data-url-with-pack-params.html": 0.6395, + "conformance2/context/constants-and-properties-2.html": 0.0957, + "conformance2/context/context-attributes-depth-stencil-antialias-obeyed.html": 0.1389, + "conformance2/context/context-mode.html": 0.089, + "conformance2/context/context-resize-changes-buffer-binding-bug.html": 0.0519, + "conformance2/context/context-sharing-texture2darray-texture3d-data-bug.html": 0.2297, + "conformance2/context/context-type-test-2.html": 0.0528, + "conformance2/context/incorrect-context-object-behaviour.html": 0.159, + "conformance2/context/methods-2.html": 0.0641, + "conformance2/context/no-experimental-webgl2.html": 0.0462, + "conformance2/extensions/ext-color-buffer-float.html": 0.4073, + "conformance2/extensions/ext-disjoint-timer-query-webgl2.html": 5.9615, + "conformance2/extensions/ext-float-blend.html": 0.1175, + "conformance2/extensions/ovr_multiview2.html": 0.1478, + "conformance2/extensions/ovr_multiview2_depth.html": 0.0683, + "conformance2/extensions/ovr_multiview2_draw_buffers.html": 0.0455, + "conformance2/extensions/ovr_multiview2_flat_varying.html": 0.0655, + "conformance2/extensions/ovr_multiview2_instanced_draw.html": 0.1294, + "conformance2/extensions/ovr_multiview2_non_multiview_shaders.html": 0.0488, + "conformance2/extensions/ovr_multiview2_single_view_operations.html": 0.0766, + "conformance2/extensions/ovr_multiview2_timer_query.html": 0.0613, + "conformance2/extensions/ovr_multiview2_transform_feedback.html": 0.0701, + "conformance2/extensions/promoted-extensions-in-shaders.html": 0.2942, + "conformance2/extensions/promoted-extensions.html": 0.048, + "conformance2/glsl3/array-as-return-value.html": 0.1379, + "conformance2/glsl3/array-assign-constructor.html": 0.1844, + "conformance2/glsl3/array-assign.html": 0.1762, + "conformance2/glsl3/array-complex-indexing.html": 0.2039, + "conformance2/glsl3/array-element-increment.html": 0.2707, + "conformance2/glsl3/array-equality.html": 0.1073, + "conformance2/glsl3/array-in-complex-expression.html": 0.1146, + "conformance2/glsl3/array-initialize-with-same-name-array.html": 0.1339, + "conformance2/glsl3/array-length-side-effects.html": 0.1356, + "conformance2/glsl3/attrib-location-length-limits.html": 0.0773, + "conformance2/glsl3/bool-type-cast-bug-uint-ivec-uvec.html": 0.2453, + "conformance2/glsl3/compare-structs-containing-arrays.html": 0.2115, + "conformance2/glsl3/compound-assignment-type-combination.html": 1.1308, + "conformance2/glsl3/const-array-init.html": 0.1116, + "conformance2/glsl3/const-struct-from-array-as-function-parameter.html": 6.1263, + "conformance2/glsl3/float-parsing.html": 0.2447, + "conformance2/glsl3/forbidden-operators.html": 0.173, + "conformance2/glsl3/forward-declaration.html": 0.0872, + "conformance2/glsl3/frag-depth.html": 0.0941, + "conformance2/glsl3/gradient-in-discontinuous-loop.html": 0.0762, + "conformance2/glsl3/input-with-interpotaion-as-lvalue.html": 0.0865, + "conformance2/glsl3/invalid-default-precision.html": 0.0581, + "conformance2/glsl3/invalid-invariant.html": 0.0584, + "conformance2/glsl3/loops-with-side-effects.html": 0.2017, + "conformance2/glsl3/misplaced-version-directive.html": 0.0824, + "conformance2/glsl3/no-attribute-vertex-shader.html": 0.2138, + "conformance2/glsl3/sampler-no-precision.html": 0.1016, + "conformance2/glsl3/sequence-operator-returns-non-constant.html": 0.0722, + "conformance2/glsl3/shader-linking.html": 0.0775, + "conformance2/glsl3/shader-with-1024-character-define.html": 0.1559, + "conformance2/glsl3/shader-with-1024-character-identifier.frag.html": 0.0989, + "conformance2/glsl3/shader-with-1025-character-define.html": 0.0785, + "conformance2/glsl3/shader-with-1025-character-identifier.frag.html": 0.1288, + "conformance2/glsl3/shader-with-invalid-characters.html": 0.0753, + "conformance2/glsl3/shader-with-mis-matching-uniform-block.html": 0.8688, + "conformance2/glsl3/short-circuiting-in-loop-condition.html": 0.1535, + "conformance2/glsl3/switch-case.html": 0.112, + "conformance2/glsl3/texture-offset-non-constant-offset.html": 0.1105, + "conformance2/glsl3/texture-offset-out-of-range.html": 0.1369, + "conformance2/glsl3/texture-offset-uniform-texture-coordinate.html": 0.1501, + "conformance2/glsl3/tricky-loop-conditions.html": 0.6497, + "conformance2/glsl3/unary-minus-operator-in-dynamic-loop.html": 0.1968, + "conformance2/glsl3/uniform-block-layout-match.html": 0.0625, + "conformance2/glsl3/uniform-block-layouts.html": 0.0662, + "conformance2/glsl3/uniform-location-length-limits.html": 0.0818, + "conformance2/glsl3/uniform-struct-with-non-square-matrix.html": 0.073, + "conformance2/glsl3/uninitialized-local-global-variables.html": 0.1009, + "conformance2/glsl3/valid-invariant.html": 0.1072, + "conformance2/glsl3/varying-struct-inline-definition.html": 0.0769, + "conformance2/glsl3/vector-dynamic-indexing-nv-driver-bug.html": 0.0842, + "conformance2/glsl3/vector-dynamic-indexing-swizzled-lvalue.html": 0.095, + "conformance2/glsl3/vector-dynamic-indexing.html": 0.1997, + "conformance2/misc/expando-loss-2.html": 0.4911, + "conformance2/misc/getextension-while-pbo-bound-stability.html": 0.0823, + "conformance2/misc/instanceof-test.html": 0.0843, + "conformance2/misc/object-deletion-behaviour-2.html": 0.0773, + "conformance2/misc/uninitialized-test-2.html": 6.6157, + "conformance2/misc/views-with-offsets.html": 0.2715, + "conformance2/offscreencanvas/context-creation-worker.html": 0.1437, + "conformance2/offscreencanvas/context-creation.html": 0.056, + "conformance2/offscreencanvas/methods-2-worker.html": 0.1361, + "conformance2/offscreencanvas/methods-2.html": 0.0803, + "conformance2/offscreencanvas/offscreencanvas-transfer-image-bitmap.html": 0.1459, + "conformance2/programs/active-built-in-attribs.html": 0.1298, + "conformance2/programs/gl-get-frag-data-location.html": 0.1448, + "conformance2/programs/sampler-uniforms.html": 0.1992, + "conformance2/query/occlusion-query.html": 3.0731, + "conformance2/query/query.html": 0.087, + "conformance2/reading/format-r11f-g11f-b10f.html": 0.2056, + "conformance2/reading/read-pixels-from-fbo-test.html": 0.1395, + "conformance2/reading/read-pixels-from-rgb8-into-pbo-bug.html": 0.0773, + "conformance2/reading/read-pixels-into-pixel-pack-buffer.html": 0.1142, + "conformance2/reading/read-pixels-pack-parameters.html": 0.2482, + "conformance2/renderbuffers/framebuffer-object-attachment.html": 0.1017, + "conformance2/renderbuffers/framebuffer-test.html": 0.0973, + "conformance2/renderbuffers/framebuffer-texture-layer.html": 0.0603, + "conformance2/renderbuffers/invalidate-framebuffer.html": 0.0814, + "conformance2/renderbuffers/multisample-with-full-sample-counts.html": 0.141, + "conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html": 0.1618, + "conformance2/renderbuffers/multisampled-renderbuffer-initialization.html": 0.2283, + "conformance2/renderbuffers/multisampled-stencil-renderbuffer-initialization.html": 0.2314, + "conformance2/renderbuffers/readbuffer.html": 0.0818, + "conformance2/rendering/attrib-type-match.html": 0.2282, + "conformance2/rendering/blitframebuffer-filter-outofbounds.html": 0.2947, + "conformance2/rendering/blitframebuffer-filter-srgb.html": 0.1312, + "conformance2/rendering/blitframebuffer-multisampled-readbuffer.html": 0.1082, + "conformance2/rendering/blitframebuffer-outside-readbuffer.html": 0.1265, + "conformance2/rendering/blitframebuffer-r11f-g11f-b10f.html": 0.2236, + "conformance2/rendering/blitframebuffer-resolve-to-back-buffer.html": 0.2335, + "conformance2/rendering/blitframebuffer-scissor-enabled.html": 0.0829, + "conformance2/rendering/blitframebuffer-size-overflow.html": 0.0777, + "conformance2/rendering/blitframebuffer-srgb-and-linear-drawbuffers.html": 0.1747, + "conformance2/rendering/blitframebuffer-stencil-only.html": 0.0962, + "conformance2/rendering/blitframebuffer-test.html": 0.0915, + "conformance2/rendering/canvas-resizing-with-pbo-bound.html": 0.2884, + "conformance2/rendering/clear-func-buffer-type-match.html": 0.0922, + "conformance2/rendering/clear-srgb-color-buffer.html": 0.0601, + "conformance2/rendering/clearbuffer-sub-source.html": 0.0994, + "conformance2/rendering/clearbufferfv-with-alpha-false.html": 0.0536, + "conformance2/rendering/clipping-wide-points.html": 0.0807, + "conformance2/rendering/depth-stencil-feedback-loop.html": 0.0896, + "conformance2/rendering/draw-buffers-dirty-state-bug.html": 0.0734, + "conformance2/rendering/draw-buffers-driver-hang.html": 0.1581, + "conformance2/rendering/draw-buffers.html": 6.355, + "conformance2/rendering/draw-with-integer-texture-base-level.html": 0.0926, + "conformance2/rendering/element-index-uint.html": 0.2218, + "conformance2/rendering/framebuffer-completeness-draw-framebuffer.html": 0.0924, + "conformance2/rendering/framebuffer-completeness-unaffected.html": 0.0901, + "conformance2/rendering/framebuffer-texture-changing-base-level.html": 0.0945, + "conformance2/rendering/framebuffer-texture-level1.html": 0.0513, + "conformance2/rendering/framebuffer-unsupported.html": 0.096, + "conformance2/rendering/fs-color-type-mismatch-color-buffer-type.html": 6.1148, + "conformance2/rendering/instanced-arrays.html": 0.1969, + "conformance2/rendering/instanced-rendering-bug.html": 0.1712, + "conformance2/rendering/instanced-rendering-large-divisor.html": 0.1564, + "conformance2/rendering/line-rendering-quality.html": 0.085, + "conformance2/rendering/multisampling-fragment-evaluation.html": 0.0806, + "conformance2/rendering/out-of-bounds-index-buffers-after-copying.html": 0.1101, + "conformance2/rendering/read-draw-when-missing-image.html": 0.1065, + "conformance2/rendering/rgb-format-support.html": 0.0928, + "conformance2/rendering/texture-switch-performance.html": 0.0022, + "conformance2/rendering/uniform-block-buffer-size.html": 0.2384, + "conformance2/rendering/vertex-id.html": 0.0827, + "conformance2/samplers/multi-context-sampler-test.html": 0.0895, + "conformance2/samplers/sampler-drawing-test.html": 0.0882, + "conformance2/samplers/samplers.html": 0.1735, + "conformance2/state/gl-enum-tests.html": 0.1672, + "conformance2/state/gl-get-calls.html": 0.0845, + "conformance2/state/gl-getstring.html": 0.1048, + "conformance2/state/gl-object-get-calls.html": 13.2314, + "conformance2/sync/sync-webgl-specific.html": 10.8383, + "conformance2/textures/canvas/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.7983, + "conformance2/textures/canvas/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.8308, + "conformance2/textures/canvas/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.4969, + "conformance2/textures/canvas/tex-2d-r16f-red-float.html": 1.3621, + "conformance2/textures/canvas/tex-2d-r16f-red-half_float.html": 0.7838, + "conformance2/textures/canvas/tex-2d-r32f-red-float.html": 0.8089, + "conformance2/textures/canvas/tex-2d-r8-red-unsigned_byte.html": 0.8099, + "conformance2/textures/canvas/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.6922, + "conformance2/textures/canvas/tex-2d-rg16f-rg-float.html": 0.6167, + "conformance2/textures/canvas/tex-2d-rg16f-rg-half_float.html": 0.4899, + "conformance2/textures/canvas/tex-2d-rg32f-rg-float.html": 0.7265, + "conformance2/textures/canvas/tex-2d-rg8-rg-unsigned_byte.html": 0.7739, + "conformance2/textures/canvas/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 1.3545, + "conformance2/textures/canvas/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.5994, + "conformance2/textures/canvas/tex-2d-rgb16f-rgb-float.html": 0.8458, + "conformance2/textures/canvas/tex-2d-rgb16f-rgb-half_float.html": 0.6097, + "conformance2/textures/canvas/tex-2d-rgb32f-rgb-float.html": 0.7416, + "conformance2/textures/canvas/tex-2d-rgb565-rgb-unsigned_byte.html": 1.0586, + "conformance2/textures/canvas/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.5011, + "conformance2/textures/canvas/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.7428, + "conformance2/textures/canvas/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.5997, + "conformance2/textures/canvas/tex-2d-rgb8-rgb-unsigned_byte.html": 0.8376, + "conformance2/textures/canvas/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 1.1348, + "conformance2/textures/canvas/tex-2d-rgb9_e5-rgb-float.html": 0.9439, + "conformance2/textures/canvas/tex-2d-rgb9_e5-rgb-half_float.html": 0.9445, + "conformance2/textures/canvas/tex-2d-rgba16f-rgba-float.html": 1.0961, + "conformance2/textures/canvas/tex-2d-rgba16f-rgba-half_float.html": 0.8465, + "conformance2/textures/canvas/tex-2d-rgba32f-rgba-float.html": 0.4985, + "conformance2/textures/canvas/tex-2d-rgba4-rgba-unsigned_byte.html": 0.8002, + "conformance2/textures/canvas/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.6026, + "conformance2/textures/canvas/tex-2d-rgba8-rgba-unsigned_byte.html": 0.8133, + "conformance2/textures/canvas/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.7201, + "conformance2/textures/canvas/tex-2d-srgb8-rgb-unsigned_byte.html": 1.1167, + "conformance2/textures/canvas/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.7078, + "conformance2/textures/canvas/tex-3d-r11f_g11f_b10f-rgb-float.html": 5.5929, + "conformance2/textures/canvas/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 5.3458, + "conformance2/textures/canvas/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 5.3682, + "conformance2/textures/canvas/tex-3d-r16f-red-float.html": 5.3834, + "conformance2/textures/canvas/tex-3d-r16f-red-half_float.html": 5.4361, + "conformance2/textures/canvas/tex-3d-r32f-red-float.html": 5.3375, + "conformance2/textures/canvas/tex-3d-r8-red-unsigned_byte.html": 5.1844, + "conformance2/textures/canvas/tex-3d-r8ui-red_integer-unsigned_byte.html": 5.1551, + "conformance2/textures/canvas/tex-3d-rg16f-rg-float.html": 5.0291, + "conformance2/textures/canvas/tex-3d-rg16f-rg-half_float.html": 5.3499, + "conformance2/textures/canvas/tex-3d-rg32f-rg-float.html": 5.5757, + "conformance2/textures/canvas/tex-3d-rg8-rg-unsigned_byte.html": 5.37, + "conformance2/textures/canvas/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 5.3586, + "conformance2/textures/canvas/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 5.3616, + "conformance2/textures/canvas/tex-3d-rgb16f-rgb-float.html": 5.1452, + "conformance2/textures/canvas/tex-3d-rgb16f-rgb-half_float.html": 5.3391, + "conformance2/textures/canvas/tex-3d-rgb32f-rgb-float.html": 5.3308, + "conformance2/textures/canvas/tex-3d-rgb565-rgb-unsigned_byte.html": 5.2192, + "conformance2/textures/canvas/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 5.1865, + "conformance2/textures/canvas/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 5.3223, + "conformance2/textures/canvas/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 5.1686, + "conformance2/textures/canvas/tex-3d-rgb8-rgb-unsigned_byte.html": 5.3443, + "conformance2/textures/canvas/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 5.3137, + "conformance2/textures/canvas/tex-3d-rgb9_e5-rgb-float.html": 5.3815, + "conformance2/textures/canvas/tex-3d-rgb9_e5-rgb-half_float.html": 5.3778, + "conformance2/textures/canvas/tex-3d-rgba16f-rgba-float.html": 5.4288, + "conformance2/textures/canvas/tex-3d-rgba16f-rgba-half_float.html": 5.1736, + "conformance2/textures/canvas/tex-3d-rgba32f-rgba-float.html": 5.1599, + "conformance2/textures/canvas/tex-3d-rgba4-rgba-unsigned_byte.html": 5.3475, + "conformance2/textures/canvas/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 5.3383, + "conformance2/textures/canvas/tex-3d-rgba8-rgba-unsigned_byte.html": 5.327, + "conformance2/textures/canvas/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 5.1503, + "conformance2/textures/canvas/tex-3d-srgb8-rgb-unsigned_byte.html": 5.6444, + "conformance2/textures/canvas/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 5.1023, + "conformance2/textures/canvas_sub_rectangle/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.8801, + "conformance2/textures/canvas_sub_rectangle/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.6247, + "conformance2/textures/canvas_sub_rectangle/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.8539, + "conformance2/textures/canvas_sub_rectangle/tex-2d-r16f-red-float.html": 1.003, + "conformance2/textures/canvas_sub_rectangle/tex-2d-r16f-red-half_float.html": 0.589, + "conformance2/textures/canvas_sub_rectangle/tex-2d-r32f-red-float.html": 0.8289, + "conformance2/textures/canvas_sub_rectangle/tex-2d-r8-red-unsigned_byte.html": 0.8951, + "conformance2/textures/canvas_sub_rectangle/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.712, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rg16f-rg-float.html": 1.23, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rg16f-rg-half_float.html": 0.5981, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rg32f-rg-float.html": 1.2271, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rg8-rg-unsigned_byte.html": 0.5975, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.584, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 1.1309, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb16f-rgb-float.html": 0.827, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb16f-rgb-half_float.html": 0.9579, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb32f-rgb-float.html": 0.5451, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb565-rgb-unsigned_byte.html": 0.5819, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 1.2525, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.5874, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.5557, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb8-rgb-unsigned_byte.html": 1.186, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 1.0342, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb9_e5-rgb-float.html": 0.8407, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgb9_e5-rgb-half_float.html": 1.115, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgba16f-rgba-float.html": 0.6145, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgba16f-rgba-half_float.html": 1.2539, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgba32f-rgba-float.html": 0.6148, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgba4-rgba-unsigned_byte.html": 1.1588, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.4832, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgba8-rgba-unsigned_byte.html": 0.8627, + "conformance2/textures/canvas_sub_rectangle/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 1.1935, + "conformance2/textures/canvas_sub_rectangle/tex-2d-srgb8-rgb-unsigned_byte.html": 0.5586, + "conformance2/textures/canvas_sub_rectangle/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.5403, + "conformance2/textures/canvas_sub_rectangle/tex-3d-r11f_g11f_b10f-rgb-float.html": 1.4879, + "conformance2/textures/canvas_sub_rectangle/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.7909, + "conformance2/textures/canvas_sub_rectangle/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 1.1483, + "conformance2/textures/canvas_sub_rectangle/tex-3d-r16f-red-float.html": 1.0384, + "conformance2/textures/canvas_sub_rectangle/tex-3d-r16f-red-half_float.html": 0.5771, + "conformance2/textures/canvas_sub_rectangle/tex-3d-r32f-red-float.html": 1.0019, + "conformance2/textures/canvas_sub_rectangle/tex-3d-r8-red-unsigned_byte.html": 0.8389, + "conformance2/textures/canvas_sub_rectangle/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.5574, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rg16f-rg-float.html": 0.7465, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rg16f-rg-half_float.html": 1.0114, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rg32f-rg-float.html": 1.3182, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rg8-rg-unsigned_byte.html": 0.8687, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 1.0781, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.5344, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb16f-rgb-float.html": 1.2073, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb16f-rgb-half_float.html": 1.3747, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb32f-rgb-float.html": 0.7843, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb565-rgb-unsigned_byte.html": 0.7446, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 1.2645, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.5821, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.961, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb8-rgb-unsigned_byte.html": 0.5305, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.5607, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb9_e5-rgb-float.html": 0.7479, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgb9_e5-rgb-half_float.html": 0.6556, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgba16f-rgba-float.html": 0.862, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgba16f-rgba-half_float.html": 0.7384, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgba32f-rgba-float.html": 0.8366, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgba4-rgba-unsigned_byte.html": 1.3691, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 1.0516, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgba8-rgba-unsigned_byte.html": 0.9563, + "conformance2/textures/canvas_sub_rectangle/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 1.2959, + "conformance2/textures/canvas_sub_rectangle/tex-3d-srgb8-rgb-unsigned_byte.html": 0.521, + "conformance2/textures/canvas_sub_rectangle/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.5934, + "conformance2/textures/image/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.2533, + "conformance2/textures/image/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.3014, + "conformance2/textures/image/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.4699, + "conformance2/textures/image/tex-2d-r16f-red-float.html": 0.3253, + "conformance2/textures/image/tex-2d-r16f-red-half_float.html": 0.1757, + "conformance2/textures/image/tex-2d-r32f-red-float.html": 0.2798, + "conformance2/textures/image/tex-2d-r8-red-unsigned_byte.html": 0.299, + "conformance2/textures/image/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.2766, + "conformance2/textures/image/tex-2d-rg16f-rg-float.html": 0.2669, + "conformance2/textures/image/tex-2d-rg16f-rg-half_float.html": 0.3017, + "conformance2/textures/image/tex-2d-rg32f-rg-float.html": 0.151, + "conformance2/textures/image/tex-2d-rg8-rg-unsigned_byte.html": 0.5049, + "conformance2/textures/image/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.283, + "conformance2/textures/image/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.16, + "conformance2/textures/image/tex-2d-rgb16f-rgb-float.html": 0.3645, + "conformance2/textures/image/tex-2d-rgb16f-rgb-half_float.html": 0.3483, + "conformance2/textures/image/tex-2d-rgb32f-rgb-float.html": 0.1986, + "conformance2/textures/image/tex-2d-rgb565-rgb-unsigned_byte.html": 0.3185, + "conformance2/textures/image/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.1898, + "conformance2/textures/image/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.4124, + "conformance2/textures/image/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.3547, + "conformance2/textures/image/tex-2d-rgb8-rgb-unsigned_byte.html": 0.1544, + "conformance2/textures/image/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.3795, + "conformance2/textures/image/tex-2d-rgb9_e5-rgb-float.html": 0.3203, + "conformance2/textures/image/tex-2d-rgb9_e5-rgb-half_float.html": 0.1628, + "conformance2/textures/image/tex-2d-rgba16f-rgba-float.html": 0.2586, + "conformance2/textures/image/tex-2d-rgba16f-rgba-half_float.html": 0.1842, + "conformance2/textures/image/tex-2d-rgba32f-rgba-float.html": 0.2993, + "conformance2/textures/image/tex-2d-rgba4-rgba-unsigned_byte.html": 0.1724, + "conformance2/textures/image/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.3649, + "conformance2/textures/image/tex-2d-rgba8-rgba-unsigned_byte.html": 0.162, + "conformance2/textures/image/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.1733, + "conformance2/textures/image/tex-2d-srgb8-rgb-unsigned_byte.html": 0.1709, + "conformance2/textures/image/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.1725, + "conformance2/textures/image/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.1536, + "conformance2/textures/image/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.3564, + "conformance2/textures/image/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.1629, + "conformance2/textures/image/tex-3d-r16f-red-float.html": 0.2328, + "conformance2/textures/image/tex-3d-r16f-red-half_float.html": 0.3732, + "conformance2/textures/image/tex-3d-r32f-red-float.html": 0.1441, + "conformance2/textures/image/tex-3d-r8-red-unsigned_byte.html": 0.4813, + "conformance2/textures/image/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.2799, + "conformance2/textures/image/tex-3d-rg16f-rg-float.html": 0.1477, + "conformance2/textures/image/tex-3d-rg16f-rg-half_float.html": 0.3884, + "conformance2/textures/image/tex-3d-rg32f-rg-float.html": 0.3272, + "conformance2/textures/image/tex-3d-rg8-rg-unsigned_byte.html": 0.4504, + "conformance2/textures/image/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.146, + "conformance2/textures/image/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.2297, + "conformance2/textures/image/tex-3d-rgb16f-rgb-float.html": 0.3838, + "conformance2/textures/image/tex-3d-rgb16f-rgb-half_float.html": 0.2535, + "conformance2/textures/image/tex-3d-rgb32f-rgb-float.html": 0.3529, + "conformance2/textures/image/tex-3d-rgb565-rgb-unsigned_byte.html": 0.3833, + "conformance2/textures/image/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.144, + "conformance2/textures/image/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.4391, + "conformance2/textures/image/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.3453, + "conformance2/textures/image/tex-3d-rgb8-rgb-unsigned_byte.html": 0.1491, + "conformance2/textures/image/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.2412, + "conformance2/textures/image/tex-3d-rgb9_e5-rgb-float.html": 0.3971, + "conformance2/textures/image/tex-3d-rgb9_e5-rgb-half_float.html": 0.1507, + "conformance2/textures/image/tex-3d-rgba16f-rgba-float.html": 0.428, + "conformance2/textures/image/tex-3d-rgba16f-rgba-half_float.html": 0.2492, + "conformance2/textures/image/tex-3d-rgba32f-rgba-float.html": 0.3797, + "conformance2/textures/image/tex-3d-rgba4-rgba-unsigned_byte.html": 0.3971, + "conformance2/textures/image/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.2225, + "conformance2/textures/image/tex-3d-rgba8-rgba-unsigned_byte.html": 0.2494, + "conformance2/textures/image/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.2355, + "conformance2/textures/image/tex-3d-srgb8-rgb-unsigned_byte.html": 0.3967, + "conformance2/textures/image/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.2655, + "conformance2/textures/image_bitmap_from_blob/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.1496, + "conformance2/textures/image_bitmap_from_blob/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.1508, + "conformance2/textures/image_bitmap_from_blob/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.1916, + "conformance2/textures/image_bitmap_from_blob/tex-2d-r16f-red-float.html": 0.4133, + "conformance2/textures/image_bitmap_from_blob/tex-2d-r16f-red-half_float.html": 0.1639, + "conformance2/textures/image_bitmap_from_blob/tex-2d-r32f-red-float.html": 0.4128, + "conformance2/textures/image_bitmap_from_blob/tex-2d-r8-red-unsigned_byte.html": 0.3275, + "conformance2/textures/image_bitmap_from_blob/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.1508, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rg16f-rg-float.html": 0.3501, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rg16f-rg-half_float.html": 0.1519, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rg32f-rg-float.html": 0.3286, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rg8-rg-unsigned_byte.html": 0.2847, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.1711, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.4247, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb16f-rgb-float.html": 0.3822, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb16f-rgb-half_float.html": 0.1503, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb32f-rgb-float.html": 0.1533, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb565-rgb-unsigned_byte.html": 0.1563, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.4123, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.1539, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.1563, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb8-rgb-unsigned_byte.html": 0.3296, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.4245, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb9_e5-rgb-float.html": 0.2529, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgb9_e5-rgb-half_float.html": 0.1878, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgba16f-rgba-float.html": 0.2513, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgba16f-rgba-half_float.html": 0.1772, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgba32f-rgba-float.html": 0.1524, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgba4-rgba-unsigned_byte.html": 0.1834, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.152, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgba8-rgba-unsigned_byte.html": 0.3798, + "conformance2/textures/image_bitmap_from_blob/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.3847, + "conformance2/textures/image_bitmap_from_blob/tex-2d-srgb8-rgb-unsigned_byte.html": 0.1587, + "conformance2/textures/image_bitmap_from_blob/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.1483, + "conformance2/textures/image_bitmap_from_blob/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.1837, + "conformance2/textures/image_bitmap_from_blob/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.1482, + "conformance2/textures/image_bitmap_from_blob/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.1817, + "conformance2/textures/image_bitmap_from_blob/tex-3d-r16f-red-float.html": 0.1513, + "conformance2/textures/image_bitmap_from_blob/tex-3d-r16f-red-half_float.html": 0.1658, + "conformance2/textures/image_bitmap_from_blob/tex-3d-r32f-red-float.html": 0.1845, + "conformance2/textures/image_bitmap_from_blob/tex-3d-r8-red-unsigned_byte.html": 0.1703, + "conformance2/textures/image_bitmap_from_blob/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.1539, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rg16f-rg-float.html": 0.1506, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rg16f-rg-half_float.html": 0.1905, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rg32f-rg-float.html": 0.2039, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rg8-rg-unsigned_byte.html": 0.1541, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.3057, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.1522, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb16f-rgb-float.html": 0.1828, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb16f-rgb-half_float.html": 0.1637, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb32f-rgb-float.html": 0.1508, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb565-rgb-unsigned_byte.html": 0.1591, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.305, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.1579, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.1736, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb8-rgb-unsigned_byte.html": 0.1483, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.1976, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb9_e5-rgb-float.html": 0.148, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgb9_e5-rgb-half_float.html": 0.1515, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgba16f-rgba-float.html": 0.1498, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgba16f-rgba-half_float.html": 0.1472, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgba32f-rgba-float.html": 0.1537, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgba4-rgba-unsigned_byte.html": 0.3013, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.2032, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgba8-rgba-unsigned_byte.html": 0.1886, + "conformance2/textures/image_bitmap_from_blob/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.213, + "conformance2/textures/image_bitmap_from_blob/tex-3d-srgb8-rgb-unsigned_byte.html": 0.1512, + "conformance2/textures/image_bitmap_from_blob/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.1514, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.6136, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.7734, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.4769, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-r16f-red-float.html": 0.4792, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-r16f-red-half_float.html": 0.7415, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-r32f-red-float.html": 0.3515, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-r8-red-unsigned_byte.html": 0.3524, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.2553, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rg16f-rg-float.html": 0.3862, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rg16f-rg-half_float.html": 0.2375, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rg32f-rg-float.html": 0.6326, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rg8-rg-unsigned_byte.html": 0.5636, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.3306, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.2891, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb16f-rgb-float.html": 0.2824, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb16f-rgb-half_float.html": 0.294, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb32f-rgb-float.html": 0.8715, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb565-rgb-unsigned_byte.html": 0.396, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.3463, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.4671, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.3526, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb8-rgb-unsigned_byte.html": 0.6783, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.4981, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb9_e5-rgb-float.html": 0.5493, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgb9_e5-rgb-half_float.html": 0.3705, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgba16f-rgba-float.html": 0.653, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgba16f-rgba-half_float.html": 0.6911, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgba32f-rgba-float.html": 0.305, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgba4-rgba-unsigned_byte.html": 0.683, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.3826, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgba8-rgba-unsigned_byte.html": 0.2747, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.2552, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-srgb8-rgb-unsigned_byte.html": 0.7035, + "conformance2/textures/image_bitmap_from_canvas/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.2539, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.4984, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.3408, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.3826, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-r16f-red-float.html": 0.2685, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-r16f-red-half_float.html": 0.4846, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-r32f-red-float.html": 0.2389, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-r8-red-unsigned_byte.html": 0.2007, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.2633, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rg16f-rg-float.html": 0.3941, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rg16f-rg-half_float.html": 0.2664, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rg32f-rg-float.html": 0.3968, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rg8-rg-unsigned_byte.html": 0.2292, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.1903, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.3844, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb16f-rgb-float.html": 0.3162, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb16f-rgb-half_float.html": 0.2632, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb32f-rgb-float.html": 0.4216, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb565-rgb-unsigned_byte.html": 0.2992, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.1623, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.1607, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.1587, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb8-rgb-unsigned_byte.html": 0.1607, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.2825, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb9_e5-rgb-float.html": 0.2904, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgb9_e5-rgb-half_float.html": 0.4888, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgba16f-rgba-float.html": 0.3422, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgba16f-rgba-half_float.html": 0.1862, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgba32f-rgba-float.html": 0.3583, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgba4-rgba-unsigned_byte.html": 0.2379, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.171, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgba8-rgba-unsigned_byte.html": 0.161, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.1569, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-srgb8-rgb-unsigned_byte.html": 0.2279, + "conformance2/textures/image_bitmap_from_canvas/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.2634, + "conformance2/textures/image_bitmap_from_image/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.2475, + "conformance2/textures/image_bitmap_from_image/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.1463, + "conformance2/textures/image_bitmap_from_image/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.3361, + "conformance2/textures/image_bitmap_from_image/tex-2d-r16f-red-float.html": 0.291, + "conformance2/textures/image_bitmap_from_image/tex-2d-r16f-red-half_float.html": 0.3382, + "conformance2/textures/image_bitmap_from_image/tex-2d-r32f-red-float.html": 0.2749, + "conformance2/textures/image_bitmap_from_image/tex-2d-r8-red-unsigned_byte.html": 0.143, + "conformance2/textures/image_bitmap_from_image/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.4559, + "conformance2/textures/image_bitmap_from_image/tex-2d-rg16f-rg-float.html": 0.4261, + "conformance2/textures/image_bitmap_from_image/tex-2d-rg16f-rg-half_float.html": 0.4519, + "conformance2/textures/image_bitmap_from_image/tex-2d-rg32f-rg-float.html": 0.2419, + "conformance2/textures/image_bitmap_from_image/tex-2d-rg8-rg-unsigned_byte.html": 0.2899, + "conformance2/textures/image_bitmap_from_image/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.1469, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.411, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb16f-rgb-float.html": 0.2476, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb16f-rgb-half_float.html": 0.1487, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb32f-rgb-float.html": 0.3293, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb565-rgb-unsigned_byte.html": 0.342, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.1462, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.2827, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.4776, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb8-rgb-unsigned_byte.html": 0.3071, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.2994, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb9_e5-rgb-float.html": 0.363, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgb9_e5-rgb-half_float.html": 0.4429, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgba16f-rgba-float.html": 0.3899, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgba16f-rgba-half_float.html": 0.2925, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgba32f-rgba-float.html": 0.3371, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgba4-rgba-unsigned_byte.html": 0.2417, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.2316, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgba8-rgba-unsigned_byte.html": 0.2712, + "conformance2/textures/image_bitmap_from_image/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.2544, + "conformance2/textures/image_bitmap_from_image/tex-2d-srgb8-rgb-unsigned_byte.html": 0.3035, + "conformance2/textures/image_bitmap_from_image/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.4801, + "conformance2/textures/image_bitmap_from_image/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.23, + "conformance2/textures/image_bitmap_from_image/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.1884, + "conformance2/textures/image_bitmap_from_image/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.2072, + "conformance2/textures/image_bitmap_from_image/tex-3d-r16f-red-float.html": 0.148, + "conformance2/textures/image_bitmap_from_image/tex-3d-r16f-red-half_float.html": 0.1441, + "conformance2/textures/image_bitmap_from_image/tex-3d-r32f-red-float.html": 0.2937, + "conformance2/textures/image_bitmap_from_image/tex-3d-r8-red-unsigned_byte.html": 0.2434, + "conformance2/textures/image_bitmap_from_image/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.2986, + "conformance2/textures/image_bitmap_from_image/tex-3d-rg16f-rg-float.html": 0.2805, + "conformance2/textures/image_bitmap_from_image/tex-3d-rg16f-rg-half_float.html": 0.1438, + "conformance2/textures/image_bitmap_from_image/tex-3d-rg32f-rg-float.html": 0.1495, + "conformance2/textures/image_bitmap_from_image/tex-3d-rg8-rg-unsigned_byte.html": 0.1457, + "conformance2/textures/image_bitmap_from_image/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.147, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.2864, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb16f-rgb-float.html": 0.2477, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb16f-rgb-half_float.html": 0.1974, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb32f-rgb-float.html": 0.1936, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb565-rgb-unsigned_byte.html": 0.3173, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.3089, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.1956, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.1917, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb8-rgb-unsigned_byte.html": 0.1878, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.2211, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb9_e5-rgb-float.html": 0.2761, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgb9_e5-rgb-half_float.html": 0.2588, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgba16f-rgba-float.html": 0.1494, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgba16f-rgba-half_float.html": 0.3241, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgba32f-rgba-float.html": 0.3109, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgba4-rgba-unsigned_byte.html": 0.2249, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.1498, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgba8-rgba-unsigned_byte.html": 0.3048, + "conformance2/textures/image_bitmap_from_image/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.3076, + "conformance2/textures/image_bitmap_from_image/tex-3d-srgb8-rgb-unsigned_byte.html": 0.2198, + "conformance2/textures/image_bitmap_from_image/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.2571, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.1488, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.3365, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.4827, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-r16f-red-float.html": 0.2545, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-r16f-red-half_float.html": 0.2497, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-r32f-red-float.html": 0.2355, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-r8-red-unsigned_byte.html": 0.1927, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.1709, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rg16f-rg-float.html": 0.2464, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rg16f-rg-half_float.html": 0.216, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rg32f-rg-float.html": 0.2302, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rg8-rg-unsigned_byte.html": 0.304, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.3915, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.1357, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb16f-rgb-float.html": 0.2357, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb16f-rgb-half_float.html": 0.2282, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb32f-rgb-float.html": 0.1394, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb565-rgb-unsigned_byte.html": 0.427, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.1785, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.346, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.2647, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb8-rgb-unsigned_byte.html": 0.2628, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.2555, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb9_e5-rgb-float.html": 0.2793, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgb9_e5-rgb-half_float.html": 0.1396, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgba16f-rgba-float.html": 0.236, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgba16f-rgba-half_float.html": 0.18, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgba32f-rgba-float.html": 0.391, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgba4-rgba-unsigned_byte.html": 0.1536, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.3443, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgba8-rgba-unsigned_byte.html": 0.1523, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.2009, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-srgb8-rgb-unsigned_byte.html": 0.1529, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.1486, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.1202, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.2278, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.1884, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-r16f-red-float.html": 0.1945, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-r16f-red-half_float.html": 0.1827, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-r32f-red-float.html": 0.1944, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-r8-red-unsigned_byte.html": 0.2315, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.1184, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rg16f-rg-float.html": 0.189, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rg16f-rg-half_float.html": 0.1903, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rg32f-rg-float.html": 0.2562, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rg8-rg-unsigned_byte.html": 0.1365, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.1074, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.0833, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb16f-rgb-float.html": 0.2196, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb16f-rgb-half_float.html": 0.1217, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb32f-rgb-float.html": 0.2054, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb565-rgb-unsigned_byte.html": 0.2649, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.0993, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.1331, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.1672, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb8-rgb-unsigned_byte.html": 0.0859, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.0982, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb9_e5-rgb-float.html": 0.2056, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgb9_e5-rgb-half_float.html": 0.0846, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgba16f-rgba-float.html": 0.1718, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgba16f-rgba-half_float.html": 0.1287, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgba32f-rgba-float.html": 0.2856, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgba4-rgba-unsigned_byte.html": 0.1824, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.1058, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgba8-rgba-unsigned_byte.html": 0.1101, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.1082, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-srgb8-rgb-unsigned_byte.html": 0.2154, + "conformance2/textures/image_bitmap_from_image_bitmap/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.1448, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.1547, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.3148, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.3937, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-r16f-red-float.html": 0.2129, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-r16f-red-half_float.html": 0.2293, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-r32f-red-float.html": 0.1333, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-r8-red-unsigned_byte.html": 0.3066, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.1545, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rg16f-rg-float.html": 0.2206, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rg16f-rg-half_float.html": 0.2473, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rg32f-rg-float.html": 0.2268, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rg8-rg-unsigned_byte.html": 0.345, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.2419, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.1384, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb16f-rgb-float.html": 0.2559, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb16f-rgb-half_float.html": 0.3587, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb32f-rgb-float.html": 0.1395, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb565-rgb-unsigned_byte.html": 0.4602, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.1835, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.3336, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.2325, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb8-rgb-unsigned_byte.html": 0.2064, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.2406, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb9_e5-rgb-float.html": 0.3051, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgb9_e5-rgb-half_float.html": 0.2361, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgba16f-rgba-float.html": 0.2328, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgba16f-rgba-half_float.html": 0.1823, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgba32f-rgba-float.html": 0.4034, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgba4-rgba-unsigned_byte.html": 0.1402, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.2381, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgba8-rgba-unsigned_byte.html": 0.1637, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.189, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-srgb8-rgb-unsigned_byte.html": 0.1561, + "conformance2/textures/image_bitmap_from_image_data/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.1542, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.1251, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.1493, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.1444, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-r16f-red-float.html": 0.0986, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-r16f-red-half_float.html": 0.2027, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-r32f-red-float.html": 0.1892, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-r8-red-unsigned_byte.html": 0.2938, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.1381, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rg16f-rg-float.html": 0.1782, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rg16f-rg-half_float.html": 0.2469, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rg32f-rg-float.html": 0.1876, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rg8-rg-unsigned_byte.html": 0.2717, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.1073, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.0974, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb16f-rgb-float.html": 0.2268, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb16f-rgb-half_float.html": 0.2202, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb32f-rgb-float.html": 0.1655, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb565-rgb-unsigned_byte.html": 0.1525, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.1097, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.1553, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.1698, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb8-rgb-unsigned_byte.html": 0.1013, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.1009, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb9_e5-rgb-float.html": 0.2795, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgb9_e5-rgb-half_float.html": 0.1953, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgba16f-rgba-float.html": 0.3042, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgba16f-rgba-half_float.html": 0.1085, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgba32f-rgba-float.html": 0.1635, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgba4-rgba-unsigned_byte.html": 0.2694, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.1019, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgba8-rgba-unsigned_byte.html": 0.1053, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.1426, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-srgb8-rgb-unsigned_byte.html": 0.2152, + "conformance2/textures/image_bitmap_from_image_data/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.1164, + "conformance2/textures/image_bitmap_from_video/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.6092, + "conformance2/textures/image_bitmap_from_video/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.3798, + "conformance2/textures/image_bitmap_from_video/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.4565, + "conformance2/textures/image_bitmap_from_video/tex-2d-r16f-red-float.html": 0.4732, + "conformance2/textures/image_bitmap_from_video/tex-2d-r16f-red-half_float.html": 0.367, + "conformance2/textures/image_bitmap_from_video/tex-2d-r32f-red-float.html": 0.4933, + "conformance2/textures/image_bitmap_from_video/tex-2d-r8-red-unsigned_byte.html": 0.4002, + "conformance2/textures/image_bitmap_from_video/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.5148, + "conformance2/textures/image_bitmap_from_video/tex-2d-rg16f-rg-float.html": 0.3815, + "conformance2/textures/image_bitmap_from_video/tex-2d-rg16f-rg-half_float.html": 0.5557, + "conformance2/textures/image_bitmap_from_video/tex-2d-rg32f-rg-float.html": 0.3767, + "conformance2/textures/image_bitmap_from_video/tex-2d-rg8-rg-unsigned_byte.html": 0.3653, + "conformance2/textures/image_bitmap_from_video/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.6863, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.3861, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb16f-rgb-float.html": 0.3868, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb16f-rgb-half_float.html": 0.6992, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb32f-rgb-float.html": 0.3647, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb565-rgb-unsigned_byte.html": 0.3642, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.5366, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.3882, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.5031, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb8-rgb-unsigned_byte.html": 0.7646, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.4345, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb9_e5-rgb-float.html": 0.7292, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgb9_e5-rgb-half_float.html": 0.5307, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgba16f-rgba-float.html": 0.3739, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgba16f-rgba-half_float.html": 0.5264, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgba32f-rgba-float.html": 0.3619, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgba4-rgba-unsigned_byte.html": 0.3727, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.5956, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgba8-rgba-unsigned_byte.html": 0.5441, + "conformance2/textures/image_bitmap_from_video/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.5142, + "conformance2/textures/image_bitmap_from_video/tex-2d-srgb8-rgb-unsigned_byte.html": 0.379, + "conformance2/textures/image_bitmap_from_video/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.4973, + "conformance2/textures/image_bitmap_from_video/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.5094, + "conformance2/textures/image_bitmap_from_video/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.6072, + "conformance2/textures/image_bitmap_from_video/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.3748, + "conformance2/textures/image_bitmap_from_video/tex-3d-r16f-red-float.html": 0.5987, + "conformance2/textures/image_bitmap_from_video/tex-3d-r16f-red-half_float.html": 0.3787, + "conformance2/textures/image_bitmap_from_video/tex-3d-r32f-red-float.html": 0.488, + "conformance2/textures/image_bitmap_from_video/tex-3d-r8-red-unsigned_byte.html": 0.3825, + "conformance2/textures/image_bitmap_from_video/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.5908, + "conformance2/textures/image_bitmap_from_video/tex-3d-rg16f-rg-float.html": 0.3979, + "conformance2/textures/image_bitmap_from_video/tex-3d-rg16f-rg-half_float.html": 0.3722, + "conformance2/textures/image_bitmap_from_video/tex-3d-rg32f-rg-float.html": 0.5391, + "conformance2/textures/image_bitmap_from_video/tex-3d-rg8-rg-unsigned_byte.html": 0.7229, + "conformance2/textures/image_bitmap_from_video/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.5232, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.3741, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb16f-rgb-float.html": 0.4883, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb16f-rgb-half_float.html": 0.511, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb32f-rgb-float.html": 0.3683, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb565-rgb-unsigned_byte.html": 0.494, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.3726, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.6182, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.3601, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb8-rgb-unsigned_byte.html": 0.5295, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.6145, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb9_e5-rgb-float.html": 0.3992, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgb9_e5-rgb-half_float.html": 0.4203, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgba16f-rgba-float.html": 0.3965, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgba16f-rgba-half_float.html": 0.5375, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgba32f-rgba-float.html": 0.5724, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgba4-rgba-unsigned_byte.html": 0.4411, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.5306, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgba8-rgba-unsigned_byte.html": 0.53, + "conformance2/textures/image_bitmap_from_video/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.4641, + "conformance2/textures/image_bitmap_from_video/tex-3d-srgb8-rgb-unsigned_byte.html": 0.3768, + "conformance2/textures/image_bitmap_from_video/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.5864, + "conformance2/textures/image_data/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.3513, + "conformance2/textures/image_data/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.2616, + "conformance2/textures/image_data/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.4148, + "conformance2/textures/image_data/tex-2d-r16f-red-float.html": 0.484, + "conformance2/textures/image_data/tex-2d-r16f-red-half_float.html": 0.4455, + "conformance2/textures/image_data/tex-2d-r32f-red-float.html": 0.3325, + "conformance2/textures/image_data/tex-2d-r8-red-unsigned_byte.html": 0.3593, + "conformance2/textures/image_data/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.708, + "conformance2/textures/image_data/tex-2d-rg16f-rg-float.html": 0.7316, + "conformance2/textures/image_data/tex-2d-rg16f-rg-half_float.html": 0.7608, + "conformance2/textures/image_data/tex-2d-rg32f-rg-float.html": 0.3489, + "conformance2/textures/image_data/tex-2d-rg8-rg-unsigned_byte.html": 0.4799, + "conformance2/textures/image_data/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.3367, + "conformance2/textures/image_data/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.5883, + "conformance2/textures/image_data/tex-2d-rgb16f-rgb-float.html": 0.2594, + "conformance2/textures/image_data/tex-2d-rgb16f-rgb-half_float.html": 0.255, + "conformance2/textures/image_data/tex-2d-rgb32f-rgb-float.html": 0.4744, + "conformance2/textures/image_data/tex-2d-rgb565-rgb-unsigned_byte.html": 0.4909, + "conformance2/textures/image_data/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.3604, + "conformance2/textures/image_data/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.4955, + "conformance2/textures/image_data/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.6965, + "conformance2/textures/image_data/tex-2d-rgb8-rgb-unsigned_byte.html": 0.4592, + "conformance2/textures/image_data/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.3815, + "conformance2/textures/image_data/tex-2d-rgb9_e5-rgb-float.html": 0.5436, + "conformance2/textures/image_data/tex-2d-rgb9_e5-rgb-half_float.html": 0.782, + "conformance2/textures/image_data/tex-2d-rgba16f-rgba-float.html": 0.5349, + "conformance2/textures/image_data/tex-2d-rgba16f-rgba-half_float.html": 0.4296, + "conformance2/textures/image_data/tex-2d-rgba32f-rgba-float.html": 0.4658, + "conformance2/textures/image_data/tex-2d-rgba4-rgba-unsigned_byte.html": 0.2732, + "conformance2/textures/image_data/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.2921, + "conformance2/textures/image_data/tex-2d-rgba8-rgba-unsigned_byte.html": 0.2657, + "conformance2/textures/image_data/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.3474, + "conformance2/textures/image_data/tex-2d-srgb8-rgb-unsigned_byte.html": 0.4428, + "conformance2/textures/image_data/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.6923, + "conformance2/textures/image_data/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.4325, + "conformance2/textures/image_data/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.3422, + "conformance2/textures/image_data/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.2228, + "conformance2/textures/image_data/tex-3d-r16f-red-float.html": 0.2398, + "conformance2/textures/image_data/tex-3d-r16f-red-half_float.html": 0.3365, + "conformance2/textures/image_data/tex-3d-r32f-red-float.html": 0.6648, + "conformance2/textures/image_data/tex-3d-r8-red-unsigned_byte.html": 0.5546, + "conformance2/textures/image_data/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.4591, + "conformance2/textures/image_data/tex-3d-rg16f-rg-float.html": 0.4365, + "conformance2/textures/image_data/tex-3d-rg16f-rg-half_float.html": 0.3348, + "conformance2/textures/image_data/tex-3d-rg32f-rg-float.html": 0.4567, + "conformance2/textures/image_data/tex-3d-rg8-rg-unsigned_byte.html": 0.305, + "conformance2/textures/image_data/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.3363, + "conformance2/textures/image_data/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.3816, + "conformance2/textures/image_data/tex-3d-rgb16f-rgb-float.html": 0.4325, + "conformance2/textures/image_data/tex-3d-rgb16f-rgb-half_float.html": 0.3196, + "conformance2/textures/image_data/tex-3d-rgb32f-rgb-float.html": 0.227, + "conformance2/textures/image_data/tex-3d-rgb565-rgb-unsigned_byte.html": 0.5654, + "conformance2/textures/image_data/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.6345, + "conformance2/textures/image_data/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.2288, + "conformance2/textures/image_data/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.2444, + "conformance2/textures/image_data/tex-3d-rgb8-rgb-unsigned_byte.html": 0.6607, + "conformance2/textures/image_data/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.2258, + "conformance2/textures/image_data/tex-3d-rgb9_e5-rgb-float.html": 0.4773, + "conformance2/textures/image_data/tex-3d-rgb9_e5-rgb-half_float.html": 0.5073, + "conformance2/textures/image_data/tex-3d-rgba16f-rgba-float.html": 0.4402, + "conformance2/textures/image_data/tex-3d-rgba16f-rgba-half_float.html": 0.5775, + "conformance2/textures/image_data/tex-3d-rgba32f-rgba-float.html": 0.6136, + "conformance2/textures/image_data/tex-3d-rgba4-rgba-unsigned_byte.html": 0.4166, + "conformance2/textures/image_data/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.2221, + "conformance2/textures/image_data/tex-3d-rgba8-rgba-unsigned_byte.html": 0.6279, + "conformance2/textures/image_data/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.6068, + "conformance2/textures/image_data/tex-3d-srgb8-rgb-unsigned_byte.html": 0.3616, + "conformance2/textures/image_data/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.4796, + "conformance2/textures/misc/active-3d-texture-bug.html": 0.1358, + "conformance2/textures/misc/angle-stuck-depth-textures.html": 0.1432, + "conformance2/textures/misc/canvas-remains-unchanged-after-used-in-webgl-texture.html": 0.0757, + "conformance2/textures/misc/compressed-tex-from-pbo-crash.html": 0.0687, + "conformance2/textures/misc/copy-texture-cube-map-AMD-bug.html": 0.0696, + "conformance2/textures/misc/copy-texture-cube-map-bug.html": 0.0534, + "conformance2/textures/misc/copy-texture-image-luma-format.html": 2.5191, + "conformance2/textures/misc/copy-texture-image-same-texture.html": 0.1997, + "conformance2/textures/misc/copy-texture-image-webgl-specific.html": 0.1204, + "conformance2/textures/misc/copy-texture-image.html": 0.3596, + "conformance2/textures/misc/generate-mipmap-with-large-base-level.html": 0.0682, + "conformance2/textures/misc/gl-get-tex-parameter.html": 0.1364, + "conformance2/textures/misc/integer-cubemap-specification-order-bug.html": 6.1355, + "conformance2/textures/misc/integer-cubemap-texture-sampling.html": 1.0823, + "conformance2/textures/misc/mipmap-fbo.html": 0.0788, + "conformance2/textures/misc/npot-video-sizing.html": 0.1654, + "conformance2/textures/misc/origin-clean-conformance-offscreencanvas.html": 0.1306, + "conformance2/textures/misc/tex-3d-mipmap-levels-intel-bug.html": 0.082, + "conformance2/textures/misc/tex-3d-size-limit.html": 0.1204, + "conformance2/textures/misc/tex-base-level-bug.html": 0.0906, + "conformance2/textures/misc/tex-image-and-sub-image-with-array-buffer-view-sub-source.html": 0.2289, + "conformance2/textures/misc/tex-image-with-bad-args-from-dom-elements.html": 0.3547, + "conformance2/textures/misc/tex-image-with-bad-args.html": 0.0654, + "conformance2/textures/misc/tex-image-with-different-data-source.html": 0.0972, + "conformance2/textures/misc/tex-input-validation.html": 0.2085, + "conformance2/textures/misc/tex-mipmap-levels.html": 0.0893, + "conformance2/textures/misc/tex-new-formats.html": 0.5746, + "conformance2/textures/misc/tex-srgb-mipmap.html": 0.2593, + "conformance2/textures/misc/tex-storage-2d.html": 0.2836, + "conformance2/textures/misc/tex-storage-and-subimage-3d.html": 0.1377, + "conformance2/textures/misc/tex-storage-compressed-formats.html": 0.0651, + "conformance2/textures/misc/tex-subimage3d-canvas-bug.html": 0.152, + "conformance2/textures/misc/tex-subimage3d-pixel-buffer-bug.html": 0.091, + "conformance2/textures/misc/tex-unpack-params-imagedata.html": 0.093, + "conformance2/textures/misc/tex-unpack-params-with-flip-y-and-premultiply-alpha.html": 0.372, + "conformance2/textures/misc/tex-unpack-params.html": 1.338, + "conformance2/textures/misc/texel-fetch-undefined.html": 0.1962, + "conformance2/textures/misc/texture-npot.html": 0.1071, + "conformance2/textures/svg_image/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.1684, + "conformance2/textures/svg_image/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.1541, + "conformance2/textures/svg_image/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.2077, + "conformance2/textures/svg_image/tex-2d-r16f-red-float.html": 0.1847, + "conformance2/textures/svg_image/tex-2d-r16f-red-half_float.html": 0.1912, + "conformance2/textures/svg_image/tex-2d-r32f-red-float.html": 0.283, + "conformance2/textures/svg_image/tex-2d-r8-red-unsigned_byte.html": 0.1495, + "conformance2/textures/svg_image/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.1641, + "conformance2/textures/svg_image/tex-2d-rg16f-rg-float.html": 0.1509, + "conformance2/textures/svg_image/tex-2d-rg16f-rg-half_float.html": 0.1737, + "conformance2/textures/svg_image/tex-2d-rg32f-rg-float.html": 0.1969, + "conformance2/textures/svg_image/tex-2d-rg8-rg-unsigned_byte.html": 0.1441, + "conformance2/textures/svg_image/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.281, + "conformance2/textures/svg_image/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.1853, + "conformance2/textures/svg_image/tex-2d-rgb16f-rgb-float.html": 0.1896, + "conformance2/textures/svg_image/tex-2d-rgb16f-rgb-half_float.html": 0.2744, + "conformance2/textures/svg_image/tex-2d-rgb32f-rgb-float.html": 0.1835, + "conformance2/textures/svg_image/tex-2d-rgb565-rgb-unsigned_byte.html": 0.1489, + "conformance2/textures/svg_image/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.1699, + "conformance2/textures/svg_image/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.1806, + "conformance2/textures/svg_image/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.2221, + "conformance2/textures/svg_image/tex-2d-rgb8-rgb-unsigned_byte.html": 0.1686, + "conformance2/textures/svg_image/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.2053, + "conformance2/textures/svg_image/tex-2d-rgb9_e5-rgb-float.html": 0.1876, + "conformance2/textures/svg_image/tex-2d-rgb9_e5-rgb-half_float.html": 0.1512, + "conformance2/textures/svg_image/tex-2d-rgba16f-rgba-float.html": 0.1484, + "conformance2/textures/svg_image/tex-2d-rgba16f-rgba-half_float.html": 0.2371, + "conformance2/textures/svg_image/tex-2d-rgba32f-rgba-float.html": 0.1781, + "conformance2/textures/svg_image/tex-2d-rgba4-rgba-unsigned_byte.html": 0.1792, + "conformance2/textures/svg_image/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.2701, + "conformance2/textures/svg_image/tex-2d-rgba8-rgba-unsigned_byte.html": 0.2404, + "conformance2/textures/svg_image/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.2592, + "conformance2/textures/svg_image/tex-2d-srgb8-rgb-unsigned_byte.html": 0.1863, + "conformance2/textures/svg_image/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.2396, + "conformance2/textures/svg_image/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.2105, + "conformance2/textures/svg_image/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.1714, + "conformance2/textures/svg_image/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.1721, + "conformance2/textures/svg_image/tex-3d-r16f-red-float.html": 0.1847, + "conformance2/textures/svg_image/tex-3d-r16f-red-half_float.html": 0.1721, + "conformance2/textures/svg_image/tex-3d-r32f-red-float.html": 0.1566, + "conformance2/textures/svg_image/tex-3d-r8-red-unsigned_byte.html": 0.178, + "conformance2/textures/svg_image/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.2142, + "conformance2/textures/svg_image/tex-3d-rg16f-rg-float.html": 0.1696, + "conformance2/textures/svg_image/tex-3d-rg16f-rg-half_float.html": 0.1694, + "conformance2/textures/svg_image/tex-3d-rg32f-rg-float.html": 0.1891, + "conformance2/textures/svg_image/tex-3d-rg8-rg-unsigned_byte.html": 0.1813, + "conformance2/textures/svg_image/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.2133, + "conformance2/textures/svg_image/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.1612, + "conformance2/textures/svg_image/tex-3d-rgb16f-rgb-float.html": 0.2018, + "conformance2/textures/svg_image/tex-3d-rgb16f-rgb-half_float.html": 0.156, + "conformance2/textures/svg_image/tex-3d-rgb32f-rgb-float.html": 0.1611, + "conformance2/textures/svg_image/tex-3d-rgb565-rgb-unsigned_byte.html": 0.1953, + "conformance2/textures/svg_image/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.1709, + "conformance2/textures/svg_image/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.2488, + "conformance2/textures/svg_image/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.1461, + "conformance2/textures/svg_image/tex-3d-rgb8-rgb-unsigned_byte.html": 0.2067, + "conformance2/textures/svg_image/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.2279, + "conformance2/textures/svg_image/tex-3d-rgb9_e5-rgb-float.html": 0.1727, + "conformance2/textures/svg_image/tex-3d-rgb9_e5-rgb-half_float.html": 0.1326, + "conformance2/textures/svg_image/tex-3d-rgba16f-rgba-float.html": 0.1706, + "conformance2/textures/svg_image/tex-3d-rgba16f-rgba-half_float.html": 0.1892, + "conformance2/textures/svg_image/tex-3d-rgba32f-rgba-float.html": 0.179, + "conformance2/textures/svg_image/tex-3d-rgba4-rgba-unsigned_byte.html": 0.2017, + "conformance2/textures/svg_image/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.1901, + "conformance2/textures/svg_image/tex-3d-rgba8-rgba-unsigned_byte.html": 0.1248, + "conformance2/textures/svg_image/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.1607, + "conformance2/textures/svg_image/tex-3d-srgb8-rgb-unsigned_byte.html": 0.1601, + "conformance2/textures/svg_image/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.2234, + "conformance2/textures/video/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.7403, + "conformance2/textures/video/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.6721, + "conformance2/textures/video/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.6137, + "conformance2/textures/video/tex-2d-r16f-red-float.html": 0.7043, + "conformance2/textures/video/tex-2d-r16f-red-half_float.html": 0.7151, + "conformance2/textures/video/tex-2d-r32f-red-float.html": 0.5895, + "conformance2/textures/video/tex-2d-r8-red-unsigned_byte.html": 0.5611, + "conformance2/textures/video/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.5596, + "conformance2/textures/video/tex-2d-rg16f-rg-float.html": 0.573, + "conformance2/textures/video/tex-2d-rg16f-rg-half_float.html": 0.5972, + "conformance2/textures/video/tex-2d-rg32f-rg-float.html": 0.6666, + "conformance2/textures/video/tex-2d-rg8-rg-unsigned_byte.html": 0.7758, + "conformance2/textures/video/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.6055, + "conformance2/textures/video/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.6072, + "conformance2/textures/video/tex-2d-rgb16f-rgb-float.html": 0.5867, + "conformance2/textures/video/tex-2d-rgb16f-rgb-half_float.html": 0.5758, + "conformance2/textures/video/tex-2d-rgb32f-rgb-float.html": 0.6942, + "conformance2/textures/video/tex-2d-rgb565-rgb-unsigned_byte.html": 0.4621, + "conformance2/textures/video/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.5729, + "conformance2/textures/video/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.6273, + "conformance2/textures/video/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.6, + "conformance2/textures/video/tex-2d-rgb8-rgb-unsigned_byte.html": 0.8253, + "conformance2/textures/video/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.7582, + "conformance2/textures/video/tex-2d-rgb9_e5-rgb-float.html": 0.6392, + "conformance2/textures/video/tex-2d-rgb9_e5-rgb-half_float.html": 0.5635, + "conformance2/textures/video/tex-2d-rgba16f-rgba-float.html": 0.7379, + "conformance2/textures/video/tex-2d-rgba16f-rgba-half_float.html": 0.65, + "conformance2/textures/video/tex-2d-rgba32f-rgba-float.html": 0.5921, + "conformance2/textures/video/tex-2d-rgba4-rgba-unsigned_byte.html": 0.7355, + "conformance2/textures/video/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.5693, + "conformance2/textures/video/tex-2d-rgba8-rgba-unsigned_byte.html": 0.573, + "conformance2/textures/video/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.6675, + "conformance2/textures/video/tex-2d-srgb8-rgb-unsigned_byte.html": 0.7505, + "conformance2/textures/video/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.5618, + "conformance2/textures/video/tex-3d-r11f_g11f_b10f-rgb-float.html": 0.7491, + "conformance2/textures/video/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 0.6821, + "conformance2/textures/video/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.8745, + "conformance2/textures/video/tex-3d-r16f-red-float.html": 0.7721, + "conformance2/textures/video/tex-3d-r16f-red-half_float.html": 0.8643, + "conformance2/textures/video/tex-3d-r32f-red-float.html": 0.7072, + "conformance2/textures/video/tex-3d-r8-red-unsigned_byte.html": 0.6871, + "conformance2/textures/video/tex-3d-r8ui-red_integer-unsigned_byte.html": 0.8637, + "conformance2/textures/video/tex-3d-rg16f-rg-float.html": 0.8169, + "conformance2/textures/video/tex-3d-rg16f-rg-half_float.html": 0.67, + "conformance2/textures/video/tex-3d-rg32f-rg-float.html": 0.9117, + "conformance2/textures/video/tex-3d-rg8-rg-unsigned_byte.html": 0.6622, + "conformance2/textures/video/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 0.6849, + "conformance2/textures/video/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.847, + "conformance2/textures/video/tex-3d-rgb16f-rgb-float.html": 0.7445, + "conformance2/textures/video/tex-3d-rgb16f-rgb-half_float.html": 0.6699, + "conformance2/textures/video/tex-3d-rgb32f-rgb-float.html": 0.8184, + "conformance2/textures/video/tex-3d-rgb565-rgb-unsigned_byte.html": 0.701, + "conformance2/textures/video/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 0.677, + "conformance2/textures/video/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 0.6995, + "conformance2/textures/video/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.6107, + "conformance2/textures/video/tex-3d-rgb8-rgb-unsigned_byte.html": 0.6699, + "conformance2/textures/video/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 0.7668, + "conformance2/textures/video/tex-3d-rgb9_e5-rgb-float.html": 0.68, + "conformance2/textures/video/tex-3d-rgb9_e5-rgb-half_float.html": 0.902, + "conformance2/textures/video/tex-3d-rgba16f-rgba-float.html": 0.9367, + "conformance2/textures/video/tex-3d-rgba16f-rgba-half_float.html": 0.6912, + "conformance2/textures/video/tex-3d-rgba32f-rgba-float.html": 0.7325, + "conformance2/textures/video/tex-3d-rgba4-rgba-unsigned_byte.html": 0.9073, + "conformance2/textures/video/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.6872, + "conformance2/textures/video/tex-3d-rgba8-rgba-unsigned_byte.html": 0.6548, + "conformance2/textures/video/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 0.6632, + "conformance2/textures/video/tex-3d-srgb8-rgb-unsigned_byte.html": 0.9389, + "conformance2/textures/video/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 0.7973, + "conformance2/textures/webgl_canvas/tex-2d-r11f_g11f_b10f-rgb-float.html": 0.458, + "conformance2/textures/webgl_canvas/tex-2d-r11f_g11f_b10f-rgb-half_float.html": 0.4617, + "conformance2/textures/webgl_canvas/tex-2d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 0.8133, + "conformance2/textures/webgl_canvas/tex-2d-r16f-red-float.html": 0.5589, + "conformance2/textures/webgl_canvas/tex-2d-r16f-red-half_float.html": 0.47, + "conformance2/textures/webgl_canvas/tex-2d-r32f-red-float.html": 0.8562, + "conformance2/textures/webgl_canvas/tex-2d-r8-red-unsigned_byte.html": 0.8411, + "conformance2/textures/webgl_canvas/tex-2d-r8ui-red_integer-unsigned_byte.html": 0.4621, + "conformance2/textures/webgl_canvas/tex-2d-rg16f-rg-float.html": 0.6011, + "conformance2/textures/webgl_canvas/tex-2d-rg16f-rg-half_float.html": 0.5891, + "conformance2/textures/webgl_canvas/tex-2d-rg32f-rg-float.html": 0.6114, + "conformance2/textures/webgl_canvas/tex-2d-rg8-rg-unsigned_byte.html": 0.4964, + "conformance2/textures/webgl_canvas/tex-2d-rg8ui-rg_integer-unsigned_byte.html": 0.4829, + "conformance2/textures/webgl_canvas/tex-2d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 0.5835, + "conformance2/textures/webgl_canvas/tex-2d-rgb16f-rgb-float.html": 0.8831, + "conformance2/textures/webgl_canvas/tex-2d-rgb16f-rgb-half_float.html": 0.4607, + "conformance2/textures/webgl_canvas/tex-2d-rgb32f-rgb-float.html": 0.4397, + "conformance2/textures/webgl_canvas/tex-2d-rgb565-rgb-unsigned_byte.html": 0.4735, + "conformance2/textures/webgl_canvas/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html": 0.8527, + "conformance2/textures/webgl_canvas/tex-2d-rgb5_a1-rgba-unsigned_byte.html": 0.4272, + "conformance2/textures/webgl_canvas/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 0.4372, + "conformance2/textures/webgl_canvas/tex-2d-rgb8-rgb-unsigned_byte.html": 0.6573, + "conformance2/textures/webgl_canvas/tex-2d-rgb8ui-rgb_integer-unsigned_byte.html": 0.6063, + "conformance2/textures/webgl_canvas/tex-2d-rgb9_e5-rgb-float.html": 0.6691, + "conformance2/textures/webgl_canvas/tex-2d-rgb9_e5-rgb-half_float.html": 0.6178, + "conformance2/textures/webgl_canvas/tex-2d-rgba16f-rgba-float.html": 0.4564, + "conformance2/textures/webgl_canvas/tex-2d-rgba16f-rgba-half_float.html": 0.5801, + "conformance2/textures/webgl_canvas/tex-2d-rgba32f-rgba-float.html": 0.439, + "conformance2/textures/webgl_canvas/tex-2d-rgba4-rgba-unsigned_byte.html": 0.5672, + "conformance2/textures/webgl_canvas/tex-2d-rgba4-rgba-unsigned_short_4_4_4_4.html": 0.4532, + "conformance2/textures/webgl_canvas/tex-2d-rgba8-rgba-unsigned_byte.html": 0.9008, + "conformance2/textures/webgl_canvas/tex-2d-rgba8ui-rgba_integer-unsigned_byte.html": 0.7364, + "conformance2/textures/webgl_canvas/tex-2d-srgb8-rgb-unsigned_byte.html": 0.4279, + "conformance2/textures/webgl_canvas/tex-2d-srgb8_alpha8-rgba-unsigned_byte.html": 0.5614, + "conformance2/textures/webgl_canvas/tex-3d-r11f_g11f_b10f-rgb-float.html": 5.6297, + "conformance2/textures/webgl_canvas/tex-3d-r11f_g11f_b10f-rgb-half_float.html": 5.299, + "conformance2/textures/webgl_canvas/tex-3d-r11f_g11f_b10f-rgb-unsigned_int_10f_11f_11f_rev.html": 5.6267, + "conformance2/textures/webgl_canvas/tex-3d-r16f-red-float.html": 5.2657, + "conformance2/textures/webgl_canvas/tex-3d-r16f-red-half_float.html": 5.3781, + "conformance2/textures/webgl_canvas/tex-3d-r32f-red-float.html": 5.2098, + "conformance2/textures/webgl_canvas/tex-3d-r8-red-unsigned_byte.html": 5.3513, + "conformance2/textures/webgl_canvas/tex-3d-r8ui-red_integer-unsigned_byte.html": 5.3794, + "conformance2/textures/webgl_canvas/tex-3d-rg16f-rg-float.html": 5.328, + "conformance2/textures/webgl_canvas/tex-3d-rg16f-rg-half_float.html": 5.459, + "conformance2/textures/webgl_canvas/tex-3d-rg32f-rg-float.html": 5.3868, + "conformance2/textures/webgl_canvas/tex-3d-rg8-rg-unsigned_byte.html": 5.2613, + "conformance2/textures/webgl_canvas/tex-3d-rg8ui-rg_integer-unsigned_byte.html": 5.5877, + "conformance2/textures/webgl_canvas/tex-3d-rgb10_a2-rgba-unsigned_int_2_10_10_10_rev.html": 5.2471, + "conformance2/textures/webgl_canvas/tex-3d-rgb16f-rgb-float.html": 5.4047, + "conformance2/textures/webgl_canvas/tex-3d-rgb16f-rgb-half_float.html": 5.3771, + "conformance2/textures/webgl_canvas/tex-3d-rgb32f-rgb-float.html": 5.1972, + "conformance2/textures/webgl_canvas/tex-3d-rgb565-rgb-unsigned_byte.html": 5.401, + "conformance2/textures/webgl_canvas/tex-3d-rgb565-rgb-unsigned_short_5_6_5.html": 5.296, + "conformance2/textures/webgl_canvas/tex-3d-rgb5_a1-rgba-unsigned_byte.html": 5.1618, + "conformance2/textures/webgl_canvas/tex-3d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html": 5.3056, + "conformance2/textures/webgl_canvas/tex-3d-rgb8-rgb-unsigned_byte.html": 5.2899, + "conformance2/textures/webgl_canvas/tex-3d-rgb8ui-rgb_integer-unsigned_byte.html": 5.245, + "conformance2/textures/webgl_canvas/tex-3d-rgb9_e5-rgb-float.html": 5.2598, + "conformance2/textures/webgl_canvas/tex-3d-rgb9_e5-rgb-half_float.html": 5.495, + "conformance2/textures/webgl_canvas/tex-3d-rgba16f-rgba-float.html": 5.2193, + "conformance2/textures/webgl_canvas/tex-3d-rgba16f-rgba-half_float.html": 5.2031, + "conformance2/textures/webgl_canvas/tex-3d-rgba32f-rgba-float.html": 5.1965, + "conformance2/textures/webgl_canvas/tex-3d-rgba4-rgba-unsigned_byte.html": 5.4407, + "conformance2/textures/webgl_canvas/tex-3d-rgba4-rgba-unsigned_short_4_4_4_4.html": 5.659, + "conformance2/textures/webgl_canvas/tex-3d-rgba8-rgba-unsigned_byte.html": 5.5831, + "conformance2/textures/webgl_canvas/tex-3d-rgba8ui-rgba_integer-unsigned_byte.html": 5.4935, + "conformance2/textures/webgl_canvas/tex-3d-srgb8-rgb-unsigned_byte.html": 5.5081, + "conformance2/textures/webgl_canvas/tex-3d-srgb8_alpha8-rgba-unsigned_byte.html": 5.2057, + "conformance2/transform_feedback/default_transform_feedback.html": 0.1657, + "conformance2/transform_feedback/non-existent-varying.html": 0.1263, + "conformance2/transform_feedback/same-buffer-two-binding-points.html": 0.1137, + "conformance2/transform_feedback/simultaneous_binding.html": 0.2288, + "conformance2/transform_feedback/switching-objects.html": 0.0916, + "conformance2/transform_feedback/too-small-buffers.html": 0.2894, + "conformance2/transform_feedback/transform_feedback.html": 0.962, + "conformance2/transform_feedback/two-unreferenced-varyings.html": 0.0582, + "conformance2/transform_feedback/unwritten-output-defaults-to-zero.html": 0.0656, + "conformance2/uniforms/dependent-buffer-change.html": 0.1136, + "conformance2/uniforms/draw-with-uniform-blocks.html": 0.1097, + "conformance2/uniforms/gl-uniform-arrays-sub-source.html": 0.425, + "conformance2/uniforms/incompatible-texture-type-for-sampler.html": 3.1533, + "conformance2/uniforms/query-uniform-blocks-after-shader-detach.html": 0.0847, + "conformance2/uniforms/simple-buffer-change.html": 0.1671, + "conformance2/uniforms/uniform-blocks-with-arrays.html": 0.1592, + "conformance2/vertex_arrays/vertex-array-object-and-disabled-attributes.html": 0.1789, + "conformance2/vertex_arrays/vertex-array-object.html": 0.1672, + "deqp/data/gles3/shaders/arrays.html": 2.2815, + "deqp/data/gles3/shaders/conditionals.html": 0.8602, + "deqp/data/gles3/shaders/constant_expressions.html": 1.4611, + "deqp/data/gles3/shaders/constants.html": 3.4331, + "deqp/data/gles3/shaders/conversions.html": 32.777, + "deqp/data/gles3/shaders/declarations.html": 1.0074, + "deqp/data/gles3/shaders/fragdata.html": 0.265, + "deqp/data/gles3/shaders/functions.html": 5.224, + "deqp/data/gles3/shaders/invalid_texture_functions.html": 1.8727, + "deqp/data/gles3/shaders/keywords.html": 4.3342, + "deqp/data/gles3/shaders/linkage.html": 2.278, + "deqp/data/gles3/shaders/negative.html": 0.3667, + "deqp/data/gles3/shaders/preprocessor.html": 10.7742, + "deqp/data/gles3/shaders/qualification_order.html": 1.0499, + "deqp/data/gles3/shaders/scoping.html": 1.2514, + "deqp/data/gles3/shaders/switch.html": 0.9289, + "deqp/data/gles3/shaders/swizzles.html": 15.3072, + "deqp/framework/opengl/simplereference/referencecontext.html": 2.0472, + "deqp/functional/gles3/attriblocation.html": 3.4032, + "deqp/functional/gles3/booleanstatequery.html": 0.2977, + "deqp/functional/gles3/buffercopy.html": 3.0961, + "deqp/functional/gles3/bufferobjectquery.html": 0.4076, + "deqp/functional/gles3/clipping.html": 11.128, + "deqp/functional/gles3/defaultvertexattribute.html": 7.9292, + "deqp/functional/gles3/draw/draw_arrays.html": 9.3682, + "deqp/functional/gles3/draw/draw_arrays_instanced.html": 10.1945, + "deqp/functional/gles3/draw/draw_elements.html": 6.6107, + "deqp/functional/gles3/draw/draw_elements_instanced.html": 8.2316, + "deqp/functional/gles3/draw/draw_range_elements.html": 5.3221, + "deqp/functional/gles3/draw/instancing.html": 0.8705, + "deqp/functional/gles3/draw/random.html": 7.4928, + "deqp/functional/gles3/fbocolorbuffer/blend.html": 6.6775, + "deqp/functional/gles3/fbocolorbuffer/clear.html": 4.8822, + "deqp/functional/gles3/fbocolorbuffer/tex2d_00.html": 8.0644, + "deqp/functional/gles3/fbocolorbuffer/tex2d_01.html": 7.071, + "deqp/functional/gles3/fbocolorbuffer/tex2d_02.html": 9.6065, + "deqp/functional/gles3/fbocolorbuffer/tex2d_03.html": 8.5414, + "deqp/functional/gles3/fbocolorbuffer/tex2d_04.html": 7.3959, + "deqp/functional/gles3/fbocolorbuffer/tex2d_05.html": 7.4611, + "deqp/functional/gles3/fbocolorbuffer/tex2darray_00.html": 8.1384, + "deqp/functional/gles3/fbocolorbuffer/tex2darray_01.html": 7.0963, + "deqp/functional/gles3/fbocolorbuffer/tex2darray_02.html": 7.8301, + "deqp/functional/gles3/fbocolorbuffer/tex2darray_03.html": 7.4302, + "deqp/functional/gles3/fbocolorbuffer/tex2darray_04.html": 8.6839, + "deqp/functional/gles3/fbocolorbuffer/tex2darray_05.html": 7.3685, + "deqp/functional/gles3/fbocolorbuffer/tex3d_00.html": 6.9243, + "deqp/functional/gles3/fbocolorbuffer/tex3d_01.html": 7.7226, + "deqp/functional/gles3/fbocolorbuffer/tex3d_02.html": 7.5911, + "deqp/functional/gles3/fbocolorbuffer/tex3d_03.html": 7.528, + "deqp/functional/gles3/fbocolorbuffer/tex3d_04.html": 8.5513, + "deqp/functional/gles3/fbocolorbuffer/tex3d_05.html": 7.1503, + "deqp/functional/gles3/fbocolorbuffer/texcube_00.html": 11.7238, + "deqp/functional/gles3/fbocolorbuffer/texcube_01.html": 10.0808, + "deqp/functional/gles3/fbocolorbuffer/texcube_02.html": 10.1591, + "deqp/functional/gles3/fbocolorbuffer/texcube_03.html": 9.5093, + "deqp/functional/gles3/fbocolorbuffer/texcube_04.html": 10.4326, + "deqp/functional/gles3/fbocolorbuffer/texcube_05.html": 9.9598, + "deqp/functional/gles3/fbocompleteness.html": 4.0055, + "deqp/functional/gles3/fbodepthbuffer.html": 8.0922, + "deqp/functional/gles3/fboinvalidate/default.html": 17.4273, + "deqp/functional/gles3/fboinvalidate/format_00.html": 8.783, + "deqp/functional/gles3/fboinvalidate/format_01.html": 9.3005, + "deqp/functional/gles3/fboinvalidate/format_02.html": 8.5566, + "deqp/functional/gles3/fboinvalidate/sub.html": 14.0135, + "deqp/functional/gles3/fboinvalidate/target.html": 22.6879, + "deqp/functional/gles3/fboinvalidate/whole.html": 14.6793, + "deqp/functional/gles3/fbomultisample.2_samples.html": 14.7244, + "deqp/functional/gles3/fbomultisample.4_samples.html": 16.3733, + "deqp/functional/gles3/fbomultisample.8_samples.html": 17.4245, + "deqp/functional/gles3/fborender/recreate_color_00.html": 8.4621, + "deqp/functional/gles3/fborender/recreate_color_01.html": 7.5015, + "deqp/functional/gles3/fborender/recreate_color_02.html": 6.8496, + "deqp/functional/gles3/fborender/recreate_color_03.html": 7.1923, + "deqp/functional/gles3/fborender/recreate_color_04.html": 8.2501, + "deqp/functional/gles3/fborender/recreate_color_05.html": 7.4724, + "deqp/functional/gles3/fborender/recreate_color_06.html": 7.0323, + "deqp/functional/gles3/fborender/recreate_depth_stencil.html": 6.9068, + "deqp/functional/gles3/fborender/resize_00.html": 6.7889, + "deqp/functional/gles3/fborender/resize_01.html": 7.1393, + "deqp/functional/gles3/fborender/resize_02.html": 6.614, + "deqp/functional/gles3/fborender/resize_03.html": 10.1654, + "deqp/functional/gles3/fborender/shared_colorbuffer_00.html": 9.2354, + "deqp/functional/gles3/fborender/shared_colorbuffer_01.html": 8.835, + "deqp/functional/gles3/fborender/shared_colorbuffer_02.html": 11.1922, + "deqp/functional/gles3/fborender/shared_colorbuffer_clear.html": 3.2704, + "deqp/functional/gles3/fborender/shared_depth_stencil.html": 6.1949, + "deqp/functional/gles3/fborender/stencil_clear.html": 3.5361, + "deqp/functional/gles3/fbostatequery.html": 0.2873, + "deqp/functional/gles3/fbostencilbuffer.html": 7.5819, + "deqp/functional/gles3/floatstatequery.html": 0.493, + "deqp/functional/gles3/fragdepth.html": 3.7569, + "deqp/functional/gles3/fragmentoutput/array.fixed.html": 3.858, + "deqp/functional/gles3/fragmentoutput/array.float.html": 6.6397, + "deqp/functional/gles3/fragmentoutput/array.int.html": 8.4499, + "deqp/functional/gles3/fragmentoutput/array.uint.html": 7.3687, + "deqp/functional/gles3/fragmentoutput/basic.fixed.html": 3.3022, + "deqp/functional/gles3/fragmentoutput/basic.float.html": 3.443, + "deqp/functional/gles3/fragmentoutput/basic.int.html": 4.2069, + "deqp/functional/gles3/fragmentoutput/basic.uint.html": 3.4387, + "deqp/functional/gles3/fragmentoutput/random_00.html": 6.0561, + "deqp/functional/gles3/fragmentoutput/random_01.html": 7.7487, + "deqp/functional/gles3/fragmentoutput/random_02.html": 9.9308, + "deqp/functional/gles3/framebufferblit/conversion_00.html": 4.0753, + "deqp/functional/gles3/framebufferblit/conversion_01.html": 3.8959, + "deqp/functional/gles3/framebufferblit/conversion_02.html": 3.529, + "deqp/functional/gles3/framebufferblit/conversion_03.html": 3.75, + "deqp/functional/gles3/framebufferblit/conversion_04.html": 6.1191, + "deqp/functional/gles3/framebufferblit/conversion_05.html": 3.2859, + "deqp/functional/gles3/framebufferblit/conversion_06.html": 3.8239, + "deqp/functional/gles3/framebufferblit/conversion_07.html": 5.6544, + "deqp/functional/gles3/framebufferblit/conversion_08.html": 5.5405, + "deqp/functional/gles3/framebufferblit/conversion_09.html": 4.146, + "deqp/functional/gles3/framebufferblit/conversion_10.html": 5.4691, + "deqp/functional/gles3/framebufferblit/conversion_11.html": 6.2265, + "deqp/functional/gles3/framebufferblit/conversion_12.html": 6.0071, + "deqp/functional/gles3/framebufferblit/conversion_13.html": 5.0864, + "deqp/functional/gles3/framebufferblit/conversion_14.html": 3.9478, + "deqp/functional/gles3/framebufferblit/conversion_15.html": 4.2084, + "deqp/functional/gles3/framebufferblit/conversion_16.html": 3.9482, + "deqp/functional/gles3/framebufferblit/conversion_17.html": 3.9627, + "deqp/functional/gles3/framebufferblit/conversion_18.html": 6.1948, + "deqp/functional/gles3/framebufferblit/conversion_19.html": 3.5246, + "deqp/functional/gles3/framebufferblit/conversion_20.html": 3.7651, + "deqp/functional/gles3/framebufferblit/conversion_21.html": 4.504, + "deqp/functional/gles3/framebufferblit/conversion_22.html": 3.8161, + "deqp/functional/gles3/framebufferblit/conversion_23.html": 4.1286, + "deqp/functional/gles3/framebufferblit/conversion_24.html": 4.4815, + "deqp/functional/gles3/framebufferblit/conversion_25.html": 5.5277, + "deqp/functional/gles3/framebufferblit/conversion_26.html": 3.4938, + "deqp/functional/gles3/framebufferblit/conversion_27.html": 3.6642, + "deqp/functional/gles3/framebufferblit/conversion_28.html": 6.3493, + "deqp/functional/gles3/framebufferblit/conversion_29.html": 6.4826, + "deqp/functional/gles3/framebufferblit/conversion_30.html": 5.0015, + "deqp/functional/gles3/framebufferblit/conversion_31.html": 5.8556, + "deqp/functional/gles3/framebufferblit/conversion_32.html": 5.4088, + "deqp/functional/gles3/framebufferblit/conversion_33.html": 5.6707, + "deqp/functional/gles3/framebufferblit/conversion_34.html": 6.6154, + "deqp/functional/gles3/framebufferblit/default_framebuffer_00.html": 6.7768, + "deqp/functional/gles3/framebufferblit/default_framebuffer_01.html": 8.4703, + "deqp/functional/gles3/framebufferblit/default_framebuffer_02.html": 4.8219, + "deqp/functional/gles3/framebufferblit/default_framebuffer_03.html": 6.6394, + "deqp/functional/gles3/framebufferblit/default_framebuffer_04.html": 14.493, + "deqp/functional/gles3/framebufferblit/default_framebuffer_05.html": 7.7779, + "deqp/functional/gles3/framebufferblit/default_framebuffer_06.html": 7.9601, + "deqp/functional/gles3/framebufferblit/depth_stencil.html": 13.9458, + "deqp/functional/gles3/framebufferblit/rect_00.html": 4.0759, + "deqp/functional/gles3/framebufferblit/rect_01.html": 4.7363, + "deqp/functional/gles3/framebufferblit/rect_02.html": 3.2513, + "deqp/functional/gles3/framebufferblit/rect_03.html": 2.1202, + "deqp/functional/gles3/framebufferblit/rect_04.html": 2.1406, + "deqp/functional/gles3/framebufferblit/rect_05.html": 0.3235, + "deqp/functional/gles3/framebufferblit/rect_06.html": 0.4611, + "deqp/functional/gles3/indexedstatequery.html": 0.2463, + "deqp/functional/gles3/instancedrendering.html": 15.1057, + "deqp/functional/gles3/integerstatequery.html": 1.01, + "deqp/functional/gles3/internalformatquery.html": 0.4186, + "deqp/functional/gles3/lifetime.html": 0.8976, + "deqp/functional/gles3/multisample.html": 15.2585, + "deqp/functional/gles3/negativebufferapi.html": 0.488, + "deqp/functional/gles3/negativefragmentapi.html": 0.2844, + "deqp/functional/gles3/negativeshaderapi.html": 0.6765, + "deqp/functional/gles3/negativestateapi.html": 0.6317, + "deqp/functional/gles3/negativetextureapi.html": 0.7939, + "deqp/functional/gles3/negativevertexarrayapi.html": 0.5539, + "deqp/functional/gles3/occlusionquery_conservative.html": 14.9602, + "deqp/functional/gles3/occlusionquery_strict.html": 16.0669, + "deqp/functional/gles3/pixelbufferobject.html": 4.3743, + "deqp/functional/gles3/primitiverestart/00.html": 3.756, + "deqp/functional/gles3/primitiverestart/01.html": 3.6657, + "deqp/functional/gles3/primitiverestart/02.html": 2.9532, + "deqp/functional/gles3/primitiverestart/03.html": 2.9528, + "deqp/functional/gles3/primitiverestart/04.html": 2.9501, + "deqp/functional/gles3/primitiverestart/05.html": 3.3868, + "deqp/functional/gles3/primitiverestart/06.html": 3.6153, + "deqp/functional/gles3/primitiverestart/07.html": 3.0391, + "deqp/functional/gles3/rasterizerdiscard.html": 5.3883, + "deqp/functional/gles3/rbostatequery.html": 0.1795, + "deqp/functional/gles3/readpixel.html": 0.9241, + "deqp/functional/gles3/samplerobject.html": 3.1574, + "deqp/functional/gles3/samplerstatequery.html": 0.2839, + "deqp/functional/gles3/shaderapi.html": 0.3913, + "deqp/functional/gles3/shaderbuiltinvar.html": 4.3877, + "deqp/functional/gles3/shadercommonfunction.html": 6.7662, + "deqp/functional/gles3/shaderderivate_dfdx.html": 8.5277, + "deqp/functional/gles3/shaderderivate_dfdy.html": 8.0247, + "deqp/functional/gles3/shaderderivate_fwidth.html": 5.9756, + "deqp/functional/gles3/shaderindexing/mat_00.html": 26.4991, + "deqp/functional/gles3/shaderindexing/mat_01.html": 31.1244, + "deqp/functional/gles3/shaderindexing/mat_02.html": 30.5794, + "deqp/functional/gles3/shaderindexing/tmp.html": 35.7644, + "deqp/functional/gles3/shaderindexing/uniform.html": 9.3684, + "deqp/functional/gles3/shaderindexing/varying.html": 21.9493, + "deqp/functional/gles3/shaderindexing/vec2.html": 21.5938, + "deqp/functional/gles3/shaderindexing/vec3.html": 24.0416, + "deqp/functional/gles3/shaderindexing/vec4.html": 19.6805, + "deqp/functional/gles3/shaderloop_do_while.html": 55.8662, + "deqp/functional/gles3/shaderloop_for.html": 53.8364, + "deqp/functional/gles3/shaderloop_while.html": 52.5401, + "deqp/functional/gles3/shadermatrix/add_assign.html": 29.692, + "deqp/functional/gles3/shadermatrix/add_const.html": 36.1871, + "deqp/functional/gles3/shadermatrix/add_dynamic.html": 44.0114, + "deqp/functional/gles3/shadermatrix/add_uniform.html": 50.5376, + "deqp/functional/gles3/shadermatrix/determinant.html": 9.8146, + "deqp/functional/gles3/shadermatrix/div_assign.html": 25.5548, + "deqp/functional/gles3/shadermatrix/div_const.html": 41.4191, + "deqp/functional/gles3/shadermatrix/div_dynamic.html": 45.1309, + "deqp/functional/gles3/shadermatrix/div_uniform.html": 43.7901, + "deqp/functional/gles3/shadermatrix/inverse.html": 17.3816, + "deqp/functional/gles3/shadermatrix/matrixcompmult.html": 29.4141, + "deqp/functional/gles3/shadermatrix/mul_assign.html": 10.8562, + "deqp/functional/gles3/shadermatrix/mul_const_highp.html": 37.8449, + "deqp/functional/gles3/shadermatrix/mul_const_lowp.html": 33.7191, + "deqp/functional/gles3/shadermatrix/mul_const_mediump.html": 33.6037, + "deqp/functional/gles3/shadermatrix/mul_dynamic_highp.html": 48.9427, + "deqp/functional/gles3/shadermatrix/mul_dynamic_lowp.html": 46.8463, + "deqp/functional/gles3/shadermatrix/mul_dynamic_mediump.html": 45.8248, + "deqp/functional/gles3/shadermatrix/mul_uniform_highp.html": 50.2833, + "deqp/functional/gles3/shadermatrix/mul_uniform_lowp.html": 54.8961, + "deqp/functional/gles3/shadermatrix/mul_uniform_mediump.html": 40.7532, + "deqp/functional/gles3/shadermatrix/negation.html": 25.6545, + "deqp/functional/gles3/shadermatrix/outerproduct.html": 23.6658, + "deqp/functional/gles3/shadermatrix/post_decrement.html": 28.6808, + "deqp/functional/gles3/shadermatrix/post_increment.html": 23.9786, + "deqp/functional/gles3/shadermatrix/pre_decrement.html": 24.9038, + "deqp/functional/gles3/shadermatrix/pre_increment.html": 26.8164, + "deqp/functional/gles3/shadermatrix/sub_assign.html": 25.4385, + "deqp/functional/gles3/shadermatrix/sub_const.html": 36.819, + "deqp/functional/gles3/shadermatrix/sub_dynamic.html": 45.0947, + "deqp/functional/gles3/shadermatrix/sub_uniform.html": 48.2929, + "deqp/functional/gles3/shadermatrix/transpose.html": 22.0677, + "deqp/functional/gles3/shadermatrix/unary_addition.html": 24.167, + "deqp/functional/gles3/shaderoperator/angle_and_trigonometry_00.html": 31.0164, + "deqp/functional/gles3/shaderoperator/angle_and_trigonometry_01.html": 20.5972, + "deqp/functional/gles3/shaderoperator/angle_and_trigonometry_02.html": 24.371, + "deqp/functional/gles3/shaderoperator/angle_and_trigonometry_03.html": 17.142, + "deqp/functional/gles3/shaderoperator/binary_operator_00.html": 81.0364, + "deqp/functional/gles3/shaderoperator/binary_operator_01.html": 87.0151, + "deqp/functional/gles3/shaderoperator/binary_operator_02.html": 53.1237, + "deqp/functional/gles3/shaderoperator/binary_operator_03.html": 53.6422, + "deqp/functional/gles3/shaderoperator/binary_operator_04.html": 68.3138, + "deqp/functional/gles3/shaderoperator/binary_operator_05.html": 63.9626, + "deqp/functional/gles3/shaderoperator/binary_operator_06.html": 60.5048, + "deqp/functional/gles3/shaderoperator/binary_operator_07.html": 41.8161, + "deqp/functional/gles3/shaderoperator/binary_operator_08.html": 38.1297, + "deqp/functional/gles3/shaderoperator/binary_operator_09.html": 66.7202, + "deqp/functional/gles3/shaderoperator/binary_operator_10.html": 59.3516, + "deqp/functional/gles3/shaderoperator/binary_operator_11.html": 60.305, + "deqp/functional/gles3/shaderoperator/binary_operator_12.html": 41.1094, + "deqp/functional/gles3/shaderoperator/binary_operator_13.html": 39.1003, + "deqp/functional/gles3/shaderoperator/binary_operator_14.html": 66.3612, + "deqp/functional/gles3/shaderoperator/binary_operator_15.html": 76.2495, + "deqp/functional/gles3/shaderoperator/bool_compare.html": 11.3458, + "deqp/functional/gles3/shaderoperator/common_functions_00.html": 36.2531, + "deqp/functional/gles3/shaderoperator/common_functions_01.html": 33.5979, + "deqp/functional/gles3/shaderoperator/common_functions_02.html": 32.5375, + "deqp/functional/gles3/shaderoperator/common_functions_03.html": 30.9384, + "deqp/functional/gles3/shaderoperator/common_functions_04.html": 38.4475, + "deqp/functional/gles3/shaderoperator/common_functions_05.html": 36.0459, + "deqp/functional/gles3/shaderoperator/common_functions_06.html": 27.9852, + "deqp/functional/gles3/shaderoperator/exponential.html": 34.6093, + "deqp/functional/gles3/shaderoperator/float_compare.html": 52.8773, + "deqp/functional/gles3/shaderoperator/geometric.html": 37.7535, + "deqp/functional/gles3/shaderoperator/int_compare.html": 34.3153, + "deqp/functional/gles3/shaderoperator/selection.html": 28.7664, + "deqp/functional/gles3/shaderoperator/sequence.html": 21.7361, + "deqp/functional/gles3/shaderoperator/unary_operator_00.html": 47.8969, + "deqp/functional/gles3/shaderoperator/unary_operator_01.html": 90.754, + "deqp/functional/gles3/shaderoperator/unary_operator_02.html": 90.5757, + "deqp/functional/gles3/shaderpackingfunction.html": 0.9445, + "deqp/functional/gles3/shaderprecision_float.html": 8.4747, + "deqp/functional/gles3/shaderprecision_int.html": 11.7359, + "deqp/functional/gles3/shaderprecision_uint.html": 7.1876, + "deqp/functional/gles3/shaderstatequery.html": 0.6561, + "deqp/functional/gles3/shaderstruct.html": 28.7979, + "deqp/functional/gles3/shaderswitch.html": 35.7998, + "deqp/functional/gles3/shadertexturefunction/texelfetch.html": 9.8206, + "deqp/functional/gles3/shadertexturefunction/texelfetchoffset.html": 12.3645, + "deqp/functional/gles3/shadertexturefunction/texture.html": 18.6943, + "deqp/functional/gles3/shadertexturefunction/texturegrad.html": 12.4453, + "deqp/functional/gles3/shadertexturefunction/texturegradoffset.html": 8.6567, + "deqp/functional/gles3/shadertexturefunction/texturelod.html": 12.4163, + "deqp/functional/gles3/shadertexturefunction/texturelodoffset.html": 9.0649, + "deqp/functional/gles3/shadertexturefunction/textureoffset.html": 12.8783, + "deqp/functional/gles3/shadertexturefunction/textureproj.html": 13.3193, + "deqp/functional/gles3/shadertexturefunction/textureprojgrad.html": 8.2227, + "deqp/functional/gles3/shadertexturefunction/textureprojgradoffset.html": 9.8511, + "deqp/functional/gles3/shadertexturefunction/textureprojlod.html": 7.3432, + "deqp/functional/gles3/shadertexturefunction/textureprojlodoffset.html": 7.3867, + "deqp/functional/gles3/shadertexturefunction/textureprojoffset.html": 12.9399, + "deqp/functional/gles3/shadertexturefunction/texturesize.html": 20.7969, + "deqp/functional/gles3/stringquery.html": 0.2059, + "deqp/functional/gles3/sync.html": 3.5786, + "deqp/functional/gles3/texturefiltering/2d_array_combinations_00.html": 4.8116, + "deqp/functional/gles3/texturefiltering/2d_array_combinations_01.html": 4.1118, + "deqp/functional/gles3/texturefiltering/2d_array_combinations_02.html": 4.0215, + "deqp/functional/gles3/texturefiltering/2d_array_combinations_03.html": 3.9845, + "deqp/functional/gles3/texturefiltering/2d_array_combinations_04.html": 4.9351, + "deqp/functional/gles3/texturefiltering/2d_array_combinations_05.html": 5.1551, + "deqp/functional/gles3/texturefiltering/2d_array_formats_00.html": 2.9061, + "deqp/functional/gles3/texturefiltering/2d_array_formats_01.html": 2.0774, + "deqp/functional/gles3/texturefiltering/2d_array_formats_02.html": 2.3194, + "deqp/functional/gles3/texturefiltering/2d_array_formats_03.html": 1.9149, + "deqp/functional/gles3/texturefiltering/2d_array_formats_04.html": 1.8911, + "deqp/functional/gles3/texturefiltering/2d_array_formats_05.html": 2.026, + "deqp/functional/gles3/texturefiltering/2d_array_formats_06.html": 2.0293, + "deqp/functional/gles3/texturefiltering/2d_array_formats_07.html": 1.7112, + "deqp/functional/gles3/texturefiltering/2d_array_formats_08.html": 1.8448, + "deqp/functional/gles3/texturefiltering/2d_array_formats_09.html": 2.2079, + "deqp/functional/gles3/texturefiltering/2d_array_sizes_00.html": 1.521, + "deqp/functional/gles3/texturefiltering/2d_array_sizes_01.html": 1.6575, + "deqp/functional/gles3/texturefiltering/2d_array_sizes_02.html": 2.6492, + "deqp/functional/gles3/texturefiltering/2d_array_sizes_03.html": 1.6687, + "deqp/functional/gles3/texturefiltering/2d_array_sizes_04.html": 5.2124, + "deqp/functional/gles3/texturefiltering/2d_combinations_00.html": 2.7517, + "deqp/functional/gles3/texturefiltering/2d_combinations_01.html": 1.8585, + "deqp/functional/gles3/texturefiltering/2d_combinations_02.html": 2.549, + "deqp/functional/gles3/texturefiltering/2d_combinations_03.html": 2.4751, + "deqp/functional/gles3/texturefiltering/2d_combinations_04.html": 1.9137, + "deqp/functional/gles3/texturefiltering/2d_combinations_05.html": 1.9528, + "deqp/functional/gles3/texturefiltering/2d_formats_00.html": 1.7575, + "deqp/functional/gles3/texturefiltering/2d_formats_01.html": 1.4187, + "deqp/functional/gles3/texturefiltering/2d_formats_02.html": 1.2324, + "deqp/functional/gles3/texturefiltering/2d_formats_03.html": 1.4403, + "deqp/functional/gles3/texturefiltering/2d_formats_04.html": 1.3127, + "deqp/functional/gles3/texturefiltering/2d_formats_05.html": 1.0501, + "deqp/functional/gles3/texturefiltering/2d_formats_06.html": 1.312, + "deqp/functional/gles3/texturefiltering/2d_formats_07.html": 1.0331, + "deqp/functional/gles3/texturefiltering/2d_formats_08.html": 1.167, + "deqp/functional/gles3/texturefiltering/2d_formats_09.html": 1.4506, + "deqp/functional/gles3/texturefiltering/2d_sizes_00.html": 1.13, + "deqp/functional/gles3/texturefiltering/2d_sizes_01.html": 0.9989, + "deqp/functional/gles3/texturefiltering/2d_sizes_02.html": 1.0524, + "deqp/functional/gles3/texturefiltering/2d_sizes_03.html": 1.1692, + "deqp/functional/gles3/texturefiltering/2d_sizes_04.html": 0.9983, + "deqp/functional/gles3/texturefiltering/2d_sizes_05.html": 1.0342, + "deqp/functional/gles3/texturefiltering/3d_combinations_00.html": 1.8289, + "deqp/functional/gles3/texturefiltering/3d_combinations_01.html": 1.865, + "deqp/functional/gles3/texturefiltering/3d_combinations_02.html": 1.7493, + "deqp/functional/gles3/texturefiltering/3d_combinations_03.html": 2.6855, + "deqp/functional/gles3/texturefiltering/3d_combinations_04.html": 2.6717, + "deqp/functional/gles3/texturefiltering/3d_combinations_05.html": 2.1689, + "deqp/functional/gles3/texturefiltering/3d_combinations_06.html": 2.5347, + "deqp/functional/gles3/texturefiltering/3d_combinations_07.html": 2.0372, + "deqp/functional/gles3/texturefiltering/3d_combinations_08.html": 1.9194, + "deqp/functional/gles3/texturefiltering/3d_combinations_09.html": 2.3432, + "deqp/functional/gles3/texturefiltering/3d_combinations_10.html": 2.5336, + "deqp/functional/gles3/texturefiltering/3d_combinations_11.html": 2.0173, + "deqp/functional/gles3/texturefiltering/3d_combinations_12.html": 1.8029, + "deqp/functional/gles3/texturefiltering/3d_combinations_13.html": 2.5222, + "deqp/functional/gles3/texturefiltering/3d_combinations_14.html": 1.7782, + "deqp/functional/gles3/texturefiltering/3d_combinations_15.html": 2.0261, + "deqp/functional/gles3/texturefiltering/3d_combinations_16.html": 2.637, + "deqp/functional/gles3/texturefiltering/3d_combinations_17.html": 1.9453, + "deqp/functional/gles3/texturefiltering/3d_combinations_18.html": 2.7134, + "deqp/functional/gles3/texturefiltering/3d_combinations_19.html": 2.5769, + "deqp/functional/gles3/texturefiltering/3d_combinations_20.html": 1.9918, + "deqp/functional/gles3/texturefiltering/3d_combinations_21.html": 2.1423, + "deqp/functional/gles3/texturefiltering/3d_combinations_22.html": 2.158, + "deqp/functional/gles3/texturefiltering/3d_combinations_23.html": 2.6336, + "deqp/functional/gles3/texturefiltering/3d_combinations_24.html": 11.6524, + "deqp/functional/gles3/texturefiltering/3d_combinations_25.html": 11.6297, + "deqp/functional/gles3/texturefiltering/3d_combinations_26.html": 11.4131, + "deqp/functional/gles3/texturefiltering/3d_combinations_27.html": 10.9508, + "deqp/functional/gles3/texturefiltering/3d_combinations_28.html": 11.0192, + "deqp/functional/gles3/texturefiltering/3d_combinations_29.html": 11.537, + "deqp/functional/gles3/texturefiltering/3d_combinations_30.html": 11.9549, + "deqp/functional/gles3/texturefiltering/3d_combinations_31.html": 12.1648, + "deqp/functional/gles3/texturefiltering/3d_combinations_32.html": 12.0043, + "deqp/functional/gles3/texturefiltering/3d_combinations_33.html": 11.6546, + "deqp/functional/gles3/texturefiltering/3d_combinations_34.html": 9.499, + "deqp/functional/gles3/texturefiltering/3d_combinations_35.html": 11.829, + "deqp/functional/gles3/texturefiltering/3d_formats_00.html": 6.4231, + "deqp/functional/gles3/texturefiltering/3d_formats_01.html": 6.4255, + "deqp/functional/gles3/texturefiltering/3d_formats_02.html": 5.6347, + "deqp/functional/gles3/texturefiltering/3d_formats_03.html": 5.1447, + "deqp/functional/gles3/texturefiltering/3d_formats_04.html": 5.6346, + "deqp/functional/gles3/texturefiltering/3d_formats_05.html": 5.2767, + "deqp/functional/gles3/texturefiltering/3d_formats_06.html": 4.8016, + "deqp/functional/gles3/texturefiltering/3d_formats_07.html": 4.7932, + "deqp/functional/gles3/texturefiltering/3d_formats_08.html": 5.8439, + "deqp/functional/gles3/texturefiltering/3d_formats_09.html": 4.7662, + "deqp/functional/gles3/texturefiltering/3d_sizes_00.html": 5.3363, + "deqp/functional/gles3/texturefiltering/3d_sizes_01.html": 5.3544, + "deqp/functional/gles3/texturefiltering/3d_sizes_02.html": 5.2958, + "deqp/functional/gles3/texturefiltering/3d_sizes_03.html": 3.9165, + "deqp/functional/gles3/texturefiltering/3d_sizes_04.html": 5.7115, + "deqp/functional/gles3/texturefiltering/cube_combinations_00.html": 5.5651, + "deqp/functional/gles3/texturefiltering/cube_combinations_01.html": 10.9564, + "deqp/functional/gles3/texturefiltering/cube_combinations_02.html": 13.1221, + "deqp/functional/gles3/texturefiltering/cube_combinations_03.html": 10.0307, + "deqp/functional/gles3/texturefiltering/cube_combinations_04.html": 12.22, + "deqp/functional/gles3/texturefiltering/cube_combinations_05.html": 17.6162, + "deqp/functional/gles3/texturefiltering/cube_formats_00.html": 5.5341, + "deqp/functional/gles3/texturefiltering/cube_formats_01.html": 6.2213, + "deqp/functional/gles3/texturefiltering/cube_formats_02.html": 6.0032, + "deqp/functional/gles3/texturefiltering/cube_formats_03.html": 4.6917, + "deqp/functional/gles3/texturefiltering/cube_formats_04.html": 6.1844, + "deqp/functional/gles3/texturefiltering/cube_formats_05.html": 4.5901, + "deqp/functional/gles3/texturefiltering/cube_formats_06.html": 4.8147, + "deqp/functional/gles3/texturefiltering/cube_formats_07.html": 6.112, + "deqp/functional/gles3/texturefiltering/cube_formats_08.html": 6.0933, + "deqp/functional/gles3/texturefiltering/cube_formats_09.html": 4.8407, + "deqp/functional/gles3/texturefiltering/cube_no_edges_visible.html": 2.4049, + "deqp/functional/gles3/texturefiltering/cube_sizes_00.html": 2.7283, + "deqp/functional/gles3/texturefiltering/cube_sizes_01.html": 6.366, + "deqp/functional/gles3/texturefiltering/cube_sizes_02.html": 6.2865, + "deqp/functional/gles3/texturefiltering/cube_sizes_03.html": 2.8203, + "deqp/functional/gles3/texturefiltering/cube_sizes_04.html": 5.6923, + "deqp/functional/gles3/textureformat/compressed_2d.html": 0.2791, + "deqp/functional/gles3/textureformat/compressed_cube.html": 0.2126, + "deqp/functional/gles3/textureformat/sized_color_2d_array_npot_00.html": 4.011, + "deqp/functional/gles3/textureformat/sized_color_2d_array_npot_01.html": 3.129, + "deqp/functional/gles3/textureformat/sized_color_2d_array_npot_02.html": 3.1491, + "deqp/functional/gles3/textureformat/sized_color_2d_array_npot_03.html": 3.3697, + "deqp/functional/gles3/textureformat/sized_color_2d_array_pot_00.html": 3.5756, + "deqp/functional/gles3/textureformat/sized_color_2d_array_pot_01.html": 4.2822, + "deqp/functional/gles3/textureformat/sized_color_2d_array_pot_02.html": 3.5236, + "deqp/functional/gles3/textureformat/sized_color_2d_array_pot_03.html": 4.7111, + "deqp/functional/gles3/textureformat/sized_color_2d_npot_00.html": 1.6455, + "deqp/functional/gles3/textureformat/sized_color_2d_npot_01.html": 1.898, + "deqp/functional/gles3/textureformat/sized_color_2d_npot_02.html": 2.2763, + "deqp/functional/gles3/textureformat/sized_color_2d_npot_03.html": 1.897, + "deqp/functional/gles3/textureformat/sized_color_2d_pot_00.html": 2.0301, + "deqp/functional/gles3/textureformat/sized_color_2d_pot_01.html": 1.8104, + "deqp/functional/gles3/textureformat/sized_color_2d_pot_02.html": 1.9045, + "deqp/functional/gles3/textureformat/sized_color_2d_pot_03.html": 1.9634, + "deqp/functional/gles3/textureformat/sized_color_3d_npot_00.html": 2.1643, + "deqp/functional/gles3/textureformat/sized_color_3d_npot_01.html": 2.1884, + "deqp/functional/gles3/textureformat/sized_color_3d_npot_02.html": 3.0835, + "deqp/functional/gles3/textureformat/sized_color_3d_npot_03.html": 3.2328, + "deqp/functional/gles3/textureformat/sized_color_3d_pot_00.html": 5.8521, + "deqp/functional/gles3/textureformat/sized_color_3d_pot_01.html": 5.2938, + "deqp/functional/gles3/textureformat/sized_color_3d_pot_02.html": 3.7121, + "deqp/functional/gles3/textureformat/sized_color_3d_pot_03.html": 5.4751, + "deqp/functional/gles3/textureformat/sized_color_cube_npot_00.html": 3.0194, + "deqp/functional/gles3/textureformat/sized_color_cube_npot_01.html": 2.7533, + "deqp/functional/gles3/textureformat/sized_color_cube_npot_02.html": 3.6207, + "deqp/functional/gles3/textureformat/sized_color_cube_npot_03.html": 2.9599, + "deqp/functional/gles3/textureformat/sized_color_cube_pot_00.html": 3.0324, + "deqp/functional/gles3/textureformat/sized_color_cube_pot_01.html": 2.9925, + "deqp/functional/gles3/textureformat/sized_color_cube_pot_02.html": 3.7645, + "deqp/functional/gles3/textureformat/sized_color_cube_pot_03.html": 4.1258, + "deqp/functional/gles3/textureformat/sized_depth_stencil.html": 3.3321, + "deqp/functional/gles3/textureformat/unsized_2d.html": 4.9306, + "deqp/functional/gles3/textureformat/unsized_2d_array.html": 3.7342, + "deqp/functional/gles3/textureformat/unsized_3d.html": 5.3631, + "deqp/functional/gles3/textureshadow/2d_array_linear_always.html": 1.9477, + "deqp/functional/gles3/textureshadow/2d_array_linear_equal.html": 2.5118, + "deqp/functional/gles3/textureshadow/2d_array_linear_greater.html": 2.3105, + "deqp/functional/gles3/textureshadow/2d_array_linear_greater_or_equal.html": 2.6051, + "deqp/functional/gles3/textureshadow/2d_array_linear_less.html": 2.3112, + "deqp/functional/gles3/textureshadow/2d_array_linear_less_or_equal.html": 2.6072, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_linear_always.html": 1.7112, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_linear_equal.html": 3.0418, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_linear_greater.html": 3.8468, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_linear_greater_or_equal.html": 3.4112, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_linear_less.html": 3.402, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_linear_less_or_equal.html": 4.0585, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_linear_never.html": 1.534, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_linear_not_equal.html": 3.0802, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_nearest_always.html": 1.4389, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_nearest_equal.html": 2.6351, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_nearest_greater.html": 2.5743, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_nearest_greater_or_equal.html": 2.6529, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_nearest_less.html": 2.8068, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_nearest_less_or_equal.html": 2.5793, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_nearest_never.html": 1.4071, + "deqp/functional/gles3/textureshadow/2d_array_linear_mipmap_nearest_not_equal.html": 2.5997, + "deqp/functional/gles3/textureshadow/2d_array_linear_never.html": 1.5254, + "deqp/functional/gles3/textureshadow/2d_array_linear_not_equal.html": 2.8252, + "deqp/functional/gles3/textureshadow/2d_array_nearest_always.html": 1.6932, + "deqp/functional/gles3/textureshadow/2d_array_nearest_equal.html": 1.4576, + "deqp/functional/gles3/textureshadow/2d_array_nearest_greater.html": 1.6861, + "deqp/functional/gles3/textureshadow/2d_array_nearest_greater_or_equal.html": 1.4644, + "deqp/functional/gles3/textureshadow/2d_array_nearest_less.html": 1.5119, + "deqp/functional/gles3/textureshadow/2d_array_nearest_less_or_equal.html": 1.7185, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_linear_always.html": 1.5438, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_linear_equal.html": 2.6332, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_linear_greater.html": 1.9934, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_linear_greater_or_equal.html": 2.3039, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_linear_less.html": 2.394, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_linear_less_or_equal.html": 2.1328, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_linear_never.html": 1.6609, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_linear_not_equal.html": 2.1217, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_always.html": 1.5836, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_equal.html": 2.4287, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_greater.html": 2.4472, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_greater_or_equal.html": 2.2293, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_less.html": 2.141, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_less_or_equal.html": 2.3937, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_never.html": 1.6823, + "deqp/functional/gles3/textureshadow/2d_array_nearest_mipmap_nearest_not_equal.html": 2.2143, + "deqp/functional/gles3/textureshadow/2d_array_nearest_never.html": 1.4836, + "deqp/functional/gles3/textureshadow/2d_array_nearest_not_equal.html": 1.4707, + "deqp/functional/gles3/textureshadow/2d_linear_always.html": 1.3184, + "deqp/functional/gles3/textureshadow/2d_linear_equal.html": 2.6363, + "deqp/functional/gles3/textureshadow/2d_linear_greater.html": 2.2101, + "deqp/functional/gles3/textureshadow/2d_linear_greater_or_equal.html": 2.3671, + "deqp/functional/gles3/textureshadow/2d_linear_less.html": 2.4253, + "deqp/functional/gles3/textureshadow/2d_linear_less_or_equal.html": 2.0798, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_linear_always.html": 1.2791, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_linear_equal.html": 3.7472, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_linear_greater.html": 2.9006, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_linear_greater_or_equal.html": 3.6126, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_linear_less.html": 3.9831, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_linear_less_or_equal.html": 2.7496, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_linear_never.html": 1.2537, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_linear_not_equal.html": 3.8321, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_always.html": 1.4291, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_equal.html": 2.2263, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_greater.html": 2.2046, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_greater_or_equal.html": 2.4706, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_less.html": 2.1037, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_less_or_equal.html": 2.5046, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_never.html": 1.2845, + "deqp/functional/gles3/textureshadow/2d_linear_mipmap_nearest_not_equal.html": 2.4117, + "deqp/functional/gles3/textureshadow/2d_linear_never.html": 1.6644, + "deqp/functional/gles3/textureshadow/2d_linear_not_equal.html": 2.4888, + "deqp/functional/gles3/textureshadow/2d_nearest_always.html": 1.4174, + "deqp/functional/gles3/textureshadow/2d_nearest_equal.html": 1.4937, + "deqp/functional/gles3/textureshadow/2d_nearest_greater.html": 1.2961, + "deqp/functional/gles3/textureshadow/2d_nearest_greater_or_equal.html": 1.2695, + "deqp/functional/gles3/textureshadow/2d_nearest_less.html": 1.4323, + "deqp/functional/gles3/textureshadow/2d_nearest_less_or_equal.html": 1.3133, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_linear_always.html": 1.2906, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_linear_equal.html": 3.4495, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_linear_greater.html": 2.0146, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_linear_greater_or_equal.html": 3.3452, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_linear_less.html": 2.6184, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_linear_less_or_equal.html": 2.0403, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_linear_never.html": 1.5026, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_linear_not_equal.html": 3.0811, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_always.html": 1.5744, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_equal.html": 2.0407, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_greater.html": 2.4718, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_greater_or_equal.html": 2.0241, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_less.html": 1.9227, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_less_or_equal.html": 2.2292, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_never.html": 1.2907, + "deqp/functional/gles3/textureshadow/2d_nearest_mipmap_nearest_not_equal.html": 1.943, + "deqp/functional/gles3/textureshadow/2d_nearest_never.html": 1.5156, + "deqp/functional/gles3/textureshadow/2d_nearest_not_equal.html": 1.5115, + "deqp/functional/gles3/textureshadow/cube_linear_always.html": 3.7981, + "deqp/functional/gles3/textureshadow/cube_linear_equal.html": 4.4037, + "deqp/functional/gles3/textureshadow/cube_linear_greater.html": 5.2709, + "deqp/functional/gles3/textureshadow/cube_linear_greater_or_equal.html": 3.872, + "deqp/functional/gles3/textureshadow/cube_linear_less.html": 4.3996, + "deqp/functional/gles3/textureshadow/cube_linear_less_or_equal.html": 5.0014, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_linear_always.html": 2.7875, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_linear_equal.html": 7.456, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_linear_greater.html": 5.4789, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_linear_greater_or_equal.html": 7.5127, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_linear_less.html": 6.8883, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_linear_less_or_equal.html": 5.6376, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_linear_never.html": 3.7527, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_linear_not_equal.html": 6.1681, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_nearest_always.html": 2.5993, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_nearest_equal.html": 5.2456, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_nearest_greater.html": 5.0182, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_nearest_greater_or_equal.html": 4.5593, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_nearest_less.html": 4.8083, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_nearest_less_or_equal.html": 5.3709, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_nearest_never.html": 3.7868, + "deqp/functional/gles3/textureshadow/cube_linear_mipmap_nearest_not_equal.html": 4.7157, + "deqp/functional/gles3/textureshadow/cube_linear_never.html": 2.5471, + "deqp/functional/gles3/textureshadow/cube_linear_not_equal.html": 4.6032, + "deqp/functional/gles3/textureshadow/cube_nearest_always.html": 2.5678, + "deqp/functional/gles3/textureshadow/cube_nearest_equal.html": 3.8303, + "deqp/functional/gles3/textureshadow/cube_nearest_greater.html": 2.6468, + "deqp/functional/gles3/textureshadow/cube_nearest_greater_or_equal.html": 3.941, + "deqp/functional/gles3/textureshadow/cube_nearest_less.html": 4.0258, + "deqp/functional/gles3/textureshadow/cube_nearest_less_or_equal.html": 2.6971, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_linear_always.html": 3.2014, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_linear_equal.html": 6.7453, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_linear_greater.html": 4.9832, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_linear_greater_or_equal.html": 5.109, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_linear_less.html": 6.5312, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_linear_less_or_equal.html": 4.8531, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_linear_never.html": 3.2369, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_linear_not_equal.html": 6.841, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_nearest_always.html": 3.6122, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_nearest_equal.html": 3.9953, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_nearest_greater.html": 3.8603, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_nearest_greater_or_equal.html": 5.0595, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_nearest_less.html": 4.3076, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_nearest_less_or_equal.html": 4.6989, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_nearest_never.html": 2.7754, + "deqp/functional/gles3/textureshadow/cube_nearest_mipmap_nearest_not_equal.html": 5.1078, + "deqp/functional/gles3/textureshadow/cube_nearest_never.html": 3.6544, + "deqp/functional/gles3/textureshadow/cube_nearest_not_equal.html": 2.9169, + "deqp/functional/gles3/texturespecification/basic_copyteximage2d.html": 11.4371, + "deqp/functional/gles3/texturespecification/basic_copytexsubimage2d.html": 9.805, + "deqp/functional/gles3/texturespecification/basic_teximage2d_2d_00.html": 6.6981, + "deqp/functional/gles3/texturespecification/basic_teximage2d_2d_01.html": 5.2655, + "deqp/functional/gles3/texturespecification/basic_teximage2d_cube_00.html": 7.4917, + "deqp/functional/gles3/texturespecification/basic_teximage2d_cube_01.html": 7.7961, + "deqp/functional/gles3/texturespecification/basic_teximage2d_cube_02.html": 7.9268, + "deqp/functional/gles3/texturespecification/basic_teximage2d_cube_03.html": 8.4727, + "deqp/functional/gles3/texturespecification/basic_teximage2d_cube_04.html": 7.2374, + "deqp/functional/gles3/texturespecification/basic_teximage3d_2d_array_00.html": 4.5835, + "deqp/functional/gles3/texturespecification/basic_teximage3d_2d_array_01.html": 4.0944, + "deqp/functional/gles3/texturespecification/basic_teximage3d_2d_array_02.html": 5.0958, + "deqp/functional/gles3/texturespecification/basic_teximage3d_3d_00.html": 4.306, + "deqp/functional/gles3/texturespecification/basic_teximage3d_3d_01.html": 3.3164, + "deqp/functional/gles3/texturespecification/basic_teximage3d_3d_02.html": 4.1125, + "deqp/functional/gles3/texturespecification/basic_teximage3d_3d_03.html": 3.3852, + "deqp/functional/gles3/texturespecification/basic_teximage3d_3d_04.html": 2.9218, + "deqp/functional/gles3/texturespecification/basic_texsubimage2d_2d_00.html": 4.9062, + "deqp/functional/gles3/texturespecification/basic_texsubimage2d_2d_01.html": 3.8954, + "deqp/functional/gles3/texturespecification/basic_texsubimage2d_2d_02.html": 3.7152, + "deqp/functional/gles3/texturespecification/basic_texsubimage2d_cube_00.html": 7.658, + "deqp/functional/gles3/texturespecification/basic_texsubimage2d_cube_01.html": 7.7112, + "deqp/functional/gles3/texturespecification/basic_texsubimage2d_cube_02.html": 9.0806, + "deqp/functional/gles3/texturespecification/basic_texsubimage2d_cube_03.html": 7.4068, + "deqp/functional/gles3/texturespecification/basic_texsubimage2d_cube_04.html": 7.2885, + "deqp/functional/gles3/texturespecification/basic_texsubimage3d_00.html": 3.5797, + "deqp/functional/gles3/texturespecification/basic_texsubimage3d_01.html": 4.2049, + "deqp/functional/gles3/texturespecification/basic_texsubimage3d_02.html": 4.2807, + "deqp/functional/gles3/texturespecification/basic_texsubimage3d_03.html": 3.1932, + "deqp/functional/gles3/texturespecification/basic_texsubimage3d_04.html": 3.343, + "deqp/functional/gles3/texturespecification/random_teximage2d_2d.html": 3.2179, + "deqp/functional/gles3/texturespecification/random_teximage2d_cube.html": 10.3838, + "deqp/functional/gles3/texturespecification/teximage2d_align.html": 8.9609, + "deqp/functional/gles3/texturespecification/teximage2d_depth.html": 1.6153, + "deqp/functional/gles3/texturespecification/teximage2d_depth_pbo.html": 1.9765, + "deqp/functional/gles3/texturespecification/teximage2d_pbo_2d_00.html": 3.3214, + "deqp/functional/gles3/texturespecification/teximage2d_pbo_2d_01.html": 3.2928, + "deqp/functional/gles3/texturespecification/teximage2d_pbo_cube_00.html": 5.8056, + "deqp/functional/gles3/texturespecification/teximage2d_pbo_cube_01.html": 6.3321, + "deqp/functional/gles3/texturespecification/teximage2d_pbo_cube_02.html": 6.6013, + "deqp/functional/gles3/texturespecification/teximage2d_pbo_cube_03.html": 6.2036, + "deqp/functional/gles3/texturespecification/teximage2d_pbo_cube_04.html": 5.4768, + "deqp/functional/gles3/texturespecification/teximage2d_pbo_params.html": 2.4499, + "deqp/functional/gles3/texturespecification/teximage2d_unpack_params.html": 1.2453, + "deqp/functional/gles3/texturespecification/teximage3d_depth.html": 2.0975, + "deqp/functional/gles3/texturespecification/teximage3d_depth_pbo.html": 1.861, + "deqp/functional/gles3/texturespecification/teximage3d_pbo_2d_array_00.html": 3.2256, + "deqp/functional/gles3/texturespecification/teximage3d_pbo_2d_array_01.html": 2.6652, + "deqp/functional/gles3/texturespecification/teximage3d_pbo_3d_00.html": 2.5086, + "deqp/functional/gles3/texturespecification/teximage3d_pbo_3d_01.html": 3.6512, + "deqp/functional/gles3/texturespecification/teximage3d_pbo_params.html": 1.5182, + "deqp/functional/gles3/texturespecification/teximage3d_unpack_params.html": 2.2642, + "deqp/functional/gles3/texturespecification/texstorage2d_format_2d_00.html": 5.8366, + "deqp/functional/gles3/texturespecification/texstorage2d_format_2d_01.html": 4.8444, + "deqp/functional/gles3/texturespecification/texstorage2d_format_2d_02.html": 4.46, + "deqp/functional/gles3/texturespecification/texstorage2d_format_cube_00.html": 6.6881, + "deqp/functional/gles3/texturespecification/texstorage2d_format_cube_01.html": 7.4021, + "deqp/functional/gles3/texturespecification/texstorage2d_format_cube_02.html": 6.2966, + "deqp/functional/gles3/texturespecification/texstorage2d_format_cube_03.html": 6.2564, + "deqp/functional/gles3/texturespecification/texstorage2d_format_cube_04.html": 6.2951, + "deqp/functional/gles3/texturespecification/texstorage2d_format_depth_stencil.html": 5.6155, + "deqp/functional/gles3/texturespecification/texstorage2d_format_size.html": 4.9593, + "deqp/functional/gles3/texturespecification/texstorage3d_format_2d_array_00.html": 3.8158, + "deqp/functional/gles3/texturespecification/texstorage3d_format_2d_array_01.html": 2.5817, + "deqp/functional/gles3/texturespecification/texstorage3d_format_2d_array_02.html": 2.8476, + "deqp/functional/gles3/texturespecification/texstorage3d_format_3d_00.html": 4.462, + "deqp/functional/gles3/texturespecification/texstorage3d_format_3d_01.html": 4.8639, + "deqp/functional/gles3/texturespecification/texstorage3d_format_3d_02.html": 5.4115, + "deqp/functional/gles3/texturespecification/texstorage3d_format_3d_03.html": 4.0468, + "deqp/functional/gles3/texturespecification/texstorage3d_format_depth_stencil.html": 1.8207, + "deqp/functional/gles3/texturespecification/texstorage3d_format_size.html": 2.5504, + "deqp/functional/gles3/texturespecification/texsubimage2d_align.html": 12.6157, + "deqp/functional/gles3/texturespecification/texsubimage2d_depth.html": 1.5775, + "deqp/functional/gles3/texturespecification/texsubimage2d_empty_tex.html": 3.6857, + "deqp/functional/gles3/texturespecification/texsubimage2d_pbo_2d_00.html": 3.9163, + "deqp/functional/gles3/texturespecification/texsubimage2d_pbo_2d_01.html": 3.1734, + "deqp/functional/gles3/texturespecification/texsubimage2d_pbo_cube_00.html": 5.7683, + "deqp/functional/gles3/texturespecification/texsubimage2d_pbo_cube_01.html": 6.9678, + "deqp/functional/gles3/texturespecification/texsubimage2d_pbo_cube_02.html": 6.4081, + "deqp/functional/gles3/texturespecification/texsubimage2d_pbo_cube_03.html": 6.3144, + "deqp/functional/gles3/texturespecification/texsubimage2d_pbo_cube_04.html": 6.5626, + "deqp/functional/gles3/texturespecification/texsubimage2d_pbo_params.html": 3.5734, + "deqp/functional/gles3/texturespecification/texsubimage2d_unpack_params.html": 2.4215, + "deqp/functional/gles3/texturespecification/texsubimage3d_depth.html": 2.0293, + "deqp/functional/gles3/texturespecification/texsubimage3d_pbo_2d_array_00.html": 4.6995, + "deqp/functional/gles3/texturespecification/texsubimage3d_pbo_2d_array_01.html": 4.4586, + "deqp/functional/gles3/texturespecification/texsubimage3d_pbo_3d_00.html": 4.5537, + "deqp/functional/gles3/texturespecification/texsubimage3d_pbo_3d_01.html": 5.4136, + "deqp/functional/gles3/texturespecification/texsubimage3d_pbo_params.html": 1.5929, + "deqp/functional/gles3/texturespecification/texsubimage3d_unpack_params.html": 1.8572, + "deqp/functional/gles3/texturestatequery.html": 1.4467, + "deqp/functional/gles3/texturewrap/eac_r11_npot.html": 0.1822, + "deqp/functional/gles3/texturewrap/eac_r11_pot.html": 0.2219, + "deqp/functional/gles3/texturewrap/eac_rg11_npot.html": 0.1844, + "deqp/functional/gles3/texturewrap/eac_rg11_pot.html": 0.1982, + "deqp/functional/gles3/texturewrap/eac_signed_r11_npot.html": 0.2159, + "deqp/functional/gles3/texturewrap/eac_signed_r11_pot.html": 0.269, + "deqp/functional/gles3/texturewrap/eac_signed_rg11_npot.html": 0.1921, + "deqp/functional/gles3/texturewrap/eac_signed_rg11_pot.html": 0.2157, + "deqp/functional/gles3/texturewrap/etc2_eac_rgba8_npot.html": 0.1834, + "deqp/functional/gles3/texturewrap/etc2_eac_rgba8_pot.html": 0.2416, + "deqp/functional/gles3/texturewrap/etc2_eac_srgb8_alpha8_npot.html": 0.2215, + "deqp/functional/gles3/texturewrap/etc2_eac_srgb8_alpha8_pot.html": 0.203, + "deqp/functional/gles3/texturewrap/etc2_rgb8_npot.html": 0.2088, + "deqp/functional/gles3/texturewrap/etc2_rgb8_pot.html": 0.212, + "deqp/functional/gles3/texturewrap/etc2_rgb8_punchthrough_alpha1_npot.html": 0.3956, + "deqp/functional/gles3/texturewrap/etc2_rgb8_punchthrough_alpha1_pot.html": 0.183, + "deqp/functional/gles3/texturewrap/etc2_srgb8_npot.html": 0.2003, + "deqp/functional/gles3/texturewrap/etc2_srgb8_pot.html": 0.2587, + "deqp/functional/gles3/texturewrap/etc2_srgb8_punchthrough_alpha1_npot.html": 0.2366, + "deqp/functional/gles3/texturewrap/etc2_srgb8_punchthrough_alpha1_pot.html": 0.2279, + "deqp/functional/gles3/texturewrap/rgba8_npot.html": 3.1939, + "deqp/functional/gles3/texturewrap/rgba8_pot.html": 2.772, + "deqp/functional/gles3/transformfeedback/array_element_interleaved_lines.html": 1.0228, + "deqp/functional/gles3/transformfeedback/array_element_interleaved_points.html": 1.0377, + "deqp/functional/gles3/transformfeedback/array_element_interleaved_triangles.html": 1.4992, + "deqp/functional/gles3/transformfeedback/array_element_separate_lines.html": 1.0652, + "deqp/functional/gles3/transformfeedback/array_element_separate_points.html": 1.4356, + "deqp/functional/gles3/transformfeedback/array_element_separate_triangles.html": 1.4721, + "deqp/functional/gles3/transformfeedback/array_interleaved_lines.html": 21.5417, + "deqp/functional/gles3/transformfeedback/array_interleaved_points.html": 21.7795, + "deqp/functional/gles3/transformfeedback/array_interleaved_triangles.html": 28.0712, + "deqp/functional/gles3/transformfeedback/array_separate_lines.html": 7.5194, + "deqp/functional/gles3/transformfeedback/array_separate_points.html": 9.435, + "deqp/functional/gles3/transformfeedback/array_separate_triangles.html": 6.961, + "deqp/functional/gles3/transformfeedback/basic_types_interleaved_lines.html": 26.5312, + "deqp/functional/gles3/transformfeedback/basic_types_interleaved_points.html": 23.7791, + "deqp/functional/gles3/transformfeedback/basic_types_interleaved_triangles.html": 21.7343, + "deqp/functional/gles3/transformfeedback/basic_types_separate_lines.html": 16.8123, + "deqp/functional/gles3/transformfeedback/basic_types_separate_points.html": 13.6588, + "deqp/functional/gles3/transformfeedback/basic_types_separate_triangles.html": 14.0749, + "deqp/functional/gles3/transformfeedback/interpolation_centroid.html": 6.7552, + "deqp/functional/gles3/transformfeedback/interpolation_flat.html": 7.6452, + "deqp/functional/gles3/transformfeedback/interpolation_smooth.html": 7.6075, + "deqp/functional/gles3/transformfeedback/point_size.html": 2.8975, + "deqp/functional/gles3/transformfeedback/position.html": 2.9616, + "deqp/functional/gles3/transformfeedback/random_interleaved_lines.html": 3.1966, + "deqp/functional/gles3/transformfeedback/random_interleaved_points.html": 4.373, + "deqp/functional/gles3/transformfeedback/random_interleaved_triangles.html": 4.723, + "deqp/functional/gles3/transformfeedback/random_separate_lines.html": 3.756, + "deqp/functional/gles3/transformfeedback/random_separate_points.html": 4.7143, + "deqp/functional/gles3/transformfeedback/random_separate_triangles.html": 3.9575, + "deqp/functional/gles3/uniformapi/info_query.html": 12.5515, + "deqp/functional/gles3/uniformapi/random.html": 4.1515, + "deqp/functional/gles3/uniformapi/value_assigned.html": 17.6536, + "deqp/functional/gles3/uniformapi/value_initial.html": 8.8696, + "deqp/functional/gles3/uniformbuffers/instance_array_basic_type.html": 4.8655, + "deqp/functional/gles3/uniformbuffers/multi_basic_types.html": 0.8877, + "deqp/functional/gles3/uniformbuffers/multi_nested_struct.html": 1.1019, + "deqp/functional/gles3/uniformbuffers/random.html": 13.5307, + "deqp/functional/gles3/uniformbuffers/single_basic_array.html": 4.9059, + "deqp/functional/gles3/uniformbuffers/single_basic_type.html": 10.6356, + "deqp/functional/gles3/uniformbuffers/single_nested_struct.html": 1.5733, + "deqp/functional/gles3/uniformbuffers/single_nested_struct_array.html": 1.2598, + "deqp/functional/gles3/uniformbuffers/single_struct.html": 0.809, + "deqp/functional/gles3/uniformbuffers/single_struct_array.html": 2.6834, + "deqp/functional/gles3/vertexarrayobject.html": 0.9648, + "deqp/functional/gles3/vertexarrays/multiple_attributes.count.html": 11.3626, + "deqp/functional/gles3/vertexarrays/multiple_attributes.output.html": 38.436, + "deqp/functional/gles3/vertexarrays/multiple_attributes.storage.html": 2.1204, + "deqp/functional/gles3/vertexarrays/multiple_attributes.stride.html": 34.5426, + "deqp/functional/gles3/vertexarrays/single_attribute.first.html": 26.9484, + "deqp/functional/gles3/vertexarrays/single_attribute.normalize.html": 22.0241, + "deqp/functional/gles3/vertexarrays/single_attribute.offset.html": 24.7036, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.byte.html": 14.6386, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.float.html": 10.8944, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.half.html": 10.7071, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.int.html": 14.6938, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.int_2_10_10_10.html": 5.6257, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.short.html": 17.5267, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.unsigned_byte.html": 15.9356, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.unsigned_int.html": 14.5724, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.unsigned_int_2_10_10_10.html": 4.1632, + "deqp/functional/gles3/vertexarrays/single_attribute.output_type.unsigned_short.html": 17.7372, + "deqp/functional/gles3/vertexarrays/single_attribute.stride.html": 22.269, + "deqp/functional/gles3/vertexarrays/single_attribute.usage.dynamic_copy.html": 12.0312, + "deqp/functional/gles3/vertexarrays/single_attribute.usage.dynamic_draw.html": 11.0325, + "deqp/functional/gles3/vertexarrays/single_attribute.usage.dynamic_read.html": 12.5408, + "deqp/functional/gles3/vertexarrays/single_attribute.usage.static_copy.html": 11.8666, + "deqp/functional/gles3/vertexarrays/single_attribute.usage.static_draw.html": 11.4432, + "deqp/functional/gles3/vertexarrays/single_attribute.usage.static_read.html": 12.2084, + "deqp/functional/gles3/vertexarrays/single_attribute.usage.stream_copy.html": 13.1299, + "deqp/functional/gles3/vertexarrays/single_attribute.usage.stream_draw.html": 16.9954, + "deqp/functional/gles3/vertexarrays/single_attribute.usage.stream_read.html": 10.7852 } } \ No newline at end of file
diff --git a/content/test/data/gpu/webgl_conformance_tests_output.json b/content/test/data/gpu/webgl_conformance_tests_output.json index fc0612a..384d525 100644 --- a/content/test/data/gpu/webgl_conformance_tests_output.json +++ b/content/test/data/gpu/webgl_conformance_tests_output.json
@@ -1,909 +1,946 @@ { "times": { - "WebglConformance_conformance_attribs_gl_bindAttribLocation_aliasing": 0.6384, - "WebglConformance_conformance_attribs_gl_bindAttribLocation_matrix": 0.1679, - "WebglConformance_conformance_attribs_gl_bindAttribLocation_nonexistent_attribute": 0.068, - "WebglConformance_conformance_attribs_gl_bindAttribLocation_repeated": 0.0738, - "WebglConformance_conformance_attribs_gl_disabled_vertex_attrib": 0.1837, - "WebglConformance_conformance_attribs_gl_enable_vertex_attrib": 0.0613, - "WebglConformance_conformance_attribs_gl_matrix_attributes": 0.2357, - "WebglConformance_conformance_attribs_gl_vertex_attrib": 0.3329, - "WebglConformance_conformance_attribs_gl_vertex_attrib_render": 0.1323, - "WebglConformance_conformance_attribs_gl_vertex_attrib_unconsumed_out_of_bounds": 0.1167, - "WebglConformance_conformance_attribs_gl_vertex_attrib_zero_issues": 0.32, - "WebglConformance_conformance_attribs_gl_vertexattribpointer": 0.5861, - "WebglConformance_conformance_attribs_gl_vertexattribpointer_offsets": 0.3778, - "WebglConformance_conformance_buffers_buffer_bind_test": 0.0659, - "WebglConformance_conformance_buffers_buffer_data_and_buffer_sub_data": 0.1164, - "WebglConformance_conformance_buffers_buffer_data_array_buffer_delete": 2.1256, - "WebglConformance_conformance_buffers_buffer_uninitialized": 0.2051, - "WebglConformance_conformance_buffers_element_array_buffer_delete_recreate": 0.0857, - "WebglConformance_conformance_buffers_index_validation": 0.0875, - "WebglConformance_conformance_buffers_index_validation_copies_indices": 0.0865, - "WebglConformance_conformance_buffers_index_validation_crash_with_buffer_sub_data": 0.0906, - "WebglConformance_conformance_buffers_index_validation_large_buffer": 0.1472, - "WebglConformance_conformance_buffers_index_validation_verifies_too_many_indices": 0.0672, - "WebglConformance_conformance_buffers_index_validation_with_resized_buffer": 0.0559, - "WebglConformance_conformance_canvas_buffer_offscreen_test": 0.2037, - "WebglConformance_conformance_canvas_buffer_preserve_test": 0.2519, - "WebglConformance_conformance_canvas_canvas_test": 0.2664, - "WebglConformance_conformance_canvas_canvas_zero_size": 0.1088, - "WebglConformance_conformance_canvas_draw_static_webgl_to_multiple_canvas_test": 0.5202, - "WebglConformance_conformance_canvas_draw_webgl_to_canvas_test": 0.3655, - "WebglConformance_conformance_canvas_drawingbuffer_hd_dpi_test": 0.2971, - "WebglConformance_conformance_canvas_drawingbuffer_static_canvas_test": 0.2199, - "WebglConformance_conformance_canvas_drawingbuffer_test": 0.1635, - "WebglConformance_conformance_canvas_framebuffer_bindings_affected_by_to_data_url": 0.1635, - "WebglConformance_conformance_canvas_framebuffer_bindings_unaffected_on_resize": 0.2072, - "WebglConformance_conformance_canvas_rapid_resizing": 2.3416, - "WebglConformance_conformance_canvas_texture_bindings_unaffected_on_resize": 0.1931, - "WebglConformance_conformance_canvas_to_data_url_test": 0.5237, - "WebglConformance_conformance_canvas_viewport_unchanged_upon_resize": 0.1043, - "WebglConformance_conformance_context_constants_and_properties": 0.0679, - "WebglConformance_conformance_context_context_attribute_preserve_drawing_buffer": 0.2695, - "WebglConformance_conformance_context_context_attributes_alpha_depth_stencil_antialias": 0.3779, - "WebglConformance_conformance_context_context_creation": 4.3364, - "WebglConformance_conformance_context_context_creation_and_destruction": 4.3646, - "WebglConformance_conformance_context_context_eviction_with_garbage_collection": 1.5065, - "WebglConformance_conformance_context_context_hidden_alpha": 0.1514, - "WebglConformance_conformance_context_context_lost": 0.1455, - "WebglConformance_conformance_context_context_lost_restored": 0.207, - "WebglConformance_conformance_context_context_no_alpha_fbo_with_alpha": 0.18, - "WebglConformance_conformance_context_context_release_upon_reload": 1.6855, - "WebglConformance_conformance_context_context_release_with_workers": 1.6403, - "WebglConformance_conformance_context_context_size_change": 0.1346, - "WebglConformance_conformance_context_context_type_test": 0.0722, - "WebglConformance_conformance_context_incorrect_context_object_behaviour": 0.1085, - "WebglConformance_conformance_context_methods": 0.0764, - "WebglConformance_conformance_context_premultiplyalpha_test": 0.5258, - "WebglConformance_conformance_context_resource_sharing_test": 0.1195, - "WebglConformance_conformance_context_user_defined_properties_on_context": 0.0975, - "WebglConformance_conformance_extensions_angle_instanced_arrays": 0.4008, - "WebglConformance_conformance_extensions_angle_instanced_arrays_out_of_bounds": 0.2828, - "WebglConformance_conformance_extensions_ext_blend_minmax": 0.1285, - "WebglConformance_conformance_extensions_ext_disjoint_timer_query": 3.1865, - "WebglConformance_conformance_extensions_ext_frag_depth": 0.3139, - "WebglConformance_conformance_extensions_ext_sRGB": 0.1558, - "WebglConformance_conformance_extensions_ext_shader_texture_lod": 0.3777, - "WebglConformance_conformance_extensions_ext_texture_filter_anisotropic": 0.1008, - "WebglConformance_conformance_extensions_get_extension": 0.3887, - "WebglConformance_conformance_extensions_oes_element_index_uint": 0.2269, - "WebglConformance_conformance_extensions_oes_standard_derivatives": 0.2896, - "WebglConformance_conformance_extensions_oes_texture_float": 0.2434, - "WebglConformance_conformance_extensions_oes_texture_float_linear": 0.3857, - "WebglConformance_conformance_extensions_oes_texture_float_with_canvas": 3.7055, - "WebglConformance_conformance_extensions_oes_texture_float_with_image": 0.2917, - "WebglConformance_conformance_extensions_oes_texture_float_with_image_data": 0.2352, - "WebglConformance_conformance_extensions_oes_texture_float_with_video": 2.5764, - "WebglConformance_conformance_extensions_oes_texture_half_float": 0.3569, - "WebglConformance_conformance_extensions_oes_texture_half_float_linear": 0.4321, - "WebglConformance_conformance_extensions_oes_texture_half_float_with_canvas": 3.7467, - "WebglConformance_conformance_extensions_oes_texture_half_float_with_image": 0.2847, - "WebglConformance_conformance_extensions_oes_texture_half_float_with_image_data": 0.2171, - "WebglConformance_conformance_extensions_oes_texture_half_float_with_video": 2.4516, - "WebglConformance_conformance_extensions_oes_vertex_array_object": 6.1164, - "WebglConformance_conformance_extensions_oes_vertex_array_object_bufferData": 0.8877, - "WebglConformance_conformance_extensions_webgl_compressed_texture_astc": 0.0722, - "WebglConformance_conformance_extensions_webgl_compressed_texture_etc": 0.056, - "WebglConformance_conformance_extensions_webgl_compressed_texture_pvrtc": 0.0624, - "WebglConformance_conformance_extensions_webgl_compressed_texture_s3tc": 0.401, - "WebglConformance_conformance_extensions_webgl_compressed_texture_s3tc_srgb": 0.6526, - "WebglConformance_conformance_extensions_webgl_compressed_texture_size_limit": 4.1255, - "WebglConformance_conformance_extensions_webgl_debug_renderer_info": 0.0905, - "WebglConformance_conformance_extensions_webgl_debug_shaders": 0.1527, - "WebglConformance_conformance_extensions_webgl_depth_texture": 0.1334, - "WebglConformance_conformance_extensions_webgl_draw_buffers": 0.4356, - "WebglConformance_conformance_extensions_webgl_draw_buffers_broadcast_return": 0.1639, - "WebglConformance_conformance_extensions_webgl_draw_buffers_feedback_loop": 6.0322, - "WebglConformance_conformance_extensions_webgl_draw_buffers_framebuffer_unsupported": 0.8746, - "WebglConformance_conformance_extensions_webgl_draw_buffers_max_draw_buffers": 0.1147, - "WebglConformance_conformance_extensions_webgl_shared_resources": 0.0602, - "WebglConformance_conformance_glsl_bugs_angle_ambiguous_function_call": 0.2228, - "WebglConformance_conformance_glsl_bugs_angle_constructor_invalid_parameters": 0.0632, - "WebglConformance_conformance_glsl_bugs_angle_d3d11_compiler_error": 0.0565, - "WebglConformance_conformance_glsl_bugs_angle_dx_variable_bug": 0.0714, - "WebglConformance_conformance_glsl_bugs_array_of_struct_with_int_first_position": 0.1722, - "WebglConformance_conformance_glsl_bugs_bool_type_cast_bug_int_float": 0.1983, - "WebglConformance_conformance_glsl_bugs_compare_loop_index_to_uniform": 0.0882, - "WebglConformance_conformance_glsl_bugs_complex_glsl_does_not_crash": 1.6633, - "WebglConformance_conformance_glsl_bugs_compound_assignment_type_combination": 2.3297, - "WebglConformance_conformance_glsl_bugs_conditional_discard_in_loop": 0.1805, - "WebglConformance_conformance_glsl_bugs_conditional_discard_optimization": 0.1709, - "WebglConformance_conformance_glsl_bugs_constant_precision_qualifier": 0.1679, - "WebglConformance_conformance_glsl_bugs_essl3_shaders_with_webgl1": 0.197, - "WebglConformance_conformance_glsl_bugs_floor_div_cos_should_not_truncate": 0.0889, - "WebglConformance_conformance_glsl_bugs_floored_division_accuracy": 0.1141, - "WebglConformance_conformance_glsl_bugs_fragcoord_linking_bug": 0.122, - "WebglConformance_conformance_glsl_bugs_gl_fragcoord_multisampling_bug": 0.147, - "WebglConformance_conformance_glsl_bugs_global_invariant_does_not_leak_across_shaders": 0.1697, - "WebglConformance_conformance_glsl_bugs_invariant_does_not_leak_across_shaders": 0.1772, - "WebglConformance_conformance_glsl_bugs_logic_inside_block_without_braces": 0.2761, - "WebglConformance_conformance_glsl_bugs_long_expressions_should_not_crash": 0.762, - "WebglConformance_conformance_glsl_bugs_loop_if_loop_gradient": 0.0751, - "WebglConformance_conformance_glsl_bugs_modulo_arithmetic_accuracy": 0.0802, - "WebglConformance_conformance_glsl_bugs_multiplication_assignment": 0.1387, - "WebglConformance_conformance_glsl_bugs_nested_functions_should_not_crash": 0.2261, - "WebglConformance_conformance_glsl_bugs_nested_loops_with_break_and_continue": 0.6054, - "WebglConformance_conformance_glsl_bugs_nested_sequence_operator": 0.1029, - "WebglConformance_conformance_glsl_bugs_pow_of_small_constant_in_user_defined_function": 0.1186, - "WebglConformance_conformance_glsl_bugs_pow_with_constant_exponent_should_not_crash": 0.256, - "WebglConformance_conformance_glsl_bugs_qualcomm_crash": 0.0874, - "WebglConformance_conformance_glsl_bugs_qualcomm_loop_with_continue_crash": 0.1419, - "WebglConformance_conformance_glsl_bugs_sampler_array_struct_function_arg": 0.0009, - "WebglConformance_conformance_glsl_bugs_sampler_array_using_loop_index": 0.1295, - "WebglConformance_conformance_glsl_bugs_sampler_struct_function_arg": 0.0813, - "WebglConformance_conformance_glsl_bugs_sequence_operator_evaluation_order": 0.2577, - "WebglConformance_conformance_glsl_bugs_sketchfab_lighting_shader_crash": 0.186, - "WebglConformance_conformance_glsl_bugs_struct_constructor_highp_bug": 0.0738, - "WebglConformance_conformance_glsl_bugs_temp_expressions_should_not_crash": 0.7563, - "WebglConformance_conformance_glsl_bugs_unary_minus_operator_float_bug": 6.0702, - "WebglConformance_conformance_glsl_bugs_undefined_index_should_not_crash": 0.911, - "WebglConformance_conformance_glsl_bugs_uniforms_should_not_lose_values": 0.1308, - "WebglConformance_conformance_glsl_bugs_varying_arrays_should_not_be_reversed": 0.106, - "WebglConformance_conformance_glsl_constructors_glsl_construct_bvec2": 0.6623, - "WebglConformance_conformance_glsl_constructors_glsl_construct_bvec3": 0.9699, - "WebglConformance_conformance_glsl_constructors_glsl_construct_bvec4": 1.1431, - "WebglConformance_conformance_glsl_constructors_glsl_construct_ivec2": 0.6794, - "WebglConformance_conformance_glsl_constructors_glsl_construct_ivec3": 0.9236, - "WebglConformance_conformance_glsl_constructors_glsl_construct_ivec4": 1.2949, - "WebglConformance_conformance_glsl_constructors_glsl_construct_mat2": 1.0736, - "WebglConformance_conformance_glsl_constructors_glsl_construct_mat3": 0.7514, - "WebglConformance_conformance_glsl_constructors_glsl_construct_mat4": 0.7804, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec2": 0.7685, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec3": 0.9602, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec4": 1.245, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec_mat_corner_cases": 0.19, - "WebglConformance_conformance_glsl_constructors_glsl_construct_vec_mat_index": 0.0749, - "WebglConformance_conformance_glsl_functions_glsl_function": 0.4147, - "WebglConformance_conformance_glsl_functions_glsl_function_abs": 0.2496, - "WebglConformance_conformance_glsl_functions_glsl_function_acos": 0.3444, - "WebglConformance_conformance_glsl_functions_glsl_function_asin": 0.2229, - "WebglConformance_conformance_glsl_functions_glsl_function_atan": 0.3114, - "WebglConformance_conformance_glsl_functions_glsl_function_atan_xy": 0.2634, - "WebglConformance_conformance_glsl_functions_glsl_function_ceil": 0.2432, - "WebglConformance_conformance_glsl_functions_glsl_function_clamp_float": 0.3004, - "WebglConformance_conformance_glsl_functions_glsl_function_clamp_gentype": 0.2, - "WebglConformance_conformance_glsl_functions_glsl_function_cos": 0.2761, - "WebglConformance_conformance_glsl_functions_glsl_function_cross": 0.1211, - "WebglConformance_conformance_glsl_functions_glsl_function_distance": 0.224, - "WebglConformance_conformance_glsl_functions_glsl_function_dot": 0.287, - "WebglConformance_conformance_glsl_functions_glsl_function_faceforward": 0.2997, - "WebglConformance_conformance_glsl_functions_glsl_function_floor": 0.2145, - "WebglConformance_conformance_glsl_functions_glsl_function_fract": 0.2004, - "WebglConformance_conformance_glsl_functions_glsl_function_length": 0.2441, - "WebglConformance_conformance_glsl_functions_glsl_function_max_float": 0.268, - "WebglConformance_conformance_glsl_functions_glsl_function_max_gentype": 0.2419, - "WebglConformance_conformance_glsl_functions_glsl_function_min_float": 0.2694, - "WebglConformance_conformance_glsl_functions_glsl_function_min_gentype": 0.2621, - "WebglConformance_conformance_glsl_functions_glsl_function_mix_float": 0.3104, - "WebglConformance_conformance_glsl_functions_glsl_function_mix_gentype": 0.2764, - "WebglConformance_conformance_glsl_functions_glsl_function_mod_float": 0.3409, - "WebglConformance_conformance_glsl_functions_glsl_function_mod_gentype": 0.2665, - "WebglConformance_conformance_glsl_functions_glsl_function_normalize": 0.2865, - "WebglConformance_conformance_glsl_functions_glsl_function_reflect": 0.2898, - "WebglConformance_conformance_glsl_functions_glsl_function_sign": 0.3005, - "WebglConformance_conformance_glsl_functions_glsl_function_sin": 0.1948, - "WebglConformance_conformance_glsl_functions_glsl_function_smoothstep_float": 0.2992, - "WebglConformance_conformance_glsl_functions_glsl_function_smoothstep_gentype": 0.3545, - "WebglConformance_conformance_glsl_functions_glsl_function_step_float": 0.2949, - "WebglConformance_conformance_glsl_functions_glsl_function_step_gentype": 0.256, - "WebglConformance_conformance_glsl_implicit_add_int_float_vert": 0.0667, - "WebglConformance_conformance_glsl_implicit_add_int_mat2_vert": 0.1405, - "WebglConformance_conformance_glsl_implicit_add_int_mat3_vert": 0.1262, - "WebglConformance_conformance_glsl_implicit_add_int_mat4_vert": 0.0631, - "WebglConformance_conformance_glsl_implicit_add_int_vec2_vert": 0.0715, - "WebglConformance_conformance_glsl_implicit_add_int_vec3_vert": 0.0827, - "WebglConformance_conformance_glsl_implicit_add_int_vec4_vert": 0.0668, - "WebglConformance_conformance_glsl_implicit_add_ivec2_vec2_vert": 0.0671, - "WebglConformance_conformance_glsl_implicit_add_ivec3_vec3_vert": 0.0738, - "WebglConformance_conformance_glsl_implicit_add_ivec4_vec4_vert": 0.0926, - "WebglConformance_conformance_glsl_implicit_assign_int_to_float_vert": 0.0669, - "WebglConformance_conformance_glsl_implicit_assign_ivec2_to_vec2_vert": 0.0665, - "WebglConformance_conformance_glsl_implicit_assign_ivec3_to_vec3_vert": 0.0625, - "WebglConformance_conformance_glsl_implicit_assign_ivec4_to_vec4_vert": 0.0549, - "WebglConformance_conformance_glsl_implicit_construct_struct_vert": 0.1311, - "WebglConformance_conformance_glsl_implicit_divide_int_float_vert": 0.0791, - "WebglConformance_conformance_glsl_implicit_divide_int_mat2_vert": 0.0724, - "WebglConformance_conformance_glsl_implicit_divide_int_mat3_vert": 0.0668, - "WebglConformance_conformance_glsl_implicit_divide_int_mat4_vert": 0.1323, - "WebglConformance_conformance_glsl_implicit_divide_int_vec2_vert": 0.0804, - "WebglConformance_conformance_glsl_implicit_divide_int_vec3_vert": 0.1086, - "WebglConformance_conformance_glsl_implicit_divide_int_vec4_vert": 0.062, - "WebglConformance_conformance_glsl_implicit_divide_ivec2_vec2_vert": 0.0888, - "WebglConformance_conformance_glsl_implicit_divide_ivec3_vec3_vert": 0.1253, - "WebglConformance_conformance_glsl_implicit_divide_ivec4_vec4_vert": 0.0691, - "WebglConformance_conformance_glsl_implicit_equal_int_float_vert": 0.0653, - "WebglConformance_conformance_glsl_implicit_equal_ivec2_vec2_vert": 0.0661, - "WebglConformance_conformance_glsl_implicit_equal_ivec3_vec3_vert": 0.1158, - "WebglConformance_conformance_glsl_implicit_equal_ivec4_vec4_vert": 0.1343, - "WebglConformance_conformance_glsl_implicit_function_int_float_vert": 0.0779, - "WebglConformance_conformance_glsl_implicit_function_ivec2_vec2_vert": 0.0713, - "WebglConformance_conformance_glsl_implicit_function_ivec3_vec3_vert": 0.0637, - "WebglConformance_conformance_glsl_implicit_function_ivec4_vec4_vert": 0.0654, - "WebglConformance_conformance_glsl_implicit_greater_than_equal_vert": 0.0483, - "WebglConformance_conformance_glsl_implicit_greater_than_vert": 0.0642, - "WebglConformance_conformance_glsl_implicit_less_than_equal_vert": 0.0725, - "WebglConformance_conformance_glsl_implicit_less_than_vert": 0.0675, - "WebglConformance_conformance_glsl_implicit_multiply_int_float_vert": 0.0771, - "WebglConformance_conformance_glsl_implicit_multiply_int_mat2_vert": 0.0699, - "WebglConformance_conformance_glsl_implicit_multiply_int_mat3_vert": 0.069, - "WebglConformance_conformance_glsl_implicit_multiply_int_mat4_vert": 0.0701, - "WebglConformance_conformance_glsl_implicit_multiply_int_vec2_vert": 0.0765, - "WebglConformance_conformance_glsl_implicit_multiply_int_vec3_vert": 0.1104, - "WebglConformance_conformance_glsl_implicit_multiply_int_vec4_vert": 0.0584, - "WebglConformance_conformance_glsl_implicit_multiply_ivec2_vec2_vert": 0.066, - "WebglConformance_conformance_glsl_implicit_multiply_ivec3_vec3_vert": 0.0645, - "WebglConformance_conformance_glsl_implicit_multiply_ivec4_vec4_vert": 0.0647, - "WebglConformance_conformance_glsl_implicit_not_equal_int_float_vert": 0.0543, - "WebglConformance_conformance_glsl_implicit_not_equal_ivec2_vec2_vert": 0.1035, - "WebglConformance_conformance_glsl_implicit_not_equal_ivec3_vec3_vert": 0.062, - "WebglConformance_conformance_glsl_implicit_not_equal_ivec4_vec4_vert": 0.0508, - "WebglConformance_conformance_glsl_implicit_subtract_int_float_vert": 0.0525, - "WebglConformance_conformance_glsl_implicit_subtract_int_mat2_vert": 0.0747, - "WebglConformance_conformance_glsl_implicit_subtract_int_mat3_vert": 0.059, - "WebglConformance_conformance_glsl_implicit_subtract_int_mat4_vert": 0.1364, - "WebglConformance_conformance_glsl_implicit_subtract_int_vec2_vert": 0.1627, - "WebglConformance_conformance_glsl_implicit_subtract_int_vec3_vert": 0.0762, - "WebglConformance_conformance_glsl_implicit_subtract_int_vec4_vert": 0.0696, - "WebglConformance_conformance_glsl_implicit_subtract_ivec2_vec2_vert": 0.0758, - "WebglConformance_conformance_glsl_implicit_subtract_ivec3_vec3_vert": 0.129, - "WebglConformance_conformance_glsl_implicit_subtract_ivec4_vec4_vert": 0.0717, - "WebglConformance_conformance_glsl_implicit_ternary_int_float_vert": 0.1331, - "WebglConformance_conformance_glsl_implicit_ternary_ivec2_vec2_vert": 0.0797, - "WebglConformance_conformance_glsl_implicit_ternary_ivec3_vec3_vert": 0.089, - "WebglConformance_conformance_glsl_implicit_ternary_ivec4_vec4_vert": 0.1142, - "WebglConformance_conformance_glsl_literals_float_literal_vert": 0.0571, - "WebglConformance_conformance_glsl_literals_literal_precision": 0.0697, - "WebglConformance_conformance_glsl_literals_overflow_leak_vert": 0.0774, - "WebglConformance_conformance_glsl_matrices_glsl_mat3_construction": 0.1283, - "WebglConformance_conformance_glsl_matrices_glsl_mat4_to_mat3": 0.1393, - "WebglConformance_conformance_glsl_matrices_matrix_compound_multiply": 0.1466, - "WebglConformance_conformance_glsl_misc_attrib_location_length_limits": 0.1018, - "WebglConformance_conformance_glsl_misc_boolean_precision": 0.1796, - "WebglConformance_conformance_glsl_misc_const_variable_initialization": 2.2131, - "WebglConformance_conformance_glsl_misc_embedded_struct_definitions_forbidden": 0.0827, - "WebglConformance_conformance_glsl_misc_empty_declaration": 0.239, - "WebglConformance_conformance_glsl_misc_empty_main_vert": 0.0663, - "WebglConformance_conformance_glsl_misc_expression_list_in_declarator_initializer": 0.7219, - "WebglConformance_conformance_glsl_misc_gl_position_unset_vert": 0.0963, - "WebglConformance_conformance_glsl_misc_global_variable_init": 0.3705, - "WebglConformance_conformance_glsl_misc_glsl_function_nodes": 0.1317, - "WebglConformance_conformance_glsl_misc_glsl_long_variable_names": 0.111, - "WebglConformance_conformance_glsl_misc_glsl_vertex_branch": 0.1155, - "WebglConformance_conformance_glsl_misc_large_loop_compile": 0.6657, - "WebglConformance_conformance_glsl_misc_local_variable_shadowing_outer_function": 0.0938, - "WebglConformance_conformance_glsl_misc_non_ascii_comments_vert": 0.1385, - "WebglConformance_conformance_glsl_misc_non_ascii_vert": 0.132, - "WebglConformance_conformance_glsl_misc_re_compile_re_link": 0.1186, - "WebglConformance_conformance_glsl_misc_sampler_operand": 0.1188, - "WebglConformance_conformance_glsl_misc_sequence_operator_returns_constant": 0.2834, - "WebglConformance_conformance_glsl_misc_shader_precision_format_obeyed": 0.1323, - "WebglConformance_conformance_glsl_misc_shader_struct_scope": 0.243, - "WebglConformance_conformance_glsl_misc_shader_uniform_packing_restrictions": 2.3586, - "WebglConformance_conformance_glsl_misc_shader_varying_packing_restrictions": 0.591, - "WebglConformance_conformance_glsl_misc_shader_with_256_character_define": 0.0912, - "WebglConformance_conformance_glsl_misc_shader_with_256_character_identifier_frag": 0.2521, - "WebglConformance_conformance_glsl_misc_shader_with_257_character_define": 0.111, - "WebglConformance_conformance_glsl_misc_shader_with_257_character_identifier_frag": 0.1158, - "WebglConformance_conformance_glsl_misc_shader_with__webgl_identifier_vert": 0.1357, - "WebglConformance_conformance_glsl_misc_shader_with_arbitrary_indexing_frag": 0.1337, - "WebglConformance_conformance_glsl_misc_shader_with_arbitrary_indexing_vert": 0.1348, - "WebglConformance_conformance_glsl_misc_shader_with_array_of_structs_containing_arrays": 0.1617, - "WebglConformance_conformance_glsl_misc_shader_with_array_of_structs_uniform": 0.1361, - "WebglConformance_conformance_glsl_misc_shader_with_attrib_array_vert": 0.0665, - "WebglConformance_conformance_glsl_misc_shader_with_attrib_struct_vert": 0.0834, - "WebglConformance_conformance_glsl_misc_shader_with_clipvertex_vert": 0.1303, - "WebglConformance_conformance_glsl_misc_shader_with_comma_assignment": 0.126, - "WebglConformance_conformance_glsl_misc_shader_with_comma_conditional_assignment": 0.2295, - "WebglConformance_conformance_glsl_misc_shader_with_comma_separated_variable_declarations": 0.0841, - "WebglConformance_conformance_glsl_misc_shader_with_conditional_scoping": 0.135, - "WebglConformance_conformance_glsl_misc_shader_with_conditional_scoping_negative": 0.1097, - "WebglConformance_conformance_glsl_misc_shader_with_default_precision_frag": 0.1402, - "WebglConformance_conformance_glsl_misc_shader_with_default_precision_vert": 0.1208, - "WebglConformance_conformance_glsl_misc_shader_with_define_line_continuation_frag": 0.0886, - "WebglConformance_conformance_glsl_misc_shader_with_dfdx_frag": 0.119, - "WebglConformance_conformance_glsl_misc_shader_with_dfdx_no_ext_frag": 0.135, - "WebglConformance_conformance_glsl_misc_shader_with_do_loop": 0.1019, - "WebglConformance_conformance_glsl_misc_shader_with_error_directive": 0.0984, - "WebglConformance_conformance_glsl_misc_shader_with_explicit_int_cast_vert": 0.0732, - "WebglConformance_conformance_glsl_misc_shader_with_float_return_value_frag": 0.1045, - "WebglConformance_conformance_glsl_misc_shader_with_for_loop": 0.091, - "WebglConformance_conformance_glsl_misc_shader_with_for_scoping": 0.0824, - "WebglConformance_conformance_glsl_misc_shader_with_frag_depth_frag": 0.058, - "WebglConformance_conformance_glsl_misc_shader_with_function_recursion_frag": 0.0782, - "WebglConformance_conformance_glsl_misc_shader_with_function_scoped_struct": 0.0885, - "WebglConformance_conformance_glsl_misc_shader_with_functional_scoping": 0.1195, - "WebglConformance_conformance_glsl_misc_shader_with_glcolor_vert": 0.1314, - "WebglConformance_conformance_glsl_misc_shader_with_gles_1_frag": 0.1348, - "WebglConformance_conformance_glsl_misc_shader_with_gles_symbol_frag": 0.1373, - "WebglConformance_conformance_glsl_misc_shader_with_global_variable_precision_mismatch": 0.23, - "WebglConformance_conformance_glsl_misc_shader_with_glprojectionmatrix_vert": 0.127, - "WebglConformance_conformance_glsl_misc_shader_with_hex_int_constant_macro": 0.0807, - "WebglConformance_conformance_glsl_misc_shader_with_implicit_vec3_to_vec4_cast_vert": 0.0676, - "WebglConformance_conformance_glsl_misc_shader_with_include_vert": 0.0896, - "WebglConformance_conformance_glsl_misc_shader_with_int_return_value_frag": 0.1402, - "WebglConformance_conformance_glsl_misc_shader_with_invalid_identifier_frag": 0.0573, - "WebglConformance_conformance_glsl_misc_shader_with_ivec2_return_value_frag": 0.0771, - "WebglConformance_conformance_glsl_misc_shader_with_ivec3_return_value_frag": 0.0575, - "WebglConformance_conformance_glsl_misc_shader_with_ivec4_return_value_frag": 0.0875, - "WebglConformance_conformance_glsl_misc_shader_with_limited_indexing_frag": 0.1356, - "WebglConformance_conformance_glsl_misc_shader_with_long_line": 0.0768, - "WebglConformance_conformance_glsl_misc_shader_with_non_ascii_error_frag": 0.0694, - "WebglConformance_conformance_glsl_misc_shader_with_non_reserved_words": 13.2084, - "WebglConformance_conformance_glsl_misc_shader_with_precision_frag": 0.2816, - "WebglConformance_conformance_glsl_misc_shader_with_preprocessor_whitespace": 0.2571, - "WebglConformance_conformance_glsl_misc_shader_with_quoted_error_frag": 0.082, - "WebglConformance_conformance_glsl_misc_shader_with_reserved_words": 2.1587, - "WebglConformance_conformance_glsl_misc_shader_with_short_circuiting_operators": 0.4794, - "WebglConformance_conformance_glsl_misc_shader_with_similar_uniform_array_names": 0.1536, - "WebglConformance_conformance_glsl_misc_shader_with_too_many_uniforms": 0.2462, - "WebglConformance_conformance_glsl_misc_shader_with_two_initializer_types": 0.0782, - "WebglConformance_conformance_glsl_misc_shader_with_undefined_preprocessor_symbol_frag": 0.1339, - "WebglConformance_conformance_glsl_misc_shader_with_uniform_in_loop_condition_vert": 0.1222, - "WebglConformance_conformance_glsl_misc_shader_with_vec2_return_value_frag": 0.0775, - "WebglConformance_conformance_glsl_misc_shader_with_vec3_return_value_frag": 0.1399, - "WebglConformance_conformance_glsl_misc_shader_with_vec4_return_value_frag": 0.1011, - "WebglConformance_conformance_glsl_misc_shader_with_vec4_vec3_vec4_conditional": 0.0757, - "WebglConformance_conformance_glsl_misc_shader_with_version_100_frag": 0.138, - "WebglConformance_conformance_glsl_misc_shader_with_version_100_vert": 0.131, - "WebglConformance_conformance_glsl_misc_shader_with_version_120_vert": 0.1313, - "WebglConformance_conformance_glsl_misc_shader_with_version_130_vert": 0.1354, - "WebglConformance_conformance_glsl_misc_shader_with_webgl_identifier_vert": 0.117, - "WebglConformance_conformance_glsl_misc_shader_with_while_loop": 0.0774, - "WebglConformance_conformance_glsl_misc_shader_without_precision_frag": 0.0706, - "WebglConformance_conformance_glsl_misc_shaders_with_constant_expression_loop_conditions": 0.2458, - "WebglConformance_conformance_glsl_misc_shaders_with_invariance": 0.2419, - "WebglConformance_conformance_glsl_misc_shaders_with_mis_matching_uniforms": 0.9098, - "WebglConformance_conformance_glsl_misc_shaders_with_mis_matching_varyings": 0.3529, - "WebglConformance_conformance_glsl_misc_shaders_with_missing_varyings": 0.2726, - "WebglConformance_conformance_glsl_misc_shaders_with_name_conflicts": 0.086, - "WebglConformance_conformance_glsl_misc_shaders_with_uniform_structs": 0.2155, - "WebglConformance_conformance_glsl_misc_shaders_with_varyings": 0.1961, - "WebglConformance_conformance_glsl_misc_shared": 0.0906, - "WebglConformance_conformance_glsl_misc_struct_assign": 0.2704, - "WebglConformance_conformance_glsl_misc_struct_equals": 0.3047, - "WebglConformance_conformance_glsl_misc_struct_mixed_array_declarators": 0.7865, - "WebglConformance_conformance_glsl_misc_struct_nesting_exceeds_maximum": 0.1071, - "WebglConformance_conformance_glsl_misc_struct_nesting_of_variable_names": 2.5569, - "WebglConformance_conformance_glsl_misc_struct_nesting_under_maximum": 0.0976, - "WebglConformance_conformance_glsl_misc_struct_specifiers_in_uniforms": 0.387, - "WebglConformance_conformance_glsl_misc_struct_unary_operators": 0.5241, - "WebglConformance_conformance_glsl_misc_ternary_operator_on_arrays": 0.1238, - "WebglConformance_conformance_glsl_misc_ternary_operators_in_global_initializers": 0.4018, - "WebglConformance_conformance_glsl_misc_ternary_operators_in_initializers": 0.3356, - "WebglConformance_conformance_glsl_misc_uniform_location_length_limits": 0.0859, - "WebglConformance_conformance_glsl_misc_uninitialized_local_global_variables": 0.2257, - "WebglConformance_conformance_glsl_preprocessor_macro_expansion_tricky": 0.0835, - "WebglConformance_conformance_glsl_reserved__webgl_field_vert": 0.1433, - "WebglConformance_conformance_glsl_reserved__webgl_function_vert": 0.1388, - "WebglConformance_conformance_glsl_reserved__webgl_struct_vert": 0.0614, - "WebglConformance_conformance_glsl_reserved__webgl_variable_vert": 0.0734, - "WebglConformance_conformance_glsl_reserved_webgl_field_vert": 0.06, - "WebglConformance_conformance_glsl_reserved_webgl_function_vert": 0.0682, - "WebglConformance_conformance_glsl_reserved_webgl_struct_vert": 0.1318, - "WebglConformance_conformance_glsl_reserved_webgl_variable_vert": 0.0665, - "WebglConformance_conformance_glsl_samplers_glsl_function_texture2d_bias": 0.1703, - "WebglConformance_conformance_glsl_samplers_glsl_function_texture2dlod": 0.2162, - "WebglConformance_conformance_glsl_samplers_glsl_function_texture2dproj": 0.1781, - "WebglConformance_conformance_glsl_samplers_glsl_function_texture2dprojlod": 0.2884, - "WebglConformance_conformance_glsl_variables_gl_fragcoord": 0.1163, - "WebglConformance_conformance_glsl_variables_gl_fragcoord_xy_values": 0.1495, - "WebglConformance_conformance_glsl_variables_gl_fragdata_and_fragcolor": 0.0666, - "WebglConformance_conformance_glsl_variables_gl_frontfacing": 0.0851, - "WebglConformance_conformance_glsl_variables_gl_pointcoord": 0.1487, - "WebglConformance_conformance_glsl_variables_glsl_built_ins": 0.267, - "WebglConformance_conformance_limits_gl_line_width": 0.1186, - "WebglConformance_conformance_limits_gl_max_texture_dimensions": 0.1641, - "WebglConformance_conformance_limits_gl_min_attribs": 0.0995, - "WebglConformance_conformance_limits_gl_min_textures": 0.0886, - "WebglConformance_conformance_limits_gl_min_uniforms": 0.1291, - "WebglConformance_conformance_misc_bad_arguments_test": 0.2097, - "WebglConformance_conformance_misc_boolean_argument_conversion": 0.1139, - "WebglConformance_conformance_misc_delayed_drawing": 1.1989, - "WebglConformance_conformance_misc_error_reporting": 0.1093, - "WebglConformance_conformance_misc_expando_loss": 0.2591, - "WebglConformance_conformance_misc_functions_returning_strings": 0.1076, - "WebglConformance_conformance_misc_instanceof_test": 0.0997, - "WebglConformance_conformance_misc_invalid_passed_params": 0.1331, - "WebglConformance_conformance_misc_is_object": 0.064, - "WebglConformance_conformance_misc_null_object_behaviour": 0.0941, - "WebglConformance_conformance_misc_object_deletion_behaviour": 0.2143, - "WebglConformance_conformance_misc_shader_precision_format": 0.0738, - "WebglConformance_conformance_misc_type_conversion_test": 0.1614, - "WebglConformance_conformance_misc_uninitialized_test": 0.2701, - "WebglConformance_conformance_misc_webgl_specific": 0.1057, - "WebglConformance_conformance_more_conformance_constants": 0.1557, - "WebglConformance_conformance_more_conformance_getContext": 0.1145, - "WebglConformance_conformance_more_conformance_methods": 0.1077, - "WebglConformance_conformance_more_conformance_quickCheckAPI_A": 0.2217, - "WebglConformance_conformance_more_conformance_quickCheckAPI_B1": 0.2462, - "WebglConformance_conformance_more_conformance_quickCheckAPI_B2": 0.1722, - "WebglConformance_conformance_more_conformance_quickCheckAPI_B3": 0.1698, - "WebglConformance_conformance_more_conformance_quickCheckAPI_B4": 0.1459, - "WebglConformance_conformance_more_conformance_quickCheckAPI_C": 0.1603, - "WebglConformance_conformance_more_conformance_quickCheckAPI_D_G": 0.15, - "WebglConformance_conformance_more_conformance_quickCheckAPI_G_I": 0.186, - "WebglConformance_conformance_more_conformance_quickCheckAPI_L_S": 0.1971, - "WebglConformance_conformance_more_conformance_quickCheckAPI_S_V": 0.1558, - "WebglConformance_conformance_more_conformance_webGLArrays": 0.2222, - "WebglConformance_conformance_more_functions_bindBuffer": 0.1732, - "WebglConformance_conformance_more_functions_bindBufferBadArgs": 0.1682, - "WebglConformance_conformance_more_functions_bindFramebufferLeaveNonZero": 0.1061, - "WebglConformance_conformance_more_functions_bufferData": 0.169, - "WebglConformance_conformance_more_functions_bufferDataBadArgs": 0.1079, - "WebglConformance_conformance_more_functions_bufferSubData": 0.1931, - "WebglConformance_conformance_more_functions_bufferSubDataBadArgs": 0.1118, - "WebglConformance_conformance_more_functions_copyTexImage2D": 0.1446, - "WebglConformance_conformance_more_functions_copyTexImage2DBadArgs": 0.1943, - "WebglConformance_conformance_more_functions_copyTexSubImage2D": 0.1744, - "WebglConformance_conformance_more_functions_copyTexSubImage2DBadArgs": 0.1769, - "WebglConformance_conformance_more_functions_deleteBufferBadArgs": 0.1021, - "WebglConformance_conformance_more_functions_drawArrays": 0.1203, - "WebglConformance_conformance_more_functions_drawArraysOutOfBounds": 0.2196, - "WebglConformance_conformance_more_functions_drawElements": 0.1614, - "WebglConformance_conformance_more_functions_isTests": 0.1686, - "WebglConformance_conformance_more_functions_isTestsBadArgs": 0.1485, - "WebglConformance_conformance_more_functions_readPixels": 0.1476, - "WebglConformance_conformance_more_functions_readPixelsBadArgs": 0.2043, - "WebglConformance_conformance_more_functions_texImage2D": 0.128, - "WebglConformance_conformance_more_functions_texImage2DBadArgs": 0.112, - "WebglConformance_conformance_more_functions_texImage2DHTML": 0.2272, - "WebglConformance_conformance_more_functions_texImage2DHTMLBadArgs": 0.1642, - "WebglConformance_conformance_more_functions_texSubImage2D": 0.1128, - "WebglConformance_conformance_more_functions_texSubImage2DBadArgs": 0.1034, - "WebglConformance_conformance_more_functions_texSubImage2DHTML": 0.1893, - "WebglConformance_conformance_more_functions_texSubImage2DHTMLBadArgs": 0.152, - "WebglConformance_conformance_more_functions_uniformMatrix": 0.7736, - "WebglConformance_conformance_more_functions_uniformMatrixBadArgs": 0.1265, - "WebglConformance_conformance_more_functions_uniformf": 0.1049, - "WebglConformance_conformance_more_functions_uniformfArrayLen1": 0.0995, - "WebglConformance_conformance_more_functions_uniformfBadArgs": 0.1189, - "WebglConformance_conformance_more_functions_uniformi": 0.1172, - "WebglConformance_conformance_more_functions_uniformiBadArgs": 0.121, - "WebglConformance_conformance_more_functions_vertexAttrib": 0.2102, - "WebglConformance_conformance_more_functions_vertexAttribBadArgs": 0.1317, - "WebglConformance_conformance_more_functions_vertexAttribPointer": 0.0947, - "WebglConformance_conformance_more_functions_vertexAttribPointerBadArgs": 0.1667, - "WebglConformance_conformance_more_glsl_arrayOutOfBounds": 0.1032, - "WebglConformance_conformance_more_glsl_uniformOutOfBounds": 0.1126, - "WebglConformance_conformance_offscreencanvas_context_attribute_preserve_drawing_buffer": 0.1692, - "WebglConformance_conformance_offscreencanvas_context_creation": 0.0714, - "WebglConformance_conformance_offscreencanvas_context_creation_worker": 0.1425, - "WebglConformance_conformance_offscreencanvas_context_lost": 0.0706, - "WebglConformance_conformance_offscreencanvas_context_lost_restored": 0.2757, - "WebglConformance_conformance_offscreencanvas_context_lost_restored_worker": 0.1723, - "WebglConformance_conformance_offscreencanvas_context_lost_worker": 0.1412, - "WebglConformance_conformance_offscreencanvas_methods": 0.0994, - "WebglConformance_conformance_offscreencanvas_methods_worker": 0.1357, - "WebglConformance_conformance_offscreencanvas_offscreencanvas_resize": 0.1327, - "WebglConformance_conformance_offscreencanvas_offscreencanvas_transfer_image_bitmap": 0.1459, - "WebglConformance_conformance_ogles_GL_abs_abs_001_to_006": 0.8709, - "WebglConformance_conformance_ogles_GL_acos_acos_001_to_006": 0.771, - "WebglConformance_conformance_ogles_GL_all_all_001_to_004": 0.503, - "WebglConformance_conformance_ogles_GL_any_any_001_to_004": 0.4639, - "WebglConformance_conformance_ogles_GL_array_array_001_to_006": 0.3437, - "WebglConformance_conformance_ogles_GL_asin_asin_001_to_006": 0.808, - "WebglConformance_conformance_ogles_GL_atan_atan_001_to_008": 0.8799, - "WebglConformance_conformance_ogles_GL_atan_atan_009_to_012": 0.6903, - "WebglConformance_conformance_ogles_GL_biConstants_biConstants_001_to_008": 0.6183, - "WebglConformance_conformance_ogles_GL_biConstants_biConstants_009_to_016": 0.6344, - "WebglConformance_conformance_ogles_GL_biuDepthRange_biuDepthRange_001_to_002": 0.3549, - "WebglConformance_conformance_ogles_GL_build_build_001_to_008": 0.178, - "WebglConformance_conformance_ogles_GL_build_build_009_to_016": 0.2872, - "WebglConformance_conformance_ogles_GL_build_build_017_to_024": 0.2437, - "WebglConformance_conformance_ogles_GL_build_build_025_to_032": 0.1836, - "WebglConformance_conformance_ogles_GL_build_build_033_to_040": 0.182, - "WebglConformance_conformance_ogles_GL_build_build_041_to_048": 0.1828, - "WebglConformance_conformance_ogles_GL_build_build_049_to_056": 0.1986, - "WebglConformance_conformance_ogles_GL_build_build_057_to_064": 0.1846, - "WebglConformance_conformance_ogles_GL_build_build_065_to_072": 0.2124, - "WebglConformance_conformance_ogles_GL_build_build_073_to_080": 0.2045, - "WebglConformance_conformance_ogles_GL_build_build_081_to_088": 0.1964, - "WebglConformance_conformance_ogles_GL_build_build_089_to_096": 0.1704, - "WebglConformance_conformance_ogles_GL_build_build_097_to_104": 0.2001, - "WebglConformance_conformance_ogles_GL_build_build_105_to_112": 0.1843, - "WebglConformance_conformance_ogles_GL_build_build_113_to_120": 0.1851, - "WebglConformance_conformance_ogles_GL_build_build_121_to_128": 0.1762, - "WebglConformance_conformance_ogles_GL_build_build_129_to_136": 0.2343, - "WebglConformance_conformance_ogles_GL_build_build_137_to_144": 0.1821, - "WebglConformance_conformance_ogles_GL_build_build_145_to_152": 0.2209, - "WebglConformance_conformance_ogles_GL_build_build_153_to_160": 0.1956, - "WebglConformance_conformance_ogles_GL_build_build_161_to_168": 0.2216, - "WebglConformance_conformance_ogles_GL_build_build_169_to_176": 0.1981, - "WebglConformance_conformance_ogles_GL_build_build_177_to_178": 0.1851, - "WebglConformance_conformance_ogles_GL_built_in_varying_array_out_of_bounds_built_in_varying_array_out_of_bounds_001_to_001": 0.2144, - "WebglConformance_conformance_ogles_GL_ceil_ceil_001_to_006": 0.9666, - "WebglConformance_conformance_ogles_GL_clamp_clamp_001_to_006": 0.5886, - "WebglConformance_conformance_ogles_GL_control_flow_control_flow_001_to_008": 0.6118, - "WebglConformance_conformance_ogles_GL_control_flow_control_flow_009_to_010": 0.2539, - "WebglConformance_conformance_ogles_GL_cos_cos_001_to_006": 0.7039, - "WebglConformance_conformance_ogles_GL_cross_cross_001_to_002": 0.3778, - "WebglConformance_conformance_ogles_GL_default_default_001_to_001": 0.21, - "WebglConformance_conformance_ogles_GL_degrees_degrees_001_to_006": 1.0441, - "WebglConformance_conformance_ogles_GL_discard_discard_001_to_002": 0.2469, - "WebglConformance_conformance_ogles_GL_distance_distance_001_to_006": 0.6304, - "WebglConformance_conformance_ogles_GL_dot_dot_001_to_006": 0.6119, - "WebglConformance_conformance_ogles_GL_equal_equal_001_to_008": 1.061, - "WebglConformance_conformance_ogles_GL_equal_equal_009_to_012": 0.4678, - "WebglConformance_conformance_ogles_GL_exp2_exp2_001_to_008": 0.7954, - "WebglConformance_conformance_ogles_GL_exp2_exp2_009_to_012": 1.1165, - "WebglConformance_conformance_ogles_GL_exp_exp_001_to_008": 0.8644, - "WebglConformance_conformance_ogles_GL_exp_exp_009_to_012": 0.6239, - "WebglConformance_conformance_ogles_GL_faceforward_faceforward_001_to_006": 1.024, - "WebglConformance_conformance_ogles_GL_floor_floor_001_to_006": 0.6997, - "WebglConformance_conformance_ogles_GL_fract_fract_001_to_006": 0.8832, - "WebglConformance_conformance_ogles_GL_functions_functions_001_to_008": 0.609, - "WebglConformance_conformance_ogles_GL_functions_functions_009_to_016": 0.6267, - "WebglConformance_conformance_ogles_GL_functions_functions_017_to_024": 0.5627, - "WebglConformance_conformance_ogles_GL_functions_functions_025_to_032": 0.5879, - "WebglConformance_conformance_ogles_GL_functions_functions_033_to_040": 0.6071, - "WebglConformance_conformance_ogles_GL_functions_functions_041_to_048": 0.5822, - "WebglConformance_conformance_ogles_GL_functions_functions_049_to_056": 0.5936, - "WebglConformance_conformance_ogles_GL_functions_functions_057_to_064": 0.5879, - "WebglConformance_conformance_ogles_GL_functions_functions_065_to_072": 0.6067, - "WebglConformance_conformance_ogles_GL_functions_functions_073_to_080": 0.5999, - "WebglConformance_conformance_ogles_GL_functions_functions_081_to_088": 0.7025, - "WebglConformance_conformance_ogles_GL_functions_functions_089_to_096": 0.5685, - "WebglConformance_conformance_ogles_GL_functions_functions_097_to_104": 0.5967, - "WebglConformance_conformance_ogles_GL_functions_functions_105_to_112": 0.6653, - "WebglConformance_conformance_ogles_GL_functions_functions_113_to_120": 0.6967, - "WebglConformance_conformance_ogles_GL_functions_functions_121_to_126": 0.4381, - "WebglConformance_conformance_ogles_GL_gl_FragCoord_gl_FragCoord_001_to_003": 0.4144, - "WebglConformance_conformance_ogles_GL_gl_FrontFacing_gl_FrontFacing_001_to_001": 0.1495, - "WebglConformance_conformance_ogles_GL_greaterThanEqual_greaterThanEqual_001_to_008": 0.8237, - "WebglConformance_conformance_ogles_GL_greaterThan_greaterThan_001_to_008": 0.8107, - "WebglConformance_conformance_ogles_GL_inversesqrt_inversesqrt_001_to_006": 0.7259, - "WebglConformance_conformance_ogles_GL_length_length_001_to_006": 0.7257, - "WebglConformance_conformance_ogles_GL_lessThanEqual_lessThanEqual_001_to_008": 0.7961, - "WebglConformance_conformance_ogles_GL_lessThan_lessThan_001_to_008": 0.8993, - "WebglConformance_conformance_ogles_GL_log2_log2_001_to_008": 0.8835, - "WebglConformance_conformance_ogles_GL_log2_log2_009_to_012": 1.1583, - "WebglConformance_conformance_ogles_GL_log_log_001_to_008": 0.9636, - "WebglConformance_conformance_ogles_GL_log_log_009_to_012": 1.1883, - "WebglConformance_conformance_ogles_GL_mat3_mat3_001_to_006": 0.545, - "WebglConformance_conformance_ogles_GL_mat_mat_001_to_008": 0.5935, - "WebglConformance_conformance_ogles_GL_mat_mat_009_to_016": 0.5361, - "WebglConformance_conformance_ogles_GL_mat_mat_017_to_024": 0.5986, - "WebglConformance_conformance_ogles_GL_mat_mat_025_to_032": 1.2655, - "WebglConformance_conformance_ogles_GL_mat_mat_033_to_040": 0.7639, - "WebglConformance_conformance_ogles_GL_mat_mat_041_to_046": 0.4664, - "WebglConformance_conformance_ogles_GL_matrixCompMult_matrixCompMult_001_to_004": 0.6252, - "WebglConformance_conformance_ogles_GL_max_max_001_to_006": 0.7022, - "WebglConformance_conformance_ogles_GL_min_min_001_to_006": 0.6127, - "WebglConformance_conformance_ogles_GL_mix_mix_001_to_006": 0.6723, - "WebglConformance_conformance_ogles_GL_mod_mod_001_to_008": 0.7925, - "WebglConformance_conformance_ogles_GL_normalize_normalize_001_to_006": 0.8991, - "WebglConformance_conformance_ogles_GL_notEqual_notEqual_001_to_008": 0.8362, - "WebglConformance_conformance_ogles_GL_notEqual_notEqual_009_to_012": 0.5786, - "WebglConformance_conformance_ogles_GL_not_not_001_to_004": 0.5573, - "WebglConformance_conformance_ogles_GL_operators_operators_001_to_008": 0.6444, - "WebglConformance_conformance_ogles_GL_operators_operators_009_to_016": 0.6153, - "WebglConformance_conformance_ogles_GL_operators_operators_017_to_024": 0.6448, - "WebglConformance_conformance_ogles_GL_operators_operators_025_to_026": 0.317, - "WebglConformance_conformance_ogles_GL_pow_pow_001_to_008": 0.6928, - "WebglConformance_conformance_ogles_GL_pow_pow_009_to_016": 0.9023, - "WebglConformance_conformance_ogles_GL_pow_pow_017_to_024": 1.378, - "WebglConformance_conformance_ogles_GL_radians_radians_001_to_006": 0.9679, - "WebglConformance_conformance_ogles_GL_reflect_reflect_001_to_006": 0.8168, - "WebglConformance_conformance_ogles_GL_refract_refract_001_to_006": 0.8081, - "WebglConformance_conformance_ogles_GL_sign_sign_001_to_006": 0.7877, - "WebglConformance_conformance_ogles_GL_sin_sin_001_to_006": 0.8896, - "WebglConformance_conformance_ogles_GL_smoothstep_smoothstep_001_to_006": 0.7871, - "WebglConformance_conformance_ogles_GL_sqrt_sqrt_001_to_006": 0.7591, - "WebglConformance_conformance_ogles_GL_step_step_001_to_006": 0.7327, - "WebglConformance_conformance_ogles_GL_struct_struct_001_to_008": 0.8787, - "WebglConformance_conformance_ogles_GL_struct_struct_009_to_016": 0.8513, - "WebglConformance_conformance_ogles_GL_struct_struct_017_to_024": 0.8832, - "WebglConformance_conformance_ogles_GL_struct_struct_025_to_032": 0.8886, - "WebglConformance_conformance_ogles_GL_struct_struct_033_to_040": 0.7846, - "WebglConformance_conformance_ogles_GL_struct_struct_041_to_048": 0.7801, - "WebglConformance_conformance_ogles_GL_struct_struct_049_to_056": 0.731, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_001_to_008": 0.8444, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_009_to_016": 0.85, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_017_to_024": 0.8172, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_025_to_032": 0.9253, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_033_to_040": 0.8943, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_041_to_048": 0.8445, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_049_to_056": 0.883, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_057_to_064": 0.8235, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_065_to_072": 0.884, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_073_to_080": 0.8133, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_081_to_088": 0.8089, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_089_to_096": 0.9096, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_097_to_104": 0.7924, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_105_to_112": 0.9358, - "WebglConformance_conformance_ogles_GL_swizzlers_swizzlers_113_to_120": 0.7917, - "WebglConformance_conformance_ogles_GL_tan_tan_001_to_006": 0.6806, - "WebglConformance_conformance_ogles_GL_vec3_vec3_001_to_008": 0.5924, - "WebglConformance_conformance_ogles_GL_vec_vec_001_to_008": 0.5613, - "WebglConformance_conformance_ogles_GL_vec_vec_009_to_016": 0.6104, - "WebglConformance_conformance_ogles_GL_vec_vec_017_to_018": 0.317, - "WebglConformance_conformance_programs_get_active_test": 0.1537, - "WebglConformance_conformance_programs_gl_bind_attrib_location_long_names_test": 0.1345, - "WebglConformance_conformance_programs_gl_bind_attrib_location_test": 0.1146, - "WebglConformance_conformance_programs_gl_get_active_attribute": 0.1831, - "WebglConformance_conformance_programs_gl_get_active_uniform": 0.1332, - "WebglConformance_conformance_programs_gl_getshadersource": 0.1167, - "WebglConformance_conformance_programs_gl_shader_test": 0.1668, - "WebglConformance_conformance_programs_invalid_UTF_16": 0.1005, - "WebglConformance_conformance_programs_program_infolog": 0.0722, - "WebglConformance_conformance_programs_program_test": 0.1408, - "WebglConformance_conformance_programs_use_program_crash_with_discard_in_fragment_shader": 0.1192, - "WebglConformance_conformance_reading_fbo_remains_unchanged_after_read_pixels": 0.1667, - "WebglConformance_conformance_reading_read_pixels_pack_alignment": 0.0841, - "WebglConformance_conformance_reading_read_pixels_test": 0.8699, - "WebglConformance_conformance_renderbuffers_feedback_loop": 0.163, - "WebglConformance_conformance_renderbuffers_framebuffer_object_attachment": 0.3322, - "WebglConformance_conformance_renderbuffers_framebuffer_state_restoration": 0.3654, - "WebglConformance_conformance_renderbuffers_framebuffer_test": 0.0832, - "WebglConformance_conformance_renderbuffers_renderbuffer_initialization": 0.1674, - "WebglConformance_conformance_rendering_clear_after_copyTexImage2D": 0.1009, - "WebglConformance_conformance_rendering_clipping_wide_points": 0.0824, - "WebglConformance_conformance_rendering_culling": 0.0699, - "WebglConformance_conformance_rendering_default_texture_draw_bug": 0.1827, - "WebglConformance_conformance_rendering_draw_arrays_out_of_bounds": 0.1317, - "WebglConformance_conformance_rendering_draw_elements_out_of_bounds": 0.1812, - "WebglConformance_conformance_rendering_draw_with_changing_start_vertex_bug": 0.1733, - "WebglConformance_conformance_rendering_framebuffer_switch": 0.1006, - "WebglConformance_conformance_rendering_framebuffer_texture_clear": 0.2102, - "WebglConformance_conformance_rendering_framebuffer_texture_switch": 0.0735, - "WebglConformance_conformance_rendering_gl_clear": 0.1775, - "WebglConformance_conformance_rendering_gl_drawarrays": 0.082, - "WebglConformance_conformance_rendering_gl_drawelements": 0.07, - "WebglConformance_conformance_rendering_gl_scissor_canvas_dimensions": 0.13, - "WebglConformance_conformance_rendering_gl_scissor_fbo_test": 0.0845, - "WebglConformance_conformance_rendering_gl_scissor_test": 0.1865, - "WebglConformance_conformance_rendering_gl_viewport_test": 0.3298, - "WebglConformance_conformance_rendering_line_loop_tri_fan": 0.0997, - "WebglConformance_conformance_rendering_many_draw_calls": 1.7666, - "WebglConformance_conformance_rendering_more_than_65536_indices": 0.1541, - "WebglConformance_conformance_rendering_multisample_corruption": 6.3189, - "WebglConformance_conformance_rendering_negative_one_index": 0.1464, - "WebglConformance_conformance_rendering_out_of_bounds_index_buffers": 0.0642, - "WebglConformance_conformance_rendering_point_no_attributes": 0.0834, - "WebglConformance_conformance_rendering_point_size": 0.0806, - "WebglConformance_conformance_rendering_point_specific_shader_variables": 0.0842, - "WebglConformance_conformance_rendering_point_with_gl_pointcoord_in_fragment_shader": 0.084, - "WebglConformance_conformance_rendering_polygon_offset": 0.1658, - "WebglConformance_conformance_rendering_simple": 0.0825, - "WebglConformance_conformance_rendering_texture_switch_performance": 0.0009, - "WebglConformance_conformance_rendering_triangle": 0.0674, - "WebglConformance_conformance_state_gl_enable_enum_test": 0.2119, - "WebglConformance_conformance_state_gl_enum_tests": 0.1493, - "WebglConformance_conformance_state_gl_get_calls": 0.1384, - "WebglConformance_conformance_state_gl_geterror": 0.0813, - "WebglConformance_conformance_state_gl_getstring": 0.0544, - "WebglConformance_conformance_state_gl_initial_state": 0.0604, - "WebglConformance_conformance_state_gl_object_get_calls": 8.285, - "WebglConformance_conformance_state_state_uneffected_after_compositing": 0.4035, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_alpha_alpha_unsigned_byte": 0.0639, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.0364, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_luminance_luminance_unsigned_byte": 0.0484, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgb_rgb_unsigned_byte": 0.0667, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.0328, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgba_rgba_unsigned_byte": 0.0379, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.0424, - "WebglConformance_conformance_textures_canvas_sub_rectangle_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.0357, - "WebglConformance_conformance_textures_canvas_tex_2d_alpha_alpha_unsigned_byte": 2.844, - "WebglConformance_conformance_textures_canvas_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 3.53, - "WebglConformance_conformance_textures_canvas_tex_2d_luminance_luminance_unsigned_byte": 3.4314, - "WebglConformance_conformance_textures_canvas_tex_2d_rgb_rgb_unsigned_byte": 14.1769, - "WebglConformance_conformance_textures_canvas_tex_2d_rgb_rgb_unsigned_short_5_6_5": 3.4464, - "WebglConformance_conformance_textures_canvas_tex_2d_rgba_rgba_unsigned_byte": 14.6245, - "WebglConformance_conformance_textures_canvas_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 3.6678, - "WebglConformance_conformance_textures_canvas_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 3.508, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_alpha_alpha_unsigned_byte": 0.3144, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.3268, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_luminance_luminance_unsigned_byte": 0.1533, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgb_rgb_unsigned_byte": 0.3029, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.3129, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgba_rgba_unsigned_byte": 0.2694, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.2589, - "WebglConformance_conformance_textures_image_bitmap_from_blob_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.2752, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_alpha_alpha_unsigned_byte": 0.3368, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.2997, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_luminance_luminance_unsigned_byte": 0.3799, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgb_rgb_unsigned_byte": 0.3059, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.3266, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgba_rgba_unsigned_byte": 0.237, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.2873, - "WebglConformance_conformance_textures_image_bitmap_from_canvas_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.4251, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_alpha_alpha_unsigned_byte": 0.2023, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.1983, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_luminance_luminance_unsigned_byte": 0.1986, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgb_rgb_unsigned_byte": 0.1843, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.1651, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgba_rgba_unsigned_byte": 0.1654, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.2015, - "WebglConformance_conformance_textures_image_bitmap_from_image_bitmap_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.1334, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_alpha_alpha_unsigned_byte": 0.1538, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.2049, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_luminance_luminance_unsigned_byte": 0.1571, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgb_rgb_unsigned_byte": 0.1333, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.126, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgba_rgba_unsigned_byte": 0.1908, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.1669, - "WebglConformance_conformance_textures_image_bitmap_from_image_data_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.2026, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_alpha_alpha_unsigned_byte": 0.2097, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.3293, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_luminance_luminance_unsigned_byte": 0.1891, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgb_rgb_unsigned_byte": 0.1733, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.1701, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgba_rgba_unsigned_byte": 0.2522, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.2601, - "WebglConformance_conformance_textures_image_bitmap_from_image_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.3264, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_alpha_alpha_unsigned_byte": 1.3914, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 1.345, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_luminance_luminance_unsigned_byte": 1.3601, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgb_rgb_unsigned_byte": 1.3486, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgb_rgb_unsigned_short_5_6_5": 1.3421, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgba_rgba_unsigned_byte": 1.3592, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 1.3421, - "WebglConformance_conformance_textures_image_bitmap_from_video_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 1.333, - "WebglConformance_conformance_textures_image_data_tex_2d_alpha_alpha_unsigned_byte": 0.2301, - "WebglConformance_conformance_textures_image_data_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.2165, - "WebglConformance_conformance_textures_image_data_tex_2d_luminance_luminance_unsigned_byte": 0.1989, - "WebglConformance_conformance_textures_image_data_tex_2d_rgb_rgb_unsigned_byte": 0.2007, - "WebglConformance_conformance_textures_image_data_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.2659, - "WebglConformance_conformance_textures_image_data_tex_2d_rgba_rgba_unsigned_byte": 0.1952, - "WebglConformance_conformance_textures_image_data_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.1386, - "WebglConformance_conformance_textures_image_data_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.2602, - "WebglConformance_conformance_textures_image_tex_2d_alpha_alpha_unsigned_byte": 0.1932, - "WebglConformance_conformance_textures_image_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.2656, - "WebglConformance_conformance_textures_image_tex_2d_luminance_luminance_unsigned_byte": 0.4068, - "WebglConformance_conformance_textures_image_tex_2d_rgb_rgb_unsigned_byte": 0.2152, - "WebglConformance_conformance_textures_image_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.2707, - "WebglConformance_conformance_textures_image_tex_2d_rgba_rgba_unsigned_byte": 0.2501, - "WebglConformance_conformance_textures_image_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.3253, - "WebglConformance_conformance_textures_image_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.2051, - "WebglConformance_conformance_textures_misc_compressed_tex_image": 0.0748, - "WebglConformance_conformance_textures_misc_copy_tex_image_2d_formats": 0.1925, - "WebglConformance_conformance_textures_misc_copy_tex_image_and_sub_image_2d": 0.3396, - "WebglConformance_conformance_textures_misc_copy_tex_image_crash": 0.1164, - "WebglConformance_conformance_textures_misc_copytexsubimage2d_large_partial_copy_corruption": 0.2158, - "WebglConformance_conformance_textures_misc_copytexsubimage2d_subrects": 0.0636, - "WebglConformance_conformance_textures_misc_cube_incomplete_fbo": 0.1029, - "WebglConformance_conformance_textures_misc_cube_map_uploads_out_of_order": 1.1555, - "WebglConformance_conformance_textures_misc_default_texture": 0.1274, - "WebglConformance_conformance_textures_misc_gl_get_tex_parameter": 0.1997, - "WebglConformance_conformance_textures_misc_gl_pixelstorei": 0.1666, - "WebglConformance_conformance_textures_misc_gl_teximage": 0.2425, - "WebglConformance_conformance_textures_misc_mipmap_fbo": 0.0903, - "WebglConformance_conformance_textures_misc_origin_clean_conformance": 0.0847, - "WebglConformance_conformance_textures_misc_origin_clean_conformance_offscreencanvas": 0.0676, - "WebglConformance_conformance_textures_misc_tex_image_and_sub_image_2d_with_array_buffer_view": 1.3876, - "WebglConformance_conformance_textures_misc_tex_image_and_uniform_binding_bugs": 0.11, - "WebglConformance_conformance_textures_misc_tex_image_canvas_corruption": 0.1031, - "WebglConformance_conformance_textures_misc_tex_image_webgl": 0.213, - "WebglConformance_conformance_textures_misc_tex_image_with_format_and_type": 0.3378, - "WebglConformance_conformance_textures_misc_tex_image_with_invalid_data": 0.067, - "WebglConformance_conformance_textures_misc_tex_input_validation": 0.2783, - "WebglConformance_conformance_textures_misc_tex_sub_image_2d": 0.1114, - "WebglConformance_conformance_textures_misc_tex_sub_image_2d_bad_args": 6.1216, - "WebglConformance_conformance_textures_misc_tex_video_using_tex_unit_non_zero": 2.6339, - "WebglConformance_conformance_textures_misc_texparameter_test": 0.1116, - "WebglConformance_conformance_textures_misc_texture_active_bind": 0.0865, - "WebglConformance_conformance_textures_misc_texture_active_bind_2": 0.105, - "WebglConformance_conformance_textures_misc_texture_attachment_formats": 0.0957, - "WebglConformance_conformance_textures_misc_texture_clear": 0.1157, - "WebglConformance_conformance_textures_misc_texture_complete": 0.1002, - "WebglConformance_conformance_textures_misc_texture_copying_feedback_loops": 0.0662, - "WebglConformance_conformance_textures_misc_texture_corner_case_videos": 0.323, - "WebglConformance_conformance_textures_misc_texture_cube_as_fbo_attachment": 0.0791, - "WebglConformance_conformance_textures_misc_texture_draw_with_2d_and_cube": 0.1644, - "WebglConformance_conformance_textures_misc_texture_fakeblack": 0.1355, - "WebglConformance_conformance_textures_misc_texture_formats_test": 0.133, - "WebglConformance_conformance_textures_misc_texture_hd_dpi": 0.1811, - "WebglConformance_conformance_textures_misc_texture_mips": 0.1169, - "WebglConformance_conformance_textures_misc_texture_npot": 0.153, - "WebglConformance_conformance_textures_misc_texture_npot_video": 0.4446, - "WebglConformance_conformance_textures_misc_texture_size": 0.7421, - "WebglConformance_conformance_textures_misc_texture_size_cube_maps": 0.5377, - "WebglConformance_conformance_textures_misc_texture_size_limit": 1.5208, - "WebglConformance_conformance_textures_misc_texture_sub_image_cube_maps": 0.1523, - "WebglConformance_conformance_textures_misc_texture_transparent_pixels_initialized": 0.0841, - "WebglConformance_conformance_textures_misc_texture_upload_cube_maps": 0.0784, - "WebglConformance_conformance_textures_misc_texture_upload_size": 1.2913, - "WebglConformance_conformance_textures_svg_image_tex_2d_alpha_alpha_unsigned_byte": 0.1665, - "WebglConformance_conformance_textures_svg_image_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 0.1229, - "WebglConformance_conformance_textures_svg_image_tex_2d_luminance_luminance_unsigned_byte": 0.1621, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgb_rgb_unsigned_byte": 0.1503, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgb_rgb_unsigned_short_5_6_5": 0.161, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgba_rgba_unsigned_byte": 0.1044, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 0.2519, - "WebglConformance_conformance_textures_svg_image_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 0.1119, - "WebglConformance_conformance_textures_video_tex_2d_alpha_alpha_unsigned_byte": 2.4013, - "WebglConformance_conformance_textures_video_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 2.3737, - "WebglConformance_conformance_textures_video_tex_2d_luminance_luminance_unsigned_byte": 2.3801, - "WebglConformance_conformance_textures_video_tex_2d_rgb_rgb_unsigned_byte": 2.5211, - "WebglConformance_conformance_textures_video_tex_2d_rgb_rgb_unsigned_short_5_6_5": 2.346, - "WebglConformance_conformance_textures_video_tex_2d_rgba_rgba_unsigned_byte": 2.3425, - "WebglConformance_conformance_textures_video_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 2.4129, - "WebglConformance_conformance_textures_video_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 2.426, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_alpha_alpha_unsigned_byte": 2.2339, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_luminance_alpha_luminance_alpha_unsigned_byte": 2.083, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_luminance_luminance_unsigned_byte": 2.275, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgb_rgb_unsigned_byte": 8.9478, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgb_rgb_unsigned_short_5_6_5": 2.1965, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgba_rgba_unsigned_byte": 8.7955, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgba_rgba_unsigned_short_4_4_4_4": 2.3054, - "WebglConformance_conformance_textures_webgl_canvas_tex_2d_rgba_rgba_unsigned_short_5_5_5_1": 2.0674, - "WebglConformance_conformance_typedarrays_array_buffer_crash": 0.0357, - "WebglConformance_conformance_typedarrays_array_buffer_view_crash": 0.0498, - "WebglConformance_conformance_typedarrays_array_large_array_tests": 0.0376, - "WebglConformance_conformance_typedarrays_array_unit_tests": 0.0614, - "WebglConformance_conformance_typedarrays_data_view_crash": 0.0392, - "WebglConformance_conformance_typedarrays_data_view_test": 0.059, - "WebglConformance_conformance_typedarrays_typed_arrays_in_workers": 0.1402, - "WebglConformance_conformance_uniforms_gl_uniform_arrays": 0.1155, - "WebglConformance_conformance_uniforms_gl_uniform_bool": 0.0761, - "WebglConformance_conformance_uniforms_gl_uniformmatrix4fv": 0.0825, - "WebglConformance_conformance_uniforms_gl_unknown_uniform": 0.1167, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_00": 1.0577, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_01": 1.0165, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_02": 0.9626, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_03": 0.7459, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_04": 0.9871, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_05": 1.0126, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_06": 0.9597, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_07": 0.9909, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_08": 1.017, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_09": 1.017, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_10": 0.9817, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_11": 0.9835, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_12": 0.9158, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_13": 0.951, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_14": 1.0498, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_15": 0.7985, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_16": 0.907, - "WebglConformance_conformance_uniforms_no_over_optimization_on_uniform_array_17": 0.9782, - "WebglConformance_conformance_uniforms_null_uniform_location": 0.0811, - "WebglConformance_conformance_uniforms_out_of_bounds_uniform_array_access": 5.1894, - "WebglConformance_conformance_uniforms_uniform_default_values": 1.7013, - "WebglConformance_conformance_uniforms_uniform_location": 0.2042, - "WebglConformance_conformance_uniforms_uniform_samplers_test": 15.3275, - "WebglConformance_conformance_uniforms_uniform_values_per_program": 0.7791, - "WebglConformance_deqp_data_gles2_shaders_conditionals": 1.0728, - "WebglConformance_deqp_data_gles2_shaders_constant_expressions": 0.8815, - "WebglConformance_deqp_data_gles2_shaders_constants": 1.9282, - "WebglConformance_deqp_data_gles2_shaders_conversions": 21.0754, - "WebglConformance_deqp_data_gles2_shaders_declarations": 0.1832, - "WebglConformance_deqp_data_gles2_shaders_fragdata": 0.2234, - "WebglConformance_deqp_data_gles2_shaders_functions": 6.13, - "WebglConformance_deqp_data_gles2_shaders_invalid_texture_functions": 0.1936, - "WebglConformance_deqp_data_gles2_shaders_keywords": 2.4475, - "WebglConformance_deqp_data_gles2_shaders_linkage": 1.379, - "WebglConformance_deqp_data_gles2_shaders_preprocessor": 8.7112, - "WebglConformance_deqp_data_gles2_shaders_qualification_order": 0.5202, - "WebglConformance_deqp_data_gles2_shaders_reserved_operators": 0.4003, - "WebglConformance_deqp_data_gles2_shaders_scoping": 1.4228, - "WebglConformance_deqp_data_gles2_shaders_swizzles": 23.2566, - "WebglExtension_ANGLE_instanced_arrays": 0.11, - "WebglExtension_EXT_blend_minmax": 0.0873, - "WebglExtension_EXT_color_buffer_half_float": 0.0767, - "WebglExtension_EXT_disjoint_timer_query": 0.0903, - "WebglExtension_EXT_frag_depth": 0.0715, - "WebglExtension_EXT_sRGB": 0.0731, - "WebglExtension_EXT_shader_texture_lod": 0.0802, - "WebglExtension_EXT_texture_filter_anisotropic": 0.0814, - "WebglExtension_OES_element_index_uint": 0.0682, - "WebglExtension_OES_standard_derivatives": 0.0713, - "WebglExtension_OES_texture_float": 0.0861, - "WebglExtension_OES_texture_float_linear": 0.0692, - "WebglExtension_OES_texture_half_float": 0.077, - "WebglExtension_OES_texture_half_float_linear": 0.1032, - "WebglExtension_OES_vertex_array_object": 0.0729, - "WebglExtension_TestCoverage": 0.0627, - "WebglExtension_WEBGL_color_buffer_float": 0.0631, - "WebglExtension_WEBGL_compressed_texture_astc": 0.0011, - "WebglExtension_WEBGL_compressed_texture_etc1": 0.0009, - "WebglExtension_WEBGL_compressed_texture_pvrtc": 0.0009, - "WebglExtension_WEBGL_compressed_texture_s3tc": 0.0887, - "WebglExtension_WEBGL_compressed_texture_s3tc_srgb": 0.0009, - "WebglExtension_WEBGL_debug_renderer_info": 0.0649, - "WebglExtension_WEBGL_debug_shaders": 0.0647, - "WebglExtension_WEBGL_depth_texture": 0.0692, - "WebglExtension_WEBGL_draw_buffers": 0.0716, - "WebglExtension_WEBGL_lose_context": 0.0775 + "WebglExtension_ANGLE_instanced_arrays": 0.0726, + "WebglExtension_EXT_blend_minmax": 0.0487, + "WebglExtension_EXT_color_buffer_half_float": 0.0444, + "WebglExtension_EXT_disjoint_timer_query": 0.0541, + "WebglExtension_EXT_float_blend": 0.0522, + "WebglExtension_EXT_frag_depth": 0.0534, + "WebglExtension_EXT_sRGB": 0.048, + "WebglExtension_EXT_shader_texture_lod": 0.048, + "WebglExtension_EXT_texture_filter_anisotropic": 0.0514, + "WebglExtension_KHR_parallel_shader_compile": 0.0008, + "WebglExtension_OES_element_index_uint": 0.0485, + "WebglExtension_OES_standard_derivatives": 0.0535, + "WebglExtension_OES_texture_float": 0.0599, + "WebglExtension_OES_texture_float_linear": 0.0483, + "WebglExtension_OES_texture_half_float": 0.0522, + "WebglExtension_OES_texture_half_float_linear": 0.0519, + "WebglExtension_OES_vertex_array_object": 0.0466, + "WebglExtension_TestCoverage": 0.0448, + "WebglExtension_WEBGL_color_buffer_float": 0.0604, + "WebglExtension_WEBGL_compressed_texture_astc": 0.0007, + "WebglExtension_WEBGL_compressed_texture_etc1": 0.0006, + "WebglExtension_WEBGL_compressed_texture_pvrtc": 0.0006, + "WebglExtension_WEBGL_compressed_texture_s3tc": 0.0451, + "WebglExtension_WEBGL_compressed_texture_s3tc_srgb": 0.0007, + "WebglExtension_WEBGL_debug_renderer_info": 0.0533, + "WebglExtension_WEBGL_debug_shaders": 0.0511, + "WebglExtension_WEBGL_depth_texture": 0.049, + "WebglExtension_WEBGL_draw_buffers": 0.0562, + "WebglExtension_WEBGL_lose_context": 0.0476, + "WebglExtension_WEBGL_multi_draw": 0.0587, + "WebglExtension_WEBGL_multi_draw_instanced": 0.0513, + "WebglExtension_WEBGL_video_texture": 0.0569, + "conformance/attribs/gl-bindAttribLocation-aliasing.html": 0.1525, + "conformance/attribs/gl-bindAttribLocation-matrix.html": 0.2017, + "conformance/attribs/gl-bindAttribLocation-nonexistent-attribute.html": 0.068, + "conformance/attribs/gl-bindAttribLocation-repeated.html": 0.069, + "conformance/attribs/gl-disabled-vertex-attrib-update.html": 0.0961, + "conformance/attribs/gl-disabled-vertex-attrib.html": 0.2328, + "conformance/attribs/gl-enable-vertex-attrib.html": 0.0671, + "conformance/attribs/gl-matrix-attributes.html": 0.3062, + "conformance/attribs/gl-vertex-attrib-context-switch.html": 0.134, + "conformance/attribs/gl-vertex-attrib-render.html": 0.0945, + "conformance/attribs/gl-vertex-attrib-unconsumed-out-of-bounds.html": 0.0797, + "conformance/attribs/gl-vertex-attrib-zero-issues.html": 0.178, + "conformance/attribs/gl-vertex-attrib.html": 0.1993, + "conformance/attribs/gl-vertexattribpointer-offsets.html": 0.2495, + "conformance/attribs/gl-vertexattribpointer.html": 0.5791, + "conformance/buffers/buffer-bind-test.html": 0.0514, + "conformance/buffers/buffer-data-and-buffer-sub-data.html": 0.0867, + "conformance/buffers/buffer-data-array-buffer-delete.html": 2.2219, + "conformance/buffers/buffer-data-dynamic-delay.html": 0.2796, + "conformance/buffers/buffer-uninitialized.html": 0.1249, + "conformance/buffers/element-array-buffer-delete-recreate.html": 0.071, + "conformance/buffers/index-validation-copies-indices.html": 0.0613, + "conformance/buffers/index-validation-crash-with-buffer-sub-data.html": 0.0618, + "conformance/buffers/index-validation-large-buffer.html": 0.068, + "conformance/buffers/index-validation-verifies-too-many-indices.html": 0.0672, + "conformance/buffers/index-validation-with-resized-buffer.html": 0.0619, + "conformance/buffers/index-validation.html": 0.0636, + "conformance/buffers/vertex-buffer-updated-after-draw.html": 0.1224, + "conformance/canvas/buffer-offscreen-test.html": 0.1773, + "conformance/canvas/buffer-preserve-test.html": 0.1731, + "conformance/canvas/canvas-test.html": 0.1746, + "conformance/canvas/canvas-zero-size.html": 0.0694, + "conformance/canvas/draw-static-webgl-to-multiple-canvas-test.html": 0.3605, + "conformance/canvas/draw-webgl-to-canvas-test.html": 0.2934, + "conformance/canvas/drawingbuffer-hd-dpi-test.html": 0.2218, + "conformance/canvas/drawingbuffer-static-canvas-test.html": 0.1016, + "conformance/canvas/drawingbuffer-test.html": 0.1058, + "conformance/canvas/framebuffer-bindings-affected-by-to-data-url.html": 0.0916, + "conformance/canvas/framebuffer-bindings-unaffected-on-resize.html": 0.1935, + "conformance/canvas/rapid-resizing.html": 1.7184, + "conformance/canvas/render-after-resize-test.html": 0.1265, + "conformance/canvas/texture-bindings-unaffected-on-resize.html": 0.1638, + "conformance/canvas/to-data-url-test.html": 0.2725, + "conformance/canvas/viewport-unchanged-upon-resize.html": 0.0681, + "conformance/context/constants-and-properties.html": 0.0541, + "conformance/context/context-attribute-preserve-drawing-buffer.html": 0.2695, + "conformance/context/context-attributes-alpha-depth-stencil-antialias.html": 0.2928, + "conformance/context/context-creation-and-destruction.html": 1.2364, + "conformance/context/context-creation.html": 1.2392, + "conformance/context/context-eviction-with-garbage-collection.html": 1.2498, + "conformance/context/context-hidden-alpha.html": 0.2023, + "conformance/context/context-lost-restored.html": 0.1732, + "conformance/context/context-lost.html": 0.1841, + "conformance/context/context-no-alpha-fbo-with-alpha.html": 0.1659, + "conformance/context/context-release-upon-reload.html": 1.2883, + "conformance/context/context-release-with-workers.html": 2.6219, + "conformance/context/context-size-change.html": 0.1689, + "conformance/context/context-type-test.html": 0.0464, + "conformance/context/incorrect-context-object-behaviour.html": 0.1377, + "conformance/context/methods.html": 0.0534, + "conformance/context/premultiplyalpha-test.html": 0.5544, + "conformance/context/user-defined-properties-on-context.html": 0.6152, + "conformance/extensions/angle-instanced-arrays-out-of-bounds.html": 0.1894, + "conformance/extensions/angle-instanced-arrays.html": 0.3384, + "conformance/extensions/ext-blend-minmax.html": 0.1547, + "conformance/extensions/ext-disjoint-timer-query.html": 5.3387, + "conformance/extensions/ext-frag-depth.html": 0.2724, + "conformance/extensions/ext-sRGB.html": 0.1326, + "conformance/extensions/ext-shader-texture-lod.html": 0.4138, + "conformance/extensions/ext-texture-compression-bptc.html": 0.067, + "conformance/extensions/ext-texture-compression-rgtc.html": 0.054, + "conformance/extensions/ext-texture-filter-anisotropic.html": 0.0967, + "conformance/extensions/get-extension.html": 0.8496, + "conformance/extensions/oes-element-index-uint.html": 0.147, + "conformance/extensions/oes-standard-derivatives.html": 0.2675, + "conformance/extensions/oes-texture-float-linear.html": 0.3344, + "conformance/extensions/oes-texture-float-with-canvas.html": 0.8207, + "conformance/extensions/oes-texture-float-with-image-data.html": 0.2489, + "conformance/extensions/oes-texture-float-with-image.html": 0.1743, + "conformance/extensions/oes-texture-float-with-video.html": 1.1355, + "conformance/extensions/oes-texture-float.html": 0.7526, + "conformance/extensions/oes-texture-half-float-linear.html": 0.3297, + "conformance/extensions/oes-texture-half-float-with-canvas.html": 1.0694, + "conformance/extensions/oes-texture-half-float-with-image-data.html": 0.1797, + "conformance/extensions/oes-texture-half-float-with-image.html": 0.2074, + "conformance/extensions/oes-texture-half-float-with-video.html": 0.9706, + "conformance/extensions/oes-texture-half-float.html": 0.75, + "conformance/extensions/oes-vertex-array-object-bufferData.html": 0.1026, + "conformance/extensions/oes-vertex-array-object.html": 0.1199, + "conformance/extensions/webgl-compressed-texture-astc.html": 0.0912, + "conformance/extensions/webgl-compressed-texture-etc.html": 0.0674, + "conformance/extensions/webgl-compressed-texture-etc1.html": 0.0703, + "conformance/extensions/webgl-compressed-texture-pvrtc.html": 0.0667, + "conformance/extensions/webgl-compressed-texture-s3tc-srgb.html": 0.715, + "conformance/extensions/webgl-compressed-texture-s3tc.html": 0.3375, + "conformance/extensions/webgl-compressed-texture-size-limit.html": 2.5368, + "conformance/extensions/webgl-debug-renderer-info.html": 0.0714, + "conformance/extensions/webgl-debug-shaders.html": 0.0673, + "conformance/extensions/webgl-depth-texture.html": 0.1902, + "conformance/extensions/webgl-draw-buffers-broadcast-return.html": 0.1681, + "conformance/extensions/webgl-draw-buffers-framebuffer-unsupported.html": 0.0681, + "conformance/extensions/webgl-draw-buffers-max-draw-buffers.html": 0.1081, + "conformance/extensions/webgl-draw-buffers.html": 6.3079, + "conformance/extensions/webgl-multi-draw.html": 0.9255, + "conformance/glsl/bugs/angle-ambiguous-function-call.html": 0.2062, + "conformance/glsl/bugs/angle-constructor-invalid-parameters.html": 0.0541, + "conformance/glsl/bugs/angle-d3d11-compiler-error.html": 0.0553, + "conformance/glsl/bugs/angle-dx-variable-bug.html": 0.062, + "conformance/glsl/bugs/array-of-struct-with-int-first-position.html": 0.126, + "conformance/glsl/bugs/assign-to-swizzled-twice-in-function.html": 0.0726, + "conformance/glsl/bugs/bool-type-cast-bug-int-float.html": 0.1346, + "conformance/glsl/bugs/compare-loop-index-to-uniform.html": 0.0677, + "conformance/glsl/bugs/complex-glsl-does-not-crash.html": 1.3188, + "conformance/glsl/bugs/compound-assignment-type-combination.html": 0.6487, + "conformance/glsl/bugs/conditional-discard-in-loop.html": 0.1722, + "conformance/glsl/bugs/conditional-discard-optimization.html": 0.1478, + "conformance/glsl/bugs/conditional-texture-fetch.html": 0.0935, + "conformance/glsl/bugs/constant-precision-qualifier.html": 0.1194, + "conformance/glsl/bugs/essl3-shaders-with-webgl1.html": 0.0803, + "conformance/glsl/bugs/floor-div-cos-should-not-truncate.html": 0.088, + "conformance/glsl/bugs/floored-division-accuracy.html": 0.0731, + "conformance/glsl/bugs/fragcoord-linking-bug.html": 0.0606, + "conformance/glsl/bugs/gl-fragcoord-multisampling-bug.html": 0.1335, + "conformance/glsl/bugs/global-invariant-does-not-leak-across-shaders.html": 0.0721, + "conformance/glsl/bugs/if-return-and-elseif.html": 0.0637, + "conformance/glsl/bugs/in-parameter-passed-as-inout-argument-and-global.html": 0.0721, + "conformance/glsl/bugs/init-array-with-loop.html": 0.0768, + "conformance/glsl/bugs/invariant-does-not-leak-across-shaders.html": 0.0546, + "conformance/glsl/bugs/logic-inside-block-without-braces.html": 0.0931, + "conformance/glsl/bugs/long-expressions-should-not-crash.html": 0.3766, + "conformance/glsl/bugs/loop-if-loop-gradient.html": 0.0662, + "conformance/glsl/bugs/modulo-arithmetic-accuracy.html": 0.0805, + "conformance/glsl/bugs/multiplication-assignment.html": 0.0644, + "conformance/glsl/bugs/nested-functions-should-not-crash.html": 0.1917, + "conformance/glsl/bugs/nested-loops-with-break-and-continue.html": 0.1344, + "conformance/glsl/bugs/nested-sequence-operator.html": 0.0776, + "conformance/glsl/bugs/pow-of-small-constant-in-user-defined-function.html": 0.0814, + "conformance/glsl/bugs/pow-with-constant-exponent-should-not-crash.html": 0.0864, + "conformance/glsl/bugs/qualcomm-crash.html": 0.1712, + "conformance/glsl/bugs/qualcomm-loop-with-continue-crash.html": 0.0602, + "conformance/glsl/bugs/sampler-array-struct-function-arg.html": 0.0956, + "conformance/glsl/bugs/sampler-array-using-loop-index.html": 0.0692, + "conformance/glsl/bugs/sampler-struct-function-arg.html": 0.0814, + "conformance/glsl/bugs/sequence-operator-evaluation-order.html": 0.1063, + "conformance/glsl/bugs/sketchfab-lighting-shader-crash.html": 0.1705, + "conformance/glsl/bugs/struct-constructor-highp-bug.html": 0.0714, + "conformance/glsl/bugs/struct-with-single-member-constructor.html": 0.0759, + "conformance/glsl/bugs/temp-expressions-should-not-crash.html": 1.0721, + "conformance/glsl/bugs/unary-minus-operator-float-bug.html": 0.0816, + "conformance/glsl/bugs/undefined-index-should-not-crash.html": 0.0596, + "conformance/glsl/bugs/uniforms-should-not-lose-values.html": 0.1034, + "conformance/glsl/bugs/varying-arrays-should-not-be-reversed.html": 0.1383, + "conformance/glsl/bugs/vector-scalar-arithmetic-inside-loop-complex.html": 0.0795, + "conformance/glsl/bugs/vector-scalar-arithmetic-inside-loop.html": 0.1043, + "conformance/glsl/constructors/glsl-construct-bvec2.html": 0.278, + "conformance/glsl/constructors/glsl-construct-bvec3.html": 0.3479, + "conformance/glsl/constructors/glsl-construct-bvec4.html": 0.5845, + "conformance/glsl/constructors/glsl-construct-ivec2.html": 0.2734, + "conformance/glsl/constructors/glsl-construct-ivec3.html": 0.3378, + "conformance/glsl/constructors/glsl-construct-ivec4.html": 0.4706, + "conformance/glsl/constructors/glsl-construct-mat2.html": 0.4085, + "conformance/glsl/constructors/glsl-construct-mat3.html": 0.241, + "conformance/glsl/constructors/glsl-construct-mat4.html": 0.237, + "conformance/glsl/constructors/glsl-construct-vec-mat-corner-cases.html": 0.072, + "conformance/glsl/constructors/glsl-construct-vec-mat-index.html": 0.0713, + "conformance/glsl/constructors/glsl-construct-vec2.html": 0.3068, + "conformance/glsl/constructors/glsl-construct-vec3.html": 0.3428, + "conformance/glsl/constructors/glsl-construct-vec4.html": 0.4603, + "conformance/glsl/functions/glsl-function-abs.html": 0.3847, + "conformance/glsl/functions/glsl-function-acos.html": 0.2546, + "conformance/glsl/functions/glsl-function-asin.html": 0.2642, + "conformance/glsl/functions/glsl-function-atan-xy.html": 0.3747, + "conformance/glsl/functions/glsl-function-atan.html": 0.278, + "conformance/glsl/functions/glsl-function-ceil.html": 0.2587, + "conformance/glsl/functions/glsl-function-clamp-float.html": 0.27, + "conformance/glsl/functions/glsl-function-clamp-gentype.html": 0.2482, + "conformance/glsl/functions/glsl-function-cos.html": 0.2457, + "conformance/glsl/functions/glsl-function-cross.html": 0.1201, + "conformance/glsl/functions/glsl-function-distance.html": 0.2779, + "conformance/glsl/functions/glsl-function-dot.html": 0.2493, + "conformance/glsl/functions/glsl-function-faceforward.html": 0.2289, + "conformance/glsl/functions/glsl-function-floor.html": 0.251, + "conformance/glsl/functions/glsl-function-fract.html": 0.2279, + "conformance/glsl/functions/glsl-function-length.html": 0.2289, + "conformance/glsl/functions/glsl-function-max-float.html": 0.2331, + "conformance/glsl/functions/glsl-function-max-gentype.html": 0.2307, + "conformance/glsl/functions/glsl-function-min-float.html": 0.2496, + "conformance/glsl/functions/glsl-function-min-gentype.html": 0.242, + "conformance/glsl/functions/glsl-function-mix-float.html": 0.2401, + "conformance/glsl/functions/glsl-function-mix-gentype.html": 0.2283, + "conformance/glsl/functions/glsl-function-mod-float.html": 0.2502, + "conformance/glsl/functions/glsl-function-mod-gentype.html": 0.2667, + "conformance/glsl/functions/glsl-function-normalize.html": 0.3491, + "conformance/glsl/functions/glsl-function-reflect.html": 0.24, + "conformance/glsl/functions/glsl-function-sign.html": 0.2534, + "conformance/glsl/functions/glsl-function-sin.html": 0.227, + "conformance/glsl/functions/glsl-function-smoothstep-float.html": 0.2602, + "conformance/glsl/functions/glsl-function-smoothstep-gentype.html": 0.36, + "conformance/glsl/functions/glsl-function-step-float.html": 0.2328, + "conformance/glsl/functions/glsl-function-step-gentype.html": 0.2242, + "conformance/glsl/functions/glsl-function.html": 0.2275, + "conformance/glsl/implicit/add_int_float.vert.html": 0.1519, + "conformance/glsl/implicit/add_int_mat2.vert.html": 0.0497, + "conformance/glsl/implicit/add_int_mat3.vert.html": 0.0632, + "conformance/glsl/implicit/add_int_mat4.vert.html": 0.0639, + "conformance/glsl/implicit/add_int_vec2.vert.html": 0.0685, + "conformance/glsl/implicit/add_int_vec3.vert.html": 0.0671, + "conformance/glsl/implicit/add_int_vec4.vert.html": 0.0757, + "conformance/glsl/implicit/add_ivec2_vec2.vert.html": 0.0564, + "conformance/glsl/implicit/add_ivec3_vec3.vert.html": 0.082, + "conformance/glsl/implicit/add_ivec4_vec4.vert.html": 0.063, + "conformance/glsl/implicit/assign_int_to_float.vert.html": 0.0661, + "conformance/glsl/implicit/assign_ivec2_to_vec2.vert.html": 0.0691, + "conformance/glsl/implicit/assign_ivec3_to_vec3.vert.html": 0.0756, + "conformance/glsl/implicit/assign_ivec4_to_vec4.vert.html": 0.0522, + "conformance/glsl/implicit/construct_struct.vert.html": 0.0574, + "conformance/glsl/implicit/divide_int_float.vert.html": 0.0513, + "conformance/glsl/implicit/divide_int_mat2.vert.html": 0.0673, + "conformance/glsl/implicit/divide_int_mat3.vert.html": 0.084, + "conformance/glsl/implicit/divide_int_mat4.vert.html": 0.0729, + "conformance/glsl/implicit/divide_int_vec2.vert.html": 0.0538, + "conformance/glsl/implicit/divide_int_vec3.vert.html": 0.0553, + "conformance/glsl/implicit/divide_int_vec4.vert.html": 0.1029, + "conformance/glsl/implicit/divide_ivec2_vec2.vert.html": 0.0697, + "conformance/glsl/implicit/divide_ivec3_vec3.vert.html": 0.0526, + "conformance/glsl/implicit/divide_ivec4_vec4.vert.html": 0.0783, + "conformance/glsl/implicit/equal_int_float.vert.html": 0.0529, + "conformance/glsl/implicit/equal_ivec2_vec2.vert.html": 0.073, + "conformance/glsl/implicit/equal_ivec3_vec3.vert.html": 0.0637, + "conformance/glsl/implicit/equal_ivec4_vec4.vert.html": 0.0662, + "conformance/glsl/implicit/function_int_float.vert.html": 0.0699, + "conformance/glsl/implicit/function_ivec2_vec2.vert.html": 0.074, + "conformance/glsl/implicit/function_ivec3_vec3.vert.html": 0.0551, + "conformance/glsl/implicit/function_ivec4_vec4.vert.html": 0.0599, + "conformance/glsl/implicit/greater_than.vert.html": 0.0587, + "conformance/glsl/implicit/greater_than_equal.vert.html": 0.0678, + "conformance/glsl/implicit/less_than.vert.html": 0.0563, + "conformance/glsl/implicit/less_than_equal.vert.html": 0.0767, + "conformance/glsl/implicit/multiply_int_float.vert.html": 0.0605, + "conformance/glsl/implicit/multiply_int_mat2.vert.html": 0.0726, + "conformance/glsl/implicit/multiply_int_mat3.vert.html": 0.0692, + "conformance/glsl/implicit/multiply_int_mat4.vert.html": 0.0656, + "conformance/glsl/implicit/multiply_int_vec2.vert.html": 0.0692, + "conformance/glsl/implicit/multiply_int_vec3.vert.html": 0.0749, + "conformance/glsl/implicit/multiply_int_vec4.vert.html": 0.0522, + "conformance/glsl/implicit/multiply_ivec2_vec2.vert.html": 0.0748, + "conformance/glsl/implicit/multiply_ivec3_vec3.vert.html": 0.072, + "conformance/glsl/implicit/multiply_ivec4_vec4.vert.html": 0.0525, + "conformance/glsl/implicit/not_equal_int_float.vert.html": 0.0746, + "conformance/glsl/implicit/not_equal_ivec2_vec2.vert.html": 0.0651, + "conformance/glsl/implicit/not_equal_ivec3_vec3.vert.html": 0.0526, + "conformance/glsl/implicit/not_equal_ivec4_vec4.vert.html": 0.0564, + "conformance/glsl/implicit/subtract_int_float.vert.html": 0.0724, + "conformance/glsl/implicit/subtract_int_mat2.vert.html": 0.0563, + "conformance/glsl/implicit/subtract_int_mat3.vert.html": 0.0698, + "conformance/glsl/implicit/subtract_int_mat4.vert.html": 0.0635, + "conformance/glsl/implicit/subtract_int_vec2.vert.html": 0.0658, + "conformance/glsl/implicit/subtract_int_vec3.vert.html": 0.0698, + "conformance/glsl/implicit/subtract_int_vec4.vert.html": 0.074, + "conformance/glsl/implicit/subtract_ivec2_vec2.vert.html": 0.0532, + "conformance/glsl/implicit/subtract_ivec3_vec3.vert.html": 0.0727, + "conformance/glsl/implicit/subtract_ivec4_vec4.vert.html": 0.0742, + "conformance/glsl/implicit/ternary_int_float.vert.html": 0.0546, + "conformance/glsl/implicit/ternary_ivec2_vec2.vert.html": 0.0716, + "conformance/glsl/implicit/ternary_ivec3_vec3.vert.html": 0.0739, + "conformance/glsl/implicit/ternary_ivec4_vec4.vert.html": 0.0519, + "conformance/glsl/literals/float_literal.vert.html": 0.0762, + "conformance/glsl/literals/literal_precision.html": 0.0776, + "conformance/glsl/literals/overflow_leak.vert.html": 0.0671, + "conformance/glsl/matrices/glsl-mat3-construction.html": 0.2402, + "conformance/glsl/matrices/glsl-mat4-to-mat3.html": 0.1147, + "conformance/glsl/matrices/matrix-compound-multiply.html": 0.1907, + "conformance/glsl/misc/attrib-location-length-limits.html": 0.075, + "conformance/glsl/misc/boolean_precision.html": 0.0664, + "conformance/glsl/misc/const-variable-initialization.html": 0.7204, + "conformance/glsl/misc/embedded-struct-definitions-forbidden.html": 0.0634, + "conformance/glsl/misc/empty-declaration.html": 0.0705, + "conformance/glsl/misc/empty_main.vert.html": 0.0608, + "conformance/glsl/misc/expression-list-in-declarator-initializer.html": 0.3173, + "conformance/glsl/misc/fragcolor-fragdata-invariant.html": 0.0668, + "conformance/glsl/misc/gl_position_unset.vert.html": 0.079, + "conformance/glsl/misc/global-variable-init.html": 0.1319, + "conformance/glsl/misc/glsl-function-nodes.html": 0.1085, + "conformance/glsl/misc/glsl-long-variable-names.html": 0.1115, + "conformance/glsl/misc/glsl-vertex-branch.html": 0.0941, + "conformance/glsl/misc/large-loop-compile.html": 0.5852, + "conformance/glsl/misc/local-variable-shadowing-outer-function.html": 0.0599, + "conformance/glsl/misc/non-ascii-comments.vert.html": 0.0585, + "conformance/glsl/misc/non-ascii.vert.html": 0.0686, + "conformance/glsl/misc/re-compile-re-link.html": 0.1002, + "conformance/glsl/misc/sampler-operand.html": 0.0593, + "conformance/glsl/misc/sequence-operator-returns-constant.html": 0.1239, + "conformance/glsl/misc/shader-precision-format-obeyed.html": 0.0777, + "conformance/glsl/misc/shader-struct-scope.html": 0.0988, + "conformance/glsl/misc/shader-uniform-packing-restrictions.html": 1.7515, + "conformance/glsl/misc/shader-varying-packing-restrictions.html": 0.374, + "conformance/glsl/misc/shader-with-256-character-define.html": 0.0719, + "conformance/glsl/misc/shader-with-256-character-identifier.frag.html": 0.0707, + "conformance/glsl/misc/shader-with-257-character-define.html": 0.0802, + "conformance/glsl/misc/shader-with-257-character-identifier.frag.html": 0.0752, + "conformance/glsl/misc/shader-with-_webgl-identifier.vert.html": 0.0487, + "conformance/glsl/misc/shader-with-arbitrary-indexing.frag.html": 0.0721, + "conformance/glsl/misc/shader-with-arbitrary-indexing.vert.html": 0.08, + "conformance/glsl/misc/shader-with-array-of-structs-containing-arrays.html": 0.1093, + "conformance/glsl/misc/shader-with-array-of-structs-uniform.html": 0.1378, + "conformance/glsl/misc/shader-with-attrib-array.vert.html": 0.154, + "conformance/glsl/misc/shader-with-attrib-struct.vert.html": 0.0538, + "conformance/glsl/misc/shader-with-clipvertex.vert.html": 0.0644, + "conformance/glsl/misc/shader-with-comma-assignment.html": 0.0866, + "conformance/glsl/misc/shader-with-comma-conditional-assignment.html": 0.1525, + "conformance/glsl/misc/shader-with-comma-separated-variable-declarations.html": 0.0828, + "conformance/glsl/misc/shader-with-conditional-scoping-negative.html": 0.0592, + "conformance/glsl/misc/shader-with-conditional-scoping.html": 0.0561, + "conformance/glsl/misc/shader-with-default-precision.frag.html": 0.0714, + "conformance/glsl/misc/shader-with-default-precision.vert.html": 0.0646, + "conformance/glsl/misc/shader-with-define-line-continuation.frag.html": 0.0713, + "conformance/glsl/misc/shader-with-dfdx-no-ext.frag.html": 0.0692, + "conformance/glsl/misc/shader-with-dfdx.frag.html": 0.0577, + "conformance/glsl/misc/shader-with-do-loop.html": 0.0526, + "conformance/glsl/misc/shader-with-error-directive.html": 0.0839, + "conformance/glsl/misc/shader-with-explicit-int-cast.vert.html": 0.0786, + "conformance/glsl/misc/shader-with-float-return-value.frag.html": 0.0708, + "conformance/glsl/misc/shader-with-for-loop.html": 0.0924, + "conformance/glsl/misc/shader-with-for-scoping.html": 0.057, + "conformance/glsl/misc/shader-with-frag-depth.frag.html": 0.0554, + "conformance/glsl/misc/shader-with-function-recursion.frag.html": 0.0857, + "conformance/glsl/misc/shader-with-function-scoped-struct.html": 0.0637, + "conformance/glsl/misc/shader-with-functional-scoping.html": 0.0559, + "conformance/glsl/misc/shader-with-glcolor.vert.html": 0.0798, + "conformance/glsl/misc/shader-with-gles-1.frag.html": 0.0658, + "conformance/glsl/misc/shader-with-gles-symbol.frag.html": 0.0716, + "conformance/glsl/misc/shader-with-global-variable-precision-mismatch.html": 0.0665, + "conformance/glsl/misc/shader-with-glprojectionmatrix.vert.html": 0.0725, + "conformance/glsl/misc/shader-with-hex-int-constant-macro.html": 0.0712, + "conformance/glsl/misc/shader-with-implicit-vec3-to-vec4-cast.vert.html": 0.081, + "conformance/glsl/misc/shader-with-include.vert.html": 0.0737, + "conformance/glsl/misc/shader-with-int-return-value.frag.html": 0.0723, + "conformance/glsl/misc/shader-with-invalid-identifier.frag.html": 0.081, + "conformance/glsl/misc/shader-with-ivec2-return-value.frag.html": 0.065, + "conformance/glsl/misc/shader-with-ivec3-return-value.frag.html": 0.0649, + "conformance/glsl/misc/shader-with-ivec4-return-value.frag.html": 0.0801, + "conformance/glsl/misc/shader-with-limited-indexing.frag.html": 0.081, + "conformance/glsl/misc/shader-with-long-line.html": 0.1081, + "conformance/glsl/misc/shader-with-non-ascii-error.frag.html": 0.0661, + "conformance/glsl/misc/shader-with-non-reserved-words.html": 15.1074, + "conformance/glsl/misc/shader-with-precision.frag.html": 0.1657, + "conformance/glsl/misc/shader-with-preprocessor-whitespace.html": 0.0784, + "conformance/glsl/misc/shader-with-quoted-error.frag.html": 0.0815, + "conformance/glsl/misc/shader-with-reserved-words.html": 1.5388, + "conformance/glsl/misc/shader-with-short-circuiting-operators.html": 0.2802, + "conformance/glsl/misc/shader-with-similar-uniform-array-names.html": 0.3321, + "conformance/glsl/misc/shader-with-too-many-uniforms.html": 0.4251, + "conformance/glsl/misc/shader-with-two-initializer-types.html": 0.085, + "conformance/glsl/misc/shader-with-undefined-preprocessor-symbol.frag.html": 0.0526, + "conformance/glsl/misc/shader-with-uniform-in-loop-condition.vert.html": 0.0925, + "conformance/glsl/misc/shader-with-vec2-return-value.frag.html": 0.0674, + "conformance/glsl/misc/shader-with-vec3-return-value.frag.html": 0.0711, + "conformance/glsl/misc/shader-with-vec4-return-value.frag.html": 0.0905, + "conformance/glsl/misc/shader-with-vec4-vec3-vec4-conditional.html": 0.065, + "conformance/glsl/misc/shader-with-version-100.frag.html": 0.0711, + "conformance/glsl/misc/shader-with-version-100.vert.html": 0.091, + "conformance/glsl/misc/shader-with-version-120.vert.html": 0.0638, + "conformance/glsl/misc/shader-with-version-130.vert.html": 0.0834, + "conformance/glsl/misc/shader-with-webgl-identifier.vert.html": 0.0636, + "conformance/glsl/misc/shader-with-while-loop.html": 0.1218, + "conformance/glsl/misc/shader-without-precision.frag.html": 0.0929, + "conformance/glsl/misc/shaders-with-constant-expression-loop-conditions.html": 0.071, + "conformance/glsl/misc/shaders-with-invariance.html": 0.1073, + "conformance/glsl/misc/shaders-with-mis-matching-uniforms.html": 0.1131, + "conformance/glsl/misc/shaders-with-mis-matching-varyings.html": 0.0701, + "conformance/glsl/misc/shaders-with-missing-varyings.html": 0.065, + "conformance/glsl/misc/shaders-with-name-conflicts.html": 0.0792, + "conformance/glsl/misc/shaders-with-uniform-structs.html": 0.0738, + "conformance/glsl/misc/shaders-with-varyings.html": 0.0659, + "conformance/glsl/misc/shared.html": 0.0795, + "conformance/glsl/misc/struct-as-inout-parameter.html": 0.1078, + "conformance/glsl/misc/struct-as-out-parameter.html": 0.1044, + "conformance/glsl/misc/struct-assign.html": 0.1121, + "conformance/glsl/misc/struct-equals.html": 0.1071, + "conformance/glsl/misc/struct-mixed-array-declarators.html": 0.3146, + "conformance/glsl/misc/struct-nesting-exceeds-maximum.html": 0.0583, + "conformance/glsl/misc/struct-nesting-of-variable-names.html": 1.0185, + "conformance/glsl/misc/struct-nesting-under-maximum.html": 0.0621, + "conformance/glsl/misc/struct-specifiers-in-uniforms.html": 0.1658, + "conformance/glsl/misc/struct-unary-operators.html": 0.1565, + "conformance/glsl/misc/ternary-operator-on-arrays.html": 0.0821, + "conformance/glsl/misc/ternary-operators-in-global-initializers.html": 0.1574, + "conformance/glsl/misc/ternary-operators-in-initializers.html": 0.1934, + "conformance/glsl/misc/uniform-location-length-limits.html": 0.0663, + "conformance/glsl/misc/uninitialized-local-global-variables.html": 0.2263, + "conformance/glsl/preprocessor/macro-expansion-tricky.html": 0.067, + "conformance/glsl/reserved/_webgl_field.vert.html": 0.0687, + "conformance/glsl/reserved/_webgl_function.vert.html": 0.0546, + "conformance/glsl/reserved/_webgl_struct.vert.html": 0.0742, + "conformance/glsl/reserved/_webgl_variable.vert.html": 0.0765, + "conformance/glsl/reserved/webgl_field.vert.html": 0.0554, + "conformance/glsl/reserved/webgl_function.vert.html": 0.0577, + "conformance/glsl/reserved/webgl_struct.vert.html": 0.0553, + "conformance/glsl/reserved/webgl_variable.vert.html": 0.0782, + "conformance/glsl/samplers/glsl-function-texture2d-bias.html": 0.1784, + "conformance/glsl/samplers/glsl-function-texture2dlod.html": 0.1816, + "conformance/glsl/samplers/glsl-function-texture2dproj.html": 0.1136, + "conformance/glsl/samplers/glsl-function-texture2dprojlod.html": 0.5508, + "conformance/glsl/variables/gl-fragcoord-xy-values.html": 0.1054, + "conformance/glsl/variables/gl-fragcoord.html": 0.081, + "conformance/glsl/variables/gl-fragdata-and-fragcolor.html": 0.0686, + "conformance/glsl/variables/gl-frontfacing.html": 0.0794, + "conformance/glsl/variables/gl-pointcoord.html": 0.1191, + "conformance/glsl/variables/glsl-built-ins.html": 0.1718, + "conformance/limits/gl-line-width.html": 0.1207, + "conformance/limits/gl-max-texture-dimensions.html": 0.0959, + "conformance/limits/gl-min-attribs.html": 0.0788, + "conformance/limits/gl-min-textures.html": 0.0662, + "conformance/limits/gl-min-uniforms.html": 0.0715, + "conformance/misc/bad-arguments-test.html": 0.1536, + "conformance/misc/boolean-argument-conversion.html": 0.0692, + "conformance/misc/delayed-drawing.html": 1.0653, + "conformance/misc/error-reporting.html": 0.0799, + "conformance/misc/expando-loss.html": 1.0716, + "conformance/misc/functions-returning-strings.html": 0.0746, + "conformance/misc/instanceof-test.html": 0.0783, + "conformance/misc/invalid-passed-params.html": 0.1272, + "conformance/misc/is-object.html": 0.0562, + "conformance/misc/null-object-behaviour.html": 0.068, + "conformance/misc/object-deletion-behaviour.html": 0.1994, + "conformance/misc/shader-precision-format.html": 0.06, + "conformance/misc/type-conversion-test.html": 0.1358, + "conformance/misc/uninitialized-test.html": 0.2003, + "conformance/misc/webgl-specific-stencil-settings.html": 0.1837, + "conformance/misc/webgl-specific.html": 0.0739, + "conformance/more/conformance/constants.html": 0.1304, + "conformance/more/conformance/getContext.html": 0.0712, + "conformance/more/conformance/methods.html": 0.074, + "conformance/more/conformance/quickCheckAPI-A.html": 0.1831, + "conformance/more/conformance/quickCheckAPI-B1.html": 0.1715, + "conformance/more/conformance/quickCheckAPI-B2.html": 0.1713, + "conformance/more/conformance/quickCheckAPI-B3.html": 0.1732, + "conformance/more/conformance/quickCheckAPI-B4.html": 0.1709, + "conformance/more/conformance/quickCheckAPI-C.html": 0.1753, + "conformance/more/conformance/quickCheckAPI-D_G.html": 3.1122, + "conformance/more/conformance/quickCheckAPI-G_I.html": 0.1912, + "conformance/more/conformance/quickCheckAPI-L_S.html": 0.1866, + "conformance/more/conformance/quickCheckAPI-S_V.html": 0.1708, + "conformance/more/conformance/webGLArrays.html": 0.101, + "conformance/more/functions/bindBuffer.html": 0.0709, + "conformance/more/functions/bindBufferBadArgs.html": 0.1091, + "conformance/more/functions/bindFramebufferLeaveNonZero.html": 0.1146, + "conformance/more/functions/bufferData.html": 0.1237, + "conformance/more/functions/bufferDataBadArgs.html": 0.0774, + "conformance/more/functions/bufferSubData.html": 0.1032, + "conformance/more/functions/bufferSubDataBadArgs.html": 0.096, + "conformance/more/functions/copyTexImage2D.html": 0.1182, + "conformance/more/functions/copyTexImage2DBadArgs.html": 0.0808, + "conformance/more/functions/copyTexSubImage2D.html": 0.1185, + "conformance/more/functions/copyTexSubImage2DBadArgs.html": 0.0995, + "conformance/more/functions/deleteBufferBadArgs.html": 0.0703, + "conformance/more/functions/drawArrays.html": 0.1251, + "conformance/more/functions/drawElements.html": 0.1096, + "conformance/more/functions/isTests.html": 0.1092, + "conformance/more/functions/isTestsBadArgs.html": 0.1522, + "conformance/more/functions/readPixels.html": 0.093, + "conformance/more/functions/readPixelsBadArgs.html": 0.1611, + "conformance/more/functions/texImage2D.html": 0.0792, + "conformance/more/functions/texImage2DBadArgs.html": 0.0878, + "conformance/more/functions/texImage2DHTML.html": 0.1774, + "conformance/more/functions/texImage2DHTMLBadArgs.html": 0.1254, + "conformance/more/functions/texSubImage2D.html": 0.0774, + "conformance/more/functions/texSubImage2DBadArgs.html": 0.1001, + "conformance/more/functions/texSubImage2DHTML.html": 0.1704, + "conformance/more/functions/texSubImage2DHTMLBadArgs.html": 0.0852, + "conformance/more/functions/uniformMatrix.html": 0.1057, + "conformance/more/functions/uniformMatrixBadArgs.html": 0.107, + "conformance/more/functions/uniformf.html": 0.105, + "conformance/more/functions/uniformfArrayLen1.html": 0.1079, + "conformance/more/functions/uniformfBadArgs.html": 0.0985, + "conformance/more/functions/uniformi.html": 0.1165, + "conformance/more/functions/uniformiBadArgs.html": 0.0991, + "conformance/more/functions/vertexAttrib.html": 0.0842, + "conformance/more/functions/vertexAttribBadArgs.html": 0.1011, + "conformance/more/functions/vertexAttribPointer.html": 0.0866, + "conformance/more/functions/vertexAttribPointerBadArgs.html": 0.0991, + "conformance/more/glsl/arrayOutOfBounds.html": 0.1013, + "conformance/more/glsl/uniformOutOfBounds.html": 0.0882, + "conformance/offscreencanvas/context-attribute-preserve-drawing-buffer.html": 0.635, + "conformance/offscreencanvas/context-creation-worker.html": 0.1301, + "conformance/offscreencanvas/context-creation.html": 0.0622, + "conformance/offscreencanvas/context-lost-restored-worker.html": 0.2398, + "conformance/offscreencanvas/context-lost-restored.html": 0.1622, + "conformance/offscreencanvas/context-lost-worker.html": 0.1319, + "conformance/offscreencanvas/context-lost.html": 0.1729, + "conformance/offscreencanvas/methods-worker.html": 0.2253, + "conformance/offscreencanvas/methods.html": 0.0501, + "conformance/offscreencanvas/offscreencanvas-resize.html": 0.0528, + "conformance/offscreencanvas/offscreencanvas-transfer-image-bitmap.html": 0.2345, + "conformance/ogles/GL/abs/abs_001_to_006.html": 1.5671, + "conformance/ogles/GL/acos/acos_001_to_006.html": 1.6539, + "conformance/ogles/GL/all/all_001_to_004.html": 1.5076, + "conformance/ogles/GL/any/any_001_to_004.html": 1.518, + "conformance/ogles/GL/array/array_001_to_006.html": 0.3425, + "conformance/ogles/GL/asin/asin_001_to_006.html": 1.6501, + "conformance/ogles/GL/atan/atan_001_to_008.html": 3.6629, + "conformance/ogles/GL/atan/atan_009_to_012.html": 1.6989, + "conformance/ogles/GL/biConstants/biConstants_001_to_008.html": 2.3244, + "conformance/ogles/GL/biConstants/biConstants_009_to_016.html": 1.615, + "conformance/ogles/GL/biuDepthRange/biuDepthRange_001_to_002.html": 0.806, + "conformance/ogles/GL/build/build_001_to_008.html": 0.1581, + "conformance/ogles/GL/build/build_009_to_016.html": 0.2502, + "conformance/ogles/GL/build/build_017_to_024.html": 0.1624, + "conformance/ogles/GL/build/build_025_to_032.html": 0.1513, + "conformance/ogles/GL/build/build_033_to_040.html": 0.1491, + "conformance/ogles/GL/build/build_041_to_048.html": 0.154, + "conformance/ogles/GL/build/build_049_to_056.html": 0.1581, + "conformance/ogles/GL/build/build_057_to_064.html": 0.1599, + "conformance/ogles/GL/build/build_065_to_072.html": 0.1493, + "conformance/ogles/GL/build/build_073_to_080.html": 0.1574, + "conformance/ogles/GL/build/build_081_to_088.html": 0.1486, + "conformance/ogles/GL/build/build_089_to_096.html": 0.15, + "conformance/ogles/GL/build/build_097_to_104.html": 0.1548, + "conformance/ogles/GL/build/build_105_to_112.html": 0.1524, + "conformance/ogles/GL/build/build_113_to_120.html": 0.1539, + "conformance/ogles/GL/build/build_121_to_128.html": 0.1527, + "conformance/ogles/GL/build/build_129_to_136.html": 0.1496, + "conformance/ogles/GL/build/build_137_to_144.html": 0.1646, + "conformance/ogles/GL/build/build_145_to_152.html": 0.1528, + "conformance/ogles/GL/build/build_153_to_160.html": 0.1555, + "conformance/ogles/GL/build/build_161_to_168.html": 0.1603, + "conformance/ogles/GL/build/build_169_to_176.html": 0.1529, + "conformance/ogles/GL/build/build_177_to_178.html": 0.1543, + "conformance/ogles/GL/built_in_varying_array_out_of_bounds/built_in_varying_array_out_of_bounds_001_to_001.html": 0.1702, + "conformance/ogles/GL/ceil/ceil_001_to_006.html": 1.5485, + "conformance/ogles/GL/clamp/clamp_001_to_006.html": 1.5978, + "conformance/ogles/GL/control_flow/control_flow_001_to_008.html": 0.5549, + "conformance/ogles/GL/control_flow/control_flow_009_to_010.html": 0.2824, + "conformance/ogles/GL/cos/cos_001_to_006.html": 1.6715, + "conformance/ogles/GL/cross/cross_001_to_002.html": 0.8327, + "conformance/ogles/GL/default/default_001_to_001.html": 0.2652, + "conformance/ogles/GL/degrees/degrees_001_to_006.html": 1.5825, + "conformance/ogles/GL/discard/discard_001_to_002.html": 0.1709, + "conformance/ogles/GL/distance/distance_001_to_006.html": 2.0703, + "conformance/ogles/GL/dot/dot_001_to_006.html": 1.5321, + "conformance/ogles/GL/equal/equal_001_to_008.html": 1.6912, + "conformance/ogles/GL/equal/equal_009_to_012.html": 1.522, + "conformance/ogles/GL/exp/exp_001_to_008.html": 1.8586, + "conformance/ogles/GL/exp/exp_009_to_012.html": 1.6496, + "conformance/ogles/GL/exp2/exp2_001_to_008.html": 2.2771, + "conformance/ogles/GL/exp2/exp2_009_to_012.html": 1.6671, + "conformance/ogles/GL/faceforward/faceforward_001_to_006.html": 1.759, + "conformance/ogles/GL/floor/floor_001_to_006.html": 2.0722, + "conformance/ogles/GL/fract/fract_001_to_006.html": 1.6368, + "conformance/ogles/GL/functions/functions_001_to_008.html": 1.6235, + "conformance/ogles/GL/functions/functions_009_to_016.html": 0.3993, + "conformance/ogles/GL/functions/functions_017_to_024.html": 0.5181, + "conformance/ogles/GL/functions/functions_025_to_032.html": 0.4928, + "conformance/ogles/GL/functions/functions_033_to_040.html": 0.4956, + "conformance/ogles/GL/functions/functions_041_to_048.html": 0.4253, + "conformance/ogles/GL/functions/functions_049_to_056.html": 0.3974, + "conformance/ogles/GL/functions/functions_057_to_064.html": 0.4822, + "conformance/ogles/GL/functions/functions_065_to_072.html": 0.4674, + "conformance/ogles/GL/functions/functions_073_to_080.html": 0.506, + "conformance/ogles/GL/functions/functions_081_to_088.html": 0.5087, + "conformance/ogles/GL/functions/functions_089_to_096.html": 0.4231, + "conformance/ogles/GL/functions/functions_097_to_104.html": 0.4952, + "conformance/ogles/GL/functions/functions_105_to_112.html": 0.4954, + "conformance/ogles/GL/functions/functions_113_to_120.html": 0.5469, + "conformance/ogles/GL/functions/functions_121_to_126.html": 0.3727, + "conformance/ogles/GL/gl_FragCoord/gl_FragCoord_001_to_003.html": 0.2693, + "conformance/ogles/GL/gl_FrontFacing/gl_FrontFacing_001_to_001.html": 0.1726, + "conformance/ogles/GL/greaterThan/greaterThan_001_to_008.html": 1.747, + "conformance/ogles/GL/greaterThanEqual/greaterThanEqual_001_to_008.html": 2.2848, + "conformance/ogles/GL/inversesqrt/inversesqrt_001_to_006.html": 1.5761, + "conformance/ogles/GL/length/length_001_to_006.html": 1.5444, + "conformance/ogles/GL/lessThan/lessThan_001_to_008.html": 2.245, + "conformance/ogles/GL/lessThanEqual/lessThanEqual_001_to_008.html": 1.6692, + "conformance/ogles/GL/log/log_001_to_008.html": 2.2689, + "conformance/ogles/GL/log/log_009_to_012.html": 1.6729, + "conformance/ogles/GL/log2/log2_001_to_008.html": 1.7789, + "conformance/ogles/GL/log2/log2_009_to_012.html": 1.6776, + "conformance/ogles/GL/mat/mat_001_to_008.html": 0.4851, + "conformance/ogles/GL/mat/mat_009_to_016.html": 0.4732, + "conformance/ogles/GL/mat/mat_017_to_024.html": 0.4191, + "conformance/ogles/GL/mat/mat_025_to_032.html": 2.2189, + "conformance/ogles/GL/mat/mat_033_to_040.html": 2.0922, + "conformance/ogles/GL/mat/mat_041_to_046.html": 0.4439, + "conformance/ogles/GL/mat3/mat3_001_to_006.html": 0.4022, + "conformance/ogles/GL/matrixCompMult/matrixCompMult_001_to_004.html": 1.5829, + "conformance/ogles/GL/max/max_001_to_006.html": 2.0687, + "conformance/ogles/GL/min/min_001_to_006.html": 1.5467, + "conformance/ogles/GL/mix/mix_001_to_006.html": 1.5752, + "conformance/ogles/GL/mod/mod_001_to_008.html": 2.102, + "conformance/ogles/GL/normalize/normalize_001_to_006.html": 1.6025, + "conformance/ogles/GL/not/not_001_to_004.html": 1.513, + "conformance/ogles/GL/notEqual/notEqual_001_to_008.html": 1.6791, + "conformance/ogles/GL/notEqual/notEqual_009_to_012.html": 2.0751, + "conformance/ogles/GL/operators/operators_001_to_008.html": 0.4858, + "conformance/ogles/GL/operators/operators_009_to_016.html": 0.3974, + "conformance/ogles/GL/operators/operators_017_to_024.html": 0.4955, + "conformance/ogles/GL/operators/operators_025_to_026.html": 0.2845, + "conformance/ogles/GL/pow/pow_001_to_008.html": 0.5795, + "conformance/ogles/GL/pow/pow_009_to_016.html": 1.8104, + "conformance/ogles/GL/pow/pow_017_to_024.html": 1.8161, + "conformance/ogles/GL/radians/radians_001_to_006.html": 1.6037, + "conformance/ogles/GL/reflect/reflect_001_to_006.html": 1.7599, + "conformance/ogles/GL/refract/refract_001_to_006.html": 2.083, + "conformance/ogles/GL/sign/sign_001_to_006.html": 1.5817, + "conformance/ogles/GL/sin/sin_001_to_006.html": 2.2086, + "conformance/ogles/GL/smoothstep/smoothstep_001_to_006.html": 2.1122, + "conformance/ogles/GL/sqrt/sqrt_001_to_006.html": 2.0595, + "conformance/ogles/GL/step/step_001_to_006.html": 2.0497, + "conformance/ogles/GL/struct/struct_001_to_008.html": 1.7044, + "conformance/ogles/GL/struct/struct_009_to_016.html": 1.6865, + "conformance/ogles/GL/struct/struct_017_to_024.html": 2.2336, + "conformance/ogles/GL/struct/struct_025_to_032.html": 2.2516, + "conformance/ogles/GL/struct/struct_033_to_040.html": 2.2287, + "conformance/ogles/GL/struct/struct_041_to_048.html": 2.2437, + "conformance/ogles/GL/struct/struct_049_to_056.html": 2.2471, + "conformance/ogles/GL/swizzlers/swizzlers_001_to_008.html": 1.682, + "conformance/ogles/GL/swizzlers/swizzlers_009_to_016.html": 2.2501, + "conformance/ogles/GL/swizzlers/swizzlers_017_to_024.html": 1.6797, + "conformance/ogles/GL/swizzlers/swizzlers_025_to_032.html": 1.7835, + "conformance/ogles/GL/swizzlers/swizzlers_033_to_040.html": 1.6988, + "conformance/ogles/GL/swizzlers/swizzlers_041_to_048.html": 2.2391, + "conformance/ogles/GL/swizzlers/swizzlers_049_to_056.html": 2.2381, + "conformance/ogles/GL/swizzlers/swizzlers_057_to_064.html": 2.2951, + "conformance/ogles/GL/swizzlers/swizzlers_065_to_072.html": 1.6923, + "conformance/ogles/GL/swizzlers/swizzlers_073_to_080.html": 1.691, + "conformance/ogles/GL/swizzlers/swizzlers_081_to_088.html": 2.2559, + "conformance/ogles/GL/swizzlers/swizzlers_089_to_096.html": 2.235, + "conformance/ogles/GL/swizzlers/swizzlers_097_to_104.html": 2.2344, + "conformance/ogles/GL/swizzlers/swizzlers_105_to_112.html": 1.6984, + "conformance/ogles/GL/swizzlers/swizzlers_113_to_120.html": 1.6655, + "conformance/ogles/GL/tan/tan_001_to_006.html": 2.109, + "conformance/ogles/GL/vec/vec_001_to_008.html": 0.4648, + "conformance/ogles/GL/vec/vec_009_to_016.html": 0.519, + "conformance/ogles/GL/vec/vec_017_to_018.html": 0.2621, + "conformance/ogles/GL/vec3/vec3_001_to_008.html": 0.484, + "conformance/programs/get-active-test.html": 0.2056, + "conformance/programs/gl-bind-attrib-location-long-names-test.html": 0.1037, + "conformance/programs/gl-bind-attrib-location-test.html": 0.0789, + "conformance/programs/gl-get-active-attribute.html": 0.1157, + "conformance/programs/gl-get-active-uniform.html": 0.1448, + "conformance/programs/gl-getshadersource.html": 0.06, + "conformance/programs/gl-shader-test.html": 0.14, + "conformance/programs/invalid-UTF-16.html": 0.0511, + "conformance/programs/program-infolog.html": 0.0566, + "conformance/programs/program-test.html": 0.1015, + "conformance/programs/use-program-crash-with-discard-in-fragment-shader.html": 0.0689, + "conformance/reading/fbo-remains-unchanged-after-read-pixels.html": 0.0664, + "conformance/reading/read-pixels-pack-alignment.html": 0.1101, + "conformance/reading/read-pixels-test.html": 0.5404, + "conformance/renderbuffers/depth-renderbuffer-initialization.html": 0.1481, + "conformance/renderbuffers/feedback-loop.html": 0.0792, + "conformance/renderbuffers/framebuffer-object-attachment.html": 0.2322, + "conformance/renderbuffers/framebuffer-state-restoration.html": 0.3172, + "conformance/renderbuffers/framebuffer-test.html": 0.0575, + "conformance/renderbuffers/renderbuffer-initialization.html": 0.1938, + "conformance/renderbuffers/stencil-renderbuffer-initialization.html": 0.1468, + "conformance/rendering/blending.html": 0.158, + "conformance/rendering/canvas-alpha-bug.html": 0.0753, + "conformance/rendering/clear-after-copyTexImage2D.html": 0.1112, + "conformance/rendering/clipping-wide-points.html": 0.0893, + "conformance/rendering/color-mask-preserved-during-implicit-clears.html": 1.2528, + "conformance/rendering/culling.html": 0.072, + "conformance/rendering/default-texture-draw-bug.html": 0.2142, + "conformance/rendering/draw-arrays-out-of-bounds.html": 0.0798, + "conformance/rendering/draw-elements-out-of-bounds.html": 0.0983, + "conformance/rendering/draw-webgl-to-canvas-2d-repeatedly.html": 0.116, + "conformance/rendering/draw-with-changing-start-vertex-bug.html": 0.1322, + "conformance/rendering/framebuffer-switch.html": 0.12, + "conformance/rendering/framebuffer-texture-clear.html": 0.1437, + "conformance/rendering/framebuffer-texture-switch.html": 0.151, + "conformance/rendering/gl-clear.html": 0.1031, + "conformance/rendering/gl-drawarrays.html": 0.0736, + "conformance/rendering/gl-drawelements.html": 0.1019, + "conformance/rendering/gl-scissor-canvas-dimensions.html": 0.0929, + "conformance/rendering/gl-scissor-fbo-test.html": 0.1017, + "conformance/rendering/gl-scissor-test.html": 0.203, + "conformance/rendering/gl-viewport-test.html": 0.3022, + "conformance/rendering/line-loop-tri-fan.html": 0.096, + "conformance/rendering/line-rendering-quality.html": 0.0947, + "conformance/rendering/many-draw-calls.html": 1.4198, + "conformance/rendering/more-than-65536-indices.html": 0.3031, + "conformance/rendering/multisample-corruption.html": 3.3642, + "conformance/rendering/negative-one-index.html": 0.0989, + "conformance/rendering/out-of-bounds-array-buffers.html": 0.0726, + "conformance/rendering/out-of-bounds-index-buffers.html": 0.0964, + "conformance/rendering/point-no-attributes.html": 0.0654, + "conformance/rendering/point-size.html": 0.0714, + "conformance/rendering/point-specific-shader-variables.html": 0.1006, + "conformance/rendering/point-with-gl-pointcoord-in-fragment-shader.html": 0.0709, + "conformance/rendering/polygon-offset.html": 0.0809, + "conformance/rendering/preservedrawingbuffer-leak.html": 0.1656, + "conformance/rendering/rendering-sampling-feedback-loop.html": 0.0752, + "conformance/rendering/rendering-stencil-large-viewport.html": 0.0714, + "conformance/rendering/scissor-rect-repeated-rendering.html": 0.1721, + "conformance/rendering/simple.html": 0.0776, + "conformance/rendering/texture-switch-performance.html": 0.001, + "conformance/rendering/triangle.html": 0.0621, + "conformance/state/gl-enable-enum-test.html": 0.1997, + "conformance/state/gl-enum-tests.html": 0.0946, + "conformance/state/gl-get-calls.html": 0.0928, + "conformance/state/gl-geterror.html": 0.0588, + "conformance/state/gl-getstring.html": 0.0605, + "conformance/state/gl-initial-state.html": 0.0664, + "conformance/state/gl-object-get-calls.html": 5.7638, + "conformance/state/state-uneffected-after-compositing.html": 0.2708, + "conformance/textures/canvas/tex-2d-alpha-alpha-unsigned_byte.html": 0.3681, + "conformance/textures/canvas/tex-2d-luminance-luminance-unsigned_byte.html": 0.7001, + "conformance/textures/canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.5858, + "conformance/textures/canvas/tex-2d-rgb-rgb-unsigned_byte.html": 1.3831, + "conformance/textures/canvas/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.4963, + "conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_byte.html": 1.8148, + "conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.6107, + "conformance/textures/canvas/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.8146, + "conformance/textures/canvas_sub_rectangle/tex-2d-alpha-alpha-unsigned_byte.html": 0.0402, + "conformance/textures/canvas_sub_rectangle/tex-2d-luminance-luminance-unsigned_byte.html": 0.0324, + "conformance/textures/canvas_sub_rectangle/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.0322, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgb-rgb-unsigned_byte.html": 0.0336, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.0329, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_byte.html": 0.0341, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.0345, + "conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.041, + "conformance/textures/image/tex-2d-alpha-alpha-unsigned_byte.html": 0.1667, + "conformance/textures/image/tex-2d-luminance-luminance-unsigned_byte.html": 0.1781, + "conformance/textures/image/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.1733, + "conformance/textures/image/tex-2d-rgb-rgb-unsigned_byte.html": 0.1743, + "conformance/textures/image/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.1733, + "conformance/textures/image/tex-2d-rgba-rgba-unsigned_byte.html": 0.1578, + "conformance/textures/image/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.1754, + "conformance/textures/image/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.173, + "conformance/textures/image_bitmap_from_blob/tex-2d-alpha-alpha-unsigned_byte.html": 0.1501, + "conformance/textures/image_bitmap_from_blob/tex-2d-luminance-luminance-unsigned_byte.html": 0.1527, + "conformance/textures/image_bitmap_from_blob/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.1716, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgb-rgb-unsigned_byte.html": 0.1662, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.1543, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgba-rgba-unsigned_byte.html": 0.2393, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.149, + "conformance/textures/image_bitmap_from_blob/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.1598, + "conformance/textures/image_bitmap_from_canvas/tex-2d-alpha-alpha-unsigned_byte.html": 0.3126, + "conformance/textures/image_bitmap_from_canvas/tex-2d-luminance-luminance-unsigned_byte.html": 0.2256, + "conformance/textures/image_bitmap_from_canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.2377, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgb-rgb-unsigned_byte.html": 0.2559, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.248, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgba-rgba-unsigned_byte.html": 0.2499, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.4003, + "conformance/textures/image_bitmap_from_canvas/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.2443, + "conformance/textures/image_bitmap_from_image/tex-2d-alpha-alpha-unsigned_byte.html": 0.1448, + "conformance/textures/image_bitmap_from_image/tex-2d-luminance-luminance-unsigned_byte.html": 0.2328, + "conformance/textures/image_bitmap_from_image/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.2366, + "conformance/textures/image_bitmap_from_image/tex-2d-rgb-rgb-unsigned_byte.html": 0.2172, + "conformance/textures/image_bitmap_from_image/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.2182, + "conformance/textures/image_bitmap_from_image/tex-2d-rgba-rgba-unsigned_byte.html": 0.2573, + "conformance/textures/image_bitmap_from_image/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.2401, + "conformance/textures/image_bitmap_from_image/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.2422, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-alpha-alpha-unsigned_byte.html": 0.129, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-luminance-luminance-unsigned_byte.html": 0.1225, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.1215, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgb-rgb-unsigned_byte.html": 0.1446, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.1463, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgba-rgba-unsigned_byte.html": 0.1447, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.1599, + "conformance/textures/image_bitmap_from_image_bitmap/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.1202, + "conformance/textures/image_bitmap_from_image_data/tex-2d-alpha-alpha-unsigned_byte.html": 0.2315, + "conformance/textures/image_bitmap_from_image_data/tex-2d-luminance-luminance-unsigned_byte.html": 0.128, + "conformance/textures/image_bitmap_from_image_data/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.1232, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgb-rgb-unsigned_byte.html": 0.118, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.1476, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgba-rgba-unsigned_byte.html": 0.1575, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.1468, + "conformance/textures/image_bitmap_from_image_data/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.1341, + "conformance/textures/image_bitmap_from_video/tex-2d-alpha-alpha-unsigned_byte.html": 0.3875, + "conformance/textures/image_bitmap_from_video/tex-2d-luminance-luminance-unsigned_byte.html": 0.3716, + "conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.3625, + "conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_byte.html": 0.3674, + "conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.3563, + "conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_byte.html": 0.3673, + "conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.3694, + "conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.3553, + "conformance/textures/image_data/tex-2d-alpha-alpha-unsigned_byte.html": 0.2381, + "conformance/textures/image_data/tex-2d-luminance-luminance-unsigned_byte.html": 0.1706, + "conformance/textures/image_data/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.1311, + "conformance/textures/image_data/tex-2d-rgb-rgb-unsigned_byte.html": 0.1865, + "conformance/textures/image_data/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.1504, + "conformance/textures/image_data/tex-2d-rgba-rgba-unsigned_byte.html": 0.1407, + "conformance/textures/image_data/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.1486, + "conformance/textures/image_data/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.2041, + "conformance/textures/misc/canvas-teximage-after-multiple-drawimages.html": 0.1338, + "conformance/textures/misc/compressed-tex-image.html": 0.0591, + "conformance/textures/misc/copy-tex-image-2d-formats.html": 0.1047, + "conformance/textures/misc/copy-tex-image-and-sub-image-2d.html": 0.2083, + "conformance/textures/misc/copy-tex-image-crash.html": 0.1169, + "conformance/textures/misc/copytexsubimage2d-large-partial-copy-corruption.html": 0.1996, + "conformance/textures/misc/copytexsubimage2d-subrects.html": 0.0601, + "conformance/textures/misc/cube-incomplete-fbo.html": 0.1252, + "conformance/textures/misc/cube-map-uploads-out-of-order.html": 1.0605, + "conformance/textures/misc/default-texture.html": 0.0561, + "conformance/textures/misc/gl-get-tex-parameter.html": 0.0646, + "conformance/textures/misc/gl-pixelstorei.html": 0.0824, + "conformance/textures/misc/gl-teximage.html": 0.3256, + "conformance/textures/misc/mipmap-fbo.html": 0.0644, + "conformance/textures/misc/origin-clean-conformance-offscreencanvas.html": 0.1593, + "conformance/textures/misc/origin-clean-conformance.html": 0.0708, + "conformance/textures/misc/tex-image-and-sub-image-2d-with-array-buffer-view.html": 0.9303, + "conformance/textures/misc/tex-image-and-uniform-binding-bugs.html": 0.064, + "conformance/textures/misc/tex-image-canvas-corruption.html": 0.1976, + "conformance/textures/misc/tex-image-webgl.html": 0.1191, + "conformance/textures/misc/tex-image-with-format-and-type.html": 0.36, + "conformance/textures/misc/tex-image-with-invalid-data.html": 0.0539, + "conformance/textures/misc/tex-input-validation.html": 0.1781, + "conformance/textures/misc/tex-sub-image-2d-bad-args.html": 0.0704, + "conformance/textures/misc/tex-sub-image-2d.html": 0.0744, + "conformance/textures/misc/tex-video-using-tex-unit-non-zero.html": 0.4619, + "conformance/textures/misc/texparameter-test.html": 0.1439, + "conformance/textures/misc/texture-active-bind-2.html": 0.0628, + "conformance/textures/misc/texture-active-bind.html": 0.0651, + "conformance/textures/misc/texture-attachment-formats.html": 0.066, + "conformance/textures/misc/texture-clear.html": 0.0636, + "conformance/textures/misc/texture-complete.html": 0.0697, + "conformance/textures/misc/texture-copying-feedback-loops.html": 0.0621, + "conformance/textures/misc/texture-corner-case-videos.html": 0.1553, + "conformance/textures/misc/texture-cube-as-fbo-attachment.html": 0.054, + "conformance/textures/misc/texture-draw-with-2d-and-cube.html": 0.071, + "conformance/textures/misc/texture-fakeblack.html": 0.0744, + "conformance/textures/misc/texture-formats-test.html": 0.1293, + "conformance/textures/misc/texture-hd-dpi.html": 0.1319, + "conformance/textures/misc/texture-mips.html": 0.0744, + "conformance/textures/misc/texture-npot-video.html": 0.1506, + "conformance/textures/misc/texture-npot.html": 0.0989, + "conformance/textures/misc/texture-size-cube-maps.html": 0.3535, + "conformance/textures/misc/texture-size-limit.html": 0.5135, + "conformance/textures/misc/texture-size.html": 0.5575, + "conformance/textures/misc/texture-sub-image-cube-maps.html": 0.1096, + "conformance/textures/misc/texture-transparent-pixels-initialized.html": 0.1562, + "conformance/textures/misc/texture-upload-cube-maps.html": 0.054, + "conformance/textures/misc/texture-upload-size.html": 0.3776, + "conformance/textures/misc/texture-video-transparent.html": 1.7545, + "conformance/textures/misc/texture-with-flip-y-and-premultiply-alpha.html": 0.0761, + "conformance/textures/svg_image/tex-2d-alpha-alpha-unsigned_byte.html": 0.1564, + "conformance/textures/svg_image/tex-2d-luminance-luminance-unsigned_byte.html": 0.1844, + "conformance/textures/svg_image/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.1853, + "conformance/textures/svg_image/tex-2d-rgb-rgb-unsigned_byte.html": 0.1873, + "conformance/textures/svg_image/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.1843, + "conformance/textures/svg_image/tex-2d-rgba-rgba-unsigned_byte.html": 0.1883, + "conformance/textures/svg_image/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.1847, + "conformance/textures/svg_image/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.1978, + "conformance/textures/video/tex-2d-alpha-alpha-unsigned_byte.html": 0.4818, + "conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html": 0.5528, + "conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.4576, + "conformance/textures/video/tex-2d-rgb-rgb-unsigned_byte.html": 0.4638, + "conformance/textures/video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.5698, + "conformance/textures/video/tex-2d-rgba-rgba-unsigned_byte.html": 0.589, + "conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.4742, + "conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.5557, + "conformance/textures/webgl_canvas/tex-2d-alpha-alpha-unsigned_byte.html": 0.7098, + "conformance/textures/webgl_canvas/tex-2d-luminance-luminance-unsigned_byte.html": 0.5856, + "conformance/textures/webgl_canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html": 0.491, + "conformance/textures/webgl_canvas/tex-2d-rgb-rgb-unsigned_byte.html": 1.5025, + "conformance/textures/webgl_canvas/tex-2d-rgb-rgb-unsigned_short_5_6_5.html": 0.5897, + "conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_byte.html": 1.4761, + "conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html": 0.4698, + "conformance/textures/webgl_canvas/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html": 0.5598, + "conformance/typedarrays/array-buffer-crash.html": 0.0436, + "conformance/typedarrays/array-buffer-view-crash.html": 0.0296, + "conformance/typedarrays/array-large-array-tests.html": 0.0295, + "conformance/typedarrays/array-unit-tests.html": 0.0554, + "conformance/typedarrays/data-view-crash.html": 0.029, + "conformance/typedarrays/data-view-test.html": 0.0657, + "conformance/typedarrays/typed-arrays-in-workers.html": 0.1381, + "conformance/uniforms/gl-uniform-arrays.html": 0.0891, + "conformance/uniforms/gl-uniform-bool.html": 0.0544, + "conformance/uniforms/gl-uniformmatrix4fv.html": 0.0923, + "conformance/uniforms/gl-unknown-uniform.html": 0.0592, + "conformance/uniforms/no-over-optimization-on-uniform-array-00.html": 0.685, + "conformance/uniforms/no-over-optimization-on-uniform-array-01.html": 0.6687, + "conformance/uniforms/no-over-optimization-on-uniform-array-02.html": 0.5858, + "conformance/uniforms/no-over-optimization-on-uniform-array-03.html": 0.5863, + "conformance/uniforms/no-over-optimization-on-uniform-array-04.html": 0.5904, + "conformance/uniforms/no-over-optimization-on-uniform-array-05.html": 0.6088, + "conformance/uniforms/no-over-optimization-on-uniform-array-06.html": 0.6185, + "conformance/uniforms/no-over-optimization-on-uniform-array-07.html": 0.5965, + "conformance/uniforms/no-over-optimization-on-uniform-array-08.html": 0.6138, + "conformance/uniforms/no-over-optimization-on-uniform-array-09.html": 0.6005, + "conformance/uniforms/no-over-optimization-on-uniform-array-10.html": 0.5976, + "conformance/uniforms/no-over-optimization-on-uniform-array-11.html": 0.6113, + "conformance/uniforms/no-over-optimization-on-uniform-array-12.html": 0.5739, + "conformance/uniforms/no-over-optimization-on-uniform-array-13.html": 0.599, + "conformance/uniforms/no-over-optimization-on-uniform-array-14.html": 0.613, + "conformance/uniforms/no-over-optimization-on-uniform-array-15.html": 0.6001, + "conformance/uniforms/no-over-optimization-on-uniform-array-16.html": 0.5861, + "conformance/uniforms/no-over-optimization-on-uniform-array-17.html": 0.6018, + "conformance/uniforms/null-uniform-location.html": 0.0641, + "conformance/uniforms/out-of-bounds-uniform-array-access.html": 2.2918, + "conformance/uniforms/uniform-default-values.html": 1.0224, + "conformance/uniforms/uniform-location.html": 0.1337, + "conformance/uniforms/uniform-samplers-test.html": 13.2381, + "conformance/uniforms/uniform-values-per-program.html": 0.6017, + "deqp/data/gles2/shaders/conditionals.html": 0.8114, + "deqp/data/gles2/shaders/constant_expressions.html": 0.615, + "deqp/data/gles2/shaders/constants.html": 1.2656, + "deqp/data/gles2/shaders/conversions.html": 15.0105, + "deqp/data/gles2/shaders/declarations.html": 0.186, + "deqp/data/gles2/shaders/fragdata.html": 0.1846, + "deqp/data/gles2/shaders/functions.html": 4.5861, + "deqp/data/gles2/shaders/invalid_texture_functions.html": 0.1871, + "deqp/data/gles2/shaders/keywords.html": 1.4358, + "deqp/data/gles2/shaders/linkage.html": 1.0845, + "deqp/data/gles2/shaders/preprocessor.html": 6.1068, + "deqp/data/gles2/shaders/qualification_order.html": 0.6936, + "deqp/data/gles2/shaders/reserved_operators.html": 0.2974, + "deqp/data/gles2/shaders/scoping.html": 0.918, + "deqp/data/gles2/shaders/swizzles.html": 15.6555 } } \ No newline at end of file
diff --git a/content/test/gpu/gather_swarming_json_results.py b/content/test/gpu/gather_swarming_json_results.py index c0a802c..993bc1a 100755 --- a/content/test/gpu/gather_swarming_json_results.py +++ b/content/test/gpu/gather_swarming_json_results.py
@@ -112,15 +112,14 @@ return None -def ExtractTestTimes(node, node_name, dest): +def ExtractTestTimes(node, node_name, dest, delim): if 'times' in node: dest[node_name] = sum(node['times']) / len(node['times']) else: - # Currently the prefix names in the trie are dropped. Could - # concatenate them if the naming convention is changed. for k in node.iterkeys(): if isinstance(node[k], dict): - ExtractTestTimes(node[k], k, dest) + test_name = node_name + delim + k if node_name else k + ExtractTestTimes(node[k], test_name, dest, delim) def GatherResults(bot, build, step): @@ -143,7 +142,8 @@ merged_json = JsonLoadStrippingUnicode(json_output) extracted_times = {'times':{}} - ExtractTestTimes(merged_json, '', extracted_times['times']) + ExtractTestTimes(merged_json['tests'], '', extracted_times['times'], + merged_json['path_delimiter']) return extracted_times, merged_json
diff --git a/content/test/mock_background_sync_controller.cc b/content/test/mock_background_sync_controller.cc index dc7b731..1e35350b 100644 --- a/content/test/mock_background_sync_controller.cc +++ b/content/test/mock_background_sync_controller.cc
@@ -15,7 +15,9 @@ } // namespace void MockBackgroundSyncController::NotifyBackgroundSyncRegistered( - const url::Origin& origin) { + const url::Origin& origin, + bool can_fire, + bool is_reregistered) { registration_count_ += 1; registration_origin_ = origin; }
diff --git a/content/test/mock_background_sync_controller.h b/content/test/mock_background_sync_controller.h index d0751bc..e6ff84d 100644 --- a/content/test/mock_background_sync_controller.h +++ b/content/test/mock_background_sync_controller.h
@@ -24,7 +24,9 @@ ~MockBackgroundSyncController() override = default; // BackgroundSyncController: - void NotifyBackgroundSyncRegistered(const url::Origin& origin) override; + void NotifyBackgroundSyncRegistered(const url::Origin& origin, + bool can_fire, + bool is_reregistered) override; void RunInBackground() override; void GetParameterOverrides( BackgroundSyncParameters* parameters) const override;
diff --git a/device/fido/fido_request_handler.h b/device/fido/fido_request_handler.h index 646cde0b..b23ecb1 100644 --- a/device/fido/fido_request_handler.h +++ b/device/fido/fido_request_handler.h
@@ -22,6 +22,8 @@ // Handles receiving response form potentially multiple connected authenticators // and relaying response to the relying party. +// +// TODO: this class should be dropped; it's not pulling its weight. template <class Response> class FidoRequestHandler : public FidoRequestHandlerBase { public: @@ -50,46 +52,27 @@ // Converts authenticator response code received from CTAP1/CTAP2 device into // FidoReturnCode and passes response data to webauth::mojom::Authenticator. void OnAuthenticatorResponse(FidoAuthenticator* authenticator, - CtapDeviceResponseCode device_response_code, + FidoReturnCode result, base::Optional<Response> response_data) { if (is_complete()) { - DVLOG(2) - << "Response from authenticator received after request is complete."; + // TODO: this should be handled at a higher level and so there should be + // a NOTREACHED() here. But some unittests are exercising this directly. return; } - base::Optional<FidoReturnCode> return_code = - ConvertDeviceResponseCodeToFidoReturnCode(device_response_code, - response_data.has_value()); - - // Any authenticator response codes that do not result from user consent - // imply that the authenticator should be dropped and that other on-going - // requests should continue until timeout is reached. - if (!return_code) { - active_authenticators().erase(authenticator->GetId()); - return; - } - - // Once response has been passed to the relying party, cancel all other on - // going requests. - CancelActiveAuthenticators(authenticator->GetId()); std::move(completion_callback_) - .Run(*return_code, std::move(response_data), + .Run(result, std::move(response_data), authenticator->AuthenticatorTransport()); } CompletionCallback completion_callback_; - private: static base::Optional<FidoReturnCode> ConvertDeviceResponseCodeToFidoReturnCode( - CtapDeviceResponseCode device_response_code, - bool response_has_value) { + CtapDeviceResponseCode device_response_code) { switch (device_response_code) { case CtapDeviceResponseCode::kSuccess: - return response_has_value - ? FidoReturnCode::kSuccess - : FidoReturnCode::kAuthenticatorResponseInvalid; + return FidoReturnCode::kSuccess; // These errors are only returned after the user interacted with the // authenticator. @@ -122,6 +105,7 @@ } } + private: DISALLOW_COPY_AND_ASSIGN(FidoRequestHandler); };
diff --git a/device/fido/fido_request_handler_unittest.cc b/device/fido/fido_request_handler_unittest.cc index 1cdd155..fdc813d 100644 --- a/device/fido/fido_request_handler_unittest.cc +++ b/device/fido/fido_request_handler_unittest.cc
@@ -229,11 +229,29 @@ // at this point. device_authenticator->SetTaskForTesting(std::make_unique<FakeFidoTask>( device_authenticator->device(), - base::BindOnce(&FakeFidoRequestHandler::OnAuthenticatorResponse, + base::BindOnce(&FakeFidoRequestHandler::HandleResponse, weak_factory_.GetWeakPtr(), authenticator))); } private: + void HandleResponse(FidoAuthenticator* authenticator, + CtapDeviceResponseCode status, + base::Optional<std::vector<uint8_t>> response) { + const base::Optional<FidoReturnCode> maybe_result = + ConvertDeviceResponseCodeToFidoReturnCode(status); + if (!maybe_result) { + FIDO_LOG(ERROR) << "Ignoring status " << static_cast<int>(status) + << " from " << authenticator->GetDisplayName(); + active_authenticators().erase(authenticator->GetId()); + return; + } + + if (!is_complete()) { + CancelActiveAuthenticators(authenticator->GetId()); + } + OnAuthenticatorResponse(authenticator, *maybe_result, std::move(response)); + } + base::WeakPtrFactory<FakeFidoRequestHandler> weak_factory_; };
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc index c138ed83..f2fda69e 100644 --- a/device/fido/get_assertion_handler_unittest.cc +++ b/device/fido/get_assertion_handler_unittest.cc
@@ -49,6 +49,8 @@ } // namespace +using testing::_; + // FidoGetAssertionHandlerTest allows testing GetAssertionRequestHandler against // MockFidoDevices injected via a ScopedFakeFidoDiscoveryFactory. class FidoGetAssertionHandlerTest : public ::testing::Test { @@ -286,8 +288,9 @@ discovery()->AddDevice(std::move(device)); - scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(get_assertion_callback().was_called()); + get_assertion_callback().WaitForCallback(); + EXPECT_EQ(FidoReturnCode::kAuthenticatorResponseInvalid, + get_assertion_callback().status()); } // Tests a scenario where the authenticator responds with credential ID that @@ -310,8 +313,9 @@ discovery()->AddDevice(std::move(device)); - scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(get_assertion_callback().was_called()); + get_assertion_callback().WaitForCallback(); + EXPECT_EQ(FidoReturnCode::kAuthenticatorResponseInvalid, + get_assertion_callback().status()); } // Tests a scenario where the authenticator responds with an empty credential. @@ -356,8 +360,9 @@ discovery()->AddDevice(std::move(device)); - scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(get_assertion_callback().was_called()); + get_assertion_callback().WaitForCallback(); + EXPECT_EQ(FidoReturnCode::kAuthenticatorResponseInvalid, + get_assertion_callback().status()); } TEST_F(FidoGetAssertionHandlerTest, @@ -664,6 +669,45 @@ get_assertion_callback().status()); } +MATCHER_P(IsCtap2Command, expected_command, "") { + return !arg.empty() && arg[0] == base::strict_cast<uint8_t>(expected_command); +} + +TEST_F(FidoGetAssertionHandlerTest, DeviceFailsImmediately) { + // Test that, when a device immediately returns an unexpected error, the + // request continues and waits for another device. + + auto broken_device = MockFidoDevice::MakeCtapWithGetInfoExpectation(); + EXPECT_CALL( + *broken_device, + DeviceTransactPtr( + IsCtap2Command(CtapRequestCommand::kAuthenticatorGetAssertion), _)) + .WillOnce(::testing::DoAll( + ::testing::WithArg<1>( + ::testing::Invoke([this](FidoDevice::DeviceCallback& callback) { + std::vector<uint8_t> response = {static_cast<uint8_t>( + CtapDeviceResponseCode::kCtap2ErrInvalidCBOR)}; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), std::move(response))); + + auto working_device = + MockFidoDevice::MakeCtapWithGetInfoExpectation(); + working_device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorGetAssertion, + test_data::kTestGetAssertionResponse); + discovery()->AddDevice(std::move(working_device)); + })), + ::testing::Return(0))); + + auto request_handler = CreateGetAssertionHandlerCtap(); + discovery()->WaitForCallToStartAndSimulateSuccess(); + discovery()->AddDevice(std::move(broken_device)); + + get_assertion_callback().WaitForCallback(); + EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); +} + // Tests a scenario where authenticator of incorrect transport type was used to // conduct CTAP GetAssertion call. //
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc index fa516c3..505fbda3 100644 --- a/device/fido/get_assertion_request_handler.cc +++ b/device/fido/get_assertion_request_handler.cc
@@ -299,7 +299,7 @@ void GetAssertionRequestHandler::HandleResponse( FidoAuthenticator* authenticator, - CtapDeviceResponseCode response_code, + CtapDeviceResponseCode status, base::Optional<AuthenticatorGetAssertionResponse> response) { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); @@ -317,22 +317,31 @@ authenticator->WillNeedPINToGetAssertion(request_, observer()) == FidoAuthenticator::GetAssertionPINDisposition::kNoPIN); + const base::Optional<FidoReturnCode> maybe_result = + ConvertDeviceResponseCodeToFidoReturnCode(status); + if (!maybe_result) { + FIDO_LOG(ERROR) << "Ignoring status " << static_cast<int>(status) + << " from " << authenticator->GetDisplayName(); + return; + } + state_ = State::kFinished; CancelActiveAuthenticators(authenticator->GetId()); - if (response_code != CtapDeviceResponseCode::kSuccess) { + if (status != CtapDeviceResponseCode::kSuccess) { FIDO_LOG(ERROR) << "Failing assertion request due to status " - << static_cast<int>(response_code) << " from " + << static_cast<int>(status) << " from " << authenticator->GetDisplayName(); - OnAuthenticatorResponse(authenticator, response_code, base::nullopt); + OnAuthenticatorResponse(authenticator, *maybe_result, base::nullopt); return; } if (!response || !ResponseValid(*authenticator, request_, *response)) { FIDO_LOG(ERROR) << "Failing assertion request due to bad response from " << authenticator->GetDisplayName(); - OnAuthenticatorResponse( - authenticator, CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt); + OnAuthenticatorResponse(authenticator, + FidoReturnCode::kAuthenticatorResponseInvalid, + base::nullopt); return; } @@ -340,8 +349,9 @@ const size_t num_responses = response->num_credentials().value_or(1); if (num_responses == 0 || (num_responses > 1 && request_.allow_list() && !request_.allow_list()->empty())) { - OnAuthenticatorResponse( - authenticator, CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt); + OnAuthenticatorResponse(authenticator, + FidoReturnCode::kAuthenticatorResponseInvalid, + base::nullopt); return; } @@ -357,7 +367,8 @@ return; } - OnAuthenticatorResponse(authenticator, response_code, std::move(responses_)); + OnAuthenticatorResponse(authenticator, FidoReturnCode::kSuccess, + std::move(responses_)); } void GetAssertionRequestHandler::HandleNextResponse( @@ -370,15 +381,21 @@ state_ = State::kFinished; if (status != CtapDeviceResponseCode::kSuccess) { - OnAuthenticatorResponse(authenticator, status, base::nullopt); + FIDO_LOG(ERROR) << "Failing assertion request due to status " + << static_cast<int>(status) << " from " + << authenticator->GetDisplayName(); + OnAuthenticatorResponse(authenticator, + FidoReturnCode::kAuthenticatorResponseInvalid, + base::nullopt); return; } if (!ResponseValid(*authenticator, request_, *response)) { FIDO_LOG(ERROR) << "Failing assertion request due to bad response from " << authenticator->GetDisplayName(); - OnAuthenticatorResponse( - authenticator, CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt); + OnAuthenticatorResponse(authenticator, + FidoReturnCode::kAuthenticatorResponseInvalid, + base::nullopt); return; } @@ -393,7 +410,8 @@ return; } - OnAuthenticatorResponse(authenticator, status, std::move(responses_)); + OnAuthenticatorResponse(authenticator, FidoReturnCode::kSuccess, + std::move(responses_)); } void GetAssertionRequestHandler::HandleTouch(FidoAuthenticator* authenticator) {
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc index 39f7f5e8..16163f6 100644 --- a/device/fido/make_credential_handler_unittest.cc +++ b/device/fido/make_credential_handler_unittest.cc
@@ -674,4 +674,43 @@ EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status()); } +MATCHER_P(IsCtap2Command, expected_command, "") { + return !arg.empty() && arg[0] == base::strict_cast<uint8_t>(expected_command); +} + +TEST_F(FidoMakeCredentialHandlerTest, DeviceFailsImmediately) { + // Test that, when a device immediately returns an unexpected error, the + // request continues and waits for another device. + + auto broken_device = MockFidoDevice::MakeCtapWithGetInfoExpectation(); + EXPECT_CALL( + *broken_device, + DeviceTransactPtr( + IsCtap2Command(CtapRequestCommand::kAuthenticatorMakeCredential), _)) + .WillOnce(::testing::DoAll( + ::testing::WithArg<1>( + ::testing::Invoke([this](FidoDevice::DeviceCallback& callback) { + std::vector<uint8_t> response = {static_cast<uint8_t>( + CtapDeviceResponseCode::kCtap2ErrInvalidCBOR)}; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), std::move(response))); + + auto working_device = + MockFidoDevice::MakeCtapWithGetInfoExpectation(); + working_device->ExpectCtap2CommandAndRespondWith( + CtapRequestCommand::kAuthenticatorMakeCredential, + test_data::kTestMakeCredentialResponse); + discovery()->AddDevice(std::move(working_device)); + })), + ::testing::Return(0))); + + auto request_handler = CreateMakeCredentialHandler(); + discovery()->WaitForCallToStartAndSimulateSuccess(); + discovery()->AddDevice(std::move(broken_device)); + + callback().WaitForCallback(); + EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); +} + } // namespace device
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc index 4388977..6137566 100644 --- a/device/fido/make_credential_request_handler.cc +++ b/device/fido/make_credential_request_handler.cc
@@ -244,7 +244,7 @@ void MakeCredentialRequestHandler::HandleResponse( FidoAuthenticator* authenticator, - CtapDeviceResponseCode response_code, + CtapDeviceResponseCode status, base::Optional<AuthenticatorMakeCredentialResponse> response) { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); @@ -259,11 +259,22 @@ authenticator->WillNeedPINToMakeCredential(request_, observer()) == MakeCredentialPINDisposition::kNoPIN); + const base::Optional<FidoReturnCode> maybe_result = + ConvertDeviceResponseCodeToFidoReturnCode(status); + if (!maybe_result) { + FIDO_LOG(ERROR) << "Ignoring status " << static_cast<int>(status) + << " from " << authenticator->GetDisplayName(); + return; + } + state_ = State::kFinished; CancelActiveAuthenticators(authenticator->GetId()); - if (response_code != CtapDeviceResponseCode::kSuccess) { - OnAuthenticatorResponse(authenticator, response_code, base::nullopt); + if (status != CtapDeviceResponseCode::kSuccess) { + FIDO_LOG(ERROR) << "Failing make credential request due to status " + << static_cast<int>(status) << " from " + << authenticator->GetDisplayName(); + OnAuthenticatorResponse(authenticator, *maybe_result, base::nullopt); return; } @@ -271,12 +282,16 @@ fido_parsing_utils::CreateSHA256Hash(request_.rp().rp_id()); if (!response || response->GetRpIdHash() != rp_id_hash) { - OnAuthenticatorResponse( - authenticator, CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt); + FIDO_LOG(ERROR) << "Failing assertion request due to bad response from " + << authenticator->GetDisplayName(); + OnAuthenticatorResponse(authenticator, + FidoReturnCode::kAuthenticatorResponseInvalid, + base::nullopt); return; } - OnAuthenticatorResponse(authenticator, response_code, std::move(response)); + OnAuthenticatorResponse(authenticator, FidoReturnCode::kSuccess, + std::move(response)); } void MakeCredentialRequestHandler::HandleTouch(
diff --git a/device/fido/pin.cc b/device/fido/pin.cc index 307add2..bd524e2 100644 --- a/device/fido/pin.cc +++ b/device/fido/pin.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "device/fido/pin.h" + #include <string> #include <utility> @@ -11,7 +13,6 @@ #include "components/cbor/values.h" #include "components/cbor/writer.h" #include "device/fido/fido_constants.h" -#include "device/fido/pin.h" #include "device/fido/pin_internal.h" #include "third_party/boringssl/src/include/openssl/aes.h" #include "third_party/boringssl/src/include/openssl/bn.h" @@ -34,6 +35,19 @@ return it.Advance() && it.Advance() && it.Advance() && it.Advance(); } +// MakePinAuth returns `LEFT(HMAC-SHA-256(secret, data), 16)`. +static std::vector<uint8_t> MakePinAuth(base::span<const uint8_t> secret, + base::span<const uint8_t> data) { + std::vector<uint8_t> pin_auth; + pin_auth.resize(SHA256_DIGEST_LENGTH); + unsigned hmac_bytes; + CHECK(HMAC(EVP_sha256(), secret.data(), secret.size(), data.data(), + data.size(), pin_auth.data(), &hmac_bytes)); + DCHECK_EQ(pin_auth.size(), static_cast<size_t>(hmac_bytes)); + pin_auth.resize(16); + return pin_auth; +} + bool IsValid(const std::string& pin) { return pin.size() >= kMinBytes && pin.size() <= kMaxBytes && pin.back() != 0 && base::IsStringUTF8(pin) && @@ -285,11 +299,9 @@ uint8_t encrypted_pin[sizeof(pin_)]; Encrypt(shared_key, pin_, encrypted_pin); - uint8_t pin_auth[SHA256_DIGEST_LENGTH]; - unsigned hmac_bytes; - CHECK(HMAC(EVP_sha256(), shared_key, sizeof(shared_key), encrypted_pin, - sizeof(pin_), pin_auth, &hmac_bytes)); - DCHECK_EQ(sizeof(pin_auth), static_cast<size_t>(hmac_bytes)); + std::vector<uint8_t> pin_auth = + MakePinAuth(base::make_span(shared_key, sizeof(shared_key)), + base::make_span(encrypted_pin, sizeof(encrypted_pin))); return EncodePINCommand( Subcommand::kSetPIN, @@ -300,7 +312,7 @@ static_cast<int>(RequestKey::kNewPINEnc), base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin))); map->emplace(static_cast<int>(RequestKey::kPINAuth), - base::span<const uint8_t>(pin_auth)); + std::move(pin_auth)); }); } @@ -354,12 +366,9 @@ memcpy(ciphertexts_concat, encrypted_pin, sizeof(encrypted_pin)); memcpy(ciphertexts_concat + sizeof(encrypted_pin), old_pin_hash_enc, sizeof(old_pin_hash_enc)); - - uint8_t pin_auth[SHA256_DIGEST_LENGTH]; - unsigned hmac_bytes; - CHECK(HMAC(EVP_sha256(), shared_key, sizeof(shared_key), ciphertexts_concat, - sizeof(ciphertexts_concat), pin_auth, &hmac_bytes)); - DCHECK_EQ(sizeof(pin_auth), static_cast<size_t>(hmac_bytes)); + std::vector<uint8_t> pin_auth = MakePinAuth( + base::make_span(shared_key, sizeof(shared_key)), + base::make_span(ciphertexts_concat, sizeof(ciphertexts_concat))); return EncodePINCommand( Subcommand::kChangePIN, [&cose_key, &encrypted_pin, &old_pin_hash_enc, @@ -373,7 +382,7 @@ static_cast<int>(RequestKey::kNewPINEnc), base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin))); map->emplace(static_cast<int>(RequestKey::kPINAuth), - base::span<const uint8_t>(pin_auth)); + std::move(pin_auth)); }); } @@ -466,16 +475,7 @@ std::vector<uint8_t> TokenResponse::PinAuth( const std::array<uint8_t, 32> client_data_hash) { - std::vector<uint8_t> pin_auth; - pin_auth.resize(SHA256_DIGEST_LENGTH); - - unsigned hmac_bytes; - CHECK(HMAC(EVP_sha256(), token_.data(), token_.size(), - client_data_hash.data(), client_data_hash.size(), pin_auth.data(), - &hmac_bytes)); - DCHECK_EQ(pin_auth.size(), static_cast<size_t>(hmac_bytes)); - pin_auth.resize(16); - return pin_auth; + return MakePinAuth(token_, client_data_hash); } } // namespace pin
diff --git a/device/fido/pin.h b/device/fido/pin.h index 4cd0fae..f13cccae 100644 --- a/device/fido/pin.h +++ b/device/fido/pin.h
@@ -19,6 +19,7 @@ #include "base/containers/span.h" #include "base/optional.h" #include "components/cbor/values.h" +#include "device/fido/fido_constants.h" namespace device { namespace pin {
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc index 4b89567..2b7a356 100644 --- a/device/fido/virtual_ctap2_device.cc +++ b/device/fido/virtual_ctap2_device.cc
@@ -370,9 +370,11 @@ &hmac_bytes)); DCHECK_EQ(sizeof(calculated_pin_auth), static_cast<size_t>(hmac_bytes)); - if (pin_auth.size() != sizeof(calculated_pin_auth) || - CRYPTO_memcmp(calculated_pin_auth, pin_auth.data(), - sizeof(calculated_pin_auth)) != 0) { + static_assert(sizeof(calculated_pin_auth) >= 16, + "calculated_pin_auth is expected to be at least 16 bytes"); + if (pin_auth.size() != 16 || + CRYPTO_memcmp(calculated_pin_auth, pin_auth.data(), pin_auth.size()) != + 0) { return CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid; }
diff --git a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc index 28dddc1..46fa4c8 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc +++ b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
@@ -198,7 +198,7 @@ if (FAILED(hr)) return false; - texture_helper_.DiscardView(); + return true; }
diff --git a/extensions/browser/updater/extension_downloader.cc b/extensions/browser/updater/extension_downloader.cc index a0c7156..eb5df4d 100644 --- a/extensions/browser/updater/extension_downloader.cc +++ b/extensions/browser/updater/extension_downloader.cc
@@ -764,7 +764,9 @@ const std::string& update_version_str = update->version; if (VLOG_IS_ON(2)) { if (update_version_str.empty()) - VLOG(2) << "Manifest indicates " << extension_id << " has no update"; + VLOG(2) << "Manifest indicates " << extension_id + << " has no update (info: " << update->info.value_or("no info") + << ")"; else VLOG(2) << "Manifest indicates " << extension_id << " latest version is '" << update_version_str << "'";
diff --git a/extensions/browser/updater/extension_downloader_unittest.cc b/extensions/browser/updater/extension_downloader_unittest.cc index d059fd2..b52d13c 100644 --- a/extensions/browser/updater/extension_downloader_unittest.cc +++ b/extensions/browser/updater/extension_downloader_unittest.cc
@@ -19,6 +19,12 @@ namespace extensions { +namespace { + +const char kTestExtensionId[] = "test_app"; + +} // namespace + class ExtensionDownloaderTest : public ExtensionsTest { protected: ExtensionDownloaderTest() {} @@ -31,28 +37,37 @@ update_url, 0, "", "", ManifestFetchData::PING, fetch_priority); } + std::unique_ptr<ManifestFetchData> CreateTestAppFetchData() { + GURL kUpdateUrl("http://localhost/manifest1"); + std::unique_ptr<ManifestFetchData> fetch( + CreateManifestFetchData(kUpdateUrl)); + ManifestFetchData::PingData zero_days(0, 0, true, 0); + fetch->AddExtension(kTestExtensionId, "1.0", &zero_days, "", "", "", + ManifestFetchData::FetchPriority::BACKGROUND); + return fetch; + } + void AddFetchDataToDownloader(ExtensionDownloaderTestHelper* helper, std::unique_ptr<ManifestFetchData> fetch) { helper->downloader().StartUpdateCheck(std::move(fetch)); } }; +// Several tests checking that OnExtensionDownloadStageChanged callback is +// called correctly. TEST_F(ExtensionDownloaderTest, TestStageChanges) { ExtensionDownloaderTestHelper helper; - GURL kUpdateUrl("http://localhost/manifest1"); - std::unique_ptr<ManifestFetchData> fetch(CreateManifestFetchData(kUpdateUrl)); - ManifestFetchData::PingData zero_days(0, 0, true, 0); - fetch->AddExtension("test_app", "1.0", &zero_days, "", std::string(), - std::string(), - ManifestFetchData::FetchPriority::BACKGROUND); + std::unique_ptr<ManifestFetchData> fetch(CreateTestAppFetchData()); GURL fetch_url = fetch->full_url(); const std::string kManifest = "<?xml version='1.0' encoding='UTF-8'?>" "<gupdate xmlns='http://www.google.com/update2/response'" " protocol='2.0'>" - " <app appid='test_app'>" + " <app appid='" + + std::string(kTestExtensionId) + + "'>" " <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'" " version='1.1' prodversionmin='1.1' />" " </app>" @@ -64,34 +79,36 @@ net::HTTP_OK); MockExtensionDownloaderDelegate& delegate = helper.delegate(); - EXPECT_CALL(delegate, IsExtensionPending("test_app")).WillOnce(Return(true)); + EXPECT_CALL(delegate, IsExtensionPending(kTestExtensionId)) + .WillOnce(Return(true)); Sequence sequence; - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::QUEUED_FOR_MANIFEST)) - .Times(AnyNumber()); - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::QUEUED_FOR_CRX)) + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::QUEUED_FOR_MANIFEST)) .Times(AnyNumber()); EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( - "test_app", + kTestExtensionId, + ExtensionDownloaderDelegate::QUEUED_FOR_CRX)) + .Times(AnyNumber()); + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, ExtensionDownloaderDelegate::DOWNLOADING_MANIFEST)) .InSequence(sequence); - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::PARSING_MANIFEST)) - .InSequence(sequence); - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::MANIFEST_LOADED)) - .InSequence(sequence); - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::DOWNLOADING_CRX)) + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::PARSING_MANIFEST)) .InSequence(sequence); EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::FINISHED)) + kTestExtensionId, + ExtensionDownloaderDelegate::MANIFEST_LOADED)) + .InSequence(sequence); + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::DOWNLOADING_CRX)) + .InSequence(sequence); + EXPECT_CALL(delegate, + OnExtensionDownloadStageChanged( + kTestExtensionId, ExtensionDownloaderDelegate::FINISHED)) .InSequence(sequence); AddFetchDataToDownloader(&helper, std::move(fetch)); @@ -104,19 +121,16 @@ TEST_F(ExtensionDownloaderTest, TestStageChangesNoUpdates) { ExtensionDownloaderTestHelper helper; - GURL kUpdateUrl("http://localhost/manifest1"); - std::unique_ptr<ManifestFetchData> fetch(CreateManifestFetchData(kUpdateUrl)); - ManifestFetchData::PingData zero_days(0, 0, true, 0); - fetch->AddExtension("test_app", "1.0", &zero_days, "", std::string(), - std::string(), - ManifestFetchData::FetchPriority::BACKGROUND); + std::unique_ptr<ManifestFetchData> fetch(CreateTestAppFetchData()); GURL fetch_url = fetch->full_url(); const std::string kManifest = "<?xml version='1.0' encoding='UTF-8'?>" "<gupdate xmlns='http://www.google.com/update2/response'" " protocol='2.0'>" - " <app appid='test_app'>" + " <app appid='" + + std::string(kTestExtensionId) + + "'>" " <updatecheck codebase='http://example.com/extension_1.2.3.4.crx'" " version='1.1' prodversionmin='1.1' />" " </app>" @@ -128,32 +142,34 @@ net::HTTP_OK); MockExtensionDownloaderDelegate& delegate = helper.delegate(); - EXPECT_CALL(delegate, IsExtensionPending("test_app")).WillOnce(Return(false)); - EXPECT_CALL(delegate, GetExtensionExistingVersion("test_app", _)) + EXPECT_CALL(delegate, IsExtensionPending(kTestExtensionId)) + .WillOnce(Return(false)); + EXPECT_CALL(delegate, GetExtensionExistingVersion(kTestExtensionId, _)) .WillOnce(DoAll(SetArgPointee<1>("1.1"), Return(true))); Sequence sequence; - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::QUEUED_FOR_MANIFEST)) + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::QUEUED_FOR_MANIFEST)) .Times(AnyNumber()); EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( - "test_app", + kTestExtensionId, ExtensionDownloaderDelegate::DOWNLOADING_MANIFEST)) .InSequence(sequence); - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::PARSING_MANIFEST)) - .InSequence(sequence); - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::MANIFEST_LOADED)) - .InSequence(sequence); - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::DOWNLOADING_CRX)) - .Times(0); EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::FINISHED)) + kTestExtensionId, + ExtensionDownloaderDelegate::PARSING_MANIFEST)) + .InSequence(sequence); + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::MANIFEST_LOADED)) + .InSequence(sequence); + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::DOWNLOADING_CRX)) + .Times(0); + EXPECT_CALL(delegate, + OnExtensionDownloadStageChanged( + kTestExtensionId, ExtensionDownloaderDelegate::FINISHED)) .InSequence(sequence); AddFetchDataToDownloader(&helper, std::move(fetch)); @@ -166,12 +182,7 @@ TEST_F(ExtensionDownloaderTest, TestStageChangesBadManifest) { ExtensionDownloaderTestHelper helper; - GURL kUpdateUrl("http://localhost/manifest1"); - std::unique_ptr<ManifestFetchData> fetch(CreateManifestFetchData(kUpdateUrl)); - ManifestFetchData::PingData zero_days(0, 0, true, 0); - fetch->AddExtension("test_app", "1.0", &zero_days, "", std::string(), - std::string(), - ManifestFetchData::FetchPriority::BACKGROUND); + std::unique_ptr<ManifestFetchData> fetch(CreateTestAppFetchData()); GURL fetch_url = fetch->full_url(); const std::string kManifest = "invalid xml"; @@ -180,24 +191,25 @@ MockExtensionDownloaderDelegate& delegate = helper.delegate(); Sequence sequence; - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::QUEUED_FOR_MANIFEST)) + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::QUEUED_FOR_MANIFEST)) .Times(AnyNumber()); EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( - "test_app", + kTestExtensionId, ExtensionDownloaderDelegate::DOWNLOADING_MANIFEST)) .InSequence(sequence); - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::PARSING_MANIFEST)) - .InSequence(sequence); - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::MANIFEST_LOADED)) - .Times(0); EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::FINISHED)) + kTestExtensionId, + ExtensionDownloaderDelegate::PARSING_MANIFEST)) + .InSequence(sequence); + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::MANIFEST_LOADED)) + .Times(0); + EXPECT_CALL(delegate, + OnExtensionDownloadStageChanged( + kTestExtensionId, ExtensionDownloaderDelegate::FINISHED)) .InSequence(sequence); AddFetchDataToDownloader(&helper, std::move(fetch)); @@ -210,12 +222,7 @@ TEST_F(ExtensionDownloaderTest, TestStageChangesBadQuery) { ExtensionDownloaderTestHelper helper; - GURL kUpdateUrl("http://localhost/manifest1"); - std::unique_ptr<ManifestFetchData> fetch(CreateManifestFetchData(kUpdateUrl)); - ManifestFetchData::PingData zero_days(0, 0, true, 0); - fetch->AddExtension("test_app", "1.0", &zero_days, "", std::string(), - std::string(), - ManifestFetchData::FetchPriority::BACKGROUND); + std::unique_ptr<ManifestFetchData> fetch(CreateTestAppFetchData()); GURL fetch_url = fetch->full_url(); helper.test_url_loader_factory().AddResponse(fetch_url.spec(), "", @@ -223,20 +230,21 @@ MockExtensionDownloaderDelegate& delegate = helper.delegate(); Sequence sequence; - EXPECT_CALL(delegate, - OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::QUEUED_FOR_MANIFEST)) + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::QUEUED_FOR_MANIFEST)) .Times(AnyNumber()); EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( - "test_app", + kTestExtensionId, ExtensionDownloaderDelegate::DOWNLOADING_MANIFEST)) .InSequence(sequence); + EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( + kTestExtensionId, + ExtensionDownloaderDelegate::PARSING_MANIFEST)) + .Times(0); EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::PARSING_MANIFEST)) - .Times(0); - EXPECT_CALL(delegate, OnExtensionDownloadStageChanged( - "test_app", ExtensionDownloaderDelegate::FINISHED)) + kTestExtensionId, ExtensionDownloaderDelegate::FINISHED)) .InSequence(sequence); AddFetchDataToDownloader(&helper, std::move(fetch)); @@ -246,4 +254,40 @@ testing::Mock::VerifyAndClearExpectations(&delegate); } +// Test that failure callback was actually called in case of empty answer from +// the update server. Regression for problem described/fixed in +// crbug.com/938265. +TEST_F(ExtensionDownloaderTest, TestNoUpdatesManifestReports) { + ExtensionDownloaderTestHelper helper; + + std::unique_ptr<ManifestFetchData> fetch(CreateTestAppFetchData()); + GURL fetch_url = fetch->full_url(); + + const std::string kManifest = + "<?xml version='1.0' encoding='UTF-8'?>" + "<gupdate xmlns='http://www.google.com/update2/response'" + " protocol='2.0'>" + " <app appid='" + + std::string(kTestExtensionId) + + "'>" + " <updatecheck info='bandwidth limit' status='noupdate' />" + " </app>" + "</gupdate>"; + helper.test_url_loader_factory().AddResponse(fetch_url.spec(), kManifest, + net::HTTP_OK); + + MockExtensionDownloaderDelegate& delegate = helper.delegate(); + EXPECT_CALL(delegate, IsExtensionPending(kTestExtensionId)) + .WillOnce(Return(true)); + // TODO(burunduk) Also check error (second argument). By now we return + // CRX_FETCH_FAILED, but probably we may want to make another one. + EXPECT_CALL(delegate, OnExtensionDownloadFailed(kTestExtensionId, _, _, _)); + + AddFetchDataToDownloader(&helper, std::move(fetch)); + + content::RunAllTasksUntilIdle(); + + testing::Mock::VerifyAndClearExpectations(&delegate); +} + } // namespace extensions
diff --git a/extensions/browser/updater/safe_manifest_parser.cc b/extensions/browser/updater/safe_manifest_parser.cc index f8c71b8..6d0539e 100644 --- a/extensions/browser/updater/safe_manifest_parser.cc +++ b/extensions/browser/updater/safe_manifest_parser.cc
@@ -64,8 +64,10 @@ const base::Value* updatecheck = data_decoder::GetXmlElementChildWithTag(app_element, updatecheck_name); - if (GetXmlElementAttribute(*updatecheck, "status") == "noupdate") + if (GetXmlElementAttribute(*updatecheck, "status") == "noupdate") { + result->info = GetXmlElementAttribute(*updatecheck, "info"); return true; + } // Get the optional minimum browser version. result->browser_min_version =
diff --git a/extensions/browser/updater/safe_manifest_parser.h b/extensions/browser/updater/safe_manifest_parser.h index dc6b451..7c951a3d 100644 --- a/extensions/browser/updater/safe_manifest_parser.h +++ b/extensions/browser/updater/safe_manifest_parser.h
@@ -29,6 +29,11 @@ std::string version; std::string browser_min_version; + // Attribute for no update: server may provide additional info about why there + // is no updates, eg. “bandwidth limit” if client is downloading extensions + // too aggressive. + base::Optional<std::string> info; + // Attributes for the full update. GURL crx_url; std::string package_hash;
diff --git a/fuchsia/base/BUILD.gn b/fuchsia/base/BUILD.gn index cc6a093..c29edaf 100644 --- a/fuchsia/base/BUILD.gn +++ b/fuchsia/base/BUILD.gn
@@ -58,6 +58,7 @@ "//base", "//fuchsia:web_fidl", "//third_party/fuchsia-sdk/sdk:modular", + "//third_party/fuchsia-sdk/sdk:web", "//url", ] }
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc index 0c9de256..2def0b0c 100644 --- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc +++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
@@ -502,8 +502,9 @@ SharedImageManager* manager, SharedImageBacking* backing, scoped_refptr<SharedContextState> context_state, - sk_sp<SkPromiseImageTexture> promise_texture) - : SharedImageRepresentationSkia(manager, backing, nullptr), + sk_sp<SkPromiseImageTexture> promise_texture, + MemoryTypeTracker* tracker) + : SharedImageRepresentationSkia(manager, backing, tracker), promise_texture_(std::move(promise_texture)), context_state_(std::move(context_state)) { DCHECK(promise_texture_); @@ -731,7 +732,8 @@ if (!promise_texture) return nullptr; return std::make_unique<SharedImageRepresentationSkiaVkAHB>( - manager, this, std::move(context_state), std::move(promise_texture)); + manager, this, std::move(context_state), std::move(promise_texture), + tracker); } auto* texture = GenGLTexture();
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc index 75a1748..f4fda014 100644 --- a/gpu/command_buffer/service/shared_image_factory.cc +++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -123,8 +123,28 @@ const gfx::ColorSpace& color_space, uint32_t usage, base::span<const uint8_t> data) { + // For now, restrict this to SHARED_IMAGE_USAGE_DISPLAY with optional + // SHARED_IMAGE_USAGE_SCANOUT. + // TODO(ericrk): SCANOUT support for Vulkan by ensuring all interop factories + // support this, and allowing them to be chosen here. + constexpr uint32_t allowed_usage = + SHARED_IMAGE_USAGE_DISPLAY | SHARED_IMAGE_USAGE_SCANOUT; + if (usage & ~allowed_usage) { + LOG(ERROR) << "Unsupported usage for SharedImage with initial data upload."; + return false; + } + + // Currently we only perform data uploads via two paths, + // |gl_backing_factory_| for GL and |wrapped_sk_image_factory_| for Vulkan. + // TODO(ericrk): Make this generic in the future. bool allow_legacy_mailbox = false; - auto* factory = GetFactoryByUsage(usage, &allow_legacy_mailbox); + SharedImageBackingFactory* factory = nullptr; + if (!using_vulkan_) { + allow_legacy_mailbox = true; + factory = gl_backing_factory_.get(); + } else { + factory = wrapped_sk_image_factory_.get(); + } if (!factory) return false; auto backing = factory->CreateSharedImage(mailbox, format, size, color_space,
diff --git a/gpu/command_buffer/service/shared_image_factory.h b/gpu/command_buffer/service/shared_image_factory.h index e2021e23..6c2a29e 100644 --- a/gpu/command_buffer/service/shared_image_factory.h +++ b/gpu/command_buffer/service/shared_image_factory.h
@@ -126,7 +126,7 @@ DawnDevice device); private: - SharedImageManager* manager_; + SharedImageManager* const manager_; std::unique_ptr<MemoryTypeTracker> tracker_; };
diff --git a/gpu/command_buffer/service/shared_image_representation.cc b/gpu/command_buffer/service/shared_image_representation.cc index 63d9963..9cedf2e 100644 --- a/gpu/command_buffer/service/shared_image_representation.cc +++ b/gpu/command_buffer/service/shared_image_representation.cc
@@ -11,6 +11,7 @@ SharedImageBacking* backing, MemoryTypeTracker* owning_tracker) : manager_(manager), backing_(backing), tracker_(owning_tracker) { + DCHECK(tracker_); backing_->AddRef(this); }
diff --git a/gpu/command_buffer/service/shared_image_representation.h b/gpu/command_buffer/service/shared_image_representation.h index a576094..27c1841 100644 --- a/gpu/command_buffer/service/shared_image_representation.h +++ b/gpu/command_buffer/service/shared_image_representation.h
@@ -54,9 +54,9 @@ bool has_context() const { return has_context_; } private: - SharedImageManager* manager_; - SharedImageBacking* backing_; - MemoryTypeTracker* tracker_; + SharedImageManager* const manager_; + SharedImageBacking* const backing_; + MemoryTypeTracker* const tracker_; bool has_context_ = true; };
diff --git a/gpu/ipc/client/image_decode_accelerator_proxy.cc b/gpu/ipc/client/image_decode_accelerator_proxy.cc index b6b35e64..ef7442f 100644 --- a/gpu/ipc/client/image_decode_accelerator_proxy.cc +++ b/gpu/ipc/client/image_decode_accelerator_proxy.cc
@@ -69,7 +69,7 @@ const uint8_t comp2_v = parse_result.frame_header.components[2].vertical_sampling_factor; - if (comp1_h != 1u || comp1_v != 1u || comp2_h == 1u || comp2_v == 1u) + if (comp1_h != 1u || comp1_v != 1u || comp2_h != 1u || comp2_v != 1u) return false; if (comp0_h == 2u && comp0_v == 2u) {
diff --git a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc index 122932f..8847c73 100644 --- a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc +++ b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc
@@ -22,7 +22,6 @@ #include "components/image_fetcher/ios/ios_image_decoder_impl.h" #include "components/keyed_service/core/service_access_type.h" #include "components/keyed_service/ios/browser_state_dependency_manager.h" -#include "components/ntp_snippets/breaking_news/breaking_news_listener.h" #include "components/ntp_snippets/category_rankers/category_ranker.h" #include "components/ntp_snippets/category_rankers/click_based_category_ranker.h" #include "components/ntp_snippets/category_rankers/constant_category_ranker.h" @@ -184,8 +183,7 @@ std::make_unique<RemoteSuggestionsDatabase>(db_provider, database_dir), std::make_unique<RemoteSuggestionsStatusServiceImpl>( identity_manager->HasPrimaryAccount(), prefs, pref_name), - /*prefetched_pages_tracker=*/nullptr, - /*breaking_news_raw_data_provider*/ nullptr, service->debug_logger(), + /*prefetched_pages_tracker=*/nullptr, service->debug_logger(), std::make_unique<base::OneShotTimer>()); service->remote_suggestions_scheduler()->SetProvider(provider.get());
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.h b/ios/chrome/browser/translate/chrome_ios_translate_client.h index a0cbbf7..32f49441 100644 --- a/ios/chrome/browser/translate/chrome_ios_translate_client.h +++ b/ios/chrome/browser/translate/chrome_ios_translate_client.h
@@ -20,16 +20,10 @@ class PrefService; -namespace metrics { -class TranslateEventProto; -} // namespace metrics - namespace translate { class TranslateAcceptLanguages; class TranslatePrefs; class TranslateManager; - -struct LanguageDetectionDetails; } // namespace translate namespace web { @@ -63,10 +57,6 @@ std::unique_ptr<translate::TranslatePrefs> GetTranslatePrefs() override; translate::TranslateAcceptLanguages* GetTranslateAcceptLanguages() override; int GetInfobarIconID() const override; - // Record language detection event. - void RecordLanguageDetectionEvent( - const translate::LanguageDetectionDetails& details) const override; - void RecordTranslateEvent(const metrics::TranslateEventProto&) override; std::unique_ptr<infobars::InfoBar> CreateInfoBar( std::unique_ptr<translate::TranslateInfoBarDelegate> delegate) const override;
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.mm b/ios/chrome/browser/translate/chrome_ios_translate_client.mm index 3843810..5b67e01 100644 --- a/ios/chrome/browser/translate/chrome_ios_translate_client.mm +++ b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
@@ -139,9 +139,6 @@ return std::make_unique<InfoBarIOS>(controller, std::move(delegate)); } -void ChromeIOSTranslateClient::RecordTranslateEvent( - const metrics::TranslateEventProto& translate_event) {} - bool ChromeIOSTranslateClient::ShowTranslateUI( translate::TranslateStep step, const std::string& source_language, @@ -193,9 +190,6 @@ return IDR_IOS_INFOBAR_TRANSLATE; } -void ChromeIOSTranslateClient::RecordLanguageDetectionEvent( - const translate::LanguageDetectionDetails& details) const {} - bool ChromeIOSTranslateClient::IsTranslatableURL(const GURL& url) { return TranslateServiceIOS::IsTranslatableURL(url); }
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm index 41a8580c..ef67729 100644 --- a/ios/chrome/browser/translate/translate_egtest.mm +++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -42,7 +42,6 @@ #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" #import "ios/chrome/test/earl_grey/chrome_matchers.h" -#import "ios/chrome/test/earl_grey/chrome_matchers_shorthand.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h" #import "ios/chrome/test/fakes/fake_language_detection_tab_helper_observer.h" #import "ios/web/public/test/earl_grey/web_view_matchers.h"
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm index 6a56b7cf..0670da4a 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -9,6 +9,7 @@ #include "components/ntp_snippets/pref_names.h" #include "components/ntp_snippets/remote/remote_suggestions_scheduler.h" #include "components/ntp_tiles/most_visited_sites.h" +#include "components/prefs/pref_service.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/favicon/ios_chrome_large_icon_cache_factory.h" #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
diff --git a/ios/chrome/browser/ui/fullscreen/BUILD.gn b/ios/chrome/browser/ui/fullscreen/BUILD.gn index b60dcf4..a755029 100644 --- a/ios/chrome/browser/ui/fullscreen/BUILD.gn +++ b/ios/chrome/browser/ui/fullscreen/BUILD.gn
@@ -146,6 +146,7 @@ "//ios/chrome/browser/web_state_list", "//ios/chrome/browser/web_state_list:test_support", "//ios/web/common", + "//ios/web/public", "//ios/web/public/test/fakes", "//testing/gmock", "//testing/gtest", @@ -171,6 +172,7 @@ "//ios/chrome/test/earl_grey:test_support", "//ios/web:earl_grey_test_support", "//ios/web/common", + "//ios/web/public", "//ios/web/public/test", "//ios/web/public/test/http_server", ]
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn index 992a0de1..39c2b27 100644 --- a/ios/chrome/test/earl_grey/BUILD.gn +++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -240,6 +240,7 @@ } source_set("test_support") { + defines = [ "CHROME_EARL_GREY_1" ] configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ @@ -255,8 +256,8 @@ "chrome_error_util.mm", "chrome_matchers.h", "chrome_matchers.mm", - "chrome_matchers_shorthand.h", - "chrome_matchers_shorthand.mm", + "chrome_matchers_app_interface.h", + "chrome_matchers_app_interface.mm", "chrome_test_case.h", "chrome_test_case.mm", ] @@ -327,3 +328,72 @@ "//ios/chrome/app:tests_hook", ] } + +source_set("eg_app_support+eg2") { + defines = [ "CHROME_EARL_GREY_2" ] + configs += [ + "//build/config/compiler:enable_arc", + "//build/config/ios:xctest_config", + ] + testonly = true + sources = [ + "chrome_error_util.h", + "chrome_error_util.mm", + "chrome_matchers_app_interface.h", + "chrome_matchers_app_interface.mm", + ] + + deps = [ + "//base", + "//components/signin/core/browser", + "//components/strings", + "//components/unified_consent", + "//ios/chrome/app/strings", + "//ios/chrome/browser/ui", + "//ios/chrome/browser/ui/authentication/cells", + "//ios/chrome/browser/ui/bookmarks:bookmarks_ui", + "//ios/chrome/browser/ui/content_suggestions:content_suggestions_ui", + "//ios/chrome/browser/ui/location_bar:location_bar", + "//ios/chrome/browser/ui/omnibox:omnibox_internal", + "//ios/chrome/browser/ui/payments:payments_ui", + "//ios/chrome/browser/ui/popup_menu:constants", + "//ios/chrome/browser/ui/settings:settings", + "//ios/chrome/browser/ui/settings/cells", + "//ios/chrome/browser/ui/settings/clear_browsing_data", + "//ios/chrome/browser/ui/settings/google_services", + "//ios/chrome/browser/ui/settings/sync", + "//ios/chrome/browser/ui/static_content", + "//ios/chrome/browser/ui/toolbar/public", + "//ios/chrome/test/app:test_support", + "//ios/testing/earl_grey:eg_app_support+eg2", + "//ios/testing/earl_grey:eg_app_support+eg2", + "//ios/third_party/earl_grey2:app_framework+link", + "//ios/web:eg_app_support+eg2", + "//ui/base", + "//ui/base:test_support", + ] +} + +source_set("eg_test_support+eg2") { + defines = [ "CHROME_EARL_GREY_2" ] + configs += [ + "//build/config/compiler:enable_arc", + "//build/config/ios:xctest_config", + ] + testonly = true + + sources = [ + "chrome_error_util.h", + "chrome_error_util.mm", + "chrome_matchers.h", + "chrome_matchers.mm", + "chrome_matchers_app_interface.h", + ] + + deps = [ + "//base", + "//ios/testing/earl_grey:eg_test_support+eg2", + "//ios/third_party/earl_grey2:test_lib", + "//url", + ] +}
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h index 6651c54..18f1d62 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers.h +++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -9,262 +9,259 @@ #include <string> -#import "ios/chrome/test/earl_grey/chrome_matchers_shorthand.h" - @protocol GREYMatcher; -@interface ChromeMatchers : NSObject +namespace chrome_test_util { + +// Matcher for element with accessibility label corresponding to |message_id| +// and accessibility trait UIAccessibilityTraitButton. +id<GREYMatcher> ButtonWithAccessibilityLabelId(int message_id); // Matcher for element with accessibility label corresponding to |label| and // accessibility trait UIAccessibilityTraitButton. -+ (id<GREYMatcher>)buttonWithAccessibilityLabel:(NSString*)label; +id<GREYMatcher> ButtonWithAccessibilityLabel(NSString* label); -// Matcher for element with accessibility label corresponding to |messageId| -// and accessibility trait UIAccessibilityTraitButton. -+ (id<GREYMatcher>)buttonWithAccessibilityLabelId:(int)messageId; - -// Matcher for element with an image corresponding to |imageId|. -+ (id<GREYMatcher>)imageViewWithImage:(int)imageId; +// Matcher for element with an image corresponding to |image_id|. +id<GREYMatcher> ImageViewWithImage(int image_id); // Matcher for element with an image defined by its name in the main bundle. -+ (id<GREYMatcher>)imageViewWithImageNamed:(NSString*)imageName; +id<GREYMatcher> ImageViewWithImageNamed(NSString* imageName); -// Matcher for element with an image corresponding to |imageId| and +// Matcher for element with an image corresponding to |image_id| and // accessibility trait UIAccessibilityTraitButton. -+ (id<GREYMatcher>)buttonWithImage:(int)imageId; +id<GREYMatcher> ButtonWithImage(int image_id); -// Matcher for element with accessibility label corresponding to |messageId| +// Matcher for element with accessibility label corresponding to |message_id| // and accessibility trait UIAccessibilityTraitStaticText. -+ (id<GREYMatcher>)staticTextWithAccessibilityLabelId:(int)messageId; +id<GREYMatcher> StaticTextWithAccessibilityLabelId(int message_id); // Matcher for element with accessibility label corresponding to |label| and // accessibility trait UIAccessibilityTraitStaticText. -+ (id<GREYMatcher>)staticTextWithAccessibilityLabel:(NSString*)label; +id<GREYMatcher> StaticTextWithAccessibilityLabel(NSString* label); -// Matcher for element with accessibility label corresponding to |messageId| +// Matcher for element with accessibility label corresponding to |message_id| // and accessibility trait UIAccessibilityTraitHeader. -+ (id<GREYMatcher>)headerWithAccessibilityLabelId:(int)messageId; +id<GREYMatcher> HeaderWithAccessibilityLabelId(int message_id); // Matcher for element with accessibility label corresponding to |label| and // accessibility trait UIAccessibilityTraitHeader. -+ (id<GREYMatcher>)headerWithAccessibilityLabel:(NSString*)label; +id<GREYMatcher> HeaderWithAccessibilityLabel(NSString* label); // Returns matcher for a cancel button. -+ (id<GREYMatcher>)cancelButton; +id<GREYMatcher> CancelButton(); // Returns matcher for a close button. -+ (id<GREYMatcher>)closeButton; +id<GREYMatcher> CloseButton(); // Matcher for the navigate forward button. -+ (id<GREYMatcher>)forwardButton; +id<GREYMatcher> ForwardButton(); // Matcher for the navigate backward button. -+ (id<GREYMatcher>)backButton; +id<GREYMatcher> BackButton(); // Matcher for the reload button. -+ (id<GREYMatcher>)reloadButton; +id<GREYMatcher> ReloadButton(); // Matcher for the stop loading button. -+ (id<GREYMatcher>)stopButton; +id<GREYMatcher> StopButton(); // Returns a matcher for the omnibox. -+ (id<GREYMatcher>)omnibox; +id<GREYMatcher> Omnibox(); // Returns a matcher for the location view. -+ (id<GREYMatcher>)defocusedLocationView; +id<GREYMatcher> DefocusedLocationView(); // Returns a matcher for the page security info button. -+ (id<GREYMatcher>)pageSecurityInfoButton; - +id<GREYMatcher> PageSecurityInfoButton(); // Returns a matcher for the page security info indicator. -+ (id<GREYMatcher>)pageSecurityInfoIndicator; +id<GREYMatcher> PageSecurityInfoIndicator(); // Returns matcher for omnibox containing |text|. Performs an exact match of the // omnibox contents. -+ (id<GREYMatcher>)omniboxText:(std::string)text; +id<GREYMatcher> OmniboxText(const std::string& text); // Returns matcher for |text| being a substring of the text in the omnibox. -+ (id<GREYMatcher>)omniboxContainingText:(std::string)text; +id<GREYMatcher> OmniboxContainingText(const std::string& text); // Returns matcher for |text| being a substring of the text in the location // view. -+ (id<GREYMatcher>)locationViewContainingText:(std::string)text; +id<GREYMatcher> LocationViewContainingText(const std::string& text); // Matcher for Tools menu button. -+ (id<GREYMatcher>)toolsMenuButton; +id<GREYMatcher> ToolsMenuButton(); // Matcher for the Share menu button. -+ (id<GREYMatcher>)shareButton; +id<GREYMatcher> ShareButton(); // Returns the GREYMatcher for the button that opens the tab switcher. -+ (id<GREYMatcher>)tabletTabSwitcherOpenButton; +id<GREYMatcher> TabletTabSwitcherOpenButton(); // Matcher for show tabs button. -+ (id<GREYMatcher>)showTabsButton; +id<GREYMatcher> ShowTabsButton(); // Matcher for SettingsSwitchCell. -+ (id<GREYMatcher>)settingsSwitchCell:(NSString*)accessibilityIdentifier - isToggledOn:(BOOL)isToggledOn; +id<GREYMatcher> SettingsSwitchCell(NSString* accessibility_identifier, + BOOL is_toggled_on); // Matcher for SettingsSwitchCell. -+ (id<GREYMatcher>)settingsSwitchCell:(NSString*)accessibilityIdentifier - isToggledOn:(BOOL)isToggledOn - isEnabled:(BOOL)isEnabled; +id<GREYMatcher> SettingsSwitchCell(NSString* accessibility_identifier, + BOOL is_toggled_on, + BOOL is_enabled); -// Matcher for SyncSwitchCell. -+ (id<GREYMatcher>)syncSwitchCell:(NSString*)accessibilityLabel - isToggledOn:(BOOL)isToggledOn; +// Matcher for LegacySyncSwitchCell. +id<GREYMatcher> SyncSwitchCell(NSString* accessibility_label, + BOOL is_toggled_on); // Matcher for the Open in New Tab option in the context menu when long pressing // a link. -+ (id<GREYMatcher>)openLinkInNewTabButton; +id<GREYMatcher> OpenLinkInNewTabButton(); // Matcher for the done button on the navigation bar. -+ (id<GREYMatcher>)navigationBarDoneButton; +id<GREYMatcher> NavigationBarDoneButton(); // Matcher for the done button on the Bookmarks navigation bar. -+ (id<GREYMatcher>)bookmarksNavigationBarDoneButton; +id<GREYMatcher> BookmarksNavigationBarDoneButton(); // Returns matcher for the account consistency setup signin button. -+ (id<GREYMatcher>)accountConsistencySetupSigninButton; +id<GREYMatcher> AccountConsistencySetupSigninButton(); // Returns matcher for the account consistency confirmation button. -+ (id<GREYMatcher>)accountConsistencyConfirmationOkButton; +id<GREYMatcher> AccountConsistencyConfirmationOkButton(); // Returns matcher for the add account accounts button. -+ (id<GREYMatcher>)addAccountButton; +id<GREYMatcher> AddAccountButton(); // Returns matcher for the sign out accounts button. -+ (id<GREYMatcher>)signOutAccountsButton; +id<GREYMatcher> SignOutAccountsButton(); // Returns matcher for the Clear Browsing Data cell on the Privacy screen. -+ (id<GREYMatcher>)clearBrowsingDataCell; +id<GREYMatcher> ClearBrowsingDataCell(); // Returns matcher for the clear browsing data button on the clear browsing data // panel. -+ (id<GREYMatcher>)clearBrowsingDataButton; +id<GREYMatcher> ClearBrowsingDataButton(); // Returns matcher for the clear browsing data view. -+ (id<GREYMatcher>)clearBrowsingDataView; +id<GREYMatcher> ClearBrowsingDataView(); // Matcher for the clear browsing data action sheet item. -+ (id<GREYMatcher>)confirmClearBrowsingDataButton; +id<GREYMatcher> ConfirmClearBrowsingDataButton(); // Returns matcher for the settings button in the tools menu. -+ (id<GREYMatcher>)settingsMenuButton; +id<GREYMatcher> SettingsMenuButton(); // Returns matcher for the "Done" button in the settings' navigation bar. -+ (id<GREYMatcher>)settingsDoneButton; +id<GREYMatcher> SettingsDoneButton(); // Returns matcher for the tools menu table view. -+ (id<GREYMatcher>)toolsMenuView; +id<GREYMatcher> ToolsMenuView(); // Returns matcher for the OK button. -+ (id<GREYMatcher>)okButton; +id<GREYMatcher> OKButton(); // Returns matcher for the primary button in the sign-in promo view. This is // "Sign in into Chrome" button for a cold state, or "Continue as John Doe" for // a warm state. -+ (id<GREYMatcher>)primarySignInButton; +id<GREYMatcher> PrimarySignInButton(); // Returns matcher for the secondary button in the sign-in promo view. This is // "Not johndoe@example.com" button. -+ (id<GREYMatcher>)secondarySignInButton; +id<GREYMatcher> SecondarySignInButton(); // Returns matcher for the button for the currently signed in account in the // settings menu. -+ (id<GREYMatcher>)settingsAccountButton; +id<GREYMatcher> SettingsAccountButton(); // Returns matcher for the accounts collection view. -+ (id<GREYMatcher>)settingsAccountsCollectionView; +id<GREYMatcher> SettingsAccountsCollectionView(); // Returns matcher for the Import Data cell in switch sync account view. -+ (id<GREYMatcher>)settingsImportDataImportButton; +id<GREYMatcher> SettingsImportDataImportButton(); // Returns matcher for the Keep Data Separate cell in switch sync account view. -+ (id<GREYMatcher>)settingsImportDataKeepSeparateButton; +id<GREYMatcher> SettingsImportDataKeepSeparateButton(); // Returns matcher for the Manage Synced Data button in sync setting view. -+ (id<GREYMatcher>)settingsSyncManageSyncedDataButton; +id<GREYMatcher> SettingsSyncManageSyncedDataButton(); // Returns matcher for the menu button to sync accounts. -+ (id<GREYMatcher>)accountsSyncButton; +id<GREYMatcher> AccountsSyncButton(); // Returns matcher for the Content Settings button on the main Settings screen. -+ (id<GREYMatcher>)contentSettingsButton; +id<GREYMatcher> ContentSettingsButton(); // Returns matcher for the Google Services Settings button on the main Settings // screen. -+ (id<GREYMatcher>)googleServicesSettingsButton; +id<GREYMatcher> GoogleServicesSettingsButton(); // Returns matcher for the back button on a settings menu. -+ (id<GREYMatcher>)settingsMenuBackButton; +id<GREYMatcher> SettingsMenuBackButton(); // Returns matcher for the Privacy cell on the main Settings screen. -+ (id<GREYMatcher>)settingsMenuPrivacyButton; +id<GREYMatcher> SettingsMenuPrivacyButton(); // Returns matcher for the Save passwords cell on the main Settings screen. -+ (id<GREYMatcher>)settingsMenuPasswordsButton; +id<GREYMatcher> SettingsMenuPasswordsButton(); // Returns matcher for the payment request collection view. -+ (id<GREYMatcher>)paymentRequestView; +id<GREYMatcher> PaymentRequestView(); // Returns matcher for the error confirmation view for payment request. -+ (id<GREYMatcher>)paymentRequestErrorView; +id<GREYMatcher> PaymentRequestErrorView(); // Returns matcher for the voice search button on the main Settings screen. -+ (id<GREYMatcher>)voiceSearchButton; +id<GREYMatcher> VoiceSearchButton(); // Returns matcher for the settings main menu view. -+ (id<GREYMatcher>)settingsCollectionView; +id<GREYMatcher> SettingsCollectionView(); // Returns matcher for the clear browsing history cell on the clear browsing // data panel. -+ (id<GREYMatcher>)clearBrowsingHistoryButton; +id<GREYMatcher> ClearBrowsingHistoryButton(); // Returns matcher for the clear cookies cell on the clear browsing data panel. -+ (id<GREYMatcher>)clearCookiesButton; +id<GREYMatcher> ClearCookiesButton(); // Returns matcher for the clear cache cell on the clear browsing data panel. -+ (id<GREYMatcher>)clearCacheButton; +id<GREYMatcher> ClearCacheButton(); // Returns matcher for the clear saved passwords cell on the clear browsing data // panel. -+ (id<GREYMatcher>)clearSavedPasswordsButton; +id<GREYMatcher> ClearSavedPasswordsButton(); // Returns matcher for the collection view of content suggestion. -+ (id<GREYMatcher>)contentSuggestionCollectionView; +id<GREYMatcher> ContentSuggestionCollectionView(); // Returns matcher for the warning message while filling in payment requests. -+ (id<GREYMatcher>)warningMessageView; +id<GREYMatcher> WarningMessageView(); // Returns matcher for the payment picker cell. -+ (id<GREYMatcher>)paymentRequestPickerRow; +id<GREYMatcher> PaymentRequestPickerRow(); // Returns matcher for the payment request search bar. -+ (id<GREYMatcher>)paymentRequestPickerSearchBar; +id<GREYMatcher> PaymentRequestPickerSearchBar(); // Returns matcher for the bookmarks button on the Tools menu. -+ (id<GREYMatcher>)bookmarksMenuButton; +id<GREYMatcher> BookmarksMenuButton(); // Returns matcher for the recent tabs button on the Tools menu. -+ (id<GREYMatcher>)recentTabsMenuButton; +id<GREYMatcher> RecentTabsMenuButton(); // Returns matcher for the system selection callout. -+ (id<GREYMatcher>)systemSelectionCallout; +id<GREYMatcher> SystemSelectionCallout(); // Returns matcher for the copy button on the system selection callout. -+ (id<GREYMatcher>)systemSelectionCalloutCopyButton; +id<GREYMatcher> SystemSelectionCalloutCopyButton(); // Returns matcher for the Copy item on the context menu. -+ (id<GREYMatcher>)contextMenuCopyButton; +id<GREYMatcher> ContextMenuCopyButton(); // Returns matcher for defoucesed omnibox on a new tab. -+ (id<GREYMatcher>)NTPOmnibox; +id<GREYMatcher> NewTabPageOmnibox(); // Returns a matcher for the current WebView. -+ (id<GREYMatcher>)webViewMatcher; +id<GREYMatcher> WebViewMatcher(); -@end +} #endif // IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_H_
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm index 1be10ea..62bbdd7 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers.mm +++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -4,551 +4,333 @@ #import "ios/chrome/test/earl_grey/chrome_matchers.h" -#import <EarlGrey/EarlGrey.h> -#import <WebKit/WebKit.h> - -#include "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" -#include "components/strings/grit/components_strings.h" -#include "components/unified_consent/feature.h" -#import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h" -#import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h" -#import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h" -#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h" -#import "ios/chrome/browser/ui/location_bar/location_bar_steady_view.h" -#import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h" -#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h" -#import "ios/chrome/browser/ui/payments/payment_request_error_view_controller.h" -#import "ios/chrome/browser/ui/payments/payment_request_picker_view_controller.h" -#import "ios/chrome/browser/ui/payments/payment_request_view_controller.h" -#import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h" -#import "ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h" -#import "ios/chrome/browser/ui/settings/cells/settings_switch_cell.h" -#import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h" -#import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.h" -#import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_ui_constants.h" -#import "ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.h" -#import "ios/chrome/browser/ui/settings/import_data_table_view_controller.h" -#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h" -#import "ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.h" -#import "ios/chrome/browser/ui/static_content/static_html_view_controller.h" -#import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h" -#import "ios/chrome/browser/ui/util/uikit_ui_util.h" -#include "ios/chrome/grit/ios_strings.h" -#import "ios/chrome/test/app/chrome_test_util.h" -#import "ios/web/public/test/earl_grey/web_view_matchers.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/test/ios/ui_image_test_utils.h" +#import "ios/chrome/test/earl_grey/chrome_matchers_app_interface.h" +#import "ios/testing/earl_grey/earl_grey_test.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -namespace { +#if defined(CHROME_EARL_GREY_2) +GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(ChromeMatchersAppInterface) +#endif -id<GREYMatcher> SettingsSwitchIsToggledOn(BOOL isToggledOn) { - MatchesBlock matches = ^BOOL(id element) { - SettingsSwitchCell* switch_cell = - base::mac::ObjCCastStrict<SettingsSwitchCell>(element); - UISwitch* switch_view = switch_cell.switchView; - return (switch_view.on && isToggledOn) || (!switch_view.on && !isToggledOn); - }; - DescribeToBlock describe = ^void(id<GREYDescription> description) { - NSString* name = - [NSString stringWithFormat:@"settingsSwitchToggledState(%@)", - isToggledOn ? @"ON" : @"OFF"]; - [description appendText:name]; - }; - return [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches - descriptionBlock:describe]; -} +namespace chrome_test_util { -id<GREYMatcher> SettingsSwitchIsEnabled(BOOL isEnabled) { - MatchesBlock matches = ^BOOL(id element) { - SettingsSwitchCell* switch_cell = - base::mac::ObjCCastStrict<SettingsSwitchCell>(element); - UISwitch* switch_view = switch_cell.switchView; - return (switch_view.enabled && isEnabled) || - (!switch_view.enabled && !isEnabled); - }; - DescribeToBlock describe = ^void(id<GREYDescription> description) { - NSString* name = - [NSString stringWithFormat:@"settingsSwitchEnabledState(%@)", - isEnabled ? @"YES" : @"NO"]; - [description appendText:name]; - }; - return [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches - descriptionBlock:describe]; +id<GREYMatcher> ButtonWithAccessibilityLabel(NSString* label) { + return [ChromeMatchersAppInterface buttonWithAccessibilityLabel:label]; } -// Returns the subview of |parentView| corresponding to the -// ContentSuggestionsViewController. Returns nil if it is not in its subviews. -UIView* SubviewWithAccessibilityIdentifier(NSString* accessibilityID, - UIView* parentView) { - if (parentView.accessibilityIdentifier == accessibilityID) { - return parentView; - } - for (UIView* view in parentView.subviews) { - UIView* resultView = - SubviewWithAccessibilityIdentifier(accessibilityID, view); - if (resultView) - return resultView; - } - return nil; +id<GREYMatcher> ButtonWithAccessibilityLabelId(int message_id) { + return [ChromeMatchersAppInterface buttonWithAccessibilityLabelID:message_id]; } -} // namespace - -@implementation ChromeMatchers - -+ (id<GREYMatcher>)buttonWithAccessibilityLabel:(NSString*)label { - return grey_allOf(grey_accessibilityLabel(label), - grey_accessibilityTrait(UIAccessibilityTraitButton), nil); +id<GREYMatcher> ImageViewWithImageNamed(NSString* imageName) { + return [ChromeMatchersAppInterface imageViewWithImageNamed:imageName]; } -+ (id<GREYMatcher>)buttonWithAccessibilityLabelId:(int)messageId { - return [ChromeMatchers - buttonWithAccessibilityLabel:l10n_util::GetNSStringWithFixup(messageId)]; +id<GREYMatcher> ImageViewWithImage(int image_id) { + return [ChromeMatchersAppInterface imageViewWithImage:image_id]; } -+ (id<GREYMatcher>)imageViewWithImageNamed:(NSString*)imageName { - UIImage* expectedImage = [UIImage imageNamed:imageName]; - MatchesBlock matches = ^BOOL(UIImageView* imageView) { - return ui::test::uiimage_utils::UIImagesAreEqual(expectedImage, - imageView.image); - }; - NSString* descriptionString = - [NSString stringWithFormat:@"Images matching image named %@", imageName]; - DescribeToBlock describe = ^(id<GREYDescription> description) { - [description appendText:descriptionString]; - }; - id<GREYMatcher> imageMatcher = - [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches - descriptionBlock:describe]; - return imageMatcher; +id<GREYMatcher> ButtonWithImage(int image_id) { + return [ChromeMatchersAppInterface buttonWithImage:image_id]; } -+ (id<GREYMatcher>)imageViewWithImage:(int)imageId { - UIImage* expectedImage = NativeImage(imageId); - MatchesBlock matches = ^BOOL(UIImageView* imageView) { - return ui::test::uiimage_utils::UIImagesAreEqual(expectedImage, - imageView.image); - }; - NSString* descriptionString = - [NSString stringWithFormat:@"Images matching %i", imageId]; - DescribeToBlock describe = ^(id<GREYDescription> description) { - [description appendText:descriptionString]; - }; - id<GREYMatcher> imageMatcher = - [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches - descriptionBlock:describe]; - return imageMatcher; +id<GREYMatcher> StaticTextWithAccessibilityLabelId(int message_id) { + return [ChromeMatchersAppInterface + staticTextWithAccessibilityLabelID:message_id]; } -+ (id<GREYMatcher>)buttonWithImage:(int)imageId { - UIImage* expectedImage = NativeImage(imageId); - MatchesBlock matches = ^BOOL(UIButton* button) { - return ui::test::uiimage_utils::UIImagesAreEqual(expectedImage, - [button currentImage]); - }; - NSString* descriptionString = - [NSString stringWithFormat:@"Images matching %i", imageId]; - DescribeToBlock describe = ^(id<GREYDescription> description) { - [description appendText:descriptionString]; - }; - id<GREYMatcher> imageMatcher = - [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches - descriptionBlock:describe]; - return grey_allOf(grey_accessibilityTrait(UIAccessibilityTraitButton), - imageMatcher, nil); +id<GREYMatcher> StaticTextWithAccessibilityLabel(NSString* label) { + return [ChromeMatchersAppInterface staticTextWithAccessibilityLabel:label]; } -+ (id<GREYMatcher>)staticTextWithAccessibilityLabelId:(int)messageId { - return [ChromeMatchers - staticTextWithAccessibilityLabel:(l10n_util::GetNSStringWithFixup( - messageId))]; +id<GREYMatcher> HeaderWithAccessibilityLabelId(int message_id) { + return [ChromeMatchersAppInterface headerWithAccessibilityLabelID:message_id]; } -+ (id<GREYMatcher>)staticTextWithAccessibilityLabel:(NSString*)label { - return grey_allOf(grey_accessibilityLabel(label), - grey_accessibilityTrait(UIAccessibilityTraitStaticText), - nil); +id<GREYMatcher> HeaderWithAccessibilityLabel(NSString* label) { + return [ChromeMatchersAppInterface headerWithAccessibilityLabel:label]; } -+ (id<GREYMatcher>)headerWithAccessibilityLabelId:(int)messageId { - return [ChromeMatchers - headerWithAccessibilityLabel:(l10n_util::GetNSStringWithFixup( - messageId))]; +id<GREYMatcher> CancelButton() { + return [ChromeMatchersAppInterface cancelButton]; } -+ (id<GREYMatcher>)headerWithAccessibilityLabel:(NSString*)label { - return grey_allOf(grey_accessibilityLabel(label), - grey_accessibilityTrait(UIAccessibilityTraitHeader), nil); +id<GREYMatcher> CloseButton() { + return [ChromeMatchersAppInterface closeButton]; } -+ (id<GREYMatcher>)cancelButton { - return [ChromeMatchers buttonWithAccessibilityLabelId:(IDS_CANCEL)]; +id<GREYMatcher> ForwardButton() { + return [ChromeMatchersAppInterface forwardButton]; } -+ (id<GREYMatcher>)closeButton { - return [ChromeMatchers buttonWithAccessibilityLabelId:(IDS_CLOSE)]; +id<GREYMatcher> BackButton() { + return [ChromeMatchersAppInterface backButton]; } -+ (id<GREYMatcher>)forwardButton { - return [ChromeMatchers buttonWithAccessibilityLabelId:(IDS_ACCNAME_FORWARD)]; +id<GREYMatcher> ReloadButton() { + return [ChromeMatchersAppInterface reloadButton]; } -+ (id<GREYMatcher>)backButton { - return [ChromeMatchers buttonWithAccessibilityLabelId:(IDS_ACCNAME_BACK)]; +id<GREYMatcher> StopButton() { + return [ChromeMatchersAppInterface stopButton]; } -+ (id<GREYMatcher>)reloadButton { - return - [ChromeMatchers buttonWithAccessibilityLabelId:(IDS_IOS_ACCNAME_RELOAD)]; +id<GREYMatcher> Omnibox() { + return [ChromeMatchersAppInterface omnibox]; } -+ (id<GREYMatcher>)stopButton { - return [ChromeMatchers buttonWithAccessibilityLabelId:(IDS_IOS_ACCNAME_STOP)]; +id<GREYMatcher> DefocusedLocationView() { + return [ChromeMatchersAppInterface defocusedLocationView]; } -+ (id<GREYMatcher>)omnibox { - return grey_allOf(grey_kindOfClass([OmniboxTextFieldIOS class]), - grey_userInteractionEnabled(), nil); +id<GREYMatcher> PageSecurityInfoButton() { + return [ChromeMatchersAppInterface pageSecurityInfoButton]; } -+ (id<GREYMatcher>)defocusedLocationView { - return grey_kindOfClass([LocationBarSteadyView class]); +id<GREYMatcher> PageSecurityInfoIndicator() { + return [ChromeMatchersAppInterface pageSecurityInfoIndicator]; } -+ (id<GREYMatcher>)pageSecurityInfoButton { - return grey_accessibilityLabel(@"Page Security Info"); +id<GREYMatcher> OmniboxText(const std::string& text) { + return [ChromeMatchersAppInterface omniboxText:base::SysUTF8ToNSString(text)]; } -+ (id<GREYMatcher>)pageSecurityInfoIndicator { - return grey_accessibilityLabel(@"Page Security Info"); +id<GREYMatcher> OmniboxContainingText(const std::string& text) { + return [ChromeMatchersAppInterface + omniboxContainingText:base::SysUTF8ToNSString(text)]; } -+ (id<GREYMatcher>)omniboxText:(std::string)text { - GREYElementMatcherBlock* matcher = [GREYElementMatcherBlock - matcherWithMatchesBlock:^BOOL(id element) { - OmniboxTextFieldIOS* omnibox = - base::mac::ObjCCast<OmniboxTextFieldIOS>(element); - return [omnibox.text isEqualToString:base::SysUTF8ToNSString(text)]; - } - descriptionBlock:^void(id<GREYDescription> description) { - [description - appendText:[NSString - stringWithFormat:@"Omnibox contains text \"%@\"", - base::SysUTF8ToNSString(text)]]; - }]; - return matcher; +id<GREYMatcher> LocationViewContainingText(const std::string& text) { + return [ChromeMatchersAppInterface + locationViewContainingText:base::SysUTF8ToNSString(text)]; } -+ (id<GREYMatcher>)omniboxContainingText:(std::string)text { - GREYElementMatcherBlock* matcher = [GREYElementMatcherBlock - matcherWithMatchesBlock:^BOOL(UITextField* element) { - return [element.text containsString:base::SysUTF8ToNSString(text)]; - } - descriptionBlock:^void(id<GREYDescription> description) { - [description - appendText:[NSString - stringWithFormat:@"Omnibox contains text \"%@\"", - base::SysUTF8ToNSString(text)]]; - }]; - return matcher; +id<GREYMatcher> ToolsMenuButton() { + return [ChromeMatchersAppInterface toolsMenuButton]; } -+ (id<GREYMatcher>)locationViewContainingText:(std::string)text { - GREYElementMatcherBlock* matcher = [GREYElementMatcherBlock - matcherWithMatchesBlock:^BOOL(LocationBarSteadyView* element) { - return [element.locationLabel.text - containsString:base::SysUTF8ToNSString(text)]; - } - descriptionBlock:^void(id<GREYDescription> description) { - [description - appendText:[NSString - stringWithFormat: - @"LocationBarSteadyView contains text \"%@\"", - base::SysUTF8ToNSString(text)]]; - }]; - return matcher; +id<GREYMatcher> ShareButton() { + return [ChromeMatchersAppInterface shareButton]; } -+ (id<GREYMatcher>)toolsMenuButton { - return grey_allOf(grey_accessibilityID(kToolbarToolsMenuButtonIdentifier), - grey_sufficientlyVisible(), nil); +id<GREYMatcher> TabletTabSwitcherOpenButton() { + return [ChromeMatchersAppInterface tabletTabSwitcherOpenButton]; } -+ (id<GREYMatcher>)shareButton { - return grey_allOf( - [ChromeMatchers - buttonWithAccessibilityLabelId:(IDS_IOS_TOOLS_MENU_SHARE)], - grey_sufficientlyVisible(), nil); +id<GREYMatcher> ShowTabsButton() { + return [ChromeMatchersAppInterface showTabsButton]; } -+ (id<GREYMatcher>)tabletTabSwitcherOpenButton { - return [ChromeMatchers - buttonWithAccessibilityLabelId:(IDS_IOS_TAB_STRIP_ENTER_TAB_SWITCHER)]; +id<GREYMatcher> SettingsSwitchCell(NSString* accessibility_identifier, + BOOL is_toggled_on) { + return [ChromeMatchersAppInterface settingsSwitchCell:accessibility_identifier + isToggledOn:is_toggled_on]; } -+ (id<GREYMatcher>)showTabsButton { - return grey_allOf(grey_accessibilityID(kToolbarStackButtonIdentifier), - grey_sufficientlyVisible(), nil); -} - -+ (id<GREYMatcher>)settingsSwitchCell:(NSString*)accessibilityIdentifier - isToggledOn:(BOOL)isToggledOn { - return [ChromeMatchers settingsSwitchCell:accessibilityIdentifier - isToggledOn:isToggledOn - isEnabled:YES]; -} - -+ (id<GREYMatcher>)settingsSwitchCell:(NSString*)accessibilityIdentifier - isToggledOn:(BOOL)isToggledOn - isEnabled:(BOOL)isEnabled { - return grey_allOf(grey_accessibilityID(accessibilityIdentifier), - SettingsSwitchIsToggledOn(isToggledOn), - SettingsSwitchIsEnabled(isEnabled), - grey_sufficientlyVisible(), nil); +id<GREYMatcher> SettingsSwitchCell(NSString* accessibility_identifier, + BOOL is_toggled_on, + BOOL is_enabled) { + return [ChromeMatchersAppInterface settingsSwitchCell:accessibility_identifier + isToggledOn:is_toggled_on + isEnabled:is_enabled]; } -+ (id<GREYMatcher>)syncSwitchCell:(NSString*)accessibilityLabel - isToggledOn:(BOOL)isToggledOn { - return grey_allOf( - grey_accessibilityLabel(accessibilityLabel), - grey_accessibilityValue( - isToggledOn ? l10n_util::GetNSString(IDS_IOS_SETTING_ON) - : l10n_util::GetNSString(IDS_IOS_SETTING_OFF)), - grey_sufficientlyVisible(), nil); +id<GREYMatcher> SyncSwitchCell(NSString* accessibility_label, + BOOL is_toggled_on) { + return [ChromeMatchersAppInterface syncSwitchCell:accessibility_label + isToggledOn:is_toggled_on]; } -+ (id<GREYMatcher>)openLinkInNewTabButton { - return [ChromeMatchers - buttonWithAccessibilityLabelId:(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)]; +id<GREYMatcher> OpenLinkInNewTabButton() { + return [ChromeMatchersAppInterface openLinkInNewTabButton]; } -+ (id<GREYMatcher>)navigationBarDoneButton { - return grey_allOf( - [ChromeMatchers - buttonWithAccessibilityLabelId:(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON)], - grey_userInteractionEnabled(), nil); +id<GREYMatcher> NavigationBarDoneButton() { + return [ChromeMatchersAppInterface navigationBarDoneButton]; } -+ (id<GREYMatcher>)bookmarksNavigationBarDoneButton { - return grey_accessibilityID(kBookmarkHomeNavigationBarDoneButtonIdentifier); +id<GREYMatcher> BookmarksNavigationBarDoneButton() { + return [ChromeMatchersAppInterface bookmarksNavigationBarDoneButton]; } -+ (id<GREYMatcher>)accountConsistencySetupSigninButton { - return [ChromeMatchers buttonWithAccessibilityLabelId: - (IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SIGNIN_BUTTON)]; +id<GREYMatcher> AccountConsistencySetupSigninButton() { + return [ChromeMatchersAppInterface accountConsistencySetupSigninButton]; } -+ (id<GREYMatcher>)accountConsistencyConfirmationOkButton { - int labelID = base::FeatureList::IsEnabled(unified_consent::kUnifiedConsent) - ? IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON - : IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OK_BUTTON; - return [ChromeMatchers buttonWithAccessibilityLabelId:(labelID)]; +id<GREYMatcher> AccountConsistencyConfirmationOkButton() { + return [ChromeMatchersAppInterface accountConsistencyConfirmationOKButton]; } -+ (id<GREYMatcher>)addAccountButton { - return grey_accessibilityID(kSettingsAccountsTableViewAddAccountCellId); +id<GREYMatcher> AddAccountButton() { + return [ChromeMatchersAppInterface addAccountButton]; } -+ (id<GREYMatcher>)signOutAccountsButton { - return grey_accessibilityID(kSettingsAccountsTableViewSignoutCellId); +id<GREYMatcher> SignOutAccountsButton() { + return [ChromeMatchersAppInterface signOutAccountsButton]; } -+ (id<GREYMatcher>)clearBrowsingDataCell { - return [ChromeMatchers - buttonWithAccessibilityLabelId:(IDS_IOS_CLEAR_BROWSING_DATA_TITLE)]; +id<GREYMatcher> ClearBrowsingDataCell() { + return [ChromeMatchersAppInterface clearBrowsingDataCell]; } -+ (id<GREYMatcher>)clearBrowsingDataButton { - return grey_accessibilityID(kClearBrowsingDataButtonIdentifier); +id<GREYMatcher> ClearBrowsingDataButton() { + return [ChromeMatchersAppInterface clearBrowsingDataButton]; } -+ (id<GREYMatcher>)clearBrowsingDataView { - return grey_accessibilityID(kClearBrowsingDataViewAccessibilityIdentifier); +id<GREYMatcher> ClearBrowsingDataView() { + return [ChromeMatchersAppInterface clearBrowsingDataView]; } -+ (id<GREYMatcher>)confirmClearBrowsingDataButton { - return grey_allOf( - grey_accessibilityLabel(l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON)), - grey_accessibilityTrait(UIAccessibilityTraitButton), - grey_not(grey_accessibilityID(kClearBrowsingDataButtonIdentifier)), - grey_userInteractionEnabled(), nil); +id<GREYMatcher> ConfirmClearBrowsingDataButton() { + return [ChromeMatchersAppInterface confirmClearBrowsingDataButton]; } -+ (id<GREYMatcher>)settingsMenuButton { - return grey_accessibilityID(kToolsMenuSettingsId); +id<GREYMatcher> SettingsMenuButton() { + return [ChromeMatchersAppInterface settingsMenuButton]; } -+ (id<GREYMatcher>)settingsDoneButton { - return grey_accessibilityID(kSettingsDoneButtonId); +id<GREYMatcher> SettingsDoneButton() { + return [ChromeMatchersAppInterface settingsDoneButton]; } -+ (id<GREYMatcher>)toolsMenuView { - return grey_accessibilityID(kPopupMenuToolsMenuTableViewId); +id<GREYMatcher> ToolsMenuView() { + return [ChromeMatchersAppInterface toolsMenuView]; } -+ (id<GREYMatcher>)okButton { - return [ChromeMatchers buttonWithAccessibilityLabelId:(IDS_OK)]; +id<GREYMatcher> OKButton() { + return [ChromeMatchersAppInterface OKButton]; } -+ (id<GREYMatcher>)primarySignInButton { - return grey_accessibilityID(kSigninPromoPrimaryButtonId); +id<GREYMatcher> PrimarySignInButton() { + return [ChromeMatchersAppInterface primarySignInButton]; } -+ (id<GREYMatcher>)secondarySignInButton { - return grey_accessibilityID(kSigninPromoSecondaryButtonId); +id<GREYMatcher> SecondarySignInButton() { + return [ChromeMatchersAppInterface secondarySignInButton]; } -+ (id<GREYMatcher>)settingsAccountButton { - return grey_accessibilityID(kSettingsAccountCellId); +id<GREYMatcher> SettingsAccountButton() { + return [ChromeMatchersAppInterface settingsAccountButton]; } -+ (id<GREYMatcher>)settingsAccountsCollectionView { - return grey_accessibilityID(kSettingsAccountsTableViewId); +id<GREYMatcher> SettingsAccountsCollectionView() { + return [ChromeMatchersAppInterface settingsAccountsCollectionView]; } -+ (id<GREYMatcher>)settingsImportDataImportButton { - return grey_accessibilityID(kImportDataImportCellId); +id<GREYMatcher> SettingsImportDataImportButton() { + return [ChromeMatchersAppInterface settingsImportDataImportButton]; } -+ (id<GREYMatcher>)settingsImportDataKeepSeparateButton { - return grey_accessibilityID(kImportDataKeepSeparateCellId); +id<GREYMatcher> SettingsImportDataKeepSeparateButton() { + return [ChromeMatchersAppInterface settingsImportDataKeepSeparateButton]; } -+ (id<GREYMatcher>)settingsSyncManageSyncedDataButton { - return grey_accessibilityID(kSettingsSyncId); +id<GREYMatcher> SettingsSyncManageSyncedDataButton() { + return [ChromeMatchersAppInterface settingsSyncManageSyncedDataButton]; } -+ (id<GREYMatcher>)accountsSyncButton { - return grey_allOf(grey_accessibilityID(kSettingsAccountsTableViewSyncCellId), - grey_sufficientlyVisible(), nil); +id<GREYMatcher> AccountsSyncButton() { + return [ChromeMatchersAppInterface accountsSyncButton]; } -+ (id<GREYMatcher>)contentSettingsButton { - return [ChromeMatchers - buttonWithAccessibilityLabelId:(IDS_IOS_CONTENT_SETTINGS_TITLE)]; +id<GREYMatcher> ContentSettingsButton() { + return [ChromeMatchersAppInterface contentSettingsButton]; } -+ (id<GREYMatcher>)googleServicesSettingsButton { - NSString* syncAndGoogleServicesTitle = - l10n_util::GetNSStringWithFixup(IDS_IOS_GOOGLE_SERVICES_SETTINGS_TITLE); - id<GREYMatcher> mainTextLabelMatcher = - grey_allOf(grey_accessibilityLabel(syncAndGoogleServicesTitle), - grey_sufficientlyVisible(), nil); - return grey_allOf(grey_kindOfClass([UITableViewCell class]), - grey_sufficientlyVisible(), - grey_descendant(mainTextLabelMatcher), nil); +id<GREYMatcher> GoogleServicesSettingsButton() { + return [ChromeMatchersAppInterface googleServicesSettingsButton]; } -+ (id<GREYMatcher>)settingsMenuBackButton { - UINavigationBar* navBar = base::mac::ObjCCastStrict<UINavigationBar>( - SubviewWithAccessibilityIdentifier( - @"SettingNavigationBar", - [[UIApplication sharedApplication] keyWindow])); - return grey_allOf(grey_anyOf(grey_accessibilityLabel(navBar.backItem.title), - grey_accessibilityLabel(@"Back"), nil), - grey_kindOfClass([UIButton class]), - grey_ancestor(grey_kindOfClass([UINavigationBar class])), - nil); +id<GREYMatcher> SettingsMenuBackButton() { + return [ChromeMatchersAppInterface settingsMenuBackButton]; } -+ (id<GREYMatcher>)settingsMenuPrivacyButton { - return [ChromeMatchers buttonWithAccessibilityLabelId: - (IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY)]; +id<GREYMatcher> SettingsMenuPrivacyButton() { + return [ChromeMatchersAppInterface settingsMenuPrivacyButton]; } -+ (id<GREYMatcher>)settingsMenuPasswordsButton { - return [ChromeMatchers buttonWithAccessibilityLabelId:(IDS_IOS_PASSWORDS)]; +id<GREYMatcher> SettingsMenuPasswordsButton() { + return [ChromeMatchersAppInterface settingsMenuPasswordsButton]; } -+ (id<GREYMatcher>)paymentRequestView { - return grey_accessibilityID(kPaymentRequestCollectionViewID); +id<GREYMatcher> PaymentRequestView() { + return [ChromeMatchersAppInterface paymentRequestView]; } -// Returns matcher for the error confirmation view for payment request. -+ (id<GREYMatcher>)paymentRequestErrorView { - return grey_accessibilityID(kPaymentRequestErrorCollectionViewID); +id<GREYMatcher> PaymentRequestErrorView() { + return [ChromeMatchersAppInterface paymentRequestErrorView]; } -+ (id<GREYMatcher>)voiceSearchButton { - return grey_allOf(grey_accessibilityID(kSettingsVoiceSearchCellId), - grey_accessibilityTrait(UIAccessibilityTraitButton), nil); +id<GREYMatcher> VoiceSearchButton() { + return [ChromeMatchersAppInterface voiceSearchButton]; } -+ (id<GREYMatcher>)settingsCollectionView { - return grey_accessibilityID(kSettingsTableViewId); +id<GREYMatcher> SettingsCollectionView() { + return [ChromeMatchersAppInterface settingsCollectionView]; } -+ (id<GREYMatcher>)clearBrowsingHistoryButton { - return grey_allOf( - grey_accessibilityID(kClearBrowsingHistoryCellAccessibilityIdentifier), - grey_sufficientlyVisible(), nil); +id<GREYMatcher> ClearBrowsingHistoryButton() { + return [ChromeMatchersAppInterface clearBrowsingHistoryButton]; } -+ (id<GREYMatcher>)clearCookiesButton { - return grey_accessibilityID(kClearCookiesCellAccessibilityIdentifier); +id<GREYMatcher> ClearCookiesButton() { + return [ChromeMatchersAppInterface clearCookiesButton]; } -+ (id<GREYMatcher>)clearCacheButton { - return grey_allOf( - grey_accessibilityID(kClearCacheCellAccessibilityIdentifier), - grey_sufficientlyVisible(), nil); +id<GREYMatcher> ClearCacheButton() { + return [ChromeMatchersAppInterface clearCacheButton]; } -+ (id<GREYMatcher>)clearSavedPasswordsButton { - return grey_accessibilityID(kClearSavedPasswordsCellAccessibilityIdentifier); +id<GREYMatcher> ClearSavedPasswordsButton() { + return [ChromeMatchersAppInterface clearSavedPasswordsButton]; } -+ (id<GREYMatcher>)contentSuggestionCollectionView { - return grey_accessibilityID( - [ContentSuggestionsViewController collectionAccessibilityIdentifier]); +id<GREYMatcher> ContentSuggestionCollectionView() { + return [ChromeMatchersAppInterface contentSuggestionCollectionView]; } -+ (id<GREYMatcher>)warningMessageView { - return grey_accessibilityID(kWarningMessageAccessibilityID); +id<GREYMatcher> WarningMessageView() { + return [ChromeMatchersAppInterface warningMessageView]; } -+ (id<GREYMatcher>)paymentRequestPickerRow { - return grey_accessibilityID(kPaymentRequestPickerRowAccessibilityID); +id<GREYMatcher> PaymentRequestPickerRow() { + return [ChromeMatchersAppInterface paymentRequestPickerRow]; } -+ (id<GREYMatcher>)paymentRequestPickerSearchBar { - return grey_accessibilityID(kPaymentRequestPickerSearchBarAccessibilityID); +id<GREYMatcher> PaymentRequestPickerSearchBar() { + return [ChromeMatchersAppInterface paymentRequestPickerSearchBar]; } -+ (id<GREYMatcher>)bookmarksMenuButton { - return grey_accessibilityID(kToolsMenuBookmarksId); +id<GREYMatcher> BookmarksMenuButton() { + return [ChromeMatchersAppInterface bookmarksMenuButton]; } -+ (id<GREYMatcher>)recentTabsMenuButton { - return grey_accessibilityID(kToolsMenuOtherDevicesId); +id<GREYMatcher> RecentTabsMenuButton() { + return [ChromeMatchersAppInterface recentTabsMenuButton]; } -+ (id<GREYMatcher>)systemSelectionCallout { - return grey_kindOfClass(NSClassFromString(@"UICalloutBarButton")); +id<GREYMatcher> SystemSelectionCallout() { + return [ChromeMatchersAppInterface systemSelectionCallout]; } -+ (id<GREYMatcher>)systemSelectionCalloutCopyButton { - return grey_accessibilityLabel(@"Copy"); +id<GREYMatcher> SystemSelectionCalloutCopyButton() { + return [ChromeMatchersAppInterface systemSelectionCalloutCopyButton]; } -+ (id<GREYMatcher>)contextMenuCopyButton { - return [ChromeMatchers - buttonWithAccessibilityLabelId:(IDS_IOS_CONTENT_CONTEXT_COPY)]; +id<GREYMatcher> ContextMenuCopyButton() { + return [ChromeMatchersAppInterface contextMenuCopyButton]; } -+ (id<GREYMatcher>)NTPOmnibox { - return grey_allOf( - grey_accessibilityLabel(l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT)), - grey_minimumVisiblePercent(0.2), nil); +id<GREYMatcher> NewTabPageOmnibox() { + return [ChromeMatchersAppInterface NTPOmnibox]; } -+ (id<GREYMatcher>)webViewMatcher { - return web::WebViewInWebState(chrome_test_util::GetCurrentWebState()); +id<GREYMatcher> WebViewMatcher() { + return [ChromeMatchersAppInterface webViewMatcher]; } -@end +} // namespace chrome_test_util
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h new file mode 100644 index 0000000..b4425bfe --- /dev/null +++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
@@ -0,0 +1,268 @@ +// 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. + +#ifndef IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_APP_INTERFACE_H_ +#define IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_APP_INTERFACE_H_ + +#import <Foundation/Foundation.h> + +@protocol GREYMatcher; + +// Helper class to return matchers for EG tests. These helpers are compiled +// into the app binary and can be called from either app or test code. +@interface ChromeMatchersAppInterface : NSObject + +// Matcher for element with accessibility label corresponding to |label| and +// accessibility trait UIAccessibilityTraitButton. ++ (id<GREYMatcher>)buttonWithAccessibilityLabel:(NSString*)label; + +// Matcher for element with accessibility label corresponding to |messageID| +// and accessibility trait UIAccessibilityTraitButton. ++ (id<GREYMatcher>)buttonWithAccessibilityLabelID:(int)messageID; + +// Matcher for element with an image corresponding to |imageID|. ++ (id<GREYMatcher>)imageViewWithImage:(int)imageID; + +// Matcher for element with an image defined by its name in the main bundle. ++ (id<GREYMatcher>)imageViewWithImageNamed:(NSString*)imageName; + +// Matcher for element with an image corresponding to |imageID| and +// accessibility trait UIAccessibilityTraitButton. ++ (id<GREYMatcher>)buttonWithImage:(int)imageID; + +// Matcher for element with accessibility label corresponding to |messageID| +// and accessibility trait UIAccessibilityTraitStaticText. ++ (id<GREYMatcher>)staticTextWithAccessibilityLabelID:(int)messageID; + +// Matcher for element with accessibility label corresponding to |label| and +// accessibility trait UIAccessibilityTraitStaticText. ++ (id<GREYMatcher>)staticTextWithAccessibilityLabel:(NSString*)label; + +// Matcher for element with accessibility label corresponding to |messageID| +// and accessibility trait UIAccessibilityTraitHeader. ++ (id<GREYMatcher>)headerWithAccessibilityLabelID:(int)messageID; + +// Matcher for element with accessibility label corresponding to |label| and +// accessibility trait UIAccessibilityTraitHeader. ++ (id<GREYMatcher>)headerWithAccessibilityLabel:(NSString*)label; + +// Returns matcher for a cancel button. ++ (id<GREYMatcher>)cancelButton; + +// Returns matcher for a close button. ++ (id<GREYMatcher>)closeButton; + +// Matcher for the navigate forward button. ++ (id<GREYMatcher>)forwardButton; + +// Matcher for the navigate backward button. ++ (id<GREYMatcher>)backButton; + +// Matcher for the reload button. ++ (id<GREYMatcher>)reloadButton; + +// Matcher for the stop loading button. ++ (id<GREYMatcher>)stopButton; + +// Returns a matcher for the omnibox. ++ (id<GREYMatcher>)omnibox; + +// Returns a matcher for the location view. ++ (id<GREYMatcher>)defocusedLocationView; + +// Returns a matcher for the page security info button. ++ (id<GREYMatcher>)pageSecurityInfoButton; + +// Returns a matcher for the page security info indicator. ++ (id<GREYMatcher>)pageSecurityInfoIndicator; + +// Returns matcher for omnibox containing |text|. Performs an exact match of the +// omnibox contents. ++ (id<GREYMatcher>)omniboxText:(NSString*)text; + +// Returns matcher for |text| being a substring of the text in the omnibox. ++ (id<GREYMatcher>)omniboxContainingText:(NSString*)text; + +// Returns matcher for |text| being a substring of the text in the location +// view. ++ (id<GREYMatcher>)locationViewContainingText:(NSString*)text; + +// Matcher for Tools menu button. ++ (id<GREYMatcher>)toolsMenuButton; + +// Matcher for the Share menu button. ++ (id<GREYMatcher>)shareButton; + +// Returns the GREYMatcher for the button that opens the tab switcher. ++ (id<GREYMatcher>)tabletTabSwitcherOpenButton; + +// Matcher for show tabs button. ++ (id<GREYMatcher>)showTabsButton; + +// Matcher for SettingsSwitchCell. ++ (id<GREYMatcher>)settingsSwitchCell:(NSString*)accessibilityIdentifier + isToggledOn:(BOOL)isToggledOn; + +// Matcher for SettingsSwitchCell. ++ (id<GREYMatcher>)settingsSwitchCell:(NSString*)accessibilityIdentifier + isToggledOn:(BOOL)isToggledOn + isEnabled:(BOOL)isEnabled; + +// Matcher for SyncSwitchCell. ++ (id<GREYMatcher>)syncSwitchCell:(NSString*)accessibilityLabel + isToggledOn:(BOOL)isToggledOn; + +// Matcher for the Open in New Tab option in the context menu when long pressing +// a link. ++ (id<GREYMatcher>)openLinkInNewTabButton; + +// Matcher for the done button on the navigation bar. ++ (id<GREYMatcher>)navigationBarDoneButton; + +// Matcher for the done button on the Bookmarks navigation bar. ++ (id<GREYMatcher>)bookmarksNavigationBarDoneButton; + +// Returns matcher for the account consistency setup signin button. ++ (id<GREYMatcher>)accountConsistencySetupSigninButton; + +// Returns matcher for the account consistency confirmation button. ++ (id<GREYMatcher>)accountConsistencyConfirmationOKButton; + +// Returns matcher for the add account accounts button. ++ (id<GREYMatcher>)addAccountButton; + +// Returns matcher for the sign out accounts button. ++ (id<GREYMatcher>)signOutAccountsButton; + +// Returns matcher for the Clear Browsing Data cell on the Privacy screen. ++ (id<GREYMatcher>)clearBrowsingDataCell; + +// Returns matcher for the clear browsing data button on the clear browsing data +// panel. ++ (id<GREYMatcher>)clearBrowsingDataButton; + +// Returns matcher for the clear browsing data view. ++ (id<GREYMatcher>)clearBrowsingDataView; + +// Matcher for the clear browsing data action sheet item. ++ (id<GREYMatcher>)confirmClearBrowsingDataButton; + +// Returns matcher for the settings button in the tools menu. ++ (id<GREYMatcher>)settingsMenuButton; + +// Returns matcher for the "Done" button in the settings' navigation bar. ++ (id<GREYMatcher>)settingsDoneButton; + +// Returns matcher for the tools menu table view. ++ (id<GREYMatcher>)toolsMenuView; + +// Returns matcher for the OK button. ++ (id<GREYMatcher>)OKButton; + +// Returns matcher for the primary button in the sign-in promo view. This is +// "Sign in into Chrome" button for a cold state, or "Continue as John Doe" for +// a warm state. ++ (id<GREYMatcher>)primarySignInButton; + +// Returns matcher for the secondary button in the sign-in promo view. This is +// "Not johndoe@example.com" button. ++ (id<GREYMatcher>)secondarySignInButton; + +// Returns matcher for the button for the currently signed in account in the +// settings menu. ++ (id<GREYMatcher>)settingsAccountButton; + +// Returns matcher for the accounts collection view. ++ (id<GREYMatcher>)settingsAccountsCollectionView; + +// Returns matcher for the Import Data cell in switch sync account view. ++ (id<GREYMatcher>)settingsImportDataImportButton; + +// Returns matcher for the Keep Data Separate cell in switch sync account view. ++ (id<GREYMatcher>)settingsImportDataKeepSeparateButton; + +// Returns matcher for the Manage Synced Data button in sync setting view. ++ (id<GREYMatcher>)settingsSyncManageSyncedDataButton; + +// Returns matcher for the menu button to sync accounts. ++ (id<GREYMatcher>)accountsSyncButton; + +// Returns matcher for the Content Settings button on the main Settings screen. ++ (id<GREYMatcher>)contentSettingsButton; + +// Returns matcher for the Google Services Settings button on the main Settings +// screen. ++ (id<GREYMatcher>)googleServicesSettingsButton; + +// Returns matcher for the back button on a settings menu. ++ (id<GREYMatcher>)settingsMenuBackButton; + +// Returns matcher for the Privacy cell on the main Settings screen. ++ (id<GREYMatcher>)settingsMenuPrivacyButton; + +// Returns matcher for the Save passwords cell on the main Settings screen. ++ (id<GREYMatcher>)settingsMenuPasswordsButton; + +// Returns matcher for the payment request collection view. ++ (id<GREYMatcher>)paymentRequestView; + +// Returns matcher for the error confirmation view for payment request. ++ (id<GREYMatcher>)paymentRequestErrorView; + +// Returns matcher for the voice search button on the main Settings screen. ++ (id<GREYMatcher>)voiceSearchButton; + +// Returns matcher for the settings main menu view. ++ (id<GREYMatcher>)settingsCollectionView; + +// Returns matcher for the clear browsing history cell on the clear browsing +// data panel. ++ (id<GREYMatcher>)clearBrowsingHistoryButton; + +// Returns matcher for the clear cookies cell on the clear browsing data panel. ++ (id<GREYMatcher>)clearCookiesButton; + +// Returns matcher for the clear cache cell on the clear browsing data panel. ++ (id<GREYMatcher>)clearCacheButton; + +// Returns matcher for the clear saved passwords cell on the clear browsing data +// panel. ++ (id<GREYMatcher>)clearSavedPasswordsButton; + +// Returns matcher for the collection view of content suggestion. ++ (id<GREYMatcher>)contentSuggestionCollectionView; + +// Returns matcher for the warning message while filling in payment requests. ++ (id<GREYMatcher>)warningMessageView; + +// Returns matcher for the payment picker cell. ++ (id<GREYMatcher>)paymentRequestPickerRow; + +// Returns matcher for the payment request search bar. ++ (id<GREYMatcher>)paymentRequestPickerSearchBar; + +// Returns matcher for the bookmarks button on the Tools menu. ++ (id<GREYMatcher>)bookmarksMenuButton; + +// Returns matcher for the recent tabs button on the Tools menu. ++ (id<GREYMatcher>)recentTabsMenuButton; + +// Returns matcher for the system selection callout. ++ (id<GREYMatcher>)systemSelectionCallout; + +// Returns matcher for the copy button on the system selection callout. ++ (id<GREYMatcher>)systemSelectionCalloutCopyButton; + +// Returns matcher for the Copy item on the context menu. ++ (id<GREYMatcher>)contextMenuCopyButton; + +// Returns matcher for defoucesed omnibox on a new tab. ++ (id<GREYMatcher>)NTPOmnibox; + +// Returns a matcher for the current WebView. ++ (id<GREYMatcher>)webViewMatcher; + +@end + +#endif // IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_APP_INTERFACE_H_
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm new file mode 100644 index 0000000..a741644 --- /dev/null +++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
@@ -0,0 +1,557 @@ +// 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. + +#import "ios/chrome/test/earl_grey/chrome_matchers_app_interface.h" + +#include "base/mac/foundation_util.h" +#include "base/strings/sys_string_conversions.h" +#include "components/strings/grit/components_strings.h" +#include "components/unified_consent/feature.h" +#import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h" +#import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h" +#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h" +#import "ios/chrome/browser/ui/location_bar/location_bar_steady_view.h" +#import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h" +#import "ios/chrome/browser/ui/payments/payment_request_edit_view_controller.h" +#import "ios/chrome/browser/ui/payments/payment_request_error_view_controller.h" +#import "ios/chrome/browser/ui/payments/payment_request_picker_view_controller.h" +#import "ios/chrome/browser/ui/payments/payment_request_view_controller.h" +#import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h" +#import "ios/chrome/browser/ui/settings/cells/clear_browsing_data_constants.h" +#import "ios/chrome/browser/ui/settings/cells/settings_switch_cell.h" +#import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h" +#import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.h" +#import "ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_ui_constants.h" +#import "ios/chrome/browser/ui/settings/google_services/accounts_table_view_controller.h" +#import "ios/chrome/browser/ui/settings/import_data_table_view_controller.h" +#import "ios/chrome/browser/ui/settings/settings_table_view_controller.h" +#import "ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.h" +#import "ios/chrome/browser/ui/static_content/static_html_view_controller.h" +#import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h" +#import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#include "ios/chrome/grit/ios_strings.h" +#import "ios/chrome/test/app/chrome_test_util.h" +#import "ios/testing/earl_grey/earl_grey_app.h" +#import "ios/web/public/test/earl_grey/web_view_matchers.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/test/ios/ui_image_test_utils.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +id<GREYMatcher> SettingsSwitchIsToggledOn(BOOL is_toggled_on) { + GREYMatchesBlock matches = ^BOOL(id element) { + SettingsSwitchCell* switch_cell = + base::mac::ObjCCastStrict<SettingsSwitchCell>(element); + UISwitch* switch_view = switch_cell.switchView; + return (switch_view.on && is_toggled_on) || + (!switch_view.on && !is_toggled_on); + }; + GREYDescribeToBlock describe = ^void(id<GREYDescription> description) { + NSString* name = + [NSString stringWithFormat:@"settingsSwitchToggledState(%@)", + is_toggled_on ? @"ON" : @"OFF"]; + [description appendText:name]; + }; + return [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches + descriptionBlock:describe]; +} + +id<GREYMatcher> SettingsSwitchIsEnabled(BOOL is_enabled) { + GREYMatchesBlock matches = ^BOOL(id element) { + SettingsSwitchCell* switch_cell = + base::mac::ObjCCastStrict<SettingsSwitchCell>(element); + UISwitch* switch_view = switch_cell.switchView; + return (switch_view.enabled && is_enabled) || + (!switch_view.enabled && !is_enabled); + }; + GREYDescribeToBlock describe = ^void(id<GREYDescription> description) { + NSString* name = + [NSString stringWithFormat:@"settingsSwitchEnabledState(%@)", + is_enabled ? @"YES" : @"NO"]; + [description appendText:name]; + }; + return [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches + descriptionBlock:describe]; +} + +// Returns the subview of |parentView| corresponding to the +// ContentSuggestionsViewController. Returns nil if it is not in its subviews. +UIView* SubviewWithAccessibilityIdentifier(NSString* accessibility_id, + UIView* parent_view) { + if (parent_view.accessibilityIdentifier == accessibility_id) { + return parent_view; + } + for (UIView* view in parent_view.subviews) { + UIView* result_view = + SubviewWithAccessibilityIdentifier(accessibility_id, view); + if (result_view) + return result_view; + } + return nil; +} + +} // namespace + +@implementation ChromeMatchersAppInterface + ++ (id<GREYMatcher>)buttonWithAccessibilityLabel:(NSString*)label { + return grey_allOf(grey_accessibilityLabel(label), + grey_accessibilityTrait(UIAccessibilityTraitButton), nil); +} + ++ (id<GREYMatcher>)buttonWithAccessibilityLabelID:(int)messageID { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabel:l10n_util::GetNSStringWithFixup(messageID)]; +} + ++ (id<GREYMatcher>)imageViewWithImageNamed:(NSString*)imageName { + UIImage* expectedImage = [UIImage imageNamed:imageName]; + GREYMatchesBlock matches = ^BOOL(UIImageView* imageView) { + return ui::test::uiimage_utils::UIImagesAreEqual(expectedImage, + imageView.image); + }; + NSString* descriptionString = + [NSString stringWithFormat:@"Images matching image named %@", imageName]; + GREYDescribeToBlock describe = ^(id<GREYDescription> description) { + [description appendText:descriptionString]; + }; + id<GREYMatcher> imageMatcher = + [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches + descriptionBlock:describe]; + return imageMatcher; +} + ++ (id<GREYMatcher>)imageViewWithImage:(int)imageID { + UIImage* expectedImage = NativeImage(imageID); + GREYMatchesBlock matches = ^BOOL(UIImageView* imageView) { + return ui::test::uiimage_utils::UIImagesAreEqual(expectedImage, + imageView.image); + }; + NSString* descriptionString = + [NSString stringWithFormat:@"Images matching %i", imageID]; + GREYDescribeToBlock describe = ^(id<GREYDescription> description) { + [description appendText:descriptionString]; + }; + id<GREYMatcher> imageMatcher = + [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches + descriptionBlock:describe]; + return imageMatcher; +} + ++ (id<GREYMatcher>)buttonWithImage:(int)imageID { + UIImage* expectedImage = NativeImage(imageID); + GREYMatchesBlock matches = ^BOOL(UIButton* button) { + return ui::test::uiimage_utils::UIImagesAreEqual(expectedImage, + [button currentImage]); + }; + NSString* descriptionString = + [NSString stringWithFormat:@"Images matching %i", imageID]; + GREYDescribeToBlock describe = ^(id<GREYDescription> description) { + [description appendText:descriptionString]; + }; + id<GREYMatcher> imageMatcher = + [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches + descriptionBlock:describe]; + return grey_allOf(grey_accessibilityTrait(UIAccessibilityTraitButton), + imageMatcher, nil); +} + ++ (id<GREYMatcher>)staticTextWithAccessibilityLabelID:(int)messageID { + return [ChromeMatchersAppInterface + staticTextWithAccessibilityLabel:(l10n_util::GetNSStringWithFixup( + messageID))]; +} + ++ (id<GREYMatcher>)staticTextWithAccessibilityLabel:(NSString*)label { + return grey_allOf(grey_accessibilityLabel(label), + grey_accessibilityTrait(UIAccessibilityTraitStaticText), + nil); +} + ++ (id<GREYMatcher>)headerWithAccessibilityLabelID:(int)messageID { + return [ChromeMatchersAppInterface + headerWithAccessibilityLabel:(l10n_util::GetNSStringWithFixup( + messageID))]; +} + ++ (id<GREYMatcher>)headerWithAccessibilityLabel:(NSString*)label { + return grey_allOf(grey_accessibilityLabel(label), + grey_accessibilityTrait(UIAccessibilityTraitHeader), nil); +} + ++ (id<GREYMatcher>)cancelButton { + return + [ChromeMatchersAppInterface buttonWithAccessibilityLabelID:(IDS_CANCEL)]; +} + ++ (id<GREYMatcher>)closeButton { + return + [ChromeMatchersAppInterface buttonWithAccessibilityLabelID:(IDS_CLOSE)]; +} + ++ (id<GREYMatcher>)forwardButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_ACCNAME_FORWARD)]; +} + ++ (id<GREYMatcher>)backButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_ACCNAME_BACK)]; +} + ++ (id<GREYMatcher>)reloadButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_ACCNAME_RELOAD)]; +} + ++ (id<GREYMatcher>)stopButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_ACCNAME_STOP)]; +} + ++ (id<GREYMatcher>)omnibox { + return grey_allOf(grey_kindOfClass([OmniboxTextFieldIOS class]), + grey_userInteractionEnabled(), nil); +} + ++ (id<GREYMatcher>)defocusedLocationView { + return grey_kindOfClass([LocationBarSteadyView class]); +} + ++ (id<GREYMatcher>)pageSecurityInfoButton { + return grey_accessibilityLabel(@"Page Security Info"); +} + ++ (id<GREYMatcher>)pageSecurityInfoIndicator { + return grey_accessibilityLabel(@"Page Security Info"); +} + ++ (id<GREYMatcher>)omniboxText:(NSString*)text { + GREYElementMatcherBlock* matcher = [GREYElementMatcherBlock + matcherWithMatchesBlock:^BOOL(id element) { + OmniboxTextFieldIOS* omnibox = + base::mac::ObjCCast<OmniboxTextFieldIOS>(element); + return [omnibox.text isEqualToString:text]; + } + descriptionBlock:^void(id<GREYDescription> description) { + [description + appendText:[NSString stringWithFormat:@"Omnibox contains text '%@'", + text]]; + }]; + return matcher; +} + ++ (id<GREYMatcher>)omniboxContainingText:(NSString*)text { + GREYElementMatcherBlock* matcher = [GREYElementMatcherBlock + matcherWithMatchesBlock:^BOOL(UITextField* element) { + return [element.text containsString:text]; + } + descriptionBlock:^void(id<GREYDescription> description) { + [description + appendText:[NSString stringWithFormat:@"Omnibox contains text '%@'", + text]]; + }]; + return matcher; +} + ++ (id<GREYMatcher>)locationViewContainingText:(NSString*)text { + GREYElementMatcherBlock* matcher = [GREYElementMatcherBlock + matcherWithMatchesBlock:^BOOL(LocationBarSteadyView* element) { + return [element.locationLabel.text containsString:text]; + } + descriptionBlock:^void(id<GREYDescription> description) { + [description + appendText:[NSString + stringWithFormat: + @"LocationBarSteadyView contains text '%@'", + text]]; + }]; + return matcher; +} + ++ (id<GREYMatcher>)toolsMenuButton { + return grey_allOf(grey_accessibilityID(kToolbarToolsMenuButtonIdentifier), + grey_sufficientlyVisible(), nil); +} + ++ (id<GREYMatcher>)shareButton { + return grey_allOf( + [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_TOOLS_MENU_SHARE)], + grey_sufficientlyVisible(), nil); +} + ++ (id<GREYMatcher>)tabletTabSwitcherOpenButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_TAB_STRIP_ENTER_TAB_SWITCHER)]; +} + ++ (id<GREYMatcher>)showTabsButton { + return grey_allOf(grey_accessibilityID(kToolbarStackButtonIdentifier), + grey_sufficientlyVisible(), nil); +} + ++ (id<GREYMatcher>)settingsSwitchCell:(NSString*)accessibilityIdentifier + isToggledOn:(BOOL)isToggledOn { + return [ChromeMatchersAppInterface settingsSwitchCell:accessibilityIdentifier + isToggledOn:isToggledOn + isEnabled:YES]; +} + ++ (id<GREYMatcher>)settingsSwitchCell:(NSString*)accessibilityIdentifier + isToggledOn:(BOOL)isToggledOn + isEnabled:(BOOL)isEnabled { + return grey_allOf(grey_accessibilityID(accessibilityIdentifier), + SettingsSwitchIsToggledOn(isToggledOn), + SettingsSwitchIsEnabled(isEnabled), + grey_sufficientlyVisible(), nil); +} + ++ (id<GREYMatcher>)syncSwitchCell:(NSString*)accessibilityLabel + isToggledOn:(BOOL)isToggledOn { + return grey_allOf( + grey_accessibilityLabel(accessibilityLabel), + grey_accessibilityValue( + isToggledOn ? l10n_util::GetNSString(IDS_IOS_SETTING_ON) + : l10n_util::GetNSString(IDS_IOS_SETTING_OFF)), + grey_sufficientlyVisible(), nil); +} + ++ (id<GREYMatcher>)openLinkInNewTabButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)]; +} + ++ (id<GREYMatcher>)navigationBarDoneButton { + return grey_allOf( + [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON)], + grey_userInteractionEnabled(), nil); +} + ++ (id<GREYMatcher>)bookmarksNavigationBarDoneButton { + return grey_accessibilityID(kBookmarkHomeNavigationBarDoneButtonIdentifier); +} + ++ (id<GREYMatcher>)accountConsistencySetupSigninButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID: + (IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SIGNIN_BUTTON)]; +} + ++ (id<GREYMatcher>)accountConsistencyConfirmationOKButton { + int labelID = base::FeatureList::IsEnabled(unified_consent::kUnifiedConsent) + ? IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON + : IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OK_BUTTON; + return [ChromeMatchersAppInterface buttonWithAccessibilityLabelID:(labelID)]; +} + ++ (id<GREYMatcher>)addAccountButton { + return grey_accessibilityID(kSettingsAccountsTableViewAddAccountCellId); +} + ++ (id<GREYMatcher>)signOutAccountsButton { + return grey_accessibilityID(kSettingsAccountsTableViewSignoutCellId); +} + ++ (id<GREYMatcher>)clearBrowsingDataCell { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_CLEAR_BROWSING_DATA_TITLE)]; +} + ++ (id<GREYMatcher>)clearBrowsingDataButton { + return grey_accessibilityID(kClearBrowsingDataButtonIdentifier); +} + ++ (id<GREYMatcher>)clearBrowsingDataView { + return grey_accessibilityID(kClearBrowsingDataViewAccessibilityIdentifier); +} + ++ (id<GREYMatcher>)confirmClearBrowsingDataButton { + return grey_allOf( + grey_accessibilityLabel(l10n_util::GetNSString(IDS_IOS_CLEAR_BUTTON)), + grey_accessibilityTrait(UIAccessibilityTraitButton), + grey_not(grey_accessibilityID(kClearBrowsingDataButtonIdentifier)), + grey_userInteractionEnabled(), nil); +} + ++ (id<GREYMatcher>)settingsMenuButton { + return grey_accessibilityID(kToolsMenuSettingsId); +} + ++ (id<GREYMatcher>)settingsDoneButton { + return grey_accessibilityID(kSettingsDoneButtonId); +} + ++ (id<GREYMatcher>)toolsMenuView { + return grey_accessibilityID(kPopupMenuToolsMenuTableViewId); +} + ++ (id<GREYMatcher>)OKButton { + return [ChromeMatchersAppInterface buttonWithAccessibilityLabelID:(IDS_OK)]; +} + ++ (id<GREYMatcher>)primarySignInButton { + return grey_accessibilityID(kSigninPromoPrimaryButtonId); +} + ++ (id<GREYMatcher>)secondarySignInButton { + return grey_accessibilityID(kSigninPromoSecondaryButtonId); +} + ++ (id<GREYMatcher>)settingsAccountButton { + return grey_accessibilityID(kSettingsAccountCellId); +} + ++ (id<GREYMatcher>)settingsAccountsCollectionView { + return grey_accessibilityID(kSettingsAccountsTableViewId); +} + ++ (id<GREYMatcher>)settingsImportDataImportButton { + return grey_accessibilityID(kImportDataImportCellId); +} + ++ (id<GREYMatcher>)settingsImportDataKeepSeparateButton { + return grey_accessibilityID(kImportDataKeepSeparateCellId); +} + ++ (id<GREYMatcher>)settingsSyncManageSyncedDataButton { + return grey_accessibilityID(kSettingsSyncId); +} + ++ (id<GREYMatcher>)accountsSyncButton { + return grey_allOf(grey_accessibilityID(kSettingsAccountsTableViewSyncCellId), + grey_sufficientlyVisible(), nil); +} + ++ (id<GREYMatcher>)contentSettingsButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_CONTENT_SETTINGS_TITLE)]; +} + ++ (id<GREYMatcher>)googleServicesSettingsButton { + NSString* syncAndGoogleServicesTitle = + l10n_util::GetNSStringWithFixup(IDS_IOS_GOOGLE_SERVICES_SETTINGS_TITLE); + id<GREYMatcher> mainTextLabelMatcher = + grey_allOf(grey_accessibilityLabel(syncAndGoogleServicesTitle), + grey_sufficientlyVisible(), nil); + return grey_allOf(grey_kindOfClass([UITableViewCell class]), + grey_sufficientlyVisible(), + grey_descendant(mainTextLabelMatcher), nil); +} + ++ (id<GREYMatcher>)settingsMenuBackButton { + UINavigationBar* navBar = base::mac::ObjCCastStrict<UINavigationBar>( + SubviewWithAccessibilityIdentifier( + @"SettingNavigationBar", + [[UIApplication sharedApplication] keyWindow])); + return grey_allOf(grey_anyOf(grey_accessibilityLabel(navBar.backItem.title), + grey_accessibilityLabel(@"Back"), nil), + grey_kindOfClass([UIButton class]), + grey_ancestor(grey_kindOfClass([UINavigationBar class])), + nil); +} + ++ (id<GREYMatcher>)settingsMenuPrivacyButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID: + (IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY)]; +} + ++ (id<GREYMatcher>)settingsMenuPasswordsButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_PASSWORDS)]; +} + ++ (id<GREYMatcher>)paymentRequestView { + return grey_accessibilityID(kPaymentRequestCollectionViewID); +} + +// Returns matcher for the error confirmation view for payment request. ++ (id<GREYMatcher>)paymentRequestErrorView { + return grey_accessibilityID(kPaymentRequestErrorCollectionViewID); +} + ++ (id<GREYMatcher>)voiceSearchButton { + return grey_allOf(grey_accessibilityID(kSettingsVoiceSearchCellId), + grey_accessibilityTrait(UIAccessibilityTraitButton), nil); +} + ++ (id<GREYMatcher>)settingsCollectionView { + return grey_accessibilityID(kSettingsTableViewId); +} + ++ (id<GREYMatcher>)clearBrowsingHistoryButton { + return grey_allOf( + grey_accessibilityID(kClearBrowsingHistoryCellAccessibilityIdentifier), + grey_sufficientlyVisible(), nil); +} + ++ (id<GREYMatcher>)clearCookiesButton { + return grey_accessibilityID(kClearCookiesCellAccessibilityIdentifier); +} + ++ (id<GREYMatcher>)clearCacheButton { + return grey_allOf( + grey_accessibilityID(kClearCacheCellAccessibilityIdentifier), + grey_sufficientlyVisible(), nil); +} + ++ (id<GREYMatcher>)clearSavedPasswordsButton { + return grey_accessibilityID(kClearSavedPasswordsCellAccessibilityIdentifier); +} + ++ (id<GREYMatcher>)contentSuggestionCollectionView { + return grey_accessibilityID( + [ContentSuggestionsViewController collectionAccessibilityIdentifier]); +} + ++ (id<GREYMatcher>)warningMessageView { + return grey_accessibilityID(kWarningMessageAccessibilityID); +} + ++ (id<GREYMatcher>)paymentRequestPickerRow { + return grey_accessibilityID(kPaymentRequestPickerRowAccessibilityID); +} + ++ (id<GREYMatcher>)paymentRequestPickerSearchBar { + return grey_accessibilityID(kPaymentRequestPickerSearchBarAccessibilityID); +} + ++ (id<GREYMatcher>)bookmarksMenuButton { + return grey_accessibilityID(kToolsMenuBookmarksId); +} + ++ (id<GREYMatcher>)recentTabsMenuButton { + return grey_accessibilityID(kToolsMenuOtherDevicesId); +} + ++ (id<GREYMatcher>)systemSelectionCallout { + return grey_kindOfClass(NSClassFromString(@"UICalloutBarButton")); +} + ++ (id<GREYMatcher>)systemSelectionCalloutCopyButton { + return grey_accessibilityLabel(@"Copy"); +} + ++ (id<GREYMatcher>)contextMenuCopyButton { + return [ChromeMatchersAppInterface + buttonWithAccessibilityLabelID:(IDS_IOS_CONTENT_CONTEXT_COPY)]; +} + ++ (id<GREYMatcher>)NTPOmnibox { + return grey_allOf( + grey_accessibilityLabel(l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT)), + grey_minimumVisiblePercent(0.2), nil); +} + ++ (id<GREYMatcher>)webViewMatcher { + return web::WebViewInWebState(chrome_test_util::GetCurrentWebState()); +} + +@end
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_shorthand.h b/ios/chrome/test/earl_grey/chrome_matchers_shorthand.h deleted file mode 100644 index 1cf9dde..0000000 --- a/ios/chrome/test/earl_grey/chrome_matchers_shorthand.h +++ /dev/null
@@ -1,267 +0,0 @@ -// 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. - -#ifndef IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_SHORTHAND_H_ -#define IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_SHORTHAND_H_ - -#import <Foundation/Foundation.h> - -#include <string> - -@protocol GREYMatcher; - -namespace chrome_test_util { - -// Matcher for element with accessibility label corresponding to |message_id| -// and accessibility trait UIAccessibilityTraitButton. -id<GREYMatcher> ButtonWithAccessibilityLabelId(int message_id); - -// Matcher for element with accessibility label corresponding to |label| and -// accessibility trait UIAccessibilityTraitButton. -id<GREYMatcher> ButtonWithAccessibilityLabel(NSString* label); - -// Matcher for element with an image corresponding to |image_id|. -id<GREYMatcher> ImageViewWithImage(int image_id); - -// Matcher for element with an image defined by its name in the main bundle. -id<GREYMatcher> ImageViewWithImageNamed(NSString* imageName); - -// Matcher for element with an image corresponding to |image_id| and -// accessibility trait UIAccessibilityTraitButton. -id<GREYMatcher> ButtonWithImage(int image_id); - -// Matcher for element with accessibility label corresponding to |message_id| -// and accessibility trait UIAccessibilityTraitStaticText. -id<GREYMatcher> StaticTextWithAccessibilityLabelId(int message_id); - -// Matcher for element with accessibility label corresponding to |label| and -// accessibility trait UIAccessibilityTraitStaticText. -id<GREYMatcher> StaticTextWithAccessibilityLabel(NSString* label); - -// Matcher for element with accessibility label corresponding to |message_id| -// and accessibility trait UIAccessibilityTraitHeader. -id<GREYMatcher> HeaderWithAccessibilityLabelId(int message_id); - -// Matcher for element with accessibility label corresponding to |label| and -// accessibility trait UIAccessibilityTraitHeader. -id<GREYMatcher> HeaderWithAccessibilityLabel(NSString* label); - -// Returns matcher for a cancel button. -id<GREYMatcher> CancelButton(); - -// Returns matcher for a close button. -id<GREYMatcher> CloseButton(); - -// Matcher for the navigate forward button. -id<GREYMatcher> ForwardButton(); - -// Matcher for the navigate backward button. -id<GREYMatcher> BackButton(); - -// Matcher for the reload button. -id<GREYMatcher> ReloadButton(); - -// Matcher for the stop loading button. -id<GREYMatcher> StopButton(); - -// Returns a matcher for the omnibox. -id<GREYMatcher> Omnibox(); - -// Returns a matcher for the location view. -id<GREYMatcher> DefocusedLocationView(); - -// Returns a matcher for the page security info button. -id<GREYMatcher> PageSecurityInfoButton(); -// Returns a matcher for the page security info indicator. -id<GREYMatcher> PageSecurityInfoIndicator(); - -// Returns matcher for omnibox containing |text|. Performs an exact match of the -// omnibox contents. -id<GREYMatcher> OmniboxText(std::string text); - -// Returns matcher for |text| being a substring of the text in the omnibox. -id<GREYMatcher> OmniboxContainingText(std::string text); - -// Returns matcher for |text| being a substring of the text in the location -// view. -id<GREYMatcher> LocationViewContainingText(std::string text); - -// Matcher for Tools menu button. -id<GREYMatcher> ToolsMenuButton(); - -// Matcher for the Share menu button. -id<GREYMatcher> ShareButton(); - -// Returns the GREYMatcher for the button that opens the tab switcher. -id<GREYMatcher> TabletTabSwitcherOpenButton(); - -// Matcher for show tabs button. -id<GREYMatcher> ShowTabsButton(); - -// Matcher for SettingsSwitchCell. -id<GREYMatcher> SettingsSwitchCell(NSString* accessibility_identifier, - BOOL is_toggled_on); - -// Matcher for SettingsSwitchCell. -id<GREYMatcher> SettingsSwitchCell(NSString* accessibility_identifier, - BOOL is_toggled_on, - BOOL is_enabled); - -// Matcher for LegacySyncSwitchCell. -id<GREYMatcher> SyncSwitchCell(NSString* accessibility_label, - BOOL is_toggled_on); - -// Matcher for the Open in New Tab option in the context menu when long pressing -// a link. -id<GREYMatcher> OpenLinkInNewTabButton(); - -// Matcher for the done button on the navigation bar. -id<GREYMatcher> NavigationBarDoneButton(); - -// Matcher for the done button on the Bookmarks navigation bar. -id<GREYMatcher> BookmarksNavigationBarDoneButton(); - -// Returns matcher for the account consistency setup signin button. -id<GREYMatcher> AccountConsistencySetupSigninButton(); - -// Returns matcher for the account consistency confirmation button. -id<GREYMatcher> AccountConsistencyConfirmationOkButton(); - -// Returns matcher for the add account accounts button. -id<GREYMatcher> AddAccountButton(); - -// Returns matcher for the sign out accounts button. -id<GREYMatcher> SignOutAccountsButton(); - -// Returns matcher for the Clear Browsing Data cell on the Privacy screen. -id<GREYMatcher> ClearBrowsingDataCell(); - -// Returns matcher for the clear browsing data button on the clear browsing data -// panel. -id<GREYMatcher> ClearBrowsingDataButton(); - -// Returns matcher for the clear browsing data view. -id<GREYMatcher> ClearBrowsingDataView(); - -// Matcher for the clear browsing data action sheet item. -id<GREYMatcher> ConfirmClearBrowsingDataButton(); - -// Returns matcher for the settings button in the tools menu. -id<GREYMatcher> SettingsMenuButton(); - -// Returns matcher for the "Done" button in the settings' navigation bar. -id<GREYMatcher> SettingsDoneButton(); - -// Returns matcher for the tools menu table view. -id<GREYMatcher> ToolsMenuView(); - -// Returns matcher for the OK button. -id<GREYMatcher> OKButton(); - -// Returns matcher for the primary button in the sign-in promo view. This is -// "Sign in into Chrome" button for a cold state, or "Continue as John Doe" for -// a warm state. -id<GREYMatcher> PrimarySignInButton(); - -// Returns matcher for the secondary button in the sign-in promo view. This is -// "Not johndoe@example.com" button. -id<GREYMatcher> SecondarySignInButton(); - -// Returns matcher for the button for the currently signed in account in the -// settings menu. -id<GREYMatcher> SettingsAccountButton(); - -// Returns matcher for the accounts collection view. -id<GREYMatcher> SettingsAccountsCollectionView(); - -// Returns matcher for the Import Data cell in switch sync account view. -id<GREYMatcher> SettingsImportDataImportButton(); - -// Returns matcher for the Keep Data Separate cell in switch sync account view. -id<GREYMatcher> SettingsImportDataKeepSeparateButton(); - -// Returns matcher for the Manage Synced Data button in sync setting view. -id<GREYMatcher> SettingsSyncManageSyncedDataButton(); - -// Returns matcher for the menu button to sync accounts. -id<GREYMatcher> AccountsSyncButton(); - -// Returns matcher for the Content Settings button on the main Settings screen. -id<GREYMatcher> ContentSettingsButton(); - -// Returns matcher for the Google Services Settings button on the main Settings -// screen. -id<GREYMatcher> GoogleServicesSettingsButton(); - -// Returns matcher for the back button on a settings menu. -id<GREYMatcher> SettingsMenuBackButton(); - -// Returns matcher for the Privacy cell on the main Settings screen. -id<GREYMatcher> SettingsMenuPrivacyButton(); - -// Returns matcher for the Save passwords cell on the main Settings screen. -id<GREYMatcher> SettingsMenuPasswordsButton(); - -// Returns matcher for the payment request collection view. -id<GREYMatcher> PaymentRequestView(); - -// Returns matcher for the error confirmation view for payment request. -id<GREYMatcher> PaymentRequestErrorView(); - -// Returns matcher for the voice search button on the main Settings screen. -id<GREYMatcher> VoiceSearchButton(); - -// Returns matcher for the settings main menu view. -id<GREYMatcher> SettingsCollectionView(); - -// Returns matcher for the clear browsing history cell on the clear browsing -// data panel. -id<GREYMatcher> ClearBrowsingHistoryButton(); - -// Returns matcher for the clear cookies cell on the clear browsing data panel. -id<GREYMatcher> ClearCookiesButton(); - -// Returns matcher for the clear cache cell on the clear browsing data panel. -id<GREYMatcher> ClearCacheButton(); - -// Returns matcher for the clear saved passwords cell on the clear browsing data -// panel. -id<GREYMatcher> ClearSavedPasswordsButton(); - -// Returns matcher for the collection view of content suggestion. -id<GREYMatcher> ContentSuggestionCollectionView(); - -// Returns matcher for the warning message while filling in payment requests. -id<GREYMatcher> WarningMessageView(); - -// Returns matcher for the payment picker cell. -id<GREYMatcher> PaymentRequestPickerRow(); - -// Returns matcher for the payment request search bar. -id<GREYMatcher> PaymentRequestPickerSearchBar(); - -// Returns matcher for the bookmarks button on the Tools menu. -id<GREYMatcher> BookmarksMenuButton(); - -// Returns matcher for the recent tabs button on the Tools menu. -id<GREYMatcher> RecentTabsMenuButton(); - -// Returns matcher for the system selection callout. -id<GREYMatcher> SystemSelectionCallout(); - -// Returns matcher for the copy button on the system selection callout. -id<GREYMatcher> SystemSelectionCalloutCopyButton(); - -// Returns matcher for the Copy item on the context menu. -id<GREYMatcher> ContextMenuCopyButton(); - -// Returns matcher for defoucesed omnibox on a new tab. -id<GREYMatcher> NewTabPageOmnibox(); - -// Returns a matcher for the current WebView. -id<GREYMatcher> WebViewMatcher(); - -} - -#endif // IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_SHORTHAND_H_
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_shorthand.mm b/ios/chrome/test/earl_grey/chrome_matchers_shorthand.mm deleted file mode 100644 index 07bcfbfa..0000000 --- a/ios/chrome/test/earl_grey/chrome_matchers_shorthand.mm +++ /dev/null
@@ -1,330 +0,0 @@ -// 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. - -#import <EarlGrey/EarlGrey.h> -#import <WebKit/WebKit.h> - -#import "ios/chrome/test/earl_grey/chrome_matchers_shorthand.h" - -#import "ios/chrome/test/earl_grey/chrome_matchers.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace chrome_test_util { - -id<GREYMatcher> ButtonWithAccessibilityLabel(NSString* label) { - return [ChromeMatchers buttonWithAccessibilityLabel:label]; -} - -id<GREYMatcher> ButtonWithAccessibilityLabelId(int message_id) { - return [ChromeMatchers buttonWithAccessibilityLabelId:message_id]; -} - -id<GREYMatcher> ImageViewWithImageNamed(NSString* imageName) { - return [ChromeMatchers imageViewWithImageNamed:imageName]; -} - -id<GREYMatcher> ImageViewWithImage(int image_id) { - return [ChromeMatchers imageViewWithImage:image_id]; -} - -id<GREYMatcher> ButtonWithImage(int image_id) { - return [ChromeMatchers buttonWithImage:image_id]; -} - -id<GREYMatcher> StaticTextWithAccessibilityLabelId(int message_id) { - return [ChromeMatchers staticTextWithAccessibilityLabelId:message_id]; -} - -id<GREYMatcher> StaticTextWithAccessibilityLabel(NSString* label) { - return [ChromeMatchers staticTextWithAccessibilityLabel:label]; -} - -id<GREYMatcher> HeaderWithAccessibilityLabelId(int message_id) { - return [ChromeMatchers headerWithAccessibilityLabelId:message_id]; -} - -id<GREYMatcher> HeaderWithAccessibilityLabel(NSString* label) { - return [ChromeMatchers headerWithAccessibilityLabel:label]; -} - -id<GREYMatcher> CancelButton() { - return [ChromeMatchers cancelButton]; -} - -id<GREYMatcher> CloseButton() { - return [ChromeMatchers closeButton]; -} - -id<GREYMatcher> ForwardButton() { - return [ChromeMatchers forwardButton]; -} - -id<GREYMatcher> BackButton() { - return [ChromeMatchers backButton]; -} - -id<GREYMatcher> ReloadButton() { - return [ChromeMatchers reloadButton]; -} - -id<GREYMatcher> StopButton() { - return [ChromeMatchers stopButton]; -} - -id<GREYMatcher> Omnibox() { - return [ChromeMatchers omnibox]; -} - -id<GREYMatcher> DefocusedLocationView() { - return [ChromeMatchers defocusedLocationView]; -} - -id<GREYMatcher> PageSecurityInfoButton() { - return [ChromeMatchers pageSecurityInfoButton]; -} - -id<GREYMatcher> PageSecurityInfoIndicator() { - return [ChromeMatchers pageSecurityInfoIndicator]; -} - -id<GREYMatcher> OmniboxText(std::string text) { - return [ChromeMatchers omniboxText:text]; -} - -id<GREYMatcher> OmniboxContainingText(std::string text) { - return [ChromeMatchers omniboxContainingText:text]; -} - -id<GREYMatcher> LocationViewContainingText(std::string text) { - return [ChromeMatchers locationViewContainingText:text]; -} - -id<GREYMatcher> ToolsMenuButton() { - return [ChromeMatchers toolsMenuButton]; -} - -id<GREYMatcher> ShareButton() { - return [ChromeMatchers shareButton]; -} - -id<GREYMatcher> TabletTabSwitcherOpenButton() { - return [ChromeMatchers tabletTabSwitcherOpenButton]; -} - -id<GREYMatcher> ShowTabsButton() { - return [ChromeMatchers showTabsButton]; -} - -id<GREYMatcher> SettingsSwitchCell(NSString* accessibility_identifier, - BOOL is_toggled_on) { - return [ChromeMatchers settingsSwitchCell:accessibility_identifier - isToggledOn:is_toggled_on]; -} - -id<GREYMatcher> SettingsSwitchCell(NSString* accessibility_identifier, - BOOL is_toggled_on, - BOOL is_enabled) { - return [ChromeMatchers settingsSwitchCell:accessibility_identifier - isToggledOn:is_toggled_on - isEnabled:is_enabled]; -} - -id<GREYMatcher> SyncSwitchCell(NSString* accessibility_label, - BOOL is_toggled_on) { - return [ChromeMatchers syncSwitchCell:accessibility_label - isToggledOn:is_toggled_on]; -} - -id<GREYMatcher> OpenLinkInNewTabButton() { - return [ChromeMatchers openLinkInNewTabButton]; -} - -id<GREYMatcher> NavigationBarDoneButton() { - return [ChromeMatchers navigationBarDoneButton]; -} - -id<GREYMatcher> BookmarksNavigationBarDoneButton() { - return [ChromeMatchers bookmarksNavigationBarDoneButton]; -} - -id<GREYMatcher> AccountConsistencySetupSigninButton() { - return [ChromeMatchers accountConsistencySetupSigninButton]; -} - -id<GREYMatcher> AccountConsistencyConfirmationOkButton() { - return [ChromeMatchers accountConsistencyConfirmationOkButton]; -} - -id<GREYMatcher> AddAccountButton() { - return [ChromeMatchers addAccountButton]; -} - -id<GREYMatcher> SignOutAccountsButton() { - return [ChromeMatchers signOutAccountsButton]; -} - -id<GREYMatcher> ClearBrowsingDataCell() { - return [ChromeMatchers clearBrowsingDataCell]; -} - -id<GREYMatcher> ClearBrowsingDataButton() { - return [ChromeMatchers clearBrowsingDataButton]; -} - -id<GREYMatcher> ClearBrowsingDataView() { - return [ChromeMatchers clearBrowsingDataView]; -} - -id<GREYMatcher> ConfirmClearBrowsingDataButton() { - return [ChromeMatchers confirmClearBrowsingDataButton]; -} - -id<GREYMatcher> SettingsMenuButton() { - return [ChromeMatchers settingsMenuButton]; -} - -id<GREYMatcher> SettingsDoneButton() { - return [ChromeMatchers settingsDoneButton]; -} - -id<GREYMatcher> ToolsMenuView() { - return [ChromeMatchers toolsMenuView]; -} - -id<GREYMatcher> OKButton() { - return [ChromeMatchers okButton]; -} - -id<GREYMatcher> PrimarySignInButton() { - return [ChromeMatchers primarySignInButton]; -} - -id<GREYMatcher> SecondarySignInButton() { - return [ChromeMatchers secondarySignInButton]; -} - -id<GREYMatcher> SettingsAccountButton() { - return [ChromeMatchers settingsAccountButton]; -} - -id<GREYMatcher> SettingsAccountsCollectionView() { - return [ChromeMatchers settingsAccountsCollectionView]; -} - -id<GREYMatcher> SettingsImportDataImportButton() { - return [ChromeMatchers settingsImportDataImportButton]; -} - -id<GREYMatcher> SettingsImportDataKeepSeparateButton() { - return [ChromeMatchers settingsImportDataKeepSeparateButton]; -} - -id<GREYMatcher> SettingsSyncManageSyncedDataButton() { - return [ChromeMatchers settingsSyncManageSyncedDataButton]; -} - -id<GREYMatcher> AccountsSyncButton() { - return [ChromeMatchers accountsSyncButton]; -} - -id<GREYMatcher> ContentSettingsButton() { - return [ChromeMatchers contentSettingsButton]; -} - -id<GREYMatcher> GoogleServicesSettingsButton() { - return [ChromeMatchers googleServicesSettingsButton]; -} - -id<GREYMatcher> SettingsMenuBackButton() { - return [ChromeMatchers settingsMenuBackButton]; -} - -id<GREYMatcher> SettingsMenuPrivacyButton() { - return [ChromeMatchers settingsMenuPrivacyButton]; -} - -id<GREYMatcher> SettingsMenuPasswordsButton() { - return [ChromeMatchers settingsMenuPasswordsButton]; -} - -id<GREYMatcher> PaymentRequestView() { - return [ChromeMatchers paymentRequestView]; -} - -id<GREYMatcher> PaymentRequestErrorView() { - return [ChromeMatchers paymentRequestErrorView]; -} - -id<GREYMatcher> VoiceSearchButton() { - return [ChromeMatchers voiceSearchButton]; -} - -id<GREYMatcher> SettingsCollectionView() { - return [ChromeMatchers settingsCollectionView]; -} - -id<GREYMatcher> ClearBrowsingHistoryButton() { - return [ChromeMatchers clearBrowsingHistoryButton]; -} - -id<GREYMatcher> ClearCookiesButton() { - return [ChromeMatchers clearCookiesButton]; -} - -id<GREYMatcher> ClearCacheButton() { - return [ChromeMatchers clearCacheButton]; -} - -id<GREYMatcher> ClearSavedPasswordsButton() { - return [ChromeMatchers clearSavedPasswordsButton]; -} - -id<GREYMatcher> ContentSuggestionCollectionView() { - return [ChromeMatchers contentSuggestionCollectionView]; -} - -id<GREYMatcher> WarningMessageView() { - return [ChromeMatchers warningMessageView]; -} - -id<GREYMatcher> PaymentRequestPickerRow() { - return [ChromeMatchers paymentRequestPickerRow]; -} - -id<GREYMatcher> PaymentRequestPickerSearchBar() { - return [ChromeMatchers paymentRequestPickerSearchBar]; -} - -id<GREYMatcher> BookmarksMenuButton() { - return [ChromeMatchers bookmarksMenuButton]; -} - -id<GREYMatcher> RecentTabsMenuButton() { - return [ChromeMatchers recentTabsMenuButton]; -} - -id<GREYMatcher> SystemSelectionCallout() { - return [ChromeMatchers systemSelectionCallout]; -} - -id<GREYMatcher> SystemSelectionCalloutCopyButton() { - return [ChromeMatchers systemSelectionCalloutCopyButton]; -} - -id<GREYMatcher> ContextMenuCopyButton() { - return [ChromeMatchers contextMenuCopyButton]; -} - -id<GREYMatcher> NewTabPageOmnibox() { - return [ChromeMatchers NTPOmnibox]; -} - -id<GREYMatcher> WebViewMatcher() { - return [ChromeMatchers webViewMatcher]; -} - -} // namespace chrome_test_util
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn index 35ab14e..61830d7 100644 --- a/ios/chrome/test/earl_grey2/BUILD.gn +++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -53,13 +53,6 @@ ] } -group("eg_test_support+eg2") { - testonly = true - public_deps = [ - ":shared_helper_headers", - ] -} - source_set("eg2_tests") { configs += [ "//build/config/compiler:enable_arc", @@ -72,7 +65,8 @@ ] deps = [ - ":eg_test_support+eg2", + ":shared_helper_headers", + "//ios/chrome/test/earl_grey:eg_test_support+eg2", "//ios/third_party/earl_grey2:test_lib", ]
diff --git a/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni b/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni index b43068b..592eda5 100644 --- a/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni +++ b/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni
@@ -89,6 +89,7 @@ deps = [ ":$_deps_group_name", "//ios/chrome/app:main", + "//ios/chrome/test/earl_grey:eg_app_support+eg2", "//ios/chrome/test/earl_grey:hooks", "//ios/chrome/test/earl_grey2:eg_app_support+eg2", "//ios/testing:http_server_bundle_data", @@ -150,7 +151,7 @@ if (!defined(deps)) { deps = [] } - deps += [ "//ios/chrome/test/earl_grey2:eg_test_support+eg2" ] + deps += [ "//ios/chrome/test/earl_grey:eg_test_support+eg2" ] } }
diff --git a/ios/chrome/test/earl_grey2/smoke_egtest.mm b/ios/chrome/test/earl_grey2/smoke_egtest.mm index 37696705..78027971 100644 --- a/ios/chrome/test/earl_grey2/smoke_egtest.mm +++ b/ios/chrome/test/earl_grey2/smoke_egtest.mm
@@ -6,6 +6,7 @@ #import <UIKit/UIKit.h> #import <XCTest/XCTest.h> +#import "ios/chrome/test/earl_grey/chrome_matchers.h" #import "ios/chrome/test/earl_grey2/chrome_earl_grey_edo.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -30,22 +31,14 @@ // Tests that the tools menu is tappable. - (void)testTapToolsMenu { - id<GREYMatcher> toolsMenuButtonID = - grey_allOf(grey_accessibilityID(@"kToolbarToolsMenuButtonIdentifier"), - grey_sufficientlyVisible(), nil); - [[EarlGrey selectElementWithMatcher:toolsMenuButtonID] + [[EarlGrey selectElementWithMatcher:chrome_test_util::ToolsMenuButton()] performAction:grey_tap()]; } // Tests that a tab can be opened. - (void)testOpenTab { // Open tools menu. - // TODO(crbug.com/917114): Calling the string directly is temporary while we - // roll out a solution to access constants across the code base for EG2. - id<GREYMatcher> toolsMenuButtonID = - grey_allOf(grey_accessibilityID(@"kToolbarToolsMenuButtonIdentifier"), - grey_sufficientlyVisible(), nil); - [[EarlGrey selectElementWithMatcher:toolsMenuButtonID] + [[EarlGrey selectElementWithMatcher:chrome_test_util::ToolsMenuButton()] performAction:grey_tap()]; // Open new tab.
diff --git a/ios/web_view/internal/translate/web_view_translate_client.h b/ios/web_view/internal/translate/web_view_translate_client.h index 93c2195..8b7692b 100644 --- a/ios/web_view/internal/translate/web_view_translate_client.h +++ b/ios/web_view/internal/translate/web_view_translate_client.h
@@ -19,16 +19,10 @@ class PrefService; -namespace metrics { -class TranslateEventProto; -} // namespace metrics - namespace translate { class TranslateAcceptLanguages; class TranslatePrefs; class TranslateManager; - -struct LanguageDetectionDetails; } // namespace translate namespace web { @@ -68,9 +62,6 @@ std::unique_ptr<translate::TranslatePrefs> GetTranslatePrefs() override; translate::TranslateAcceptLanguages* GetTranslateAcceptLanguages() override; int GetInfobarIconID() const override; - void RecordLanguageDetectionEvent( - const translate::LanguageDetectionDetails& details) const override; - void RecordTranslateEvent(const metrics::TranslateEventProto&) override; std::unique_ptr<infobars::InfoBar> CreateInfoBar( std::unique_ptr<translate::TranslateInfoBarDelegate> delegate) const override;
diff --git a/ios/web_view/internal/translate/web_view_translate_client.mm b/ios/web_view/internal/translate/web_view_translate_client.mm index f2b958d..2065cd6 100644 --- a/ios/web_view/internal/translate/web_view_translate_client.mm +++ b/ios/web_view/internal/translate/web_view_translate_client.mm
@@ -113,16 +113,6 @@ return 0; } -void WebViewTranslateClient::RecordLanguageDetectionEvent( - const translate::LanguageDetectionDetails& details) const { - // TODO(crbug.com/722679): Implementing gaia-keyed logging. -} - -void WebViewTranslateClient::RecordTranslateEvent( - const metrics::TranslateEventProto&) { - // TODO(crbug.com/728491): Implementing gaia-keyed logging. -} - bool WebViewTranslateClient::IsTranslatableURL(const GURL& url) { return !url.is_empty() && !url.SchemeIs(url::kFtpScheme); }
diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc index f7868fe..09419a4 100644 --- a/ipc/ipc_channel_proxy.cc +++ b/ipc/ipc_channel_proxy.cc
@@ -221,7 +221,10 @@ } // Called on the IPC::Channel thread -void ChannelProxy::Context::OnSendMessage(std::unique_ptr<Message> message) { +void ChannelProxy::Context::OnSendMessage(std::unique_ptr<Message> message, + const char* debug_name) { + const char* context = debug_name ? debug_name : ""; + TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION scoped_event(context); if (!channel_) { OnChannelClosed(); return; @@ -383,10 +386,10 @@ support->AddGenericAssociatedInterface(name, factory); } -void ChannelProxy::Context::Send(Message* message) { +void ChannelProxy::Context::Send(Message* message, const char* debug_name) { ipc_task_runner()->PostTask( FROM_HERE, base::BindOnce(&ChannelProxy::Context::OnSendMessage, this, - base::WrapUnique(message))); + base::WrapUnique(message), debug_name)); } //----------------------------------------------------------------------------- @@ -513,11 +516,11 @@ bool ChannelProxy::Send(Message* message) { DCHECK(!message->is_sync()) << "Need to use IPC::SyncChannel"; - SendInternal(message); + SendInternal(message, TRACE_HEAP_PROFILER_API_GET_CURRENT_TASK_CONTEXT()); return true; } -void ChannelProxy::SendInternal(Message* message) { +void ChannelProxy::SendInternal(Message* message, const char* debug_name) { DCHECK(did_init_); // TODO(alexeypa): add DCHECK(CalledOnValidThread()) here. Currently there are @@ -535,7 +538,7 @@ Logging::GetInstance()->OnSendMessage(message); #endif - context_->Send(message); + context_->Send(message, debug_name); } void ChannelProxy::AddFilter(MessageFilter* filter) {
diff --git a/ipc/ipc_channel_proxy.h b/ipc/ipc_channel_proxy.h index cbffc5500..864e75f 100644 --- a/ipc/ipc_channel_proxy.h +++ b/ipc/ipc_channel_proxy.h
@@ -270,7 +270,7 @@ void OnDispatchMessage(const Message& message); // Sends |message| from appropriate thread. - void Send(Message* message); + void Send(Message* message, const char* debug_name); protected: friend class base::RefCountedThreadSafe<Context>; @@ -312,7 +312,8 @@ void CreateChannel(std::unique_ptr<ChannelFactory> factory); // Methods called on the IO thread. - void OnSendMessage(std::unique_ptr<Message> message_ptr); + void OnSendMessage(std::unique_ptr<Message> message_ptr, + const char* debug_name); void OnAddFilter(); void OnRemoveFilter(MessageFilter* filter); @@ -392,7 +393,7 @@ bool did_init() const { return did_init_; } // A Send() which doesn't DCHECK if the message is synchronous. - void SendInternal(Message* message); + void SendInternal(Message* message, const char* debug_name); private: friend class IpcSecurityTestUtil;
diff --git a/ipc/ipc_sync_channel.cc b/ipc/ipc_sync_channel.cc index a3f1c3b1..73c7f9a 100644 --- a/ipc/ipc_sync_channel.cc +++ b/ipc/ipc_sync_channel.cc
@@ -605,7 +605,8 @@ "line", IPC_MESSAGE_ID_LINE(message->type())); #endif if (!message->is_sync()) { - ChannelProxy::SendInternal(message); + ChannelProxy::SendInternal( + message, TRACE_HEAP_PROFILER_API_GET_CURRENT_TASK_CONTEXT()); return true; } @@ -620,7 +621,8 @@ return false; } - ChannelProxy::SendInternal(message); + ChannelProxy::SendInternal( + message, TRACE_HEAP_PROFILER_API_GET_CURRENT_TASK_CONTEXT()); // Wait for reply, or for any other incoming synchronous messages. // |this| might get deleted, so only call static functions at this point.
diff --git a/media/BUILD.gn b/media/BUILD.gn index f44243c..f9ae1d9 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn
@@ -314,6 +314,18 @@ } } +fuzzer_test("media_jpeg_parser_picture_fuzzer") { + sources = [ + "filters/jpeg_parser_picture_fuzzertest.cc", + ] + deps = [ + ":test_support", + "//base", + ] + seed_corpus = "test/data" + dict = "test/jpeg.dict" +} + fuzzer_test("media_vp8_parser_fuzzer") { sources = [ "filters/vp8_parser_fuzzertest.cc",
diff --git a/media/filters/jpeg_parser.h b/media/filters/jpeg_parser.h index 39df6b1..0717756 100644 --- a/media/filters/jpeg_parser.h +++ b/media/filters/jpeg_parser.h
@@ -12,10 +12,10 @@ namespace media { -// It's not a full featured JPEG parser implememtation. It only parses JPEG -// baseline sequential process. For explanations of each struct and its -// members, see JPEG specification at -// http://www.w3.org/Graphics/JPEG/itu-t81.pdf. +// It's not a full featured JPEG parser implementation. It only parses JPEG +// baseline sequential process (invalid or progressive JPEGs should fail but not +// crash). For explanations of each struct and its members, see JPEG +// specification at http://www.w3.org/Graphics/JPEG/itu-t81.pdf. enum JpegMarker { JPEG_SOF0 = 0xC0, // start of frame (baseline)
diff --git a/media/filters/jpeg_parser_picture_fuzzertest.cc b/media/filters/jpeg_parser_picture_fuzzertest.cc new file mode 100644 index 0000000..d41fcb6a --- /dev/null +++ b/media/filters/jpeg_parser_picture_fuzzertest.cc
@@ -0,0 +1,22 @@ +// 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 <stddef.h> +#include <stdint.h> + +#include "base/logging.h" +#include "media/filters/jpeg_parser.h" + +struct Environment { + Environment() { logging::SetMinLogLevel(logging::LOG_FATAL); } +}; + +Environment* env = new Environment(); + +// Entry point for LibFuzzer. +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + media::JpegParseResult result; + ParseJpegPicture(data, size, &result); + return 0; +}
diff --git a/media/test/jpeg.dict b/media/test/jpeg.dict new file mode 100644 index 0000000..02eeba2 --- /dev/null +++ b/media/test/jpeg.dict
@@ -0,0 +1,22 @@ +# +# AFL dictionary for JPEG images +# ------------------------------ +# +# Created by Michal Zalewski <lcamtuf@google.com> +# + +header_jfif="JFIF\x00" +header_jfxx="JFXX\x00" + +section_ffc0="\xff\xc0" +section_ffc2="\xff\xc2" +section_ffc4="\xff\xc4" +section_ffd0="\xff\xd0" +section_ffd8="\xff\xd8" +section_ffd9="\xff\xd9" +section_ffda="\xff\xda" +section_ffdb="\xff\xdb" +section_ffdd="\xff\xdd" +section_ffe0="\xff\xe0" +section_ffe1="\xff\xe1" +section_fffe="\xff\xfe" \ No newline at end of file
diff --git a/net/dns/context_host_resolver.cc b/net/dns/context_host_resolver.cc index 2ce87e6..658ac8f 100644 --- a/net/dns/context_host_resolver.cc +++ b/net/dns/context_host_resolver.cc
@@ -12,6 +12,7 @@ #include "base/time/tick_clock.h" #include "net/dns/dns_client.h" #include "net/dns/dns_config.h" +#include "net/dns/host_cache.h" #include "net/dns/host_resolver_manager.h" #include "net/dns/host_resolver_proc.h" #include "net/url_request/url_request_context.h" @@ -79,14 +80,18 @@ DISALLOW_COPY_AND_ASSIGN(WrappedRequest); }; -ContextHostResolver::ContextHostResolver(HostResolverManager* manager) - : manager_(manager) { +ContextHostResolver::ContextHostResolver(HostResolverManager* manager, + std::unique_ptr<HostCache> host_cache) + : manager_(manager), host_cache_(std::move(host_cache)) { DCHECK(manager_); } ContextHostResolver::ContextHostResolver( - std::unique_ptr<HostResolverManager> owned_manager) - : manager_(owned_manager.get()), owned_manager_(std::move(owned_manager)) { + std::unique_ptr<HostResolverManager> owned_manager, + std::unique_ptr<HostCache> host_cache) + : manager_(owned_manager.get()), + owned_manager_(std::move(owned_manager)), + host_cache_(std::move(host_cache)) { DCHECK(manager_); }
diff --git a/net/dns/context_host_resolver.h b/net/dns/context_host_resolver.h index 0f8f5be9..c8cb5f7 100644 --- a/net/dns/context_host_resolver.h +++ b/net/dns/context_host_resolver.h
@@ -21,23 +21,26 @@ class DnsClient; struct DnsConfig; +class HostCache; class HostResolverManager; struct ProcTaskParams; class URLRequestContext; -// Wrapper for HostResolverManager that sets per-context parameters for created -// requests. Except for tests, typically only interacted with through the -// HostResolver interface. +// Wrapper for HostResolverManager, expected to be owned by a URLRequestContext, +// that sets per-URLRequestContext parameters for created requests. Except for +// tests, typically only interacted with through the HostResolver interface. // // See HostResolver::Create[...]() methods for construction. class NET_EXPORT ContextHostResolver : public HostResolver { public: // Creates a ContextHostResolver that forwards all of its requests through - // |manager|. - explicit ContextHostResolver(HostResolverManager* manager); + // |manager|. Requests will be cached using |host_cache| if not null. + explicit ContextHostResolver(HostResolverManager* manager, + std::unique_ptr<HostCache> host_cache); // Same except the created resolver will own its own HostResolverManager. explicit ContextHostResolver( - std::unique_ptr<HostResolverManager> owned_manager); + std::unique_ptr<HostResolverManager> owned_manager, + std::unique_ptr<HostCache> host_cache); ~ContextHostResolver() override; // HostResolver methods: @@ -91,6 +94,8 @@ std::unordered_set<WrappedRequest*> active_requests_; URLRequestContext* context_ = nullptr; + // TODO(crbug.com/934402): Use this cache for resolves. + std::unique_ptr<HostCache> host_cache_; DISALLOW_COPY_AND_ASSIGN(ContextHostResolver); };
diff --git a/net/dns/context_host_resolver_unittest.cc b/net/dns/context_host_resolver_unittest.cc index cbaafd12..d050d6c 100644 --- a/net/dns/context_host_resolver_unittest.cc +++ b/net/dns/context_host_resolver_unittest.cc
@@ -79,7 +79,8 @@ false /* delay */, &context); SetMockDnsRules(std::move(rules)); - auto resolver = std::make_unique<ContextHostResolver>(manager_.get()); + auto resolver = std::make_unique<ContextHostResolver>( + manager_.get(), nullptr /* host_cache */); resolver->SetRequestContext(&context); std::unique_ptr<HostResolver::ResolveHostRequest> request = resolver->CreateRequest(HostPortPair("example.com", 100), @@ -106,7 +107,8 @@ MockDnsClientRule::Result(MockDnsClientRule::EMPTY), false /* delay */); SetMockDnsRules(std::move(rules)); - auto resolver = std::make_unique<ContextHostResolver>(manager_.get()); + auto resolver = std::make_unique<ContextHostResolver>( + manager_.get(), nullptr /* host_cache */); std::unique_ptr<HostResolver::ResolveHostRequest> request = resolver->CreateRequest(HostPortPair("example.com", 100), NetLogWithSource(), base::nullopt); @@ -148,11 +150,13 @@ MockDnsClientRule::Result(MockDnsClientRule::EMPTY), false /* delay */); SetMockDnsRules(std::move(rules)); - auto resolver1 = std::make_unique<ContextHostResolver>(manager_.get()); + auto resolver1 = std::make_unique<ContextHostResolver>( + manager_.get(), nullptr /* host_cache */); std::unique_ptr<HostResolver::ResolveHostRequest> request1 = resolver1->CreateRequest(HostPortPair("example.com", 100), NetLogWithSource(), base::nullopt); - auto resolver2 = std::make_unique<ContextHostResolver>(manager_.get()); + auto resolver2 = std::make_unique<ContextHostResolver>( + manager_.get(), nullptr /* host_cache */); std::unique_ptr<HostResolver::ResolveHostRequest> request2 = resolver2->CreateRequest(HostPortPair("google.com", 100), NetLogWithSource(), base::nullopt); @@ -194,11 +198,13 @@ SetMockDnsRules(std::move(rules)); // Make ResolveHostRequests the same hostname for both resolvers. - auto resolver1 = std::make_unique<ContextHostResolver>(manager_.get()); + auto resolver1 = std::make_unique<ContextHostResolver>( + manager_.get(), nullptr /* host_cache */); std::unique_ptr<HostResolver::ResolveHostRequest> request1 = resolver1->CreateRequest(HostPortPair("example.com", 100), NetLogWithSource(), base::nullopt); - auto resolver2 = std::make_unique<ContextHostResolver>(manager_.get()); + auto resolver2 = std::make_unique<ContextHostResolver>( + manager_.get(), nullptr /* host_cache */); std::unique_ptr<HostResolver::ResolveHostRequest> request2 = resolver2->CreateRequest(HostPortPair("example.com", 100), NetLogWithSource(), base::nullopt); @@ -237,7 +243,8 @@ MockDnsClientRule::Result(MockDnsClientRule::EMPTY), false /* delay */); SetMockDnsRules(std::move(rules)); - auto resolver = std::make_unique<ContextHostResolver>(manager_.get()); + auto resolver = std::make_unique<ContextHostResolver>( + manager_.get(), nullptr /* host_cache */); std::unique_ptr<HostResolver::ResolveHostRequest> request = resolver->CreateRequest(HostPortPair("example.com", 100), NetLogWithSource(), base::nullopt);
diff --git a/net/dns/fuzzed_context_host_resolver.cc b/net/dns/fuzzed_context_host_resolver.cc index 85cc76c..7354529f 100644 --- a/net/dns/fuzzed_context_host_resolver.cc +++ b/net/dns/fuzzed_context_host_resolver.cc
@@ -29,6 +29,7 @@ #include "net/dns/dns_client.h" #include "net/dns/dns_config.h" #include "net/dns/dns_hosts.h" +#include "net/dns/host_cache.h" #include "net/dns/host_resolver_manager.h" #include "net/dns/host_resolver_proc.h" #include "net/dns/mdns_client.h" @@ -346,11 +347,13 @@ FuzzedContextHostResolver::FuzzedContextHostResolver( const Options& options, NetLog* net_log, - base::FuzzedDataProvider* data_provider) + base::FuzzedDataProvider* data_provider, + bool enable_caching) : ContextHostResolver( std::make_unique<FuzzedHostResolverManager>(options, net_log, - data_provider)), + data_provider), + enable_caching ? HostCache::CreateDefaultCache() : nullptr), data_provider_(data_provider), socket_factory_(data_provider), net_log_(net_log) {}
diff --git a/net/dns/fuzzed_context_host_resolver.h b/net/dns/fuzzed_context_host_resolver.h index 26bad94a..a48a685 100644 --- a/net/dns/fuzzed_context_host_resolver.h +++ b/net/dns/fuzzed_context_host_resolver.h
@@ -43,7 +43,8 @@ public: FuzzedContextHostResolver(const Options& options, NetLog* net_log, - base::FuzzedDataProvider* data_provider); + base::FuzzedDataProvider* data_provider, + bool enable_caching); ~FuzzedContextHostResolver() override; // Enable / disable the async resolver. When enabled, installs a
diff --git a/net/dns/host_resolver.cc b/net/dns/host_resolver.cc index de85c316..d3104e7 100644 --- a/net/dns/host_resolver.cc +++ b/net/dns/host_resolver.cc
@@ -98,16 +98,19 @@ std::unique_ptr<HostResolver> HostResolver::Factory::CreateResolver( HostResolverManager* manager, - base::StringPiece host_mapping_rules) { - return HostResolver::CreateResolver(manager, host_mapping_rules); + base::StringPiece host_mapping_rules, + bool enable_caching) { + return HostResolver::CreateResolver(manager, host_mapping_rules, + enable_caching); } std::unique_ptr<HostResolver> HostResolver::Factory::CreateStandaloneResolver( NetLog* net_log, const Options& options, - base::StringPiece host_mapping_rules) { - return HostResolver::CreateStandaloneResolver(net_log, options, - host_mapping_rules); + base::StringPiece host_mapping_rules, + bool enable_caching) { + return HostResolver::CreateStandaloneResolver( + net_log, options, host_mapping_rules, enable_caching); } HostResolver::~HostResolver() = default; @@ -173,10 +176,13 @@ // static std::unique_ptr<HostResolver> HostResolver::CreateResolver( HostResolverManager* manager, - base::StringPiece host_mapping_rules) { + base::StringPiece host_mapping_rules, + bool enable_caching) { DCHECK(manager); - auto resolver = std::make_unique<ContextHostResolver>(manager); + auto cache = enable_caching ? HostCache::CreateDefaultCache() : nullptr; + auto resolver = + std::make_unique<ContextHostResolver>(manager, std::move(cache)); if (host_mapping_rules.empty()) return resolver; @@ -190,10 +196,11 @@ std::unique_ptr<HostResolver> HostResolver::CreateStandaloneResolver( NetLog* net_log, base::Optional<Options> options, - base::StringPiece host_mapping_rules) { - auto resolver = std::make_unique<ContextHostResolver>( - std::make_unique<HostResolverManager>( - std::move(options).value_or(Options()), net_log)); + base::StringPiece host_mapping_rules, + bool enable_caching) { + std::unique_ptr<ContextHostResolver> resolver = + CreateStandaloneContextResolver(net_log, std::move(options), + enable_caching); if (host_mapping_rules.empty()) return resolver; @@ -206,10 +213,14 @@ // static std::unique_ptr<ContextHostResolver> HostResolver::CreateStandaloneContextResolver(NetLog* net_log, - base::Optional<Options> options) { + base::Optional<Options> options, + bool enable_caching) { + auto cache = enable_caching ? HostCache::CreateDefaultCache() : nullptr; + return std::make_unique<ContextHostResolver>( std::make_unique<HostResolverManager>( - std::move(options).value_or(Options()), net_log)); + std::move(options).value_or(Options()), net_log), + std::move(cache)); } // static
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h index 3eb81d9..6db1ed9c 100644 --- a/net/dns/host_resolver.h +++ b/net/dns/host_resolver.h
@@ -126,6 +126,8 @@ size_t max_concurrent_resolves; size_t max_retry_attempts; + // TODO(crbug.com/934402): Remove once caching is fully handled and enabled + // at the per-context level. bool enable_caching; }; @@ -138,13 +140,15 @@ // See HostResolver::CreateResolver. virtual std::unique_ptr<HostResolver> CreateResolver( HostResolverManager* manager, - base::StringPiece host_mapping_rules); + base::StringPiece host_mapping_rules, + bool enable_caching); // See HostResolver::CreateStandaloneResolver. virtual std::unique_ptr<HostResolver> CreateStandaloneResolver( NetLog* net_log, const Options& options, - base::StringPiece host_mapping_rules); + base::StringPiece host_mapping_rules, + bool enable_caching); }; // Parameter-grouping struct for additional optional parameters for @@ -320,7 +324,8 @@ // requests. See MappedHostResolver for details. static std::unique_ptr<HostResolver> CreateResolver( HostResolverManager* manager, - base::StringPiece host_mapping_rules = ""); + base::StringPiece host_mapping_rules = "", + bool enable_caching = true); // Creates a HostResolver independent of any global HostResolverManager. Only // for tests and standalone tools not part of the browser. @@ -330,13 +335,15 @@ static std::unique_ptr<HostResolver> CreateStandaloneResolver( NetLog* net_log, base::Optional<Options> options = base::nullopt, - base::StringPiece host_mapping_rules = ""); + base::StringPiece host_mapping_rules = "", + bool enable_caching = true); // Same, but explicitly returns the implementing ContextHostResolver. Only // used by tests and by StaleHostResolver in Cronet. No mapping rules can be // applied because doing so requires wrapping the ContextHostResolver. static std::unique_ptr<ContextHostResolver> CreateStandaloneContextResolver( NetLog* net_log, - base::Optional<Options> options = base::nullopt); + base::Optional<Options> options = base::nullopt, + bool enable_caching = true); // Helpers for interacting with HostCache and ProcResolver. static AddressFamily DnsQueryTypeToAddressFamily(DnsQueryType query_type);
diff --git a/net/dns/host_resolver_manager.h b/net/dns/host_resolver_manager.h index 488690c0..6339c87 100644 --- a/net/dns/host_resolver_manager.h +++ b/net/dns/host_resolver_manager.h
@@ -362,6 +362,7 @@ void UpdateModeForHistogram(const DnsConfig& dns_config); // Cache of host resolution results. + // TODO(crbug.com/934402): Remove the manager-wide HostCache. std::unique_ptr<HostCache> cache_; // Used for multicast DNS tasks. Created on first use using
diff --git a/net/dns/host_resolver_manager_fuzzer.cc b/net/dns/host_resolver_manager_fuzzer.cc index b12a064f..9d7534f 100644 --- a/net/dns/host_resolver_manager_fuzzer.cc +++ b/net/dns/host_resolver_manager_fuzzer.cc
@@ -204,9 +204,10 @@ net::HostResolver::Options options; options.max_concurrent_resolves = data_provider.ConsumeIntegralInRange(1, 8); - options.enable_caching = data_provider.ConsumeBool(); - net::FuzzedContextHostResolver host_resolver(options, &net_log, - &data_provider); + bool enable_caching = data_provider.ConsumeBool(); + options.enable_caching = enable_caching; + net::FuzzedContextHostResolver host_resolver( + options, &net_log, &data_provider, enable_caching); host_resolver.SetDnsClientEnabled(data_provider.ConsumeBool()); std::vector<std::unique_ptr<DnsRequest>> dns_requests;
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc index dda391ed..2e791d95 100644 --- a/net/dns/mock_host_resolver.cc +++ b/net/dns/mock_host_resolver.cc
@@ -627,12 +627,13 @@ std::unique_ptr<HostResolver> MockHostResolverFactory::CreateResolver( HostResolverManager* manager, - base::StringPiece host_mapping_rules) { + base::StringPiece host_mapping_rules, + bool enable_caching) { DCHECK(host_mapping_rules.empty()); // Explicit new to access private constructor. - auto resolver = base::WrapUnique( - new MockHostResolverBase(use_caching_, cache_invalidation_num_)); + auto resolver = base::WrapUnique(new MockHostResolverBase( + enable_caching && use_caching_, cache_invalidation_num_)); if (rules_) resolver->set_rules(rules_.get()); return resolver; @@ -641,8 +642,9 @@ std::unique_ptr<HostResolver> MockHostResolverFactory::CreateStandaloneResolver( NetLog* net_log, const HostResolver::Options& options, - base::StringPiece host_mapping_rules) { - return CreateResolver(nullptr, host_mapping_rules); + base::StringPiece host_mapping_rules, + bool enable_caching) { + return CreateResolver(nullptr, host_mapping_rules, enable_caching); } //-----------------------------------------------------------------------------
diff --git a/net/dns/mock_host_resolver.h b/net/dns/mock_host_resolver.h index da194d0..8e0d80e 100644 --- a/net/dns/mock_host_resolver.h +++ b/net/dns/mock_host_resolver.h
@@ -295,6 +295,11 @@ }; // Factory that will always create and return Mock(Caching)HostResolvers. +// +// The default behavior is to create a non-caching mock, even if the tested code +// requests caching enabled (via the |enable_caching| parameter in the creation +// methods). A caching mock will only be created if both |use_caching| is set on +// factory construction and |enable_caching| is set in the creation method. class MockHostResolverFactory : public HostResolver::Factory { public: MockHostResolverFactory( @@ -305,11 +310,13 @@ std::unique_ptr<HostResolver> CreateResolver( HostResolverManager* manager, - base::StringPiece host_mapping_rules) override; + base::StringPiece host_mapping_rules, + bool enable_caching) override; std::unique_ptr<HostResolver> CreateStandaloneResolver( NetLog* net_log, const HostResolver::Options& options, - base::StringPiece host_mapping_rules) override; + base::StringPiece host_mapping_rules, + bool enable_caching) override; private: const scoped_refptr<RuleBasedHostResolverProc> rules_;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index f425393..05cf9a3 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -1959,10 +1959,8 @@ } // TODO(https://crbug.com/928551): Support for redirect on CONNECT is -// deprecated, and support will be removed. -// -// The code in this method handles the temporary histogramming and -// compatibility-mode policy during the phase-out. +// deprecated. Should remove the ERR_HTTPS_PROXY_TUNNEL_RESPONSE_REDIRECT error +// code and supporting plumbing + histogram once this change sticks on Stable. int HttpNetworkTransaction::DoCreateStreamCompletedTunnelResponseRedirect() { bool is_main_frame = (request_->load_flags & LOAD_MAIN_FRAME_DEPRECATED) == LOAD_MAIN_FRAME_DEPRECATED; @@ -1972,18 +1970,7 @@ "Net.Proxy.RedirectDuringConnect", GetTunnelRedirectHistogramValue(is_main_frame, was_auto_detected)); - // For legacy compatibility, the proxy is allowed to redirect CONNECT - // if: - // (a) the request was for a top-level frame - // (b) the proxy server was explicitly configured (i.e. not - // auto-detected). - if (is_main_frame && !was_auto_detected) { - // Return OK and let the caller read the proxy's error page - next_state_ = STATE_NONE; - return OK; - } - - // Otherwise let the request fail. + // Fail the request. stream_.reset(); return ERR_HTTPS_PROXY_TUNNEL_RESPONSE_REDIRECT; }
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 38ced1c..5aa23e7 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -9525,7 +9525,7 @@ CONNECT_TIMING_HAS_SSL_TIMES); } -// Test that an HTTPS Proxy can redirect a CONNECT request for main frames. +// Test that an HTTPS Proxy cannot redirect a CONNECT request for main frames. TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) { session_deps_.proxy_resolution_service = ProxyResolutionService::CreateFixedFromPacResult( @@ -9533,7 +9533,6 @@ TestNetLog net_log; session_deps_.net_log = &net_log; - base::TimeTicks start_time = base::TimeTicks::Now(); const base::TimeDelta kTimeIncrement = base::TimeDelta::FromSeconds(4); session_deps_.host_resolver->set_ondemand_mode(true); @@ -9589,43 +9588,7 @@ data.Resume(); rv = callback.WaitForResult(); - EXPECT_THAT(rv, IsOk()); - const HttpResponseInfo* response = trans.GetResponseInfo(); - - ASSERT_TRUE(response); - - EXPECT_EQ(302, response->headers->response_code()); - std::string url; - EXPECT_TRUE(response->headers->IsRedirect(&url)); - EXPECT_EQ("http://login.example.com/", url); - - LoadTimingInfo load_timing_info; - EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info)); - - EXPECT_FALSE(load_timing_info.socket_reused); - EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id); - - // In the case of redirects from proxies, just as with all responses from - // proxies, DNS and SSL times reflect timing to look up the destination's - // name, and negotiate an SSL connection to it (Neither of which are done in - // this case), which the DNS and SSL times for the proxy are all included in - // connect_start / connect_end. See - // HttpNetworkTransaction::OnHttpsProxyTunnelResponseRedirect - - EXPECT_TRUE(load_timing_info.connect_timing.dns_start.is_null()); - EXPECT_TRUE(load_timing_info.connect_timing.dns_end.is_null()); - EXPECT_TRUE(load_timing_info.connect_timing.ssl_start.is_null()); - EXPECT_TRUE(load_timing_info.connect_timing.ssl_end.is_null()); - - EXPECT_EQ(start_time, load_timing_info.proxy_resolve_start); - EXPECT_EQ(start_time, load_timing_info.proxy_resolve_end); - EXPECT_EQ(start_time, load_timing_info.connect_timing.connect_start); - EXPECT_EQ(start_time + 3 * kTimeIncrement, - load_timing_info.connect_timing.connect_end); - - EXPECT_TRUE(load_timing_info.send_start.is_null()); - EXPECT_TRUE(load_timing_info.send_end.is_null()); - EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); + EXPECT_THAT(rv, IsError(ERR_HTTPS_PROXY_TUNNEL_RESPONSE_REDIRECT)); } // Test that an HTTPS Proxy cannot redirect a CONNECT request for subresources. @@ -9732,7 +9695,7 @@ HttpNetworkTransaction::kMainFrameByAutoDetectedProxy, 1); } -// Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request for main +// Tests that an HTTPS (SPDY) Proxy's cannot redirect a CONNECT request for main // frames. TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) { base::HistogramTester histograms; @@ -9741,7 +9704,6 @@ TestNetLog net_log; session_deps_.net_log = &net_log; - base::TimeTicks start_time = base::TimeTicks::Now(); const base::TimeDelta kTimeIncrement = base::TimeDelta::FromSeconds(4); session_deps_.host_resolver->set_ondemand_mode(true); @@ -9803,45 +9765,7 @@ FastForwardBy(kTimeIncrement); data.Resume(); rv = callback.WaitForResult(); - EXPECT_THAT(rv, IsOk()); - const HttpResponseInfo* response = trans.GetResponseInfo(); - - ASSERT_TRUE(response); - - EXPECT_EQ(302, response->headers->response_code()); - std::string url; - EXPECT_TRUE(response->headers->IsRedirect(&url)); - EXPECT_EQ("http://login.example.com/", url); - - LoadTimingInfo load_timing_info; - EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info)); - - EXPECT_FALSE(load_timing_info.socket_reused); - EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id); - - // No proxy resolution times, since there's no PAC script. - EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); - EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); - - // In the case of redirects from proxies, just as with all responses from - // proxies, DNS and SSL times reflect timing to look up the destination's - // name, and negotiate an SSL connection to it (Neither of which are done in - // this case), which the DNS and SSL times for the proxy are all included in - // connect_start / connect_end. See - // HttpNetworkTransaction::OnHttpsProxyTunnelResponseRedirect. - - EXPECT_TRUE(load_timing_info.connect_timing.dns_start.is_null()); - EXPECT_TRUE(load_timing_info.connect_timing.dns_end.is_null()); - EXPECT_TRUE(load_timing_info.connect_timing.ssl_start.is_null()); - EXPECT_TRUE(load_timing_info.connect_timing.ssl_end.is_null()); - - EXPECT_EQ(start_time, load_timing_info.connect_timing.connect_start); - EXPECT_EQ(start_time + 3 * kTimeIncrement, - load_timing_info.connect_timing.connect_end); - - EXPECT_TRUE(load_timing_info.send_start.is_null()); - EXPECT_TRUE(load_timing_info.send_end.is_null()); - EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); + EXPECT_THAT(rv, IsError(ERR_HTTPS_PROXY_TUNNEL_RESPONSE_REDIRECT)); histograms.ExpectUniqueSample( "Net.Proxy.RedirectDuringConnect",
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index d93a76a..ff33971 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -69695,6 +69695,23 @@ { "name": "tnosha.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, { "name": "dpucarriersma.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, { "name": "mainelosap.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "smithcountytxtaxrates.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "techsharetx.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "hfsctx.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "marthasvillemo.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "wisecountytx.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "usdfc.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "dfc.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "lebanonoregon.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "readywithresourcestn.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "coleg.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "coloradobluebook.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "ocponj.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "infuse-mn.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "morgancounty-al.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "delawarenation-nsn.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "minoritywhip.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, + { "name": "gopwhip.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, { "name": "bmoattachments.org", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true }, // END OF ETLD-OWNER REQUESTED ENTRIES
diff --git a/net/quic/quic_stream_factory_fuzzer.cc b/net/quic/quic_stream_factory_fuzzer.cc index 20f1c85..ad44343 100644 --- a/net/quic/quic_stream_factory_fuzzer.cc +++ b/net/quic/quic_stream_factory_fuzzer.cc
@@ -84,7 +84,8 @@ base::FuzzedDataProvider data_provider(data, size); FuzzedContextHostResolver host_resolver(HostResolver::Options(), nullptr, - &data_provider); + &data_provider, + true /* enable_caching */); FuzzedSocketFactory socket_factory(&data_provider); // Initialize this on each loop since some options mutate this.
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc index d5f6308..1964d203 100644 --- a/net/url_request/url_request_context_builder.cc +++ b/net/url_request/url_request_context_builder.cc
@@ -433,20 +433,24 @@ } else if (host_resolver_manager_) { if (host_resolver_factory_) { host_resolver_ = host_resolver_factory_->CreateResolver( - host_resolver_manager_, host_mapping_rules_); + host_resolver_manager_, host_mapping_rules_, + true /* enable_caching */); } else { host_resolver_ = HostResolver::CreateResolver(host_resolver_manager_, - host_mapping_rules_); + host_mapping_rules_, + true /* enable_caching */); } } else { // TODO(crbug.com/934402): Make setting a resolver or manager required, so // the builder should never have to create a standalone resolver. if (host_resolver_factory_) { host_resolver_ = host_resolver_factory_->CreateStandaloneResolver( - context->net_log(), HostResolver::Options(), host_mapping_rules_); + context->net_log(), HostResolver::Options(), host_mapping_rules_, + true /* enable_caching */); } else { host_resolver_ = HostResolver::CreateStandaloneResolver( - context->net_log(), HostResolver::Options(), host_mapping_rules_); + context->net_log(), HostResolver::Options(), host_mapping_rules_, + true /* enable_caching */); } } host_resolver_->SetRequestContext(context.get());
diff --git a/net/url_request/url_request_ftp_fuzzer.cc b/net/url_request/url_request_ftp_fuzzer.cc index c702813..9452df3 100644 --- a/net/url_request/url_request_ftp_fuzzer.cc +++ b/net/url_request/url_request_ftp_fuzzer.cc
@@ -61,7 +61,8 @@ // Need to fuzz the HostResolver to select between IPv4 and IPv6. net::FuzzedContextHostResolver host_resolver(net::HostResolver::Options(), - nullptr, &data_provider); + nullptr, &data_provider, + true /* enable_caching */); url_request_context.set_host_resolver(&host_resolver); net::URLRequestJobFactoryImpl job_factory;
diff --git a/remoting/base/DEPS b/remoting/base/DEPS index 0d4159d..374d8bbf 100644 --- a/remoting/base/DEPS +++ b/remoting/base/DEPS
@@ -5,6 +5,7 @@ "+net", "+services/network/public/cpp", "+third_party/breakpad", + "+third_party/grpc", "+third_party/zlib", "+ui/base", ]
diff --git a/remoting/signaling/grpc_support/BUILD.gn b/remoting/base/grpc_support/BUILD.gn similarity index 100% rename from remoting/signaling/grpc_support/BUILD.gn rename to remoting/base/grpc_support/BUILD.gn
diff --git a/remoting/signaling/grpc_support/README.md b/remoting/base/grpc_support/README.md similarity index 100% rename from remoting/signaling/grpc_support/README.md rename to remoting/base/grpc_support/README.md
diff --git a/remoting/signaling/grpc_support/grpc_async_executor.cc b/remoting/base/grpc_support/grpc_async_executor.cc similarity index 97% rename from remoting/signaling/grpc_support/grpc_async_executor.cc rename to remoting/base/grpc_support/grpc_async_executor.cc index a6c14e3..88d70ec 100644 --- a/remoting/signaling/grpc_support/grpc_async_executor.cc +++ b/remoting/base/grpc_support/grpc_async_executor.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 "remoting/signaling/grpc_support/grpc_async_executor.h" +#include "remoting/base/grpc_support/grpc_async_executor.h" #include <algorithm> #include <utility> @@ -12,7 +12,7 @@ #include "base/no_destructor.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/thread.h" -#include "remoting/signaling/grpc_support/grpc_async_request.h" +#include "remoting/base/grpc_support/grpc_async_request.h" #include "third_party/grpc/src/include/grpcpp/completion_queue.h" namespace remoting {
diff --git a/remoting/signaling/grpc_support/grpc_async_executor.h b/remoting/base/grpc_support/grpc_async_executor.h similarity index 86% rename from remoting/signaling/grpc_support/grpc_async_executor.h rename to remoting/base/grpc_support/grpc_async_executor.h index 9271dd702..b63b5f3 100644 --- a/remoting/signaling/grpc_support/grpc_async_executor.h +++ b/remoting/base/grpc_support/grpc_async_executor.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 REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_EXECUTOR_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_EXECUTOR_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_EXECUTOR_H_ +#define REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_EXECUTOR_H_ #include <list> #include <memory> @@ -12,7 +12,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" -#include "remoting/signaling/grpc_support/grpc_executor.h" +#include "remoting/base/grpc_support/grpc_executor.h" namespace remoting { @@ -55,4 +55,4 @@ } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_EXECUTOR_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_EXECUTOR_H_
diff --git a/remoting/signaling/grpc_support/grpc_async_executor_unittest.cc b/remoting/base/grpc_support/grpc_async_executor_unittest.cc similarity index 97% rename from remoting/signaling/grpc_support/grpc_async_executor_unittest.cc rename to remoting/base/grpc_support/grpc_async_executor_unittest.cc index 859ca1dc..b9e37052 100644 --- a/remoting/signaling/grpc_support/grpc_async_executor_unittest.cc +++ b/remoting/base/grpc_support/grpc_async_executor_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 "remoting/signaling/grpc_support/grpc_async_executor.h" +#include "remoting/base/grpc_support/grpc_async_executor.h" #include <memory> #include <string> @@ -15,11 +15,11 @@ #include "base/test/mock_callback.h" #include "base/test/scoped_task_environment.h" #include "base/threading/sequenced_task_runner_handle.h" -#include "remoting/signaling/grpc_support/grpc_async_server_streaming_request.h" -#include "remoting/signaling/grpc_support/grpc_async_test_server.h" -#include "remoting/signaling/grpc_support/grpc_async_unary_request.h" -#include "remoting/signaling/grpc_support/grpc_support_test_services.grpc.pb.h" -#include "remoting/signaling/grpc_support/grpc_test_util.h" +#include "remoting/base/grpc_support/grpc_async_server_streaming_request.h" +#include "remoting/base/grpc_support/grpc_async_test_server.h" +#include "remoting/base/grpc_support/grpc_async_unary_request.h" +#include "remoting/base/grpc_support/grpc_support_test_services.grpc.pb.h" +#include "remoting/base/grpc_support/grpc_test_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/grpc/src/include/grpcpp/grpcpp.h"
diff --git a/remoting/signaling/grpc_support/grpc_async_request.cc b/remoting/base/grpc_support/grpc_async_request.cc similarity index 92% rename from remoting/signaling/grpc_support/grpc_async_request.cc rename to remoting/base/grpc_support/grpc_async_request.cc index 8be4cfc..5879fa9 100644 --- a/remoting/signaling/grpc_support/grpc_async_request.cc +++ b/remoting/base/grpc_support/grpc_async_request.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 "remoting/signaling/grpc_support/grpc_async_request.h" +#include "remoting/base/grpc_support/grpc_async_request.h" #include "third_party/grpc/src/include/grpcpp/client_context.h"
diff --git a/remoting/signaling/grpc_support/grpc_async_request.h b/remoting/base/grpc_support/grpc_async_request.h similarity index 93% rename from remoting/signaling/grpc_support/grpc_async_request.h rename to remoting/base/grpc_support/grpc_async_request.h index 1181ae4..8a857b10 100644 --- a/remoting/signaling/grpc_support/grpc_async_request.h +++ b/remoting/base/grpc_support/grpc_async_request.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 REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_REQUEST_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_REQUEST_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_REQUEST_H_ +#define REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_REQUEST_H_ #include <memory> #include <utility> @@ -86,4 +86,4 @@ } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_REQUEST_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_REQUEST_H_
diff --git a/remoting/signaling/grpc_support/grpc_async_server_streaming_request.cc b/remoting/base/grpc_support/grpc_async_server_streaming_request.cc similarity index 96% rename from remoting/signaling/grpc_support/grpc_async_server_streaming_request.cc rename to remoting/base/grpc_support/grpc_async_server_streaming_request.cc index 72a1c48d..0f8f922b 100644 --- a/remoting/signaling/grpc_support/grpc_async_server_streaming_request.cc +++ b/remoting/base/grpc_support/grpc_async_server_streaming_request.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 "remoting/signaling/grpc_support/grpc_async_server_streaming_request.h" +#include "remoting/base/grpc_support/grpc_async_server_streaming_request.h" #include "base/bind.h"
diff --git a/remoting/signaling/grpc_support/grpc_async_server_streaming_request.h b/remoting/base/grpc_support/grpc_async_server_streaming_request.h similarity index 93% rename from remoting/signaling/grpc_support/grpc_async_server_streaming_request.h rename to remoting/base/grpc_support/grpc_async_server_streaming_request.h index bae2f26..285d61cf 100644 --- a/remoting/signaling/grpc_support/grpc_async_server_streaming_request.h +++ b/remoting/base/grpc_support/grpc_async_server_streaming_request.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 REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_SERVER_STREAMING_REQUEST_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_SERVER_STREAMING_REQUEST_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_SERVER_STREAMING_REQUEST_H_ +#define REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_SERVER_STREAMING_REQUEST_H_ #include <memory> #include <utility> @@ -13,8 +13,8 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" -#include "remoting/signaling/grpc_support/grpc_async_request.h" -#include "remoting/signaling/grpc_support/scoped_grpc_server_stream.h" +#include "remoting/base/grpc_support/grpc_async_request.h" +#include "remoting/base/grpc_support/scoped_grpc_server_stream.h" #include "third_party/grpc/src/include/grpcpp/support/async_stream.h" namespace remoting { @@ -156,4 +156,4 @@ } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_SERVER_STREAMING_REQUEST_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_SERVER_STREAMING_REQUEST_H_
diff --git a/remoting/signaling/grpc_support/grpc_async_test_server.cc b/remoting/base/grpc_support/grpc_async_test_server.cc similarity index 93% rename from remoting/signaling/grpc_support/grpc_async_test_server.cc rename to remoting/base/grpc_support/grpc_async_test_server.cc index 797a7858..107cd22 100644 --- a/remoting/signaling/grpc_support/grpc_async_test_server.cc +++ b/remoting/base/grpc_support/grpc_async_test_server.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 "remoting/signaling/grpc_support/grpc_async_test_server.h" +#include "remoting/base/grpc_support/grpc_async_test_server.h" #include <utility>
diff --git a/remoting/signaling/grpc_support/grpc_async_test_server.h b/remoting/base/grpc_support/grpc_async_test_server.h similarity index 92% rename from remoting/signaling/grpc_support/grpc_async_test_server.h rename to remoting/base/grpc_support/grpc_async_test_server.h index 93ed11c..dc8758b 100644 --- a/remoting/signaling/grpc_support/grpc_async_test_server.h +++ b/remoting/base/grpc_support/grpc_async_test_server.h
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_TEST_SERVER_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_TEST_SERVER_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_TEST_SERVER_H_ +#define REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_TEST_SERVER_H_ #include <memory> #include "base/macros.h" -#include "remoting/signaling/grpc_support/grpc_channel.h" -#include "remoting/signaling/grpc_support/grpc_test_util.h" +#include "remoting/base/grpc_support/grpc_channel.h" +#include "remoting/base/grpc_support/grpc_test_util.h" #include "third_party/grpc/src/include/grpcpp/impl/codegen/service_type.h" #include "third_party/grpc/src/include/grpcpp/server.h" @@ -106,4 +106,4 @@ } // namespace test } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_TEST_SERVER_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_TEST_SERVER_H_
diff --git a/remoting/signaling/grpc_support/grpc_async_unary_request.h b/remoting/base/grpc_support/grpc_async_unary_request.h similarity index 93% rename from remoting/signaling/grpc_support/grpc_async_unary_request.h rename to remoting/base/grpc_support/grpc_async_unary_request.h index e1ef13f..e370ee8 100644 --- a/remoting/signaling/grpc_support/grpc_async_unary_request.h +++ b/remoting/base/grpc_support/grpc_async_unary_request.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 REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_UNARY_REQUEST_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_UNARY_REQUEST_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_UNARY_REQUEST_H_ +#define REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_UNARY_REQUEST_H_ #include <memory> #include <utility> @@ -12,7 +12,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/sequence_checker.h" -#include "remoting/signaling/grpc_support/grpc_async_request.h" +#include "remoting/base/grpc_support/grpc_async_request.h" #include "third_party/grpc/src/include/grpcpp/support/async_unary_call.h" namespace remoting { @@ -107,4 +107,4 @@ } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_ASYNC_UNARY_REQUEST_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_GRPC_ASYNC_UNARY_REQUEST_H_
diff --git a/remoting/signaling/grpc_support/grpc_authenticated_executor.cc b/remoting/base/grpc_support/grpc_authenticated_executor.cc similarity index 89% rename from remoting/signaling/grpc_support/grpc_authenticated_executor.cc rename to remoting/base/grpc_support/grpc_authenticated_executor.cc index f3315f5..601d26c 100644 --- a/remoting/signaling/grpc_support/grpc_authenticated_executor.cc +++ b/remoting/base/grpc_support/grpc_authenticated_executor.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/signaling/grpc_support/grpc_authenticated_executor.h" +#include "remoting/base/grpc_support/grpc_authenticated_executor.h" #include <utility> #include "base/bind.h" -#include "remoting/signaling/grpc_support/grpc_async_executor.h" -#include "remoting/signaling/grpc_support/grpc_async_request.h" +#include "remoting/base/grpc_support/grpc_async_executor.h" +#include "remoting/base/grpc_support/grpc_async_request.h" #include "third_party/grpc/src/include/grpcpp/client_context.h" #include "third_party/grpc/src/include/grpcpp/security/credentials.h"
diff --git a/remoting/signaling/grpc_support/grpc_authenticated_executor.h b/remoting/base/grpc_support/grpc_authenticated_executor.h similarity index 82% rename from remoting/signaling/grpc_support/grpc_authenticated_executor.h rename to remoting/base/grpc_support/grpc_authenticated_executor.h index 9a3d6d2..d28d92e 100644 --- a/remoting/signaling/grpc_support/grpc_authenticated_executor.h +++ b/remoting/base/grpc_support/grpc_authenticated_executor.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 REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_AUTHENTICATED_EXECUTOR_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_AUTHENTICATED_EXECUTOR_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_GRPC_AUTHENTICATED_EXECUTOR_H_ +#define REMOTING_BASE_GRPC_SUPPORT_GRPC_AUTHENTICATED_EXECUTOR_H_ #include <memory> #include <string> #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "remoting/base/grpc_support/grpc_executor.h" #include "remoting/base/oauth_token_getter.h" -#include "remoting/signaling/grpc_support/grpc_executor.h" namespace remoting { @@ -47,4 +47,4 @@ } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_AUTHENTICATED_EXECUTOR_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_GRPC_AUTHENTICATED_EXECUTOR_H_
diff --git a/remoting/signaling/grpc_support/grpc_authenticated_executor_unittest.cc b/remoting/base/grpc_support/grpc_authenticated_executor_unittest.cc similarity index 95% rename from remoting/signaling/grpc_support/grpc_authenticated_executor_unittest.cc rename to remoting/base/grpc_support/grpc_authenticated_executor_unittest.cc index bb9a687..b29fcd6 100644 --- a/remoting/signaling/grpc_support/grpc_authenticated_executor_unittest.cc +++ b/remoting/base/grpc_support/grpc_authenticated_executor_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 "remoting/signaling/grpc_support/grpc_authenticated_executor.h" +#include "remoting/base/grpc_support/grpc_authenticated_executor.h" #include <memory> #include <utility> @@ -12,9 +12,9 @@ #include "base/test/scoped_task_environment.h" #include "base/threading/sequenced_task_runner_handle.h" #include "remoting/base/fake_oauth_token_getter.h" +#include "remoting/base/grpc_support/grpc_async_unary_request.h" +#include "remoting/base/grpc_support/grpc_support_test_services.pb.h" #include "remoting/base/oauth_token_getter.h" -#include "remoting/signaling/grpc_support/grpc_async_unary_request.h" -#include "remoting/signaling/grpc_support/grpc_support_test_services.pb.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/remoting/signaling/grpc_support/grpc_channel.cc b/remoting/base/grpc_support/grpc_channel.cc similarity index 82% rename from remoting/signaling/grpc_support/grpc_channel.cc rename to remoting/base/grpc_support/grpc_channel.cc index b926a694..6465a60 100644 --- a/remoting/signaling/grpc_support/grpc_channel.cc +++ b/remoting/base/grpc_support/grpc_channel.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 "remoting/signaling/grpc_support/grpc_channel.h" +#include "remoting/base/grpc_support/grpc_channel.h" #include "third_party/grpc/src/include/grpcpp/grpcpp.h" @@ -10,7 +10,7 @@ namespace { -#include "remoting/signaling/grpc_support/root_certs_prod.inc" +#include "remoting/base/grpc_support/root_certs_prod.inc" } // namespace
diff --git a/remoting/signaling/grpc_support/grpc_channel.h b/remoting/base/grpc_support/grpc_channel.h similarity index 64% rename from remoting/signaling/grpc_support/grpc_channel.h rename to remoting/base/grpc_support/grpc_channel.h index 8631fd3..040221f 100644 --- a/remoting/signaling/grpc_support/grpc_channel.h +++ b/remoting/base/grpc_support/grpc_channel.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 REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_CHANNEL_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_CHANNEL_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_GRPC_CHANNEL_H_ +#define REMOTING_BASE_GRPC_SUPPORT_GRPC_CHANNEL_H_ #include <memory> @@ -12,10 +12,10 @@ namespace remoting { // TODO(yuweih): See if you should create a wrapper for the shared pointer. -#include "remoting/signaling/grpc_support/using_grpc_channel_shared_ptr.inc" +#include "remoting/base/grpc_support/using_grpc_channel_shared_ptr.inc" GrpcChannelSharedPtr CreateSslChannelForEndpoint(const std::string& endpoint); } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_CHANNEL_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_GRPC_CHANNEL_H_
diff --git a/remoting/signaling/grpc_support/grpc_executor.h b/remoting/base/grpc_support/grpc_executor.h similarity index 82% rename from remoting/signaling/grpc_support/grpc_executor.h rename to remoting/base/grpc_support/grpc_executor.h index 8d94fbc..2e38e75 100644 --- a/remoting/signaling/grpc_support/grpc_executor.h +++ b/remoting/base/grpc_support/grpc_executor.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 REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_EXECUTOR_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_EXECUTOR_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_GRPC_EXECUTOR_H_ +#define REMOTING_BASE_GRPC_SUPPORT_GRPC_EXECUTOR_H_ #include <memory> @@ -33,4 +33,4 @@ } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_EXECUTOR_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_GRPC_EXECUTOR_H_
diff --git a/remoting/signaling/grpc_support/grpc_support_test_services.proto b/remoting/base/grpc_support/grpc_support_test_services.proto similarity index 100% rename from remoting/signaling/grpc_support/grpc_support_test_services.proto rename to remoting/base/grpc_support/grpc_support_test_services.proto
diff --git a/remoting/signaling/grpc_support/grpc_test_util.cc b/remoting/base/grpc_support/grpc_test_util.cc similarity index 95% rename from remoting/signaling/grpc_support/grpc_test_util.cc rename to remoting/base/grpc_support/grpc_test_util.cc index c07b0d6..77beb563 100644 --- a/remoting/signaling/grpc_support/grpc_test_util.cc +++ b/remoting/base/grpc_support/grpc_test_util.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 "remoting/signaling/grpc_support/grpc_test_util.h" +#include "remoting/base/grpc_support/grpc_test_util.h" #include "base/run_loop.h" #include "base/test/bind_test_util.h"
diff --git a/remoting/signaling/grpc_support/grpc_test_util.h b/remoting/base/grpc_support/grpc_test_util.h similarity index 93% rename from remoting/signaling/grpc_support/grpc_test_util.h rename to remoting/base/grpc_support/grpc_test_util.h index 7717b537b..02c6a33 100644 --- a/remoting/signaling/grpc_support/grpc_test_util.h +++ b/remoting/base/grpc_support/grpc_test_util.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 REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_TEST_UTIL_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_TEST_UTIL_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_GRPC_TEST_UTIL_H_ +#define REMOTING_BASE_GRPC_SUPPORT_GRPC_TEST_UTIL_H_ #include <memory> @@ -11,7 +11,7 @@ #include "base/location.h" #include "base/logging.h" #include "base/macros.h" -#include "remoting/signaling/grpc_support/grpc_async_executor.h" +#include "remoting/base/grpc_support/grpc_async_executor.h" #include "third_party/grpc/src/include/grpcpp/grpcpp.h" namespace base { @@ -114,4 +114,4 @@ } // namespace test } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_GRPC_TEST_UTIL_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_GRPC_TEST_UTIL_H_
diff --git a/remoting/signaling/grpc_support/root_certs_prod.inc b/remoting/base/grpc_support/root_certs_prod.inc similarity index 100% rename from remoting/signaling/grpc_support/root_certs_prod.inc rename to remoting/base/grpc_support/root_certs_prod.inc
diff --git a/remoting/signaling/grpc_support/scoped_grpc_server_stream.cc b/remoting/base/grpc_support/scoped_grpc_server_stream.cc similarity index 75% rename from remoting/signaling/grpc_support/scoped_grpc_server_stream.cc rename to remoting/base/grpc_support/scoped_grpc_server_stream.cc index 4ed9a0c4..d1d5b2c 100644 --- a/remoting/signaling/grpc_support/scoped_grpc_server_stream.cc +++ b/remoting/base/grpc_support/scoped_grpc_server_stream.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "remoting/signaling/grpc_support/scoped_grpc_server_stream.h" +#include "remoting/base/grpc_support/scoped_grpc_server_stream.h" -#include "remoting/signaling/grpc_support/grpc_async_server_streaming_request.h" +#include "remoting/base/grpc_support/grpc_async_server_streaming_request.h" namespace remoting {
diff --git a/remoting/signaling/grpc_support/scoped_grpc_server_stream.h b/remoting/base/grpc_support/scoped_grpc_server_stream.h similarity index 77% rename from remoting/signaling/grpc_support/scoped_grpc_server_stream.h rename to remoting/base/grpc_support/scoped_grpc_server_stream.h index 423e7b6..0e64d6f 100644 --- a/remoting/signaling/grpc_support/scoped_grpc_server_stream.h +++ b/remoting/base/grpc_support/scoped_grpc_server_stream.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 REMOTING_SIGNALING_GRPC_SUPPORT_SCOPED_GRPC_SERVER_STREAM_H_ -#define REMOTING_SIGNALING_GRPC_SUPPORT_SCOPED_GRPC_SERVER_STREAM_H_ +#ifndef REMOTING_BASE_GRPC_SUPPORT_SCOPED_GRPC_SERVER_STREAM_H_ +#define REMOTING_BASE_GRPC_SUPPORT_SCOPED_GRPC_SERVER_STREAM_H_ #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -27,4 +27,4 @@ } // namespace remoting -#endif // REMOTING_SIGNALING_GRPC_SUPPORT_SCOPED_GRPC_SERVER_STREAM_H_ +#endif // REMOTING_BASE_GRPC_SUPPORT_SCOPED_GRPC_SERVER_STREAM_H_
diff --git a/remoting/signaling/grpc_support/using_grpc_channel_shared_ptr.inc b/remoting/base/grpc_support/using_grpc_channel_shared_ptr.inc similarity index 100% rename from remoting/signaling/grpc_support/using_grpc_channel_shared_ptr.inc rename to remoting/base/grpc_support/using_grpc_channel_shared_ptr.inc
diff --git a/remoting/signaling/BUILD.gn b/remoting/signaling/BUILD.gn index 32d3c69..d3d3150 100644 --- a/remoting/signaling/BUILD.gn +++ b/remoting/signaling/BUILD.gn
@@ -64,7 +64,7 @@ "//jingle:jingle_glue", "//net", "//remoting/base", - "//remoting/signaling/grpc_support", + "//remoting/base/grpc_support", "//third_party/grpc:grpcpp", ] @@ -88,7 +88,7 @@ ] deps -= [ "//google_apis", - "//remoting/signaling/grpc_support", + "//remoting/base/grpc_support", "//third_party/grpc:grpcpp", ] public_deps -= [ ":ftl_grpc_library" ] @@ -140,7 +140,7 @@ deps = [ ":test_support", "//net:test_support", - "//remoting/signaling/grpc_support:unit_tests", + "//remoting/base/grpc_support:unit_tests", "//testing/gmock", "//testing/gtest", ]
diff --git a/remoting/signaling/ftl_grpc_context.cc b/remoting/signaling/ftl_grpc_context.cc index 2c132844..a01195e 100644 --- a/remoting/signaling/ftl_grpc_context.cc +++ b/remoting/signaling/ftl_grpc_context.cc
@@ -11,9 +11,7 @@ #include "build/build_config.h" #include "google_apis/google_api_keys.h" #include "remoting/base/service_urls.h" -#include "third_party/grpc/src/include/grpcpp/channel.h" #include "third_party/grpc/src/include/grpcpp/client_context.h" -#include "third_party/grpc/src/include/grpcpp/grpcpp.h" namespace remoting {
diff --git a/remoting/signaling/ftl_grpc_context.h b/remoting/signaling/ftl_grpc_context.h index 386dca3..a7df143 100644 --- a/remoting/signaling/ftl_grpc_context.h +++ b/remoting/signaling/ftl_grpc_context.h
@@ -10,8 +10,8 @@ #include "base/macros.h" #include "net/base/backoff_entry.h" +#include "remoting/base/grpc_support/grpc_channel.h" #include "remoting/signaling/ftl.pb.h" -#include "remoting/signaling/grpc_support/grpc_channel.h" namespace grpc { class ClientContext;
diff --git a/remoting/signaling/ftl_message_reception_channel.cc b/remoting/signaling/ftl_message_reception_channel.cc index c8870c3..9da0ac7c 100644 --- a/remoting/signaling/ftl_message_reception_channel.cc +++ b/remoting/signaling/ftl_message_reception_channel.cc
@@ -9,9 +9,9 @@ #include "base/bind_helpers.h" #include "base/callback.h" #include "base/logging.h" +#include "remoting/base/grpc_support/scoped_grpc_server_stream.h" #include "remoting/signaling/ftl_grpc_context.h" #include "remoting/signaling/ftl_services.grpc.pb.h" -#include "remoting/signaling/grpc_support/scoped_grpc_server_stream.h" namespace remoting {
diff --git a/remoting/signaling/ftl_message_reception_channel_unittest.cc b/remoting/signaling/ftl_message_reception_channel_unittest.cc index 5c7a3cb1..686fbdff 100644 --- a/remoting/signaling/ftl_message_reception_channel_unittest.cc +++ b/remoting/signaling/ftl_message_reception_channel_unittest.cc
@@ -18,10 +18,10 @@ #include "base/test/mock_callback.h" #include "base/test/scoped_task_environment.h" #include "base/threading/sequenced_task_runner_handle.h" +#include "remoting/base/grpc_support/grpc_test_util.h" +#include "remoting/base/grpc_support/scoped_grpc_server_stream.h" #include "remoting/signaling/ftl.pb.h" #include "remoting/signaling/ftl_grpc_context.h" -#include "remoting/signaling/grpc_support/grpc_test_util.h" -#include "remoting/signaling/grpc_support/scoped_grpc_server_stream.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/remoting/signaling/ftl_messaging_client.cc b/remoting/signaling/ftl_messaging_client.cc index 41a365f..d5f68e4 100644 --- a/remoting/signaling/ftl_messaging_client.cc +++ b/remoting/signaling/ftl_messaging_client.cc
@@ -11,12 +11,12 @@ #include "base/guid.h" #include "base/logging.h" #include "base/time/time.h" +#include "remoting/base/grpc_support/grpc_async_server_streaming_request.h" +#include "remoting/base/grpc_support/grpc_async_unary_request.h" +#include "remoting/base/grpc_support/grpc_authenticated_executor.h" +#include "remoting/base/grpc_support/grpc_executor.h" #include "remoting/signaling/ftl_grpc_context.h" #include "remoting/signaling/ftl_message_reception_channel.h" -#include "remoting/signaling/grpc_support/grpc_async_server_streaming_request.h" -#include "remoting/signaling/grpc_support/grpc_async_unary_request.h" -#include "remoting/signaling/grpc_support/grpc_authenticated_executor.h" -#include "remoting/signaling/grpc_support/grpc_executor.h" #include "remoting/signaling/registration_manager.h" namespace remoting {
diff --git a/remoting/signaling/ftl_messaging_client_unittest.cc b/remoting/signaling/ftl_messaging_client_unittest.cc index 0b5e6a6d..6ff46831 100644 --- a/remoting/signaling/ftl_messaging_client_unittest.cc +++ b/remoting/signaling/ftl_messaging_client_unittest.cc
@@ -18,12 +18,12 @@ #include "base/test/bind_test_util.h" #include "base/test/mock_callback.h" #include "base/test/scoped_task_environment.h" +#include "remoting/base/grpc_support/grpc_async_executor.h" +#include "remoting/base/grpc_support/grpc_async_test_server.h" +#include "remoting/base/grpc_support/grpc_test_util.h" +#include "remoting/base/grpc_support/scoped_grpc_server_stream.h" #include "remoting/signaling/ftl_grpc_context.h" #include "remoting/signaling/ftl_services.grpc.pb.h" -#include "remoting/signaling/grpc_support/grpc_async_executor.h" -#include "remoting/signaling/grpc_support/grpc_async_test_server.h" -#include "remoting/signaling/grpc_support/grpc_test_util.h" -#include "remoting/signaling/grpc_support/scoped_grpc_server_stream.h" #include "remoting/signaling/message_reception_channel.h" #include "remoting/signaling/registration_manager.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/remoting/signaling/ftl_registration_manager.cc b/remoting/signaling/ftl_registration_manager.cc index 5fbb60a4..f93cc32 100644 --- a/remoting/signaling/ftl_registration_manager.cc +++ b/remoting/signaling/ftl_registration_manager.cc
@@ -10,11 +10,11 @@ #include "base/callback.h" #include "base/logging.h" #include "base/time/time.h" +#include "remoting/base/grpc_support/grpc_async_unary_request.h" +#include "remoting/base/grpc_support/grpc_authenticated_executor.h" +#include "remoting/base/grpc_support/grpc_executor.h" #include "remoting/signaling/ftl_device_id_provider.h" #include "remoting/signaling/ftl_grpc_context.h" -#include "remoting/signaling/grpc_support/grpc_async_unary_request.h" -#include "remoting/signaling/grpc_support/grpc_authenticated_executor.h" -#include "remoting/signaling/grpc_support/grpc_executor.h" namespace remoting {
diff --git a/remoting/test/ftl_services_playground.cc b/remoting/test/ftl_services_playground.cc index 58fd89a..8a29c3a 100644 --- a/remoting/test/ftl_services_playground.cc +++ b/remoting/test/ftl_services_playground.cc
@@ -19,10 +19,10 @@ #include "base/path_service.h" #include "base/run_loop.h" #include "base/task/post_task.h" +#include "remoting/base/grpc_support/grpc_async_unary_request.h" #include "remoting/base/oauth_token_getter_impl.h" #include "remoting/signaling/ftl_grpc_context.h" #include "remoting/signaling/ftl_services.grpc.pb.h" -#include "remoting/signaling/grpc_support/grpc_async_unary_request.h" #include "remoting/test/cli_util.h" #include "remoting/test/test_device_id_provider.h" #include "remoting/test/test_oauth_token_getter.h"
diff --git a/remoting/test/ftl_services_playground.h b/remoting/test/ftl_services_playground.h index 8b10970..3a2afcb5 100644 --- a/remoting/test/ftl_services_playground.h +++ b/remoting/test/ftl_services_playground.h
@@ -11,10 +11,10 @@ #include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "remoting/base/grpc_support/grpc_authenticated_executor.h" #include "remoting/base/oauth_token_getter.h" #include "remoting/signaling/ftl_messaging_client.h" #include "remoting/signaling/ftl_registration_manager.h" -#include "remoting/signaling/grpc_support/grpc_authenticated_executor.h" namespace remoting {
diff --git a/remoting/test/ftl_signaling_playground.cc b/remoting/test/ftl_signaling_playground.cc index b92d04c..77fc219 100644 --- a/remoting/test/ftl_signaling_playground.cc +++ b/remoting/test/ftl_signaling_playground.cc
@@ -22,6 +22,7 @@ #include "base/task/post_task.h" #include "jingle/glue/thread_wrapper.h" #include "remoting/base/chromium_url_request.h" +#include "remoting/base/grpc_support/grpc_async_unary_request.h" #include "remoting/base/logging.h" #include "remoting/base/oauth_token_getter_impl.h" #include "remoting/base/rsa_key_pair.h" @@ -39,7 +40,6 @@ #include "remoting/signaling/ftl_grpc_context.h" #include "remoting/signaling/ftl_services.grpc.pb.h" #include "remoting/signaling/ftl_signal_strategy.h" -#include "remoting/signaling/grpc_support/grpc_async_unary_request.h" #include "remoting/test/cli_util.h" #include "remoting/test/test_device_id_provider.h" #include "remoting/test/test_oauth_token_getter.h"
diff --git a/services/device/hid/hid_connection_impl_unittest.cc b/services/device/hid/hid_connection_impl_unittest.cc index 92f692d6..592af904 100644 --- a/services/device/hid/hid_connection_impl_unittest.cc +++ b/services/device/hid/hid_connection_impl_unittest.cc
@@ -176,19 +176,24 @@ kMaxReportSizeBytes, kMaxReportSizeBytes, 0); } + std::vector<uint8_t> CreateTestReportBuffer(uint8_t report_id, size_t size) { + std::vector<uint8_t> buffer(size); + buffer[0] = report_id; + for (size_t i = 1; i < size; ++i) + buffer[i] = i; + return buffer; + } + std::unique_ptr<HidConnectionImpl> hid_connection_impl_; scoped_refptr<FakeHidConnection> fake_connection_; std::unique_ptr<TestHidConnectionClient> connection_client_; }; TEST_F(HidConnectionImplTest, ReadWrite) { - CreateHidConnection(false); - // Buffer contents: [0x42 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09] + CreateHidConnection(/*with_connection_client=*/false); const size_t kTestBufferSize = kMaxReportSizeBytes; - std::vector<uint8_t> buffer_vec(kTestBufferSize); - buffer_vec[0] = kTestReportId; - for (size_t i = 1; i < kTestBufferSize; ++i) - buffer_vec[i] = i; + std::vector<uint8_t> buffer_vec = + CreateTestReportBuffer(kTestReportId, kTestBufferSize); // Simulate an output report (host to device). TestIoCallback write_callback; @@ -216,13 +221,10 @@ } TEST_F(HidConnectionImplTest, ReadWriteWithConnectionClient) { - CreateHidConnection(true); - // Buffer contents: [0x42 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09] + CreateHidConnection(/*with_connection_client=*/true); const size_t kTestBufferSize = kMaxReportSizeBytes; - std::vector<uint8_t> buffer_vec(kTestBufferSize); - buffer_vec[0] = kTestReportId; - for (size_t i = 1; i < kTestBufferSize; ++i) - buffer_vec[i] = i; + std::vector<uint8_t> buffer_vec = + CreateTestReportBuffer(kTestReportId, kTestBufferSize); // Simulate an output report (host to device). TestIoCallback write_callback; @@ -246,4 +248,30 @@ } } +TEST_F(HidConnectionImplTest, DestroyWithPendingInputReport) { + CreateHidConnection(/*with_connection_client=*/false); + const size_t kTestBufferSize = kMaxReportSizeBytes; + std::vector<uint8_t> buffer_vec = + CreateTestReportBuffer(kTestReportId, kTestBufferSize); + + // Simulate an input report (device to host). + auto buffer = base::MakeRefCounted<base::RefCountedBytes>(buffer_vec); + ASSERT_EQ(buffer->size(), kTestBufferSize); + fake_connection_->SimulateInputReport(buffer); + + // Destroy the connection without reading the report. + hid_connection_impl_.reset(); +} + +TEST_F(HidConnectionImplTest, DestroyWithPendingRead) { + CreateHidConnection(/*with_connection_client=*/false); + + // Simulate reading an input report. + TestIoCallback read_callback; + hid_connection_impl_->Read(read_callback.GetReadCallback()); + + // Destroy the connection without receiving an input report. + hid_connection_impl_.reset(); +} + } // namespace device
diff --git a/services/metrics/public/cpp/ukm_recorder.h b/services/metrics/public/cpp/ukm_recorder.h index 2083c2d..3a52ab7f 100644 --- a/services/metrics/public/cpp/ukm_recorder.h +++ b/services/metrics/public/cpp/ukm_recorder.h
@@ -18,6 +18,7 @@ #include "url/gurl.h" class BackgroundFetchDelegateImpl; +class BackgroundSyncMetrics; class IOSChromePasswordManagerClient; class MediaEngagementSession; class PlatformNotificationServiceImpl; @@ -103,6 +104,7 @@ private: friend BackgroundFetchDelegateImpl; + friend BackgroundSyncMetrics; friend DelegatingUkmRecorder; friend IOSChromePasswordManagerClient; friend MediaEngagementSession;
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index 9e6abaf7..f1c7896d 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -1360,7 +1360,8 @@ private_internal_resolver = network_service_->host_resolver_factory()->CreateStandaloneResolver( - url_request_context_->net_log(), options, ""); + url_request_context_->net_log(), options, "", + false /* enable_caching */); private_internal_resolver->SetRequestContext(url_request_context_); internal_resolver = private_internal_resolver.get();
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index 8efdc47..76b9a03b 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -2993,8 +2993,8 @@ network_context->GetNumOutstandingResolveHostRequestsForTesting()); } -// Test factory of net::HostResolvers. Creates standard -// net::ContextHostResolver. Keeps pointers to all created resolvers. +// Test factory of net::HostResolvers. Creates standard (but potentially non- +// caching) net::ContextHostResolver. Keeps pointers to all created resolvers. class TestResolverFactory : public net::HostResolver::Factory { public: static TestResolverFactory* CreateAndSetFactory(NetworkService* service) { @@ -3006,9 +3006,11 @@ std::unique_ptr<net::HostResolver> CreateResolver( net::HostResolverManager* manager, - base::StringPiece host_mapping_rules) override { + base::StringPiece host_mapping_rules, + bool enable_caching) override { DCHECK(host_mapping_rules.empty()); - auto resolver = std::make_unique<net::ContextHostResolver>(manager); + auto resolver = std::make_unique<net::ContextHostResolver>( + manager, nullptr /* host_cache */); resolvers_.push_back(resolver.get()); return resolver; } @@ -3016,10 +3018,12 @@ std::unique_ptr<net::HostResolver> CreateStandaloneResolver( net::NetLog* net_log, const net::HostResolver::Options& options, - base::StringPiece host_mapping_rules) override { + base::StringPiece host_mapping_rules, + bool enable_caching) override { DCHECK(host_mapping_rules.empty()); std::unique_ptr<net::ContextHostResolver> resolver = - net::HostResolver::CreateStandaloneContextResolver(net_log, options); + net::HostResolver::CreateStandaloneContextResolver(net_log, options, + enable_caching); resolvers_.push_back(resolver.get()); return resolver; }
diff --git a/skia/ext/opacity_filter_canvas.cc b/skia/ext/opacity_filter_canvas.cc index 76578cb..5baed1d8 100644 --- a/skia/ext/opacity_filter_canvas.cc +++ b/skia/ext/opacity_filter_canvas.cc
@@ -4,7 +4,6 @@ #include "skia/ext/opacity_filter_canvas.h" #include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkTLazy.h" namespace skia {
diff --git a/third_party/blink/public/web/web_element.h b/third_party/blink/public/web/web_element.h index 062c5ff..44de9e7 100644 --- a/third_party/blink/public/web/web_element.h +++ b/third_party/blink/public/web/web_element.h
@@ -78,9 +78,6 @@ // element has no ShadowRoot or has a UA ShadowRoot. WebNode ShadowRoot() const; - // If this element takes up space in the layout of the page. - bool HasNonEmptyLayoutSize() const; - // Returns the bounds of the element in Visual Viewport. The bounds // have been adjusted to include any transformations, including page scale. // This function will update the layout if required.
diff --git a/third_party/blink/renderer/bindings/modules/BUILD.gn b/third_party/blink/renderer/bindings/modules/BUILD.gn index 1412454..251dc682 100644 --- a/third_party/blink/renderer/bindings/modules/BUILD.gn +++ b/third_party/blink/renderer/bindings/modules/BUILD.gn
@@ -68,6 +68,7 @@ "//third_party/blink/renderer/modules/webmidi/midi_message_event.idl", "//third_party/blink/renderer/modules/websockets/close_event.idl", "//third_party/blink/renderer/modules/xr/xr_input_source_event.idl", + "//third_party/blink/renderer/modules/xr/xr_reference_space_event.idl", "//third_party/blink/renderer/modules/xr/xr_session_event.idl", ]
diff --git a/third_party/blink/renderer/core/DEPS b/third_party/blink/renderer/core/DEPS index fe8bdee5..73d42b89 100644 --- a/third_party/blink/renderer/core/DEPS +++ b/third_party/blink/renderer/core/DEPS
@@ -3,6 +3,7 @@ "+base/barrier_closure.h", "+base/files/file.h", "+base/mac/foundation_util.h", + "+base/mac/mac_util.h", "+base/mac/scoped_cftyperef.h", "+base/mac/scoped_nsobject.h", "+base/memory/scoped_policy.h",
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index b10ee7c..8a7abae 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1208,14 +1208,6 @@ viewport->SetScrollOffset(new_offset, kProgrammaticScroll, scroll_behavior); } -bool Element::HasNonEmptyLayoutSize() const { - GetDocument().UpdateStyleAndLayout(); - - if (LayoutBoxModelObject* box = GetLayoutBoxModelObject()) - return box->HasNonEmptyLayoutSize(); - return false; -} - IntRect Element::BoundsInViewport() const { GetDocument().EnsurePaintLocationDataValidForNode(this);
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index bf59e7b..24558a1 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -331,8 +331,6 @@ DOMRectList* getClientRects(); DOMRect* getBoundingClientRect(); - bool HasNonEmptyLayoutSize() const; - const AtomicString& computedRole(); String computedName();
diff --git a/third_party/blink/renderer/core/exported/web_element.cc b/third_party/blink/renderer/core/exported/web_element.cc index d847663..c239472e0 100644 --- a/third_party/blink/renderer/core/exported/web_element.cc +++ b/third_party/blink/renderer/core/exported/web_element.cc
@@ -144,10 +144,6 @@ return WebNode(root); } -bool WebElement::HasNonEmptyLayoutSize() const { - return ConstUnwrap<Element>()->HasNonEmptyLayoutSize(); -} - WebRect WebElement::BoundsInViewport() const { return ConstUnwrap<Element>()->BoundsInViewport(); }
diff --git a/third_party/blink/renderer/core/exported/web_element_test.cc b/third_party/blink/renderer/core/exported/web_element_test.cc index 0f5b6a0..47db70bc 100644 --- a/third_party/blink/renderer/core/exported/web_element_test.cc +++ b/third_party/blink/renderer/core/exported/web_element_test.cc
@@ -17,64 +17,6 @@ namespace blink { -static const char kBlockWithContinuations[] = - "<head> <style> form {display: inline;} </style> </head>" - "<body>" - " <form>" - " <div id='testElement'>" - " <input type='password' id='password'/>" - " </div>" - " </form>" - "</body>"; - -static const char kEmptyBlock[] = - "<head> <style> form {display: inline;} </style> </head>" - "<body> <form id='testElement'> </form> </body>"; - -static const char kEmptyInline[] = - "<body> <span id='testElement'> </span> </body>"; - -static const char kBlockWithDisplayNone[] = - "<head> <style> form {display: none;} </style> </head>" - "<body>" - " <form id='testElement'>" - " <div>" - " <input type='password' id='password'/>" - " </div>" - " </form>" - "</body>"; - -static const char kBlockWithContent[] = - "<div id='testElement'>" - " <div>Hello</div> " - "</div>"; - -static const char kBlockWithText[] = - "<div id='testElement'>" - " <div>Hello</div> " - "</div>"; - -static const char kBlockWithEmptyZeroSizedSVG[] = - "<div id='testElement'>" - " <svg height='0'><g><rect width='100' height='100'/></g></svg> " - "</div>"; - -static const char kBlockWithInlines[] = - "<div id='testElement'>" - " <span>Hello</span> " - "</div>"; - -static const char kBlockWithEmptyInlines[] = - "<div id='testElement'>" - " <span></span> " - "</div>"; - -static const char kBlockWithEmptyFirstChild[] = - "<div id='testElement'>" - " <div style='position: absolute'></div> " - " <div style='position: absolute'>Hello</div> " - "</div>"; - class WebElementTest : public PageTestBase { protected: void InsertHTML(String html); @@ -91,46 +33,6 @@ return WebElement(element); } -TEST_F(WebElementTest, HasNonEmptyLayoutSize) { - GetDocument().SetCompatibilityMode(Document::kQuirksMode); - InsertHTML(kEmptyBlock); - EXPECT_FALSE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kEmptyInline); - EXPECT_FALSE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kBlockWithDisplayNone); - EXPECT_FALSE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kBlockWithEmptyInlines); - EXPECT_FALSE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kBlockWithEmptyZeroSizedSVG); - EXPECT_FALSE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kBlockWithContinuations); - EXPECT_TRUE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kBlockWithInlines); - EXPECT_TRUE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kBlockWithContent); - EXPECT_TRUE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kBlockWithText); - EXPECT_TRUE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kEmptyBlock); - ShadowRoot& root = GetDocument() - .getElementById("testElement") - ->CreateV0ShadowRootForTesting(); - root.SetInnerHTMLFromString("<div>Hello World</div>"); - EXPECT_TRUE(TestElement().HasNonEmptyLayoutSize()); - - InsertHTML(kBlockWithEmptyFirstChild); - EXPECT_TRUE(TestElement().HasNonEmptyLayoutSize()); -} - TEST_F(WebElementTest, IsEditable) { InsertHTML("<div id=testElement></div>"); EXPECT_FALSE(TestElement().IsEditable());
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc index adc8548..b5a0254 100644 --- a/third_party/blink/renderer/core/html/html_element.cc +++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -1031,18 +1031,11 @@ return Directionality(); } -TextDirection HTMLElement::Directionality( - Node** strong_directionality_text_node) const { +TextDirection HTMLElement::Directionality() const { if (auto* input_element = ToHTMLInputElementOrNull(*this)) { bool has_strong_directionality; TextDirection text_direction = DetermineDirectionality( input_element->value(), &has_strong_directionality); - if (strong_directionality_text_node) { - *strong_directionality_text_node = - has_strong_directionality - ? const_cast<HTMLInputElement*>(input_element) - : nullptr; - } return text_direction; } @@ -1072,16 +1065,11 @@ bool has_strong_directionality; TextDirection text_direction = DetermineDirectionality( node->textContent(true), &has_strong_directionality); - if (has_strong_directionality) { - if (strong_directionality_text_node) - *strong_directionality_text_node = node; + if (has_strong_directionality) return text_direction; - } } node = FlatTreeTraversal::Next(*node, this); } - if (strong_directionality_text_node) - *strong_directionality_text_node = nullptr; return TextDirection::kLtr; }
diff --git a/third_party/blink/renderer/core/html/html_element.h b/third_party/blink/renderer/core/html/html_element.h index 69b6940..75cd11af 100644 --- a/third_party/blink/renderer/core/html/html_element.h +++ b/third_party/blink/renderer/core/html/html_element.h
@@ -198,8 +198,7 @@ bool SelfOrAncestorHasDirAutoAttribute() const; void AdjustDirectionalityIfNeededAfterChildAttributeChanged(Element* child); void AdjustDirectionalityIfNeededAfterChildrenChanged(const ChildrenChange&); - TextDirection Directionality( - Node** strong_directionality_text_node = nullptr) const; + TextDirection Directionality() const; TranslateAttributeMode GetTranslateAttributeMode() const;
diff --git a/third_party/blink/renderer/core/inspector/inspect_tools.cc b/third_party/blink/renderer/core/inspector/inspect_tools.cc index 58cd63c..e877a48 100644 --- a/third_party/blink/renderer/core/inspector/inspect_tools.cc +++ b/third_party/blink/renderer/core/inspector/inspect_tools.cc
@@ -38,8 +38,8 @@ Vector<Color> bgcolors; String font_size; String font_weight; - InspectorCSSAgent::GetBackgroundColors(ToElement(node), &bgcolors, &font_size, - &font_weight); + // TODO(crbug.com/951817): make InspectorCSSAgent::GetBackgroundColors work + // fast enough for large tables (and other heavy pages) and call it here. if (bgcolors.size() == 1) { result.font_size = font_size; result.font_weight = font_weight;
diff --git a/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.cc b/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.cc index 52ec7c4..e400bc9 100644 --- a/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.cc +++ b/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.cc
@@ -21,9 +21,9 @@ block_size_(block_size.ToDouble()) { // Immediately store the result data, so that it remains immutable between // layout calls to the child. - if (GetLayoutBox()->IsLayoutCustom()) { - SerializedScriptValue* data = - ToLayoutCustom(GetLayoutBox())->GetFragmentResultData(); + auto* layout_custom = DynamicTo<LayoutCustom>(GetLayoutBox()); + if (layout_custom) { + SerializedScriptValue* data = layout_custom->GetFragmentResultData(); if (data) layout_worklet_world_v8_data_.Set(isolate, data->Deserialize(isolate)); }
diff --git a/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc b/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc index 4e1bc228..ad16e4c6 100644 --- a/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc +++ b/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc
@@ -101,8 +101,9 @@ box->SetOverridePercentageResolutionBlockSize( percentage_resolution_logical_height); - if (box->IsLayoutCustom()) - ToLayoutCustom(box)->SetConstraintData(constraint_data_); + auto* layout_custom = DynamicTo<LayoutCustom>(box); + if (layout_custom) + layout_custom->SetConstraintData(constraint_data_); // TODO(cbiesinger): Can this just be ForceLayout()? box->ForceLayoutWithPaintInvalidation(); @@ -110,8 +111,8 @@ box->ClearOverridePercentageResolutionBlockSize(); box->ClearOverrideSize(); - if (box->IsLayoutCustom()) - ToLayoutCustom(box)->ClearConstraintData(); + if (layout_custom) + layout_custom->ClearConstraintData(); LayoutUnit fragment_inline_size = is_parallel_writing_mode ? box->LogicalWidth() : box->LogicalHeight();
diff --git a/third_party/blink/renderer/core/layout/custom/layout_custom.h b/third_party/blink/renderer/core/layout/custom/layout_custom.h index d4e61f0..02f1b7ea 100644 --- a/third_party/blink/renderer/core/layout/custom/layout_custom.h +++ b/third_party/blink/renderer/core/layout/custom/layout_custom.h
@@ -7,6 +7,7 @@ #include "third_party/blink/renderer/core/layout/custom/css_layout_definition.h" #include "third_party/blink/renderer/core/layout/layout_block_flow.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" namespace blink { @@ -74,7 +75,12 @@ scoped_refptr<SerializedScriptValue> fragment_result_data_; }; -DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutCustom, IsLayoutCustom()); +template <> +struct DowncastTraits<LayoutCustom> { + static bool AllowFrom(const LayoutObject& object) { + return object.IsLayoutCustom(); + } +}; } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 1647a9f4..6ef1242 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3638,12 +3638,12 @@ // For quirks mode, we skip most auto-height containing blocks when computing // percentages. + auto* layout_custom = DynamicTo<LayoutCustom>(containing_block); return containing_block->GetDocument().InQuirksMode() && containing_block->StyleRef().LogicalHeight().IsAuto() && !containing_block->IsTableCell() && !containing_block->IsOutOfFlowPositioned() && - !(containing_block->IsLayoutCustom() && - ToLayoutCustom(containing_block)->IsLoaded()) && + !(layout_custom && layout_custom->IsLoaded()) && !containing_block->HasOverridePercentageResolutionBlockSize() && !containing_block->IsLayoutGrid() && !containing_block->IsFlexibleBoxIncludingDeprecatedAndNG(); @@ -5390,15 +5390,16 @@ // Children of LayoutCustom object's are only considered "items" when it has a // loaded algorithm. bool LayoutBox::IsCustomItem() const { - return Parent() && Parent()->IsLayoutCustom() && - ToLayoutCustom(Parent())->State() == LayoutCustomState::kBlock; + auto* parent_layout_box = DynamicTo<LayoutCustom>(Parent()); + return parent_layout_box && + parent_layout_box->State() == LayoutCustomState::kBlock; } // LayoutCustom items are only shrink-to-fit during the web-developer defined // layout phase (not during fallback). bool LayoutBox::IsCustomItemShrinkToFit() const { DCHECK(IsCustomItem()); - return ToLayoutCustom(Parent())->Phase() == LayoutCustomPhase::kCustom; + return To<LayoutCustom>(Parent())->Phase() == LayoutCustomPhase::kCustom; } void LayoutBox::AddVisualEffectOverflow() {
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc index 41da2e2..3fbddd0a 100644 --- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc +++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -583,27 +583,6 @@ descendant.AddOutlineRects(rects, additional_offset, include_block_overflows); } -bool LayoutBoxModelObject::HasNonEmptyLayoutSize() const { - for (const LayoutBoxModelObject* root = this; root; - root = root->Continuation()) { - for (const LayoutObject* object = root; object; - object = object->NextInPreOrder(root)) { - if (object->IsBox()) { - const LayoutBox& box = ToLayoutBox(*object); - if (box.LogicalHeight() && box.LogicalWidth()) - return true; - } else if (object->IsLayoutInline()) { - const LayoutInline& layout_inline = ToLayoutInline(*object); - if (!layout_inline.LinesBoundingBox().IsEmpty()) - return true; - } else { - DCHECK(object->IsText() || object->IsSVG()); - } - } - } - return false; -} - void LayoutBoxModelObject::AbsoluteQuadsForSelf( Vector<FloatQuad>& quads, MapCoordinatesFlags mode) const {
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.h b/third_party/blink/renderer/core/layout/layout_box_model_object.h index ea0b611b..ad32cec 100644 --- a/third_party/blink/renderer/core/layout/layout_box_model_object.h +++ b/third_party/blink/renderer/core/layout/layout_box_model_object.h
@@ -175,9 +175,6 @@ virtual LayoutRect VisualOverflowRect() const = 0; - // Checks if this box, or any of it's descendants, or any of it's - // continuations, will take up space in the layout of the page. - bool HasNonEmptyLayoutSize() const; bool UsesCompositedScrolling() const; // Returns which layers backgrounds should be painted into for overflow
diff --git a/third_party/blink/renderer/core/layout/layout_theme_mac.mm b/third_party/blink/renderer/core/layout/layout_theme_mac.mm index 029aae2..271020a 100644 --- a/third_party/blink/renderer/core/layout/layout_theme_mac.mm +++ b/third_party/blink/renderer/core/layout/layout_theme_mac.mm
@@ -25,6 +25,7 @@ #import <Cocoa/Cocoa.h> #import <math.h> +#import "base/mac/mac_util.h" #import "third_party/blink/public/platform/mac/web_sandbox_support.h" #import "third_party/blink/public/platform/platform.h" #import "third_party/blink/renderer/core/css_value_keywords.h" @@ -38,7 +39,6 @@ #import "third_party/blink/renderer/platform/graphics/bitmap_image.h" #import "third_party/blink/renderer/platform/mac/block_exceptions.h" #import "third_party/blink/renderer/platform/mac/color_mac.h" -#import "third_party/blink/renderer/platform/mac/version_util_mac.h" #import "third_party/blink/renderer/platform/mac/web_core_ns_cell_extras.h" #import "third_party/blink/renderer/platform/runtime_enabled_features.h" #import "third_party/blink/renderer/platform/text/platform_locale.h" @@ -942,7 +942,7 @@ // this is achieved by calling |setCenteredLook| with NO. In OS10.11 and // later, instead call |setPlaceholderString| with an empty string. // See https://crbug.com/752362. - if (IsOS10_10()) { + if (base::mac::IsAtMostOS10_10()) { SEL sel = @selector(setCenteredLook:); if ([search_ respondsToSelector:sel]) { BOOL bool_value = NO;
diff --git a/third_party/blink/renderer/devtools/front_end/main/Main.js b/third_party/blink/renderer/devtools/front_end/main/Main.js index 61a98c40..8206ed8 100644 --- a/third_party/blink/renderer/devtools/front_end/main/Main.js +++ b/third_party/blink/renderer/devtools/front_end/main/Main.js
@@ -266,11 +266,36 @@ Main.Main.time('Main._lateInitialization'); this._registerShortcuts(); Extensions.extensionServer.initializeExtensions(); - for (const extension of self.runtime.extensions('late-initialization')) - extension.instance().then(instance => (/** @type {!Common.Runnable} */ (instance)).run()); + const extensions = self.runtime.extensions('late-initialization'); + const promises = []; + for (const extension of extensions) { + const setting = extension.descriptor()['setting']; + if (!setting || Common.settings.moduleSetting(setting).get()) { + promises.push(extension.instance().then(instance => (/** @type {!Common.Runnable} */ (instance)).run())); + continue; + } + /** + * @param {!Common.Event} event + */ + async function changeListener(event) { + if (!event.data) + return; + Common.settings.moduleSetting(setting).removeChangeListener(changeListener); + (/** @type {!Common.Runnable} */ (await extension.instance())).run(); + } + Common.settings.moduleSetting(setting).addChangeListener(changeListener); + } + this._lateInitDonePromise = Promise.all(promises); Main.Main.timeEnd('Main._lateInitialization'); } + /** + * @return {!Promise} + */ + lateInitDonePromiseForTest() { + return this._lateInitDonePromise; + } + _registerForwardedShortcuts() { /** @const */ const forwardedActions = [ 'main.toggle-dock', 'debugger.toggle-breakpoints-active', 'debugger.toggle-pause', 'commandMenu.show',
diff --git a/third_party/blink/renderer/devtools/front_end/perf_ui/LiveHeapProfile.js b/third_party/blink/renderer/devtools/front_end/perf_ui/LiveHeapProfile.js index bf152d6..7150085 100644 --- a/third_party/blink/renderer/devtools/front_end/perf_ui/LiveHeapProfile.js +++ b/third_party/blink/renderer/devtools/front_end/perf_ui/LiveHeapProfile.js
@@ -15,19 +15,6 @@ this._setting.addChangeListener(event => event.data ? this._startProfiling() : this._stopProfiling()); if (this._setting.get()) this._startProfiling(); - PerfUI.LiveHeapProfile.hasStartedForTest(true); - } - - /** - * @param {boolean=} started - * @return {!Promise} - */ - static hasStartedForTest(started) { - if (!PerfUI.LiveHeapProfile._startedPromise) - PerfUI.LiveHeapProfile._startedPromise = new Promise(r => PerfUI.LiveHeapProfile._startedCallback = r); - if (started) - PerfUI.LiveHeapProfile._startedCallback(); - return PerfUI.LiveHeapProfile._startedPromise; } /** @@ -82,7 +69,7 @@ SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this._loadEventFired, this); for (const model of SDK.targetManager.models(SDK.HeapProfilerModel)) model.stopSampling(); - PerfUI.LineLevelProfile.Memory.instance().reset(); + self.runtime.sharedInstance(PerfUI.LineLevelProfile.Memory).reset(); } _stopProfiling() {
diff --git a/third_party/blink/renderer/devtools/front_end/perf_ui/module.json b/third_party/blink/renderer/devtools/front_end/perf_ui/module.json index 2d488c9..dabd82d 100644 --- a/third_party/blink/renderer/devtools/front_end/perf_ui/module.json +++ b/third_party/blink/renderer/devtools/front_end/perf_ui/module.json
@@ -3,7 +3,8 @@ { "type": "late-initialization", "className": "PerfUI.LiveHeapProfile", - "experiment": "liveHeapProfile" + "experiment": "liveHeapProfile", + "setting": "memoryLiveHeapProfile" }, { "type": "@SourceFrame.LineDecorator",
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index dea3c0f..a943f08 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -492,12 +492,12 @@ "xr/xr_presentation_context.idl", "xr/xr_ray.idl", "xr/xr_reference_space.idl", + "xr/xr_reference_space_event.idl", "xr/xr_render_state.idl", "xr/xr_rigid_transform.idl", "xr/xr_session.idl", "xr/xr_session_event.idl", "xr/xr_space.idl", - "xr/xr_stage_bounds.idl", "xr/xr_stationary_reference_space.idl", "xr/xr_unbounded_reference_space.idl", "xr/xr_view.idl", @@ -816,6 +816,7 @@ "webusb/usb_device_filter.idl", "webusb/usb_device_request_options.idl", "xr/xr_input_source_event_init.idl", + "xr/xr_reference_space_event_init.idl", "xr/xr_reference_space_options.idl", "xr/xr_render_state_init.idl", "xr/xr_session_creation_options.idl",
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc index b8854d1..1a577db 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
@@ -739,42 +739,49 @@ std::move(saved_event)); } break; case ParamEvent::kSetTarget: { - // Don't want to remove the SetTarget event, so bump the index. But - // we do want to insert a cancelEvent so that we stop this - // automation and hold the value when we get there. - ++cancelled_event_index; + if (cancelled_event->Time() < cancel_time) { + // Don't want to remove the SetTarget event if it started before the + // cancel time, so bump the index. But we do want to insert a + // cancelEvent so that we stop this automation and hold the value when + // we get there. + ++cancelled_event_index; - new_event = ParamEvent::CreateCancelValuesEvent(cancel_time, nullptr); + new_event = ParamEvent::CreateCancelValuesEvent(cancel_time, nullptr); + } } break; case ParamEvent::kSetValueCurve: { - double new_duration = cancel_time - cancelled_event->Time(); + // If the setValueCurve event started strictly before the cancel time, + // there might be something to do.... + if (cancelled_event->Time() < cancel_time) { + if (cancel_time > + cancelled_event->Time() + cancelled_event->Duration()) { + // If the cancellation time is past the end of the curve there's + // nothing to do except remove the following events. + ++cancelled_event_index; + } else { + // Cancellation time is in the middle of the curve. Therefore, + // create a new SetValueCurve event with the appropriate new + // parameters to cancel this event properly. Since it's illegal + // to insert any event within a SetValueCurve event, we can + // compute the new end value now instead of doing when running + // the timeline. + double new_duration = cancel_time - cancelled_event->Time(); + float end_value = ValueCurveAtTime( + cancel_time, cancelled_event->Time(), cancelled_event->Duration(), + cancelled_event->Curve().data(), cancelled_event->Curve().size()); - if (cancel_time > cancelled_event->Time() + cancelled_event->Duration()) { - // If the cancellation time is past the end of the curve, - // there's nothing to do except remove the following events. - ++cancelled_event_index; - } else { - // Cancellation time is in the middle of the curve. Therefore, - // create a new SetValueCurve event with the appropriate new - // parameters to cancel this event properly. Since it's illegal - // to insert any event within a SetValueCurve event, we can - // compute the new end value now instead of doing when running - // the timeline. - float end_value = ValueCurveAtTime( - cancel_time, cancelled_event->Time(), cancelled_event->Duration(), - cancelled_event->Curve().data(), cancelled_event->Curve().size()); + // Replace the existing SetValueCurve with this new one that is + // identical except for the duration. + new_event = ParamEvent::CreateGeneralEvent( + event_type, cancelled_event->Value(), cancelled_event->Time(), + cancelled_event->InitialValue(), cancelled_event->CallTime(), + cancelled_event->TimeConstant(), new_duration, + cancelled_event->Curve(), cancelled_event->CurvePointsPerSecond(), + end_value, nullptr); - // Replace the existing SetValueCurve with this new one that is - // identical except for the duration. - new_event = ParamEvent::CreateGeneralEvent( - event_type, cancelled_event->Value(), cancelled_event->Time(), - cancelled_event->InitialValue(), cancelled_event->CallTime(), - cancelled_event->TimeConstant(), new_duration, - cancelled_event->Curve(), cancelled_event->CurvePointsPerSecond(), - end_value, nullptr); - - new_set_value_event = ParamEvent::CreateSetValueEvent( - end_value, cancelled_event->Time() + new_duration); + new_set_value_event = ParamEvent::CreateSetValueEvent( + end_value, cancelled_event->Time() + new_duration); + } } } break; case ParamEvent::kSetValue:
diff --git a/third_party/blink/renderer/modules/xr/BUILD.gn b/third_party/blink/renderer/modules/xr/BUILD.gn index cc7885f2..3862966 100644 --- a/third_party/blink/renderer/modules/xr/BUILD.gn +++ b/third_party/blink/renderer/modules/xr/BUILD.gn
@@ -36,6 +36,8 @@ "xr_ray.h", "xr_reference_space.cc", "xr_reference_space.h", + "xr_reference_space_event.cc", + "xr_reference_space_event.h", "xr_render_state.cc", "xr_render_state.h", "xr_rigid_transform.cc", @@ -46,8 +48,6 @@ "xr_session_event.h", "xr_space.cc", "xr_space.h", - "xr_stage_bounds.cc", - "xr_stage_bounds.h", "xr_stationary_reference_space.cc", "xr_stationary_reference_space.h", "xr_target_ray_space.cc",
diff --git a/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc b/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc index 32d97ec..1b3bd8e5 100644 --- a/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc +++ b/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc
@@ -5,8 +5,9 @@ #include "third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h" #include "device/vr/public/mojom/vr_service.mojom-blink.h" +#include "third_party/blink/renderer/modules/xr/xr_reference_space_event.h" +#include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" -#include "third_party/blink/renderer/modules/xr/xr_stage_bounds.h" namespace blink { @@ -15,10 +16,12 @@ XRBoundedReferenceSpace::~XRBoundedReferenceSpace() = default; -void XRBoundedReferenceSpace::UpdateBoundsGeometry( - XRStageBounds* bounds_geometry) { - // TODO(https://crbug.com/917411): Support bounds geometry and fire a 'reset' - // event when the bounds change. +void XRBoundedReferenceSpace::setOriginOffset(XRRigidTransform* transform) { + XRReferenceSpace::setOriginOffset(transform); + + // Force a bounds update. + stage_parameters_id_ = 0; + EnsureUpdated(); } // No default pose for bounded reference spaces. @@ -26,7 +29,14 @@ return nullptr; } -void XRBoundedReferenceSpace::UpdateFloorLevelTransform() { +void XRBoundedReferenceSpace::EnsureUpdated() { + // Check first to see if the stage parameters have updated since the last + // call. We only need to update the transform and bounds if it has. + if (stage_parameters_id_ == session()->StageParametersId()) + return; + + stage_parameters_id_ = session()->StageParametersId(); + const device::mojom::blink::VRDisplayInfoPtr& display_info = session()->GetVRDisplayInfo(); @@ -37,13 +47,48 @@ floor_level_transform_ = std::make_unique<TransformationMatrix>( m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15]); + + // In order to ensure that the bounds continue to line up with the user's + // physical environment we need to transform by the inverse of the + // originOffset. + TransformationMatrix bounds_transform = + originOffset()->InverseTransformMatrix(); + + if (display_info->stageParameters->bounds) { + bounds_geometry_.clear(); + + for (const auto& bound : *(display_info->stageParameters->bounds)) { + FloatPoint3D p = + bounds_transform.MapPoint(FloatPoint3D(bound->x, 0.0, bound->z)); + bounds_geometry_.push_back( + DOMPointReadOnly::Create(p.X(), p.Y(), p.Z(), 1.0)); + } + } else { + double hx = display_info->stageParameters->sizeX * 0.5; + double hz = display_info->stageParameters->sizeZ * 0.5; + FloatPoint3D a = bounds_transform.MapPoint(FloatPoint3D(hx, 0.0, -hz)); + FloatPoint3D b = bounds_transform.MapPoint(FloatPoint3D(hx, 0.0, hz)); + FloatPoint3D c = bounds_transform.MapPoint(FloatPoint3D(-hx, 0.0, hz)); + FloatPoint3D d = bounds_transform.MapPoint(FloatPoint3D(-hx, 0.0, -hz)); + + bounds_geometry_.clear(); + bounds_geometry_.push_back( + DOMPointReadOnly::Create(a.X(), a.Y(), a.Z(), 1.0)); + bounds_geometry_.push_back( + DOMPointReadOnly::Create(b.X(), b.Y(), b.Z(), 1.0)); + bounds_geometry_.push_back( + DOMPointReadOnly::Create(c.X(), c.Y(), c.Z(), 1.0)); + bounds_geometry_.push_back( + DOMPointReadOnly::Create(d.X(), d.Y(), d.Z(), 1.0)); + } } else { // If stage parameters aren't available set the transform to null, which // will subsequently cause this reference space to return null poses. floor_level_transform_.reset(); + bounds_geometry_.clear(); } - display_info_id_ = session()->DisplayInfoPtrId(); + DispatchEvent(*XRReferenceSpaceEvent::Create(event_type_names::kReset, this)); } // Transforms a given pose from a "base" reference space used by the XR @@ -53,10 +98,7 @@ std::unique_ptr<TransformationMatrix> XRBoundedReferenceSpace::TransformBasePose( const TransformationMatrix& base_pose) { - // Check first to see if the xrDisplayInfo has updated since the last - // call. If so, update the pose transform. - if (display_info_id_ != session()->DisplayInfoPtrId()) - UpdateFloorLevelTransform(); + EnsureUpdated(); // If the reference space has a transform apply it to the base pose and return // that, otherwise return null. @@ -70,6 +112,11 @@ return nullptr; } +HeapVector<Member<DOMPointReadOnly>> XRBoundedReferenceSpace::boundsGeometry() { + EnsureUpdated(); + return bounds_geometry_; +} + void XRBoundedReferenceSpace::Trace(blink::Visitor* visitor) { visitor->Trace(bounds_geometry_); XRReferenceSpace::Trace(visitor);
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 31cf00bc1..98433cf 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
@@ -11,8 +11,6 @@ namespace blink { -class XRStageBounds; - class XRBoundedReferenceSpace final : public XRReferenceSpace { DEFINE_WRAPPERTYPEINFO(); @@ -20,24 +18,22 @@ XRBoundedReferenceSpace(XRSession*); ~XRBoundedReferenceSpace() override; - void UpdateBoundsGeometry(XRStageBounds*); - std::unique_ptr<TransformationMatrix> DefaultPose() override; std::unique_ptr<TransformationMatrix> TransformBasePose( const TransformationMatrix& base_pose) override; - HeapVector<Member<DOMPointReadOnly>> boundsGeometry() const { - return bounds_geometry_; - } + void setOriginOffset(XRRigidTransform*) override; + + HeapVector<Member<DOMPointReadOnly>> boundsGeometry(); void Trace(blink::Visitor*) override; private: - void UpdateFloorLevelTransform(); + void EnsureUpdated(); HeapVector<Member<DOMPointReadOnly>> bounds_geometry_; std::unique_ptr<TransformationMatrix> floor_level_transform_; - unsigned int display_info_id_ = 0; + unsigned int stage_parameters_id_ = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_ray.cc b/third_party/blink/renderer/modules/xr/xr_ray.cc index e8353bea..0be5ebc 100644 --- a/third_party/blink/renderer/modules/xr/xr_ray.cc +++ b/third_party/blink/renderer/modules/xr/xr_ray.cc
@@ -8,6 +8,8 @@ #include <cmath> #include <utility> +#include "third_party/blink/renderer/core/geometry/dom_point_init.h" +#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" #include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h" #include "third_party/blink/renderer/modules/xr/xr_utils.h" #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" @@ -16,6 +18,7 @@ #include "ui/gfx/geometry/vector3d_f.h" namespace blink { + XRRay::XRRay(std::unique_ptr<TransformationMatrix> matrix) { Set(std::move(matrix)); }
diff --git a/third_party/blink/renderer/modules/xr/xr_ray.h b/third_party/blink/renderer/modules/xr/xr_ray.h index 6abb625e..f30bbfaa 100644 --- a/third_party/blink/renderer/modules/xr/xr_ray.h +++ b/third_party/blink/renderer/modules/xr/xr_ray.h
@@ -7,14 +7,15 @@ #include <memory> -#include "third_party/blink/renderer/core/geometry/dom_point_init.h" -#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/geometry/float_point_3d.h" -#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/member.h" namespace blink { +class DOMPointInit; +class DOMPointReadOnly; class TransformationMatrix; class XRRigidTransform;
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space.cc b/third_party/blink/renderer/modules/xr/xr_reference_space.cc index c5398bcb..e906a66f8 100644 --- a/third_party/blink/renderer/modules/xr/xr_reference_space.cc +++ b/third_party/blink/renderer/modules/xr/xr_reference_space.cc
@@ -7,7 +7,6 @@ #include "device/vr/public/mojom/vr_service.mojom-blink.h" #include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" -#include "third_party/blink/renderer/modules/xr/xr_stage_bounds.h" namespace blink {
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 3d1c507f..e0d18795 100644 --- a/third_party/blink/renderer/modules/xr/xr_reference_space.h +++ b/third_party/blink/renderer/modules/xr/xr_reference_space.h
@@ -31,9 +31,11 @@ std::unique_ptr<TransformationMatrix> GetTransformToMojoSpace() override; XRRigidTransform* originOffset() const { return origin_offset_; } - void setOriginOffset(XRRigidTransform*); + virtual void setOriginOffset(XRRigidTransform*); TransformationMatrix InverseOriginOffsetMatrix() override; + DEFINE_ATTRIBUTE_EVENT_LISTENER(reset, kReset) + void Trace(blink::Visitor*) override; private:
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space_event.cc b/third_party/blink/renderer/modules/xr/xr_reference_space_event.cc new file mode 100644 index 0000000..194959d4 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_reference_space_event.cc
@@ -0,0 +1,41 @@ +// 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 "third_party/blink/renderer/modules/xr/xr_reference_space_event.h" + +#include "third_party/blink/renderer/modules/xr/xr_reference_space.h" +#include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h" + +namespace blink { + +XRReferenceSpaceEvent::XRReferenceSpaceEvent() = default; + +XRReferenceSpaceEvent::XRReferenceSpaceEvent(const AtomicString& type, + XRReferenceSpace* reference_space) + : Event(type, Bubbles::kNo, Cancelable::kYes), + reference_space_(reference_space) {} + +XRReferenceSpaceEvent::XRReferenceSpaceEvent( + const AtomicString& type, + const XRReferenceSpaceEventInit* initializer) + : Event(type, initializer) { + if (initializer->hasReferenceSpace()) + reference_space_ = initializer->referenceSpace(); + if (initializer->hasTransform()) + transform_ = initializer->transform(); +} + +XRReferenceSpaceEvent::~XRReferenceSpaceEvent() = default; + +const AtomicString& XRReferenceSpaceEvent::InterfaceName() const { + return event_interface_names::kXRReferenceSpaceEvent; +} + +void XRReferenceSpaceEvent::Trace(blink::Visitor* visitor) { + visitor->Trace(reference_space_); + visitor->Trace(transform_); + Event::Trace(visitor); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space_event.h b/third_party/blink/renderer/modules/xr/xr_reference_space_event.h new file mode 100644 index 0000000..8a017f9 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_reference_space_event.h
@@ -0,0 +1,53 @@ +// 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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFERENCE_SPACE_EVENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFERENCE_SPACE_EVENT_H_ + +#include "third_party/blink/renderer/modules/event_modules.h" +#include "third_party/blink/renderer/modules/xr/xr_reference_space_event_init.h" + +namespace blink { + +class XRReferenceSpace; +class XRRigidTransform; + +class XRReferenceSpaceEvent final : public Event { + DEFINE_WRAPPERTYPEINFO(); + + public: + static XRReferenceSpaceEvent* Create() { + return MakeGarbageCollected<XRReferenceSpaceEvent>(); + } + static XRReferenceSpaceEvent* Create(const AtomicString& type, + XRReferenceSpace* reference_space) { + return MakeGarbageCollected<XRReferenceSpaceEvent>(type, reference_space); + } + static XRReferenceSpaceEvent* Create( + const AtomicString& type, + const XRReferenceSpaceEventInit* initializer) { + return MakeGarbageCollected<XRReferenceSpaceEvent>(type, initializer); + } + + XRReferenceSpaceEvent(); + XRReferenceSpaceEvent(const AtomicString& type, XRReferenceSpace*); + XRReferenceSpaceEvent(const AtomicString& type, + const XRReferenceSpaceEventInit*); + ~XRReferenceSpaceEvent() override; + + XRReferenceSpace* referenceSpace() const { return reference_space_.Get(); } + XRRigidTransform* transform() const { return transform_.Get(); } + + const AtomicString& InterfaceName() const override; + + void Trace(blink::Visitor*) override; + + private: + Member<XRReferenceSpace> reference_space_; + Member<XRRigidTransform> transform_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_REFERENCE_SPACE_EVENT_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space_event.idl b/third_party/blink/renderer/modules/xr/xr_reference_space_event.idl new file mode 100644 index 0000000..63263126 --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_reference_space_event.idl
@@ -0,0 +1,14 @@ +// 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. + +// https://immersive-web.github.io/webxr/#xrreferencespaceevent-interface +[ + SecureContext, + Exposed=Window, + OriginTrialEnabled=WebXR, + Constructor(DOMString type, XRReferenceSpaceEventInit eventInitDict) +] interface XRReferenceSpaceEvent : Event { + readonly attribute XRReferenceSpace referenceSpace; + readonly attribute XRRigidTransform transform; +};
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space_event_init.idl b/third_party/blink/renderer/modules/xr/xr_reference_space_event_init.idl new file mode 100644 index 0000000..cd6b20d --- /dev/null +++ b/third_party/blink/renderer/modules/xr/xr_reference_space_event_init.idl
@@ -0,0 +1,9 @@ +// 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. + +// https://immersive-web.github.io/webxr/#xrreferencespaceevent-interface +dictionary XRReferenceSpaceEventInit : EventInit { + required XRReferenceSpace referenceSpace; + XRRigidTransform transform; +};
diff --git a/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc b/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc index ee34bad..e70d9f02 100644 --- a/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc +++ b/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
@@ -4,7 +4,12 @@ #include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h" +#include <utility> + +#include "third_party/blink/renderer/core/geometry/dom_point_init.h" +#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" #include "third_party/blink/renderer/modules/xr/xr_utils.h" +#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/xr/xr_rigid_transform.h b/third_party/blink/renderer/modules/xr/xr_rigid_transform.h index 732e006ea..8dc5c2c 100644 --- a/third_party/blink/renderer/modules/xr/xr_rigid_transform.h +++ b/third_party/blink/renderer/modules/xr/xr_rigid_transform.h
@@ -6,17 +6,17 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_RIGID_TRANSFORM_H_ #include <memory> -#include <utility> -#include "third_party/blink/renderer/core/geometry/dom_point_init.h" -#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" -#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" namespace blink { +class DOMPointInit; +class DOMPointReadOnly; +class TransformationMatrix; + // MODULES_EXPORT is required for unit tests using XRRigidTransform (currently // just xr_rigid_transform_test.cc) to build without linker errors. class MODULES_EXPORT XRRigidTransform : public ScriptWrappable {
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc index e96c3a2e..aa4ed96 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -272,12 +272,24 @@ reference_space = MakeGarbageCollected<XRStationaryReferenceSpace>(this, subtype); } else if (options->type() == "bounded") { - // TODO(https://crbug.com/917411): Bounded reference spaces cannot be - // returned unless they have bounds geometry. Until we implement that they - // will be considered unsupported. - return ScriptPromise::RejectWithDOMException( - script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError, - kReferenceSpaceNotSupported)); + bool supports_bounded = false; + if (immersive() && display_info_->stageParameters) { + if (display_info_->stageParameters->bounds) { + supports_bounded = true; + } else if (display_info_->stageParameters->sizeX > 0 && + display_info_->stageParameters->sizeZ > 0) { + supports_bounded = true; + } + } + + if (supports_bounded) { + reference_space = MakeGarbageCollected<XRBoundedReferenceSpace>(this); + } else { + return ScriptPromise::RejectWithDOMException( + script_state, + DOMException::Create(DOMExceptionCode::kNotSupportedError, + kReferenceSpaceNotSupported)); + } } else if (options->type() == "unbounded") { if (immersive() && environment_integration_) { reference_space = MakeGarbageCollected<XRUnboundedReferenceSpace>(this); @@ -930,6 +942,20 @@ void XRSession::SetXRDisplayInfo( device::mojom::blink::VRDisplayInfoPtr display_info) { + // 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 (display_info_) { + if (display_info_->Equals(*display_info)) + return; + + if (display_info_->stageParameters && display_info->stageParameters && + !display_info_->stageParameters->Equals( + *(display_info->stageParameters))) + stage_parameters_id_++; + } + display_info_id_++; display_info_ = std::move(display_info); is_external_ = display_info_->capabilities->hasExternalDisplay;
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h index d8c25720..022b976 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.h +++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -173,6 +173,7 @@ // Incremented every time display_info_ is changed, so that other objects that // depend on it can know when they need to update. unsigned int DisplayInfoPtrId() const { return display_info_id_; } + unsigned int StageParametersId() const { return stage_parameters_id_; } void SetNonImmersiveProjectionMatrix(const WTF::Vector<float>&); void SetXRDisplayInfo(device::mojom::blink::VRDisplayInfoPtr display_info); @@ -228,7 +229,8 @@ bool has_xr_focus_ = true; bool is_external_ = false; - int display_info_id_ = 0; + unsigned int display_info_id_ = 0; + unsigned int stage_parameters_id_ = 0; device::mojom::blink::VRDisplayInfoPtr display_info_; mojo::Binding<device::mojom::blink::XRSessionClient> client_binding_;
diff --git a/third_party/blink/renderer/modules/xr/xr_session_event.h b/third_party/blink/renderer/modules/xr/xr_session_event.h index ecfd00e5..fba43174 100644 --- a/third_party/blink/renderer/modules/xr/xr_session_event.h +++ b/third_party/blink/renderer/modules/xr/xr_session_event.h
@@ -44,4 +44,4 @@ } // namespace blink -#endif // XRDisplayEvent_h +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_SESSION_EVENT_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_space.h b/third_party/blink/renderer/modules/xr/xr_space.h index da2ce0b..772c6c1 100644 --- a/third_party/blink/renderer/modules/xr/xr_space.h +++ b/third_party/blink/renderer/modules/xr/xr_space.h
@@ -47,8 +47,6 @@ XRSession* session() const { return session_; } - DEFINE_ATTRIBUTE_EVENT_LISTENER(reset, kReset) - // EventTarget overrides. ExecutionContext* GetExecutionContext() const override; const AtomicString& InterfaceName() const override;
diff --git a/third_party/blink/renderer/modules/xr/xr_stage_bounds.cc b/third_party/blink/renderer/modules/xr/xr_stage_bounds.cc deleted file mode 100644 index a85149eb..0000000 --- a/third_party/blink/renderer/modules/xr/xr_stage_bounds.cc +++ /dev/null
@@ -1,14 +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 "third_party/blink/renderer/modules/xr/xr_stage_bounds.h" - -namespace blink { - -void XRStageBounds::Trace(blink::Visitor* visitor) { - visitor->Trace(geometry_); - ScriptWrappable::Trace(visitor); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_stage_bounds.h b/third_party/blink/renderer/modules/xr/xr_stage_bounds.h deleted file mode 100644 index 77cf827..0000000 --- a/third_party/blink/renderer/modules/xr/xr_stage_bounds.h +++ /dev/null
@@ -1,31 +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 THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STAGE_BOUNDS_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STAGE_BOUNDS_H_ - -#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" -#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" -#include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/wtf/forward.h" - -namespace blink { - -class XRStageBounds final : public ScriptWrappable { - DEFINE_WRAPPERTYPEINFO(); - - public: - XRStageBounds() = default; - - HeapVector<Member<DOMPointReadOnly>> geometry() const { return geometry_; } - - void Trace(blink::Visitor*) override; - - private: - HeapVector<Member<DOMPointReadOnly>> geometry_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_STAGE_BOUNDS_H_
diff --git a/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl b/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl deleted file mode 100644 index 86c6fd9..0000000 --- a/third_party/blink/renderer/modules/xr/xr_stage_bounds.idl +++ /dev/null
@@ -1,12 +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. - -// https://immersive-web.github.io/webxr/#xrstagebounds-interface -[ - SecureContext, - Exposed=Window, - RuntimeEnabled=WebXR -] interface XRStageBounds { - readonly attribute FrozenArray<DOMPointReadOnly> geometry; -};
diff --git a/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc b/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc index c9ae1a8..8887caa 100644 --- a/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc +++ b/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc
@@ -6,7 +6,6 @@ #include "device/vr/public/mojom/vr_service.mojom-blink.h" #include "third_party/blink/renderer/modules/xr/xr_session.h" -#include "third_party/blink/renderer/modules/xr/xr_stage_bounds.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/xr/xr_utils.cc b/third_party/blink/renderer/modules/xr/xr_utils.cc index 8fbee2e5..923b229 100644 --- a/third_party/blink/renderer/modules/xr/xr_utils.cc +++ b/third_party/blink/renderer/modules/xr/xr_utils.cc
@@ -6,6 +6,7 @@ #include <cmath> +#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" namespace blink {
diff --git a/third_party/blink/renderer/modules/xr/xr_utils.h b/third_party/blink/renderer/modules/xr/xr_utils.h index 9263867d..a380cf0 100644 --- a/third_party/blink/renderer/modules/xr/xr_utils.h +++ b/third_party/blink/renderer/modules/xr/xr_utils.h
@@ -7,13 +7,13 @@ #include <memory> -#include "third_party/blink/renderer/core/geometry/dom_point_init.h" -#include "third_party/blink/renderer/core/geometry/dom_point_read_only.h" #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" -#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" namespace blink { +class DOMPointReadOnly; +class TransformationMatrix; + DOMFloat32Array* transformationMatrixToDOMFloat32Array( const TransformationMatrix&);
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index be5aa7c..93cb193e2 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1205,8 +1205,6 @@ "mac/graphics_context_canvas.mm", "mac/local_current_graphics_context.h", "mac/local_current_graphics_context.mm", - "mac/version_util_mac.h", - "mac/version_util_mac.mm", "mac/web_core_ns_cell_extras.h", "mac/web_core_ns_cell_extras.mm", "mediastream/media_stream_center.cc", @@ -1780,7 +1778,6 @@ "loader/allowed_by_nosniff_test.cc", "loader/cors/cors_test.cc", "mac/graphics_context_canvas_test.mm", - "mac/version_util_mac_test.mm", "mhtml/mhtml_parser_test.cc", "mojo/big_string_mojom_traits_test.cc", "mojo/geometry_struct_traits_test.cc",
diff --git a/third_party/blink/renderer/platform/fonts/DEPS b/third_party/blink/renderer/platform/fonts/DEPS index dbb11b1f..60b1d13 100644 --- a/third_party/blink/renderer/platform/fonts/DEPS +++ b/third_party/blink/renderer/platform/fonts/DEPS
@@ -6,9 +6,7 @@ "+third_party/blink/renderer/platform/fonts", # Dependencies. - "+base/mac/foundation_util.h", - "+base/mac/scoped_cftyperef.h", - "+base/mac/scoped_nsobject.h", + "+base/mac", "+cc", "+third_party/blink/renderer/platform/font_family_names.h", "+third_party/blink/renderer/platform/geometry", @@ -16,7 +14,6 @@ "+third_party/blink/renderer/platform/histogram.h", "+third_party/blink/renderer/platform/instrumentation", "+third_party/blink/renderer/platform/language.h", - "+third_party/blink/renderer/platform/mac/version_util_mac.h", "+third_party/blink/renderer/platform/platform_export.h", "+third_party/blink/renderer/platform/resolution_units.h", "+third_party/blink/renderer/platform/runtime_enabled_features.h",
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm index 06708fc..0b9c2ef 100644 --- a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm +++ b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm
@@ -37,7 +37,6 @@ #include "base/mac/scoped_nsobject.h" #include "base/stl_util.h" #include "third_party/blink/renderer/platform/fonts/font_cache.h" -#include "third_party/blink/renderer/platform/mac/version_util_mac.h" #import "third_party/blink/renderer/platform/wtf/hash_set.h" #import "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm index c1d9ad6..0636b18 100644 --- a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm +++ b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm
@@ -6,13 +6,9 @@ #include <AppKit/AppKit.h> +#include "base/mac/mac_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/font_family_names.h" -#include "third_party/blink/renderer/platform/mac/version_util_mac.h" - -@interface NSString (YosemiteAdditions) -- (BOOL)containsString:(NSString*)string; -@end namespace blink { @@ -24,7 +20,7 @@ } TEST(FontMatcherMacTest, YosemiteFontWeights) { - if (!IsOS10_10()) + if (!base::mac::IsOS10_10()) return; TestSystemFontContainsString(FontSelectionValue(100), @"-UltraLight");
diff --git a/third_party/blink/renderer/platform/mac/version_util_mac.h b/third_party/blink/renderer/platform/mac/version_util_mac.h deleted file mode 100644 index 063cf5bd..0000000 --- a/third_party/blink/renderer/platform/mac/version_util_mac.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_MAC_VERSION_UTIL_MAC_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_MAC_VERSION_UTIL_MAC_H_ - -#include "third_party/blink/renderer/platform/platform_export.h" - -#include <AvailabilityMacros.h> - -namespace blink { - -namespace internal { - -PLATFORM_EXPORT int MacOSXMinorVersion(); - -template <int V, int ID> -constexpr bool IsOS() { - return MAC_OS_X_VERSION_MIN_REQUIRED <= ID && MacOSXMinorVersion() == V; -} - -} // namespace internal - -const auto IsOS10_10 = internal::IsOS<10, 101000>; -const auto IsOS10_11 = internal::IsOS<11, 101100>; -const auto IsOS10_12 = internal::IsOS<12, 101200>; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_MAC_VERSION_UTIL_MAC_H_
diff --git a/third_party/blink/renderer/platform/mac/version_util_mac.mm b/third_party/blink/renderer/platform/mac/version_util_mac.mm deleted file mode 100644 index 2750c6b..0000000 --- a/third_party/blink/renderer/platform/mac/version_util_mac.mm +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "third_party/blink/renderer/platform/mac/version_util_mac.h" - -#include <sstream> -#include <string> -#include <sys/utsname.h> - -namespace { - -// Returns the running system's Darwin major version. Don't call this, it's -// an implementation detail and its result is meant to be cached by -// MacOSXMinorVersion. -int DarwinMajorVersionInternal() { - // The implementation of this method was copied from Chromium, with minor - // modifications to avoid the use of methods in base/. For further details, - // see - // https://code.google.com/p/chromium/codesearch#chromium/src/base/mac/mac_util.mm - struct utsname unameInfo; - if (uname(&unameInfo) != 0) - return 0; - - if (strcmp(unameInfo.sysname, "Darwin") != 0) - return 0; - - std::string releaseString(unameInfo.release); - size_t pos = releaseString.find_first_of('.'); - if (pos == std::string::npos) - return 0; - - std::istringstream convert(releaseString.substr(0, pos)); - int majorVersion; - if (!(convert >> majorVersion)) - return 0; - - return majorVersion; -} - -// Returns the running system's Mac OS X minor version. This is the |y| value -// in 10.y or 10.y.z. Don't call this, it's an implementation detail and the -// result is meant to be cached by MacOSXMinorVersion. -int MacOSXMinorVersionInternal() { - int darwinMajorVersion = DarwinMajorVersionInternal(); - return darwinMajorVersion - 4; -} - -} // namespace - -// Returns the running system's Mac OS X minor version. This is the |y| value -// in 10.y or 10.y.z. -int blink::internal::MacOSXMinorVersion() { - static int minor_version = MacOSXMinorVersionInternal(); - return minor_version; -}
diff --git a/third_party/blink/renderer/platform/mac/version_util_mac_test.mm b/third_party/blink/renderer/platform/mac/version_util_mac_test.mm deleted file mode 100644 index 1fd3d7eb..0000000 --- a/third_party/blink/renderer/platform/mac/version_util_mac_test.mm +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "third_party/blink/renderer/platform/mac/version_util_mac.h" - -#include <AppKit/AppKit.h> -#include <gtest/gtest.h> - -#ifndef NSAppKitVersionNumber10_10 -#define NSAppKitVersionNumber10_10 1343 -#endif - -// This number was determined by writing a tiny Cocoa App on 10.10.4. -#define NSAppKitVersionNumber10_10Max 1348 - -// This number was measured on OSX 10.11 Beta 15A234d. The 10.11 -// AppKit.framework does not provide an NSAppKitVersionNumber preprocessor -// definition for OSX 10.11. -#define NSAppKitVersionNumber10_11Max 1389 - -// AppKit version is loosely correlated to OSX version. It's still useful as a -// sanity check in unit tests, though we don't want to rely on it in production -// code. -TEST(VersionUtilMac, AppKitVersions) { - if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_10Max && - floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_10) { - EXPECT_TRUE(blink::IsOS10_10()); - EXPECT_FALSE(blink::IsOS10_11()); - return; - } - - if (floor(NSAppKitVersionNumber) == NSAppKitVersionNumber10_11Max) { - EXPECT_FALSE(blink::IsOS10_10()); - EXPECT_TRUE(blink::IsOS10_11()); - return; - } -}
diff --git a/third_party/blink/renderer/platform/text/DEPS b/third_party/blink/renderer/platform/text/DEPS index a106aee..e8f9276 100644 --- a/third_party/blink/renderer/platform/text/DEPS +++ b/third_party/blink/renderer/platform/text/DEPS
@@ -6,12 +6,10 @@ "+third_party/blink/renderer/platform/text", # Dependencies. - "+base/mac/scoped_nsobject.h", - "+base/mac/scoped_typeref.h", + "+base/mac", "+third_party/blink/renderer/platform/date_components.h", "+third_party/blink/renderer/platform/heap", "+third_party/blink/renderer/platform/language.h", - "+third_party/blink/renderer/platform/mac/version_util_mac.h", "+third_party/blink/renderer/platform/platform_export.h", "+third_party/blink/renderer/platform/runtime_enabled_features.h", "+third_party/blink/renderer/platform/testing",
diff --git a/third_party/blink/renderer/platform/text/locale_mac_test.mm b/third_party/blink/renderer/platform/text/locale_mac_test.mm index b9ab231..4d118e8 100644 --- a/third_party/blink/renderer/platform/text/locale_mac_test.mm +++ b/third_party/blink/renderer/platform/text/locale_mac_test.mm
@@ -26,10 +26,10 @@ #include "third_party/blink/renderer/platform/text/locale_mac.h" #include <memory> +#include "base/mac/mac_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/date_components.h" -#include "third_party/blink/renderer/platform/mac/version_util_mac.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" #include "third_party/blink/renderer/platform/wtf/date_math.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" @@ -228,7 +228,7 @@ // (which is a non-breaking space) instead of \x20 for those spaces. The // 10.13+ behavior is probably more correct, but there does not appear to be a // way to configure NSDateFormatter to behave that way on < 10.13. - bool expect_ar_nbsp = !IsOS10_10() && !IsOS10_11() && !IsOS10_12(); + const bool expect_ar_nbsp = base::mac::IsAtLeastOS10_13(); EXPECT_STREQ("1:23 PM", FormatTime("en_US", 13, 23, 00, 000, true).Utf8().data());
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index bde3370..12b15ec 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -363,6 +363,11 @@ # Permit using crash keys inside Blink without jumping through # hoops. 'crash_reporter::.*CrashKey.*', + + # Useful for platform-specific code. + 'base::mac::(CFToNSCast|NSToCFCast)', + 'base::mac::Is(AtMost|AtLeast)?OS.+', + 'base::(scoped_nsobject|ScopedCFTypeRef)', ], 'disallowed': [ '.+', @@ -428,10 +433,6 @@ ], }, { - 'paths': ['third_party/blink/renderer/core/editing/web_substring_util.mm'], - 'allowed': ['base::mac::CFToNSCast'], - }, - { 'paths': ['third_party/blink/renderer/core/fetch/data_consumer_handle_test_util.cc'], 'allowed': [ # The existing code already contains gin::IsolateHolder.
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 13ab7a7..be3a489 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -548,7 +548,6 @@ crbug.com/377847 external/wpt/css/css-tables/subpixel-table-cell-width-002.html [ Failure ] crbug.com/377847 external/wpt/css/css-tables/subpixel-table-width-001.html [ Failure ] crbug.com/764031 external/wpt/css/css-tables/toggle-row-display-property-001.html [ Failure ] -crbug.com/613753 external/wpt/css/css-tables/border-spacing-included-in-sizes-001.tentative.html [ Failure ] # [css-contain] @@ -3078,6 +3077,7 @@ crbug.com/952266 virtual/omt-worker-fetch/external/wpt/workers/modules/dedicated-worker-options-credentials.html [ Timeout ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-wrap.html [ Failure ] crbug.com/626703 [ Mac10.12 ] external/wpt/media-source/mediasource-config-change-webm-av-framesize.html [ Timeout ] crbug.com/626703 [ Mac10.13 ] external/wpt/media-source/mediasource-config-change-webm-av-framesize.html [ Timeout ] crbug.com/626703 [ Retina ] external/wpt/media-source/mediasource-config-change-webm-av-framesize.html [ Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json index 7fdcdd28..3d2dd9c 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -30829,6 +30829,30 @@ {} ] ], + "css/css-animations/animation-opacity-pause-and-set-time.html": [ + [ + "css/css-animations/animation-opacity-pause-and-set-time.html", + [ + [ + "/css/css-animations/animation-opacity-pause-and-set-time-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-animations/animation-transform-pause-and-set-time.html": [ + [ + "css/css-animations/animation-transform-pause-and-set-time.html", + [ + [ + "/css/css-animations/animation-transform-pause-and-set-time-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-backgrounds/background-334.html": [ [ "css/css-backgrounds/background-334.html", @@ -128815,6 +128839,16 @@ {} ] ], + "css/css-animations/animation-opacity-pause-and-set-time-ref.html": [ + [ + {} + ] + ], + "css/css-animations/animation-transform-pause-and-set-time-ref.html": [ + [ + {} + ] + ], "css/css-animations/animationevent-interface.js": [ [ {} @@ -145490,6 +145524,11 @@ {} ] ], + "css/css-tables/border-spacing-included-in-sizes-001-expected.txt": [ + [ + {} + ] + ], "css/css-tables/bounding-box-computation-1-expected.txt": [ [ {} @@ -232557,9 +232596,9 @@ {} ] ], - "css/css-tables/border-spacing-included-in-sizes-001.tentative.html": [ + "css/css-tables/border-spacing-included-in-sizes-001.html": [ [ - "css/css-tables/border-spacing-included-in-sizes-001.tentative.html", + "css/css-tables/border-spacing-included-in-sizes-001.html", {} ] ], @@ -363224,6 +363263,14 @@ "b1d2258f4d79d33e8eedf1d8e5f7c7661c44b1f0", "manual" ], + "css/css-animations/animation-opacity-pause-and-set-time-ref.html": [ + "ab9f614ed8e7e846b9c5f3c5d66a0827db4d6637", + "support" + ], + "css/css-animations/animation-opacity-pause-and-set-time.html": [ + "c63c2f3b9fe3fd0b2e4a727398f1843febf339eb", + "reftest" + ], "css/css-animations/animation-play-state-001-manual.html": [ "779f2fe3102c0a8618b9ef9e078ad8bdc061eb16", "manual" @@ -363300,6 +363347,14 @@ "24ffa39e93b3c54e9343af187ce59a630ec224dd", "manual" ], + "css/css-animations/animation-transform-pause-and-set-time-ref.html": [ + "3cadfd851841deca1b3c9ec5030e34d7e4783ec0", + "support" + ], + "css/css-animations/animation-transform-pause-and-set-time.html": [ + "e8a9bd9706bde58182bcbdd4c10839f320d90708", + "reftest" + ], "css/css-animations/animationevent-interface.html": [ "5b1bc4265f0f06b9b564d66ecc76fd6a11b6fef2", "testharness" @@ -392080,8 +392135,12 @@ "7248befef57932b2d849630637051e02b480a361", "reftest" ], - "css/css-tables/border-spacing-included-in-sizes-001.tentative.html": [ - "b65e29ed27cc72b2662e919d198790cc84a6bc5e", + "css/css-tables/border-spacing-included-in-sizes-001-expected.txt": [ + "5e292f5722c603651d8b973b9ff9294da6f990cc", + "support" + ], + "css/css-tables/border-spacing-included-in-sizes-001.html": [ + "3f0802305fed5be27d92dc2d65dc273fc852ab85", "testharness" ], "css/css-tables/bounding-box-computation-1-expected.txt": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/border-spacing-included-in-sizes-001-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-tables/border-spacing-included-in-sizes-001-expected.txt new file mode 100644 index 0000000..5e292f5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/border-spacing-included-in-sizes-001-expected.txt
@@ -0,0 +1,38 @@ +This is a testharness.js-based test. +FAIL tbody 1 assert_equals: +<tbody class="outline" data-expected-height="100"> + <tr> + <td></td> + <td></td> + </tr> + </tbody> +height expected 100 but got 120 +FAIL tbody 2 assert_equals: +<tbody class="outline" data-expected-height="150"> + <tr></tr> + <tr></tr> + <tr></tr> + <tr> + <td></td> + <td></td> + </tr> + <tr></tr> + <tr></tr> + </tbody> +height expected 150 but got 160 +FAIL tbody 3 assert_equals: +<tbody class="outline" data-expected-height="100"> + <tr> + <td></td> + <td></td> + </tr> + </tbody> +height expected 100 but got 110 +FAIL tfoot tr 4 assert_equals: +<tr style="outline: 2px dashed black" data-expected-width="210" data-expected-height="100"> + <td></td> + <td></td> + </tr> +width expected 210 but got 230 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/border-spacing-included-in-sizes-001.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-tables/border-spacing-included-in-sizes-001.html similarity index 90% rename from third_party/blink/web_tests/external/wpt/css/css-tables/border-spacing-included-in-sizes-001.tentative.html rename to third_party/blink/web_tests/external/wpt/css/css-tables/border-spacing-included-in-sizes-001.html index b65e29e..3f08023 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-tables/border-spacing-included-in-sizes-001.tentative.html +++ b/third_party/blink/web_tests/external/wpt/css/css-tables/border-spacing-included-in-sizes-001.html
@@ -4,6 +4,8 @@ <script src='/resources/check-layout-th.js'></script> <link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org"> <link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetheight"> +<link rel="help" href="https://www.w3.org/TR/css-tables-3/#bounding-box-assignment"> +<link rel="bookmark" href="https://crbug.com/613753" /> <meta name="flags" content="" /> <meta name="assert" content="border-spacing occurring outside rows and sections is not included in their height and width" />
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-suspend.https.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-suspend.https.html index d5bcbfe..89d361d 100644 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-suspend.https.html +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworklet-suspend.https.html
@@ -14,22 +14,24 @@ const context = new AudioContext(); const filePath = 'processors/dummy-processor.js'; + context.suspend(); + // Suspends the context right away and then activate worklet. The current // time must not advance since the context is suspended. audit.define( {label: 'load-worklet-and-suspend'}, async (task, should) => { - context.suspend(); - const suspendTime = context.currentTime; await context.audioWorklet.addModule(filePath); + const suspendTime = context.currentTime; const dummy = new AudioWorkletNode(context, 'dummy'); dummy.connect(context.destination); task.timeout(() => { - should(context.currentTime, 'context.currentTime') - .beEqualTo(suspendTime); + should(context.currentTime === suspendTime, + 'context.currentTime did not change after worklet started') + .beTrue(); should(context.state, 'context.state').beEqualTo('suspended'); task.done(); - }, 1000); + }, 500); }); audit.run();
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html index 69dc85a..d20786e 100644 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-lowpass.html
@@ -34,7 +34,7 @@ createTestAndRun(context, 'lowpass', { should: should, - threshold: 4.6943e-8, + threshold: 9.7869e-8, filterParameters: filterParameters }).then(task.done.bind(task)); });
diff --git a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt index 20cbc03..2a2b3c7 100644 --- a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 218 tests; 205 PASS, 13 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 218 tests; 213 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS Partial interface Navigator: original interface defined PASS Partial dictionary WebGLContextAttributes: original dictionary defined @@ -207,14 +207,14 @@ PASS XRInputSourceEvent interface: attribute frame PASS XRInputSourceEvent interface: attribute inputSource PASS XRInputSourceEvent interface: attribute buttonIndex -FAIL XRReferenceSpaceEvent interface: existence and properties of interface object assert_own_property: self does not have own property "XRReferenceSpaceEvent" expected property "XRReferenceSpaceEvent" missing -FAIL XRReferenceSpaceEvent interface object length assert_own_property: self does not have own property "XRReferenceSpaceEvent" expected property "XRReferenceSpaceEvent" missing -FAIL XRReferenceSpaceEvent interface object name assert_own_property: self does not have own property "XRReferenceSpaceEvent" expected property "XRReferenceSpaceEvent" missing -FAIL XRReferenceSpaceEvent interface: existence and properties of interface prototype object assert_own_property: self does not have own property "XRReferenceSpaceEvent" expected property "XRReferenceSpaceEvent" missing -FAIL XRReferenceSpaceEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "XRReferenceSpaceEvent" expected property "XRReferenceSpaceEvent" missing -FAIL XRReferenceSpaceEvent interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "XRReferenceSpaceEvent" expected property "XRReferenceSpaceEvent" missing -FAIL XRReferenceSpaceEvent interface: attribute referenceSpace assert_own_property: self does not have own property "XRReferenceSpaceEvent" expected property "XRReferenceSpaceEvent" missing -FAIL XRReferenceSpaceEvent interface: attribute transform assert_own_property: self does not have own property "XRReferenceSpaceEvent" expected property "XRReferenceSpaceEvent" missing +PASS XRReferenceSpaceEvent interface: existence and properties of interface object +PASS XRReferenceSpaceEvent interface object length +PASS XRReferenceSpaceEvent interface object name +PASS XRReferenceSpaceEvent interface: existence and properties of interface prototype object +PASS XRReferenceSpaceEvent interface: existence and properties of interface prototype object's "constructor" property +PASS XRReferenceSpaceEvent interface: existence and properties of interface prototype object's @@unscopables property +PASS XRReferenceSpaceEvent interface: attribute referenceSpace +PASS XRReferenceSpaceEvent interface: attribute transform PASS WebGLRenderingContext interface: operation makeXRCompatible() PASS Navigator interface: attribute xr PASS Navigator interface: navigator must inherit property "xr" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_test_constants.js b/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_test_constants.js index aab0417a..c38c012b 100644 --- a/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_test_constants.js +++ b/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_test_constants.js
@@ -30,3 +30,12 @@ const VALID_STAGE_TRANSFORM = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1.0, 1.65, -1.0, 1]; + +const VALID_BOUNDS = [ + { x: 3.0, y: 0, z: -2.0 }, + { x: 3.5, y: 0, z: 0.0 }, + { x: 3.0, y: 0, z: 2.0 }, + { x: -3.0, y: 0, z: 2.0 }, + { x: -3.5, y: 0, z: 0.0 }, + { x: -3.0, y: 0, z: -2.0 } +];
diff --git a/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile.js b/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile.js index a2afcec..6130fa4 100644 --- a/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile.js +++ b/third_party/blink/web_tests/http/tests/devtools/profiler/live-line-level-heap-profile.js
@@ -6,7 +6,7 @@ TestRunner.addResult(`Tests that the live line-level heap profile is shown in the text editor.\n`); Common.settingForTest('memoryLiveHeapProfile').set(true); await self.runtime.loadModulePromise('perf_ui'); - await PerfUI.LiveHeapProfile.hasStartedForTest(); + await Main.Main._instanceForTest.lateInitDonePromiseForTest(); await TestRunner.loadModule('sources_test_runner'); await TestRunner.showPanel('sources');
diff --git a/third_party/blink/web_tests/webaudio/AudioParam/audioparam-cancel-and-hold.html b/third_party/blink/web_tests/webaudio/AudioParam/audioparam-cancel-and-hold.html index f398520..8147dcb 100644 --- a/third_party/blink/web_tests/webaudio/AudioParam/audioparam-cancel-and-hold.html +++ b/third_party/blink/web_tests/webaudio/AudioParam/audioparam-cancel-and-hold.html
@@ -354,6 +354,103 @@ .then(task.done.bind(task)); }); + audit.define('cancel future setTarget', (task, should) => { + const context = + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate); + const src = new ConstantSourceNode(context); + src.connect(context.destination); + + src.offset.setValueAtTime(0.5, 0); + src.offset.setTargetAtTime(0, 0.75 * renderDuration, 0.1); + // Now cancel the effect of the setTarget. + src.offset.cancelAndHoldAtTime(0.5 * renderDuration); + + src.start(); + context.startRendering() + .then(buffer => { + let actual = buffer.getChannelData(0); + // Because the setTarget was cancelled, the output should be a + // constant. + should(actual, 'After cancelling future setTarget event, output') + .beConstantValueOf(0.5); + }) + .then(task.done.bind(task)); + }); + + audit.define('cancel setTarget now', (task, should) => { + const context = + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate); + const src = new ConstantSourceNode(context); + src.connect(context.destination); + + src.offset.setValueAtTime(0.5, 0); + src.offset.setTargetAtTime(0, 0.5 * renderDuration, 0.1); + // Now cancel the effect of the setTarget. + src.offset.cancelAndHoldAtTime(0.5 * renderDuration); + + src.start(); + context.startRendering() + .then(buffer => { + let actual = buffer.getChannelData(0); + // Because the setTarget was cancelled, the output should be a + // constant. + should( + actual, + 'After cancelling setTarget event starting now, output') + .beConstantValueOf(0.5); + }) + .then(task.done.bind(task)); + }); + + audit.define('cancel future setValueCurve', (task, should) => { + const context = + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate); + const src = new ConstantSourceNode(context); + src.connect(context.destination); + + src.offset.setValueAtTime(0.5, 0); + src.offset.setValueCurveAtTime([-1, 1], 0.75 * renderDuration, 0.1); + // Now cancel the effect of the setTarget. + src.offset.cancelAndHoldAtTime(0.5 * renderDuration); + + src.start(); + context.startRendering() + .then(buffer => { + let actual = buffer.getChannelData(0); + // Because the setTarget was cancelled, the output should be a + // constant. + should( + actual, 'After cancelling future setValueCurve event, output') + .beConstantValueOf(0.5); + }) + .then(task.done.bind(task)); + }); + + audit.define('cancel setValueCurve now', (task, should) => { + const context = + new OfflineAudioContext(1, renderDuration * sampleRate, sampleRate); + const src = new ConstantSourceNode(context); + src.connect(context.destination); + + src.offset.setValueAtTime(0.5, 0); + src.offset.setValueCurveAtTime([-1, 1], 0.5 * renderDuration, 0.1); + // Now cancel the effect of the setTarget. + src.offset.cancelAndHoldAtTime(0.5 * renderDuration); + + src.start(); + context.startRendering() + .then(buffer => { + let actual = buffer.getChannelData(0); + // Because the setTarget was cancelled, the output should be a + // constant. + should( + actual, + 'After cancelling current setValueCurve event starting now, output') + .beConstantValueOf(0.5); + }) + .then(task.done.bind(task)); + }); + audit.run(); // Common function for doing a linearRamp test. This just does a linear
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index cc551426..ea8c4ca 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -10536,6 +10536,11 @@ method constructor setter onreset setter originOffset +interface XRReferenceSpaceEvent : Event + attribute @@toStringTag + getter referenceSpace + getter transform + method constructor interface XRRenderState attribute @@toStringTag getter baseLayer @@ -10579,10 +10584,6 @@ interface XRSpace : EventTarget attribute @@toStringTag method constructor -interface XRStageBounds - attribute @@toStringTag - getter geometry - method constructor interface XRStationaryReferenceSpace : XRReferenceSpace attribute @@toStringTag getter subtype
diff --git a/third_party/blink/web_tests/xr/resources/xr-internal-device-mocking.js b/third_party/blink/web_tests/xr/resources/xr-internal-device-mocking.js index 19bf18c..77f8213 100644 --- a/third_party/blink/web_tests/xr/resources/xr-internal-device-mocking.js +++ b/third_party/blink/web_tests/xr/resources/xr-internal-device-mocking.js
@@ -4,6 +4,13 @@ * for interal tests. The main mocked objects are found in * ../external/wpt/resources/chromium/webxr-test.js. */ +const default_stage_parameters = { + standingTransform: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1.65, 0, 1], + sizeX: 1.5, + sizeZ: 1.5, + bounds: null +}; + MockRuntime.prototype.base_getFrameData = MockRuntime.prototype.getFrameData; MockRuntime.prototype.getFrameData = function() { @@ -67,14 +74,10 @@ MockRuntime.prototype.setStageTransform = function(value) { if (value) { if (!this.displayInfo_.stageParameters) { - this.displayInfo_.stageParameters = { - standingTransform: value, - sizeX: 1.5, - sizeZ: 1.5, - }; - } else { - this.displayInfo_.stageParameters.standingTransform = value; + this.displayInfo_.stageParameters = default_stage_parameters; } + + this.displayInfo_.stageParameters.standingTransform = value; } else if (this.displayInfo_.stageParameters) { this.displayInfo_.stageParameters = null; } @@ -82,6 +85,27 @@ this.sessionClient_.onChanged(this.displayInfo_); }; +MockRuntime.prototype.setStageSize = function(x, z) { + if (!this.displayInfo_.stageParameters) { + this.displayInfo_.stageParameters = default_stage_parameters; + } + + this.displayInfo_.stageParameters.sizeX = x; + this.displayInfo_.stageParameters.sizeZ = z; + + this.sessionClient_.onChanged(this.displayInfo_); +}; + +MockRuntime.prototype.setStageBounds = function(value) { + if (!this.displayInfo_.stageParameters) { + this.displayInfo_.stageParameters = default_stage_parameters; + } + + this.displayInfo_.stageParameters.bounds = value; + + this.sessionClient_.onChanged(this.displayInfo_); +}; + MockRuntime.prototype.getSubmitFrameCount = function() { return this.presentation_provider_.submit_frame_count_; };
diff --git a/third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html b/third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html new file mode 100644 index 0000000..a1e15ba6 --- /dev/null +++ b/third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html
@@ -0,0 +1,100 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> +<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> +<script src="../external/wpt/resources/chromium/webxr-test.js"></script> +<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> +<script src="../xr/resources/xr-internal-device-mocking.js"></script> +<script src="../xr/resources/xr-test-utils.js"></script> +<canvas id="webgl-canvas"></canvas> + +<script> +let testName = + "'XRBoundedReferenceSpace updates properly when the changes are applied"; + +let fakeDeviceInitParams = { supportsImmersive:true }; + +let requestSessionOptions = [ + { mode: 'immersive-vr' }, +]; + +let testFunction = function(session, t, fakeDeviceController) { + // Session must have a baseLayer or else frame requests will be ignored. + session.updateRenderState({ + baseLayer: new XRWebGLLayer(session, gl), + outputContext: getOutputContext() + }); + + fakeDeviceController.setStageTransform(VALID_STAGE_TRANSFORM); + fakeDeviceController.setStageSize(2.0, 3.0); + fakeDeviceController.setXRPresentationFrameData(ORIGIN_POSE, [{ + eye:"left", + projectionMatrix: VALID_PROJECTION_MATRIX, + viewMatrix: VALID_VIEW_MATRIX + }, { + eye:"right", + projectionMatrix: VALID_PROJECTION_MATRIX, + viewMatrix: VALID_VIEW_MATRIX + }]); + + return new Promise((resolve, reject) => { + session.requestAnimationFrame(() => { + session.requestReferenceSpace({ type: "bounded" }) + .then((referenceSpace) => { + function onFirstFrame(time, xrFrame) { + t.step(() => { + // Ensure that the correct transform is being applied. + let pose = xrFrame.getViewerPose(referenceSpace); + assert_not_equals(pose, null); + + let poseMatrix = pose.transform.matrix; + assert_matrices_approx_equal(poseMatrix, VALID_STAGE_TRANSFORM); + + // If an explicit array of bounds points was not provided then the + // bounds geometry should represent the four corners of the rectangle + // defined by the stage size. + assert_equals(referenceSpace.boundsGeometry.length, 4); + for (point of referenceSpace.boundsGeometry) { + // Ensure corners are half the width & depth away from the origin. + assert_equals(Math.abs(point.x), 1.0); + assert_equals(point.y, 0.0); + assert_equals(Math.abs(point.z), 1.5); + assert_equals(point.w, 1.0); + } + }); + + // Now set the bounds explicitly and check again on the next frame. + fakeDeviceController.setStageBounds(VALID_BOUNDS); + session.requestAnimationFrame(onFrame); + } + + function onFrame(time, xrFrame) { + t.step(() => { + // After setting the bounds explicitly, make sure that's reflected + // in the boundsGeometry. + assert_equals(referenceSpace.boundsGeometry.length, VALID_BOUNDS.length); + for (i = 0; i < VALID_BOUNDS.length; ++i) { + let valid_point = VALID_BOUNDS[i]; + let bounds_point = referenceSpace.boundsGeometry[i]; + assert_equals(valid_point.x, bounds_point.x); + assert_equals(point.y, 0.0); + assert_equals(valid_point.z, bounds_point.z); + assert_equals(point.w, 1.0); + } + }); + + // Finished. + resolve(); + } + + session.requestAnimationFrame(onFirstFrame); + }); + }); + }); +}; + +xr_session_promise_test( + testFunction, fakeDeviceInitParams, requestSessionOptions, testName); + +</script>
diff --git a/third_party/inspector_protocol/README.chromium b/third_party/inspector_protocol/README.chromium index 3aa6bb47..831ec945 100644 --- a/third_party/inspector_protocol/README.chromium +++ b/third_party/inspector_protocol/README.chromium
@@ -2,7 +2,7 @@ Short Name: inspector_protocol URL: https://chromium.googlesource.com/deps/inspector_protocol/ Version: 0 -Revision: a8dc93daa67c3bfad9c56aa9641ab2f3bc6d3fc0 +Revision: 0f1e67db47db6e547ca67324dc1d2ca850a80d49 License: BSD License File: LICENSE Security Critical: no
diff --git a/third_party/inspector_protocol/encoding/encoding.cc b/third_party/inspector_protocol/encoding/encoding.cc index ceda4437..352687d 100644 --- a/third_party/inspector_protocol/encoding/encoding.cc +++ b/third_party/inspector_protocol/encoding/encoding.cc
@@ -151,7 +151,7 @@ // Writes the start of a token with |type|. The |value| may indicate the size, // or it may be the payload if the value is an unsigned integer. -template <class C> +template <typename C> void WriteTokenStartTmpl(MajorType type, uint64_t value, C* encoded) { if (value < 24) { // Values 0-23 are encoded directly into the additional info of the @@ -233,7 +233,7 @@ return kStopByte; } -template <class C> +template <typename C> void EncodeInt32Tmpl(int32_t value, C* out) { if (value >= 0) { internals::WriteTokenStart(MajorType::UNSIGNED, value, out); @@ -249,7 +249,7 @@ EncodeInt32Tmpl(value, out); } -template <class C> +template <typename C> void EncodeString16Tmpl(span<uint16_t> in, C* out) { uint64_t byte_length = static_cast<uint64_t>(in.size_bytes()); internals::WriteTokenStart(MajorType::BYTE_STRING, byte_length, out); @@ -274,7 +274,7 @@ EncodeString16Tmpl(in, out); } -template <class C> +template <typename C> void EncodeString8Tmpl(span<uint8_t> in, C* out) { internals::WriteTokenStart(MajorType::STRING, static_cast<uint64_t>(in.size_bytes()), out); @@ -287,7 +287,7 @@ EncodeString8Tmpl(in, out); } -template <class C> +template <typename C> void EncodeFromLatin1Tmpl(span<uint8_t> latin1, C* out) { for (std::ptrdiff_t ii = 0; ii < latin1.size(); ++ii) { if (latin1[ii] <= 127) @@ -303,7 +303,7 @@ utf8.push_back((latin1[ii] | 0x80) & 0xbf); } } - EncodeString8(SpanFromVector(utf8), out); + EncodeString8(SpanFrom(utf8), out); return; } EncodeString8(latin1, out); @@ -315,7 +315,7 @@ EncodeFromLatin1Tmpl(latin1, out); } -template <class C> +template <typename C> void EncodeFromUTF16Tmpl(span<uint16_t> utf16, C* out) { // If there's at least one non-ASCII char, encode as STRING16 (UTF16). for (uint16_t ch : utf16) { @@ -336,7 +336,7 @@ EncodeFromUTF16Tmpl(utf16, out); } -template <class C> +template <typename C> void EncodeBinaryTmpl(span<uint8_t> in, C* out) { out->push_back(kExpectedConversionToBase64Tag); uint64_t byte_length = static_cast<uint64_t>(in.size_bytes()); @@ -359,7 +359,7 @@ // bit wide length, plus a 32 bit length for that string. constexpr std::ptrdiff_t kEncodedEnvelopeHeaderSize = 1 + 1 + sizeof(uint32_t); -template <class C> +template <typename C> void EncodeDoubleTmpl(double value, C* out) { // The additional_info=27 indicates 64 bits for the double follow. // See RFC 7049 Section 2.3, Table 1. @@ -382,7 +382,7 @@ // cbor::EnvelopeEncoder - for wrapping submessages // ============================================================================= -template <class C> +template <typename C> void EncodeStartTmpl(C* out, std::size_t& byte_size_pos) { assert(byte_size_pos == 0); out->push_back(kInitialByteForEnvelope); @@ -399,7 +399,7 @@ EncodeStartTmpl<std::string>(out, byte_size_pos_); } -template <class C> +template <typename C> bool EncodeStopTmpl(C* out, std::size_t& byte_size_pos) { assert(byte_size_pos != 0); // The byte size is the size of the payload, that is, all the @@ -429,7 +429,7 @@ // ============================================================================= namespace { -template <class C> +template <typename C> class CBOREncoder : public StreamingParserHandler { public: CBOREncoder(C* out, Status* status) : out_(out), status_(status) { @@ -931,6 +931,56 @@ } out->HandleError(Status{Error::CBOR_TRAILING_JUNK, tokenizer.Status().pos}); } + +// ============================================================================= +// cbor::AppendString8EntryToMap - for limited in-place editing of messages +// ============================================================================= + +template <typename C> +Status AppendString8EntryToCBORMapTmpl(span<uint8_t> string8_key, + span<uint8_t> string8_value, + C* cbor) { + span<uint8_t> bytes(reinterpret_cast<const uint8_t*>(cbor->data()), + cbor->size()); + CBORTokenizer tokenizer(bytes); + if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) + return tokenizer.Status(); + if (tokenizer.TokenTag() != CBORTokenTag::ENVELOPE) + return Status(Error::CBOR_INVALID_ENVELOPE, 0); + std::ptrdiff_t envelope_size = tokenizer.GetEnvelopeContents().size(); + std::size_t old_size = cbor->size(); + if (old_size != std::size_t(envelope_size) + kEncodedEnvelopeHeaderSize) + return Status(Error::CBOR_INVALID_ENVELOPE, 0); + if (envelope_size == 0 || + (tokenizer.GetEnvelopeContents()[0] != EncodeIndefiniteLengthMapStart())) + return Status(Error::CBOR_MAP_START_EXPECTED, kEncodedEnvelopeHeaderSize); + if (cbor->back() != EncodeStop()) + return Status(Error::CBOR_MAP_STOP_EXPECTED, cbor->size() - 1); + cbor->pop_back(); + EncodeString8(string8_key, cbor); + EncodeString8(string8_value, cbor); + cbor->push_back(EncodeStop()); + std::size_t new_envelope_size = envelope_size + (cbor->size() - old_size); + if (new_envelope_size > std::numeric_limits<uint32_t>::max()) + return Status(Error::CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED, 0); + std::size_t size_pos = cbor->size() - new_envelope_size - sizeof(uint32_t); + uint8_t* out = reinterpret_cast<uint8_t*>(&cbor->at(size_pos)); + *(out++) = (new_envelope_size >> 24) & 0xff; + *(out++) = (new_envelope_size >> 16) & 0xff; + *(out++) = (new_envelope_size >> 8) & 0xff; + *(out) = new_envelope_size & 0xff; + return Status(); +} +Status AppendString8EntryToCBORMap(span<uint8_t> string8_key, + span<uint8_t> string8_value, + std::vector<uint8_t>* cbor) { + return AppendString8EntryToCBORMapTmpl(string8_key, string8_value, cbor); +} +Status AppendString8EntryToCBORMap(span<uint8_t> string8_key, + span<uint8_t> string8_value, + std::string* cbor) { + return AppendString8EntryToCBORMapTmpl(string8_key, string8_value, cbor); +} } // namespace cbor namespace json { @@ -941,7 +991,7 @@ namespace { // Prints |value| to |out| with 4 hex digits, most significant chunk first. -template <class C> +template <typename C> void PrintHex(uint16_t value, C* out) { for (int ii = 3; ii >= 0; --ii) { int four_bits = 0xf & (value >> (4 * ii)); @@ -985,7 +1035,7 @@ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz0123456789+/"; -template <class C> +template <typename C> void Base64Encode(const span<uint8_t>& in, C* out) { // The following three cases are based on the tables in the example // section in https://en.wikipedia.org/wiki/Base64. We process three @@ -1018,7 +1068,7 @@ } // Implements a handler for JSON parser events to emit a JSON string. -template <class C> +template <typename C> class JSONEncoder : public StreamingParserHandler { public: JSONEncoder(const Platform* platform, C* out, Status* status) @@ -1904,7 +1954,7 @@ // ============================================================================= // json::ConvertCBORToJSON, json::ConvertJSONToCBOR - for transcoding // ============================================================================= -template <class C> +template <typename C> Status ConvertCBORToJSONTmpl(const Platform& platform, span<uint8_t> cbor, C* json) { @@ -1926,7 +1976,7 @@ return ConvertCBORToJSONTmpl(platform, cbor, json); } -template <class C> +template <typename C> Status ConvertJSONToCBORTmpl(const Platform& platform, span<uint8_t> json, C* cbor) {
diff --git a/third_party/inspector_protocol/encoding/encoding.h b/third_party/inspector_protocol/encoding/encoding.h index dc6dbfd..a5137a8 100644 --- a/third_party/inspector_protocol/encoding/encoding.h +++ b/third_party/inspector_protocol/encoding/encoding.h
@@ -54,11 +54,11 @@ }; template <typename T> -span<T> SpanFromVector(const std::vector<T>& v) { +span<T> SpanFrom(const std::vector<T>& v) { return span<T>(v.data(), v.size()); } -inline span<uint8_t> SpanFromStdString(const std::string& v) { +inline span<uint8_t> SpanFrom(const std::string& v) { return span<uint8_t>(reinterpret_cast<const uint8_t*>(v.data()), v.size()); } @@ -97,6 +97,8 @@ CBOR_STRING8_MUST_BE_7BIT = 0x1c, CBOR_TRAILING_JUNK = 0x1d, CBOR_MAP_START_EXPECTED = 0x1e, + CBOR_MAP_STOP_EXPECTED = 0x1f, + CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED = 0x20, }; // A status value with position that can be copied. The default status @@ -392,6 +394,20 @@ // that case. void ParseCBOR(span<uint8_t> bytes, StreamingParserHandler* out); +// ============================================================================= +// cbor::AppendString8EntryToMap - for limited in-place editing of messages +// ============================================================================= + +// Modifies the |cbor| message by appending a new key/value entry at the end +// of the map. Patches up the envelope size; Status.ok() iff successful. +// If not successful, |cbor| may be corrupted after this call. +Status AppendString8EntryToCBORMap(span<uint8_t> string8_key, + span<uint8_t> string8_value, + std::vector<uint8_t>* cbor); +Status AppendString8EntryToCBORMap(span<uint8_t> string8_key, + span<uint8_t> string8_value, + std::string* cbor); + namespace internals { // Exposed only for writing tests. int8_t ReadTokenStart(span<uint8_t> bytes, cbor::MajorType* type,
diff --git a/third_party/inspector_protocol/encoding/encoding_test.cc b/third_party/inspector_protocol/encoding/encoding_test.cc index baf7868..5c302d53 100644 --- a/third_party/inspector_protocol/encoding/encoding_test.cc +++ b/third_party/inspector_protocol/encoding/encoding_test.cc
@@ -133,14 +133,14 @@ TEST(IsCBORMessage, SomeSmokeTests) { std::vector<uint8_t> empty; - EXPECT_FALSE(IsCBORMessage(SpanFromVector(empty))); + EXPECT_FALSE(IsCBORMessage(SpanFrom(empty))); std::vector<uint8_t> hello = {'H', 'e', 'l', 'o', ' ', 't', 'h', 'e', 'r', 'e', '!'}; - EXPECT_FALSE(IsCBORMessage(SpanFromVector(hello))); + EXPECT_FALSE(IsCBORMessage(SpanFrom(hello))); std::vector<uint8_t> example = {0xd8, 0x5a, 0, 0, 0, 0}; - EXPECT_TRUE(IsCBORMessage(SpanFromVector(example))); + EXPECT_TRUE(IsCBORMessage(SpanFrom(example))); std::vector<uint8_t> one = {0xd8, 0x5a, 0, 0, 0, 1, 1}; - EXPECT_TRUE(IsCBORMessage(SpanFromVector(one))); + EXPECT_TRUE(IsCBORMessage(SpanFrom(one))); } // ============================================================================= @@ -161,7 +161,7 @@ EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 1>{{23}})); // Reverse direction: decode with CBORTokenizer. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); EXPECT_EQ(23, tokenizer.GetInt32()); tokenizer.Next(); @@ -179,7 +179,7 @@ EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 2>{{24, 42}})); // Reverse direction: decode with CBORTokenizer. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); EXPECT_EQ(42, tokenizer.GetInt32()); tokenizer.Next(); @@ -199,7 +199,7 @@ EXPECT_EQ(0xf4, encoded[2]); // Reverse direction: decode with CBORTokenizer. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); EXPECT_EQ(500, tokenizer.GetInt32()); tokenizer.Next(); @@ -218,7 +218,7 @@ ElementsAreArray(std::array<uint8_t, 5>{{26, 0x7f, 0xff, 0xff, 0xff}})); // Reverse direction: decode with CBORTokenizer. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); EXPECT_EQ(std::numeric_limits<int32_t>::max(), tokenizer.GetInt32()); tokenizer.Next(); @@ -241,7 +241,7 @@ ElementsAreArray(std::array<uint8_t, 5>{{26, 0xde, 0xad, 0xbe, 0xef}})); // Now try to decode; we treat this as an invalid INT32. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); // 0xdeadbeef is > std::numerical_limits<int32_t>::max(). EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag()); EXPECT_EQ(Error::CBOR_INVALID_INT32, tokenizer.Status().error); @@ -263,7 +263,7 @@ for (const TestCase& test : tests) { SCOPED_TRACE(test.msg); - CBORTokenizer tokenizer(SpanFromVector(test.data)); + CBORTokenizer tokenizer(SpanFrom(test.data)); EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag()); EXPECT_EQ(Error::CBOR_INVALID_INT32, tokenizer.Status().error); } @@ -282,7 +282,7 @@ EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 1>{{1 << 5 | 23}})); // Reverse direction: decode with CBORTokenizer. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); EXPECT_EQ(-24, tokenizer.GetInt32()); tokenizer.Next(); @@ -304,7 +304,7 @@ SCOPED_TRACE(std::string("example ") + std::to_string(example)); std::vector<uint8_t> encoded; EncodeInt32(example, &encoded); - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag()); EXPECT_EQ(example, tokenizer.GetInt32()); tokenizer.Next(); @@ -326,7 +326,7 @@ EXPECT_EQ(2 << 5, encoded[0]); // Reverse direction: decode with CBORTokenizer. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag()); span<uint8_t> decoded_string16_wirerep = tokenizer.GetString16WireRep(); EXPECT_TRUE(decoded_string16_wirerep.empty()); @@ -364,7 +364,7 @@ EXPECT_THAT(encoded, ElementsAreArray(encoded_expected)); // Now decode to complete the roundtrip. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag()); std::vector<uint16_t> decoded = String16WireRepToHost(tokenizer.GetString16WireRep()); @@ -374,7 +374,7 @@ // For bonus points, we look at the decoded message in UTF8 as well so we can // easily see it on the terminal screen. - std::string utf8_decoded = UTF16ToUTF8(SpanFromVector(decoded)); + std::string utf8_decoded = UTF16ToUTF8(SpanFrom(decoded)); EXPECT_EQ("Hello, 🌎.", utf8_decoded); } @@ -399,7 +399,7 @@ EXPECT_EQ(0xf4, encoded[2]); // Now decode to complete the roundtrip. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag()); std::vector<uint16_t> decoded = String16WireRepToHost(tokenizer.GetString16WireRep()); @@ -419,7 +419,7 @@ TestCase{{2 << 5 | 29}, "additional info = 29 isn't recognized"}}}; for (const TestCase& test : tests) { SCOPED_TRACE(test.msg); - CBORTokenizer tokenizer(SpanFromVector(test.data)); + CBORTokenizer tokenizer(SpanFrom(test.data)); EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag()); EXPECT_EQ(Error::CBOR_INVALID_STRING16, tokenizer.Status().error); } @@ -434,7 +434,7 @@ std::string utf8_msg = "Hello, 🌎."; std::vector<uint8_t> msg(utf8_msg.begin(), utf8_msg.end()); std::vector<uint8_t> encoded; - EncodeString8(SpanFromStdString(utf8_msg), &encoded); + EncodeString8(SpanFrom(utf8_msg), &encoded); // This will be encoded as STRING of length 12, so the 12 is encoded in // the additional info part of the initial byte. Payload is one byte per // utf8 byte. @@ -445,7 +445,7 @@ EXPECT_THAT(encoded, ElementsAreArray(encoded_expected)); // Now decode to complete the roundtrip. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag()); std::vector<uint8_t> decoded(tokenizer.GetString8().begin(), tokenizer.GetString8().end()); @@ -467,8 +467,8 @@ const std::string& latin1 = example.first; const std::string& expected_utf8 = example.second; std::vector<uint8_t> encoded; - EncodeFromLatin1(SpanFromStdString(latin1), &encoded); - CBORTokenizer tokenizer(SpanFromVector(encoded)); + EncodeFromLatin1(SpanFrom(latin1), &encoded); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag()); std::vector<uint8_t> decoded(tokenizer.GetString8().begin(), tokenizer.GetString8().end()); @@ -482,7 +482,7 @@ std::vector<uint8_t> encoded; EncodeFromUTF16(span<uint16_t>(ascii.data(), ascii.size()), &encoded); - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag()); std::vector<uint8_t> decoded(tokenizer.GetString8().begin(), tokenizer.GetString8().end()); @@ -499,11 +499,11 @@ std::vector<uint8_t> encoded; EncodeFromUTF16(span<uint16_t>(msg.data(), msg.size()), &encoded); - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag()); std::vector<uint16_t> decoded = String16WireRepToHost(tokenizer.GetString16WireRep()); - std::string utf8_decoded = UTF16ToUTF8(SpanFromVector(decoded)); + std::string utf8_decoded = UTF16ToUTF8(SpanFrom(decoded)); EXPECT_EQ("Hello, 🌎.", utf8_decoded); } @@ -523,7 +523,7 @@ (2 << 5 | 13), // BYTE_STRING (type 2) of length 13 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'}})); std::vector<uint8_t> decoded; - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::BINARY, tokenizer.TokenTag()); EXPECT_EQ(0, int(tokenizer.Status().error)); decoded = std::vector<uint8_t>(tokenizer.GetBinary().begin(), @@ -552,7 +552,7 @@ {7 << 5 | 27, 0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}})); // Reverse direction: decode and compare with original value. - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::DOUBLE, tokenizer.TokenTag()); EXPECT_THAT(tokenizer.GetDouble(), testing::DoubleEq(kOriginalValue)); tokenizer.Next(); @@ -572,7 +572,7 @@ SCOPED_TRACE(std::string("example ") + std::to_string(example)); std::vector<uint8_t> encoded; EncodeDouble(example, &encoded); - CBORTokenizer tokenizer(SpanFromVector(encoded)); + CBORTokenizer tokenizer(SpanFrom(encoded)); EXPECT_EQ(CBORTokenTag::DOUBLE, tokenizer.TokenTag()); if (std::isnan(example)) EXPECT_TRUE(std::isnan(tokenizer.GetDouble())); @@ -588,7 +588,7 @@ // ============================================================================= void EncodeUTF8ForTest(const std::string& key, std::vector<uint8_t>* out) { - EncodeString8(SpanFromStdString(key), out); + EncodeString8(SpanFrom(key), out); } TEST(JSONToCBOREncoderTest, SevenBitStrings) { // When a string can be represented as 7 bit ASCII, the encoder will use the @@ -625,7 +625,7 @@ Status status; std::unique_ptr<StreamingParserHandler> encoder = NewCBOREncoder(&encoded, &status); - span<uint8_t> ascii_in = SpanFromStdString(json); + span<uint8_t> ascii_in = SpanFrom(json); json::ParseJSON(GetTestPlatform(), ascii_in, encoder.get()); std::vector<uint8_t> expected = { 0xd8, // envelope @@ -633,7 +633,7 @@ 0, 0, 0, 94, // length is 94 bytes }; expected.push_back(0xbf); // indef length map start - EncodeString8(SpanFromStdString("string"), &expected); + EncodeString8(SpanFrom("string"), &expected); // This is followed by the encoded string for "Hello, 🌎." // So, it's the same bytes that we tested above in // EncodeDecodeString16Test.RoundtripsHelloWorld. @@ -642,17 +642,17 @@ {'H', 0, 'e', 0, 'l', 0, 'l', 0, 'o', 0, ',', 0, ' ', 0, 0x3c, 0xd8, 0x0e, 0xdf, '.', 0}}) expected.push_back(ch); - EncodeString8(SpanFromStdString("double"), &expected); + EncodeString8(SpanFrom("double"), &expected); EncodeDouble(3.1415, &expected); - EncodeString8(SpanFromStdString("int"), &expected); + EncodeString8(SpanFrom("int"), &expected); EncodeInt32(1, &expected); - EncodeString8(SpanFromStdString("negative int"), &expected); + EncodeString8(SpanFrom("negative int"), &expected); EncodeInt32(-1, &expected); - EncodeString8(SpanFromStdString("bool"), &expected); + EncodeString8(SpanFrom("bool"), &expected); expected.push_back(7 << 5 | 21); // RFC 7049 Section 2.3, Table 2: true - EncodeString8(SpanFromStdString("null"), &expected); + EncodeString8(SpanFrom("null"), &expected); expected.push_back(7 << 5 | 22); // RFC 7049 Section 2.3, Table 2: null - EncodeString8(SpanFromStdString("array"), &expected); + EncodeString8(SpanFrom("array"), &expected); expected.push_back(0xd8); // envelope expected.push_back(0x5a); // byte string with 32 bit length // the length is 5 bytes (that's up to end indef length array below). @@ -687,7 +687,7 @@ Status status; std::unique_ptr<StreamingParserHandler> encoder = NewCBOREncoder(&encoded, &status); - span<uint8_t> ascii_in = SpanFromStdString(json); + span<uint8_t> ascii_in = SpanFrom(json); ParseJSON(GetTestPlatform(), ascii_in, encoder.get()); std::string decoded; std::unique_ptr<StreamingParserHandler> json_writer = @@ -713,10 +713,10 @@ encoder->HandleMapBegin(); // Emit a key. std::vector<uint16_t> key = {'f', 'o', 'o'}; - encoder->HandleString16(SpanFromVector(key)); + encoder->HandleString16(SpanFrom(key)); // Emit the binary payload, an arbitrary array of bytes that happens to // be the ascii message "Hello, world.". - encoder->HandleBinary(SpanFromVector(std::vector<uint8_t>{ + encoder->HandleBinary(SpanFrom(std::vector<uint8_t>{ 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'})); encoder->HandleMapEnd(); EXPECT_EQ(Error::OK, status.error); @@ -725,7 +725,7 @@ std::string decoded; std::unique_ptr<StreamingParserHandler> json_writer = NewJSONEncoder(&GetTestPlatform(), &decoded, &status); - ParseCBOR(SpanFromVector(encoded), json_writer.get()); + ParseCBOR(SpanFrom(encoded), json_writer.get()); EXPECT_EQ(Error::OK, status.error); EXPECT_EQ(Status::npos(), status.pos); // "Hello, world." in base64 is "SGVsbG8sIHdvcmxkLg==". @@ -754,7 +754,7 @@ const uint8_t kPayloadLen = 27; std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen}; bytes.push_back(0xbf); // start indef length map. - EncodeString8(SpanFromStdString("msg"), &bytes); // key: msg + EncodeString8(SpanFrom("msg"), &bytes); // key: msg // Now write the value, the familiar "Hello, 🌎." where the globe is expressed // as two utf16 chars. bytes.push_back(/*major type=*/2 << 5 | /*additional info=*/20); @@ -784,9 +784,9 @@ kPayloadLen}; bytes.push_back(cbor::EncodeIndefiniteLengthMapStart()); // Two UTF16 chars. - EncodeString8(SpanFromStdString("🌎"), &bytes); + EncodeString8(SpanFrom("🌎"), &bytes); // Can be encoded as a single UTF16 char. - EncodeString8(SpanFromStdString("☾"), &bytes); + EncodeString8(SpanFrom("☾"), &bytes); bytes.push_back(cbor::EncodeStop()); EXPECT_EQ(kPayloadLen, bytes.size() - 6); @@ -819,7 +819,7 @@ Status status; std::unique_ptr<StreamingParserHandler> json_writer = NewJSONEncoder(&GetTestPlatform(), &out, &status); - ParseCBOR(SpanFromStdString(json), json_writer.get()); + ParseCBOR(SpanFrom(json), json_writer.get()); EXPECT_EQ(Error::CBOR_INVALID_START_BYTE, status.error); EXPECT_EQ("", out); } @@ -829,7 +829,7 @@ std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 0xbf}; // map start // A key; so value would be next. - EncodeString8(SpanFromStdString("key"), &bytes); + EncodeString8(SpanFrom("key"), &bytes); EXPECT_EQ(kPayloadLen, bytes.size() - 6); std::string out; Status status; @@ -846,7 +846,7 @@ std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 0xbf}; // The byte for starting a map. // A key; so value would be next. - EncodeString8(SpanFromStdString("array"), &bytes); + EncodeString8(SpanFrom("array"), &bytes); bytes.push_back(0x9f); // byte for indefinite length array start. EXPECT_EQ(kPayloadLen, bytes.size() - 6); std::string out; @@ -898,9 +898,9 @@ envelopes.emplace_back(); envelopes.back().EncodeStart(&bytes); bytes.push_back(0xbf); // indef length map start - EncodeString8(SpanFromStdString("key"), &bytes); + EncodeString8(SpanFrom("key"), &bytes); } - EncodeString8(SpanFromStdString("innermost_value"), &bytes); + EncodeString8(SpanFrom("innermost_value"), &bytes); for (int ii = 0; ii < depth; ++ii) { bytes.push_back(0xff); // stop byte, finishes map. envelopes.back().EncodeStop(&bytes); @@ -967,7 +967,7 @@ constexpr uint8_t kPayloadLen = 6; std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 0xbf}; // map start - EncodeString8(SpanFromStdString("key"), &bytes); + EncodeString8(SpanFrom("key"), &bytes); int64_t error_pos = bytes.size(); bytes.push_back(6 << 5 | 5); // tags aren't supported yet. EXPECT_EQ(kPayloadLen, bytes.size() - 6); @@ -986,7 +986,7 @@ constexpr uint8_t kPayloadLen = 11; std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 0xbf}; // map start - EncodeString8(SpanFromStdString("key"), &bytes); + EncodeString8(SpanFrom("key"), &bytes); int64_t error_pos = bytes.size(); // a BYTE_STRING of length 5 as value; since we interpret these as string16, // it's going to be invalid as each character would need two bytes, but @@ -1009,7 +1009,7 @@ constexpr uint8_t kPayloadLen = 6; std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 0xbf}; // map start - EncodeString8(SpanFromStdString("key"), &bytes); + EncodeString8(SpanFrom("key"), &bytes); int64_t error_pos = bytes.size(); // a STRING of length 5 as value, but we're at the end of the bytes array // so it can't be decoded successfully. @@ -1029,7 +1029,7 @@ constexpr uint8_t kPayloadLen = 9; std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 0xbf}; // map start - EncodeString8(SpanFromStdString("key"), &bytes); + EncodeString8(SpanFrom("key"), &bytes); int64_t error_pos = bytes.size(); bytes.push_back(6 << 5 | 22); // base64 hint for JSON; indicates binary bytes.push_back(2 << 5 | 10); // BYTE_STRING (major type 2) of length 10 @@ -1051,7 +1051,7 @@ constexpr uint8_t kPayloadLen = 8; std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 0xbf}; // map start - EncodeString8(SpanFromStdString("key"), &bytes); + EncodeString8(SpanFrom("key"), &bytes); int64_t error_pos = bytes.size(); bytes.push_back(7 << 5 | 27); // initial byte for double // Just two garbage bytes, not enough to represent an actual double. @@ -1072,7 +1072,7 @@ constexpr uint8_t kPayloadLen = 14; std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 0xbf}; // map start - EncodeString8(SpanFromStdString("key"), &bytes); + EncodeString8(SpanFrom("key"), &bytes); int64_t error_pos = bytes.size(); // uint64_t max is a perfectly fine value to encode as CBOR unsigned, // but we don't support this since we only cover the int32_t range. @@ -1093,11 +1093,11 @@ constexpr uint8_t kPayloadLen = 35; std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope 0xbf}; // map start - EncodeString8(SpanFromStdString("key"), &bytes); - EncodeString8(SpanFromStdString("value"), &bytes); + EncodeString8(SpanFrom("key"), &bytes); + EncodeString8(SpanFrom("value"), &bytes); bytes.push_back(0xff); // Up to here, it's a perfectly fine msg. int64_t error_pos = bytes.size(); - EncodeString8(SpanFromStdString("trailing junk"), &bytes); + EncodeString8(SpanFrom("trailing junk"), &bytes); internals::WriteTokenStart(MajorType::UNSIGNED, std::numeric_limits<uint64_t>::max(), &bytes); @@ -1111,6 +1111,113 @@ EXPECT_EQ(error_pos, status.pos); EXPECT_EQ("", out); } + +// ============================================================================= +// cbor::AppendString8EntryToMap - for limited in-place editing of messages +// ============================================================================= + +TEST(AppendString8EntryToMapTest, AppendsEntrySuccessfully) { + constexpr uint8_t kPayloadLen = 12; + std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen, // envelope + 0xbf}; // map start + size_t pos_before_payload = bytes.size() - 1; + EncodeString8(SpanFrom("key"), &bytes); + EncodeString8(SpanFrom("value"), &bytes); + bytes.push_back(0xff); // A perfectly fine cbor message. + EXPECT_EQ(kPayloadLen, bytes.size() - pos_before_payload); + + Status status = + AppendString8EntryToCBORMap(SpanFrom("foo"), SpanFrom("bar"), &bytes); + EXPECT_EQ(Error::OK, status.error); + EXPECT_EQ(-1, status.pos); + std::string out; + std::unique_ptr<StreamingParserHandler> json_writer = + NewJSONEncoder(&GetTestPlatform(), &out, &status); + ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get()); + EXPECT_EQ("{\"key\":\"value\",\"foo\":\"bar\"}", out); + EXPECT_EQ(Error::OK, status.error); + EXPECT_EQ(-1, status.pos); +} + +TEST(AppendString8EntryToMapTest, AppendThreeEntries) { + std::vector<uint8_t> encoded = { + 0xd8, 0x5a, 0, 0, 0, 2, EncodeIndefiniteLengthMapStart(), EncodeStop()}; + EXPECT_EQ(Error::OK, AppendString8EntryToCBORMap(SpanFrom("key"), + SpanFrom("value"), &encoded) + .error); + EXPECT_EQ(Error::OK, AppendString8EntryToCBORMap(SpanFrom("key1"), + SpanFrom("value1"), &encoded) + .error); + EXPECT_EQ(Error::OK, AppendString8EntryToCBORMap(SpanFrom("key2"), + SpanFrom("value2"), &encoded) + .error); + + std::string out; + Status status; + std::unique_ptr<StreamingParserHandler> json_writer = + NewJSONEncoder(&GetTestPlatform(), &out, &status); + ParseCBOR(SpanFrom(encoded), json_writer.get()); + EXPECT_EQ("{\"key\":\"value\",\"key1\":\"value1\",\"key2\":\"value2\"}", out); + EXPECT_EQ(Error::OK, status.error); + EXPECT_EQ(-1, status.pos); +} + +TEST(AppendString8EntryToMapTest, MapStartExpected_Error) { + std::vector<uint8_t> bytes = { + 0xd8, 0x5a, 0, 0, 0, 1, EncodeIndefiniteLengthArrayStart()}; + + Status status = + AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &bytes); + EXPECT_EQ(Error::CBOR_MAP_START_EXPECTED, status.error); + EXPECT_EQ(6, status.pos); +} + +TEST(AppendString8EntryToMapTest, MapStopExpected_Error) { + std::vector<uint8_t> bytes = { + 0xd8, 0x5a, 0, 0, 0, 2, EncodeIndefiniteLengthMapStart(), 42}; + + Status status = + AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &bytes); + EXPECT_EQ(Error::CBOR_MAP_STOP_EXPECTED, status.error); + EXPECT_EQ(7, status.pos); +} + +TEST(AppendString8EntryToMapTest, InvalidEnvelope_Error) { + { // Second byte is wrong. + std::vector<uint8_t> bytes = { + 0x5a, 0, 0, 0, 2, EncodeIndefiniteLengthMapStart(), EncodeStop(), 0}; + Status status = + AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &bytes); + EXPECT_EQ(Error::CBOR_INVALID_ENVELOPE, status.error); + EXPECT_EQ(0, status.pos); + } + { // Second byte is wrong. + std::vector<uint8_t> bytes = { + 0xd8, 0x7a, 0, 0, 0, 2, EncodeIndefiniteLengthMapStart(), EncodeStop()}; + Status status = + AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &bytes); + EXPECT_EQ(Error::CBOR_INVALID_ENVELOPE, status.error); + EXPECT_EQ(0, status.pos); + } + { // Invalid envelope size example. + std::vector<uint8_t> bytes = { + 0xd8, 0x5a, 0, 0, 0, 3, EncodeIndefiniteLengthMapStart(), EncodeStop(), + }; + Status status = + AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &bytes); + EXPECT_EQ(Error::CBOR_INVALID_ENVELOPE, status.error); + EXPECT_EQ(0, status.pos); + } + { // Invalid envelope size example. + std::vector<uint8_t> bytes = { + 0xd8, 0x5a, 0, 0, 0, 1, EncodeIndefiniteLengthMapStart(), EncodeStop(), + }; + Status status = + AppendString8EntryToCBORMap(SpanFrom("key"), SpanFrom("value"), &bytes); + EXPECT_EQ(Error::CBOR_INVALID_ENVELOPE, status.error); + EXPECT_EQ(0, status.pos); + } +} } // namespace cbor namespace json { @@ -1120,7 +1227,7 @@ // ============================================================================= void WriteUTF8AsUTF16(StreamingParserHandler* writer, const std::string& utf8) { - writer->HandleString16(SpanFromVector(UTF8ToUTF16(SpanFromStdString(utf8)))); + writer->HandleString16(SpanFrom(UTF8ToUTF16(SpanFrom(utf8)))); } TEST(JsonStdStringWriterTest, HelloWorld) { @@ -1133,8 +1240,8 @@ WriteUTF8AsUTF16(writer.get(), "Hello, 🌎."); std::string key = "msg1-as-utf8"; std::string value = "Hello, 🌎."; - writer->HandleString8(SpanFromStdString(key)); - writer->HandleString8(SpanFromStdString(value)); + writer->HandleString8(SpanFrom(key)); + writer->HandleString8(SpanFrom(value)); WriteUTF8AsUTF16(writer.get(), "msg2"); WriteUTF8AsUTF16(writer.get(), "\\\b\r\n\t\f\""); WriteUTF8AsUTF16(writer.get(), "nested"); @@ -1173,11 +1280,11 @@ std::unique_ptr<StreamingParserHandler> writer = NewJSONEncoder(&GetTestPlatform(), &out, &status); writer->HandleMapBegin(); - writer->HandleString8(SpanFromStdString("Infinity")); + writer->HandleString8(SpanFrom("Infinity")); writer->HandleDouble(std::numeric_limits<double>::infinity()); - writer->HandleString8(SpanFromStdString("-Infinity")); + writer->HandleString8(SpanFrom("-Infinity")); writer->HandleDouble(-std::numeric_limits<double>::infinity()); - writer->HandleString8(SpanFromStdString("NaN")); + writer->HandleString8(SpanFrom("NaN")); writer->HandleDouble(std::numeric_limits<double>::quiet_NaN()); writer->HandleMapEnd(); EXPECT_TRUE(status.ok()); @@ -1193,7 +1300,7 @@ Status status; std::unique_ptr<StreamingParserHandler> writer = NewJSONEncoder(&GetTestPlatform(), &out, &status); - writer->HandleBinary(SpanFromVector(std::vector<uint8_t>({'M', 'a', 'n'}))); + writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M', 'a', 'n'}))); EXPECT_TRUE(status.ok()); EXPECT_EQ("\"TWFu\"", out); } @@ -1202,7 +1309,7 @@ Status status; std::unique_ptr<StreamingParserHandler> writer = NewJSONEncoder(&GetTestPlatform(), &out, &status); - writer->HandleBinary(SpanFromVector(std::vector<uint8_t>({'M', 'a'}))); + writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M', 'a'}))); EXPECT_TRUE(status.ok()); EXPECT_EQ("\"TWE=\"", out); } @@ -1211,7 +1318,7 @@ Status status; std::unique_ptr<StreamingParserHandler> writer = NewJSONEncoder(&GetTestPlatform(), &out, &status); - writer->HandleBinary(SpanFromVector(std::vector<uint8_t>({'M'}))); + writer->HandleBinary(SpanFrom(std::vector<uint8_t>({'M'}))); EXPECT_TRUE(status.ok()); EXPECT_EQ("\"TQ==\"", out); } @@ -1220,7 +1327,7 @@ Status status; std::unique_ptr<StreamingParserHandler> writer = NewJSONEncoder(&GetTestPlatform(), &out, &status); - writer->HandleBinary(SpanFromVector(std::vector<uint8_t>( + writer->HandleBinary(SpanFrom(std::vector<uint8_t>( {'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'}))); EXPECT_TRUE(status.ok()); EXPECT_EQ("\"SGVsbG8sIHdvcmxkLg==\"", out); @@ -1335,7 +1442,7 @@ TEST_F(JsonParserTest, SimpleDictionary) { std::string json = "{\"foo\": 42}"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_TRUE(log_.status().ok()); EXPECT_EQ( "map begin\n" @@ -1347,7 +1454,7 @@ TEST_F(JsonParserTest, Whitespace) { std::string json = "\n {\n\"msg\"\n: \v\"Hello, world.\"\t\r}\t"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_TRUE(log_.status().ok()); EXPECT_EQ( "map begin\n" @@ -1359,7 +1466,7 @@ TEST_F(JsonParserTest, NestedDictionary) { std::string json = "{\"foo\": {\"bar\": {\"baz\": 1}, \"bar2\": 2}}"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_TRUE(log_.status().ok()); EXPECT_EQ( "map begin\n" @@ -1379,7 +1486,7 @@ TEST_F(JsonParserTest, Doubles) { std::string json = "{\"foo\": 3.1415, \"bar\": 31415e-4}"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_TRUE(log_.status().ok()); EXPECT_EQ( "map begin\n" @@ -1394,7 +1501,7 @@ TEST_F(JsonParserTest, Unicode) { // Globe character. 0xF0 0x9F 0x8C 0x8E in utf8, 0xD83C 0xDF0E in utf16. std::string json = "{\"msg\": \"Hello, \\uD83C\\uDF0E.\"}"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_TRUE(log_.status().ok()); EXPECT_EQ( "map begin\n" @@ -1411,8 +1518,8 @@ // We provide the moon with json escape, but the earth as utf16 input. // Either way they arrive as utf8 (after decoding in log_.str()). std::vector<uint16_t> json = - UTF8ToUTF16(SpanFromStdString("{\"space\": \"🌎 \\uD83C\\uDF19.\"}")); - ParseJSON(GetTestPlatform(), SpanFromVector(json), &log_); + UTF8ToUTF16(SpanFrom("{\"space\": \"🌎 \\uD83C\\uDF19.\"}")); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_TRUE(log_.status().ok()); EXPECT_EQ( "map begin\n" @@ -1438,7 +1545,7 @@ "\"3 byte\":\"屋\"," "\"4 byte\":\"🌎\"" "}"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_TRUE(log_.status().ok()); EXPECT_EQ( "map begin\n" @@ -1459,7 +1566,7 @@ std::string json = "{\"foo\": 3.1415} junk"; int64_t junk_idx = json.find("junk"); EXPECT_GT(junk_idx, 0); - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, log_.status().error); EXPECT_EQ(junk_idx, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1475,11 +1582,11 @@ return json; } -TEST_F(JsonParserTest, StackLimitExceededError) { - // kStackLimit is 1000 (see json_parser.cc). First let's +TEST_F(JsonParserTest, StackLimitExceededError_BelowLimit) { + // kStackLimit is 300 (see json_parser.cc). First let's // try with a small nested example. std::string json_3 = MakeNestedJson(3); - ParseJSON(GetTestPlatform(), SpanFromStdString(json_3), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json_3), &log_); EXPECT_TRUE(log_.status().ok()); EXPECT_EQ( "map begin\n" @@ -1493,26 +1600,31 @@ "map end\n" "map end\n", log_.str()); +} +TEST_F(JsonParserTest, StackLimitExceededError_AtLimit) { // Now with kStackLimit (300). - log_ = Log(); std::string json_limit = MakeNestedJson(300); ParseJSON(GetTestPlatform(), span<uint8_t>(reinterpret_cast<const uint8_t*>(json_limit.data()), json_limit.size()), &log_); EXPECT_TRUE(log_.status().ok()); - // Now with kStackLimit + 1 (1001) - it exceeds in the innermost instance. - log_ = Log(); - std::string exceeded = MakeNestedJson(1001); - ParseJSON(GetTestPlatform(), SpanFromStdString(exceeded), &log_); +} + +TEST_F(JsonParserTest, StackLimitExceededError_AboveLimit) { + // Now with kStackLimit + 1 (301) - it exceeds in the innermost instance. + std::string exceeded = MakeNestedJson(301); + ParseJSON(GetTestPlatform(), SpanFrom(exceeded), &log_); EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error); EXPECT_EQ(static_cast<std::ptrdiff_t>(strlen("{\"foo\":") * 301), log_.status().pos); +} + +TEST_F(JsonParserTest, StackLimitExceededError_WayAboveLimit) { // Now way past the limit. Still, the point of exceeding is 301. - log_ = Log(); std::string far_out = MakeNestedJson(320); - ParseJSON(GetTestPlatform(), SpanFromStdString(far_out), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(far_out), &log_); EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error); EXPECT_EQ(static_cast<std::ptrdiff_t>(strlen("{\"foo\":") * 301), log_.status().pos); @@ -1520,7 +1632,7 @@ TEST_F(JsonParserTest, NoInputError) { std::string json = ""; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_NO_INPUT, log_.status().error); EXPECT_EQ(0, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1528,7 +1640,7 @@ TEST_F(JsonParserTest, InvalidTokenError) { std::string json = "|"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_INVALID_TOKEN, log_.status().error); EXPECT_EQ(0, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1537,7 +1649,7 @@ TEST_F(JsonParserTest, InvalidNumberError) { // Mantissa exceeds max (the constant used here is int64_t max). std::string json = "1E9223372036854775807"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_INVALID_NUMBER, log_.status().error); EXPECT_EQ(0, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1546,7 +1658,7 @@ TEST_F(JsonParserTest, InvalidStringError) { // \x22 is an unsupported escape sequence std::string json = "\"foo\\x22\""; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_INVALID_STRING, log_.status().error); EXPECT_EQ(0, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1554,7 +1666,7 @@ TEST_F(JsonParserTest, UnexpectedArrayEndError) { std::string json = "[1,2,]"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_ARRAY_END, log_.status().error); EXPECT_EQ(5, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1562,7 +1674,7 @@ TEST_F(JsonParserTest, CommaOrArrayEndExpectedError) { std::string json = "[1,2 2"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED, log_.status().error); EXPECT_EQ(5, log_.status().pos); @@ -1572,7 +1684,7 @@ TEST_F(JsonParserTest, StringLiteralExpectedError) { // There's an error because the key bar, a string, is not terminated. std::string json = "{\"foo\": 3.1415, \"bar: 31415e-4}"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_STRING_LITERAL_EXPECTED, log_.status().error); EXPECT_EQ(16, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1580,7 +1692,7 @@ TEST_F(JsonParserTest, ColonExpectedError) { std::string json = "{\"foo\", 42}"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_COLON_EXPECTED, log_.status().error); EXPECT_EQ(6, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1588,7 +1700,7 @@ TEST_F(JsonParserTest, UnexpectedMapEndError) { std::string json = "{\"foo\": 42, }"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_MAP_END, log_.status().error); EXPECT_EQ(12, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1597,7 +1709,7 @@ TEST_F(JsonParserTest, CommaOrMapEndExpectedError) { // The second separator should be a comma. std::string json = "{\"foo\": 3.1415: \"bar\": 0}"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_MAP_END_EXPECTED, log_.status().error); EXPECT_EQ(14, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1605,7 +1717,7 @@ TEST_F(JsonParserTest, ValueExpectedError) { std::string json = "}"; - ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_); + ParseJSON(GetTestPlatform(), SpanFrom(json), &log_); EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, log_.status().error); EXPECT_EQ(0, log_.status().pos); EXPECT_EQ("", log_.str()); @@ -1615,15 +1727,14 @@ std::string json = "{\"msg\":\"Hello, world.\"}"; std::string cbor; { - Status status = - ConvertJSONToCBOR(GetTestPlatform(), SpanFromStdString(json), &cbor); + Status status = ConvertJSONToCBOR(GetTestPlatform(), SpanFrom(json), &cbor); EXPECT_EQ(Error::OK, status.error); EXPECT_EQ(Status::npos(), status.pos); } std::string roundtrip_json; { - Status status = ConvertCBORToJSON(GetTestPlatform(), - SpanFromStdString(cbor), &roundtrip_json); + Status status = + ConvertCBORToJSON(GetTestPlatform(), SpanFrom(cbor), &roundtrip_json); EXPECT_EQ(Error::OK, status.error); EXPECT_EQ(Status::npos(), status.pos); }
diff --git a/third_party/inspector_protocol/lib/encoding_cpp.template b/third_party/inspector_protocol/lib/encoding_cpp.template index 7127409..a5376142 100644 --- a/third_party/inspector_protocol/lib/encoding_cpp.template +++ b/third_party/inspector_protocol/lib/encoding_cpp.template
@@ -158,7 +158,7 @@ // Writes the start of a token with |type|. The |value| may indicate the size, // or it may be the payload if the value is an unsigned integer. -template <class C> +template <typename C> void WriteTokenStartTmpl(MajorType type, uint64_t value, C* encoded) { if (value < 24) { // Values 0-23 are encoded directly into the additional info of the @@ -240,7 +240,7 @@ return kStopByte; } -template <class C> +template <typename C> void EncodeInt32Tmpl(int32_t value, C* out) { if (value >= 0) { internals::WriteTokenStart(MajorType::UNSIGNED, value, out); @@ -256,7 +256,7 @@ EncodeInt32Tmpl(value, out); } -template <class C> +template <typename C> void EncodeString16Tmpl(span<uint16_t> in, C* out) { uint64_t byte_length = static_cast<uint64_t>(in.size_bytes()); internals::WriteTokenStart(MajorType::BYTE_STRING, byte_length, out); @@ -281,7 +281,7 @@ EncodeString16Tmpl(in, out); } -template <class C> +template <typename C> void EncodeString8Tmpl(span<uint8_t> in, C* out) { internals::WriteTokenStart(MajorType::STRING, static_cast<uint64_t>(in.size_bytes()), out); @@ -294,7 +294,7 @@ EncodeString8Tmpl(in, out); } -template <class C> +template <typename C> void EncodeFromLatin1Tmpl(span<uint8_t> latin1, C* out) { for (std::ptrdiff_t ii = 0; ii < latin1.size(); ++ii) { if (latin1[ii] <= 127) @@ -310,7 +310,7 @@ utf8.push_back((latin1[ii] | 0x80) & 0xbf); } } - EncodeString8(SpanFromVector(utf8), out); + EncodeString8(SpanFrom(utf8), out); return; } EncodeString8(latin1, out); @@ -322,7 +322,7 @@ EncodeFromLatin1Tmpl(latin1, out); } -template <class C> +template <typename C> void EncodeFromUTF16Tmpl(span<uint16_t> utf16, C* out) { // If there's at least one non-ASCII char, encode as STRING16 (UTF16). for (uint16_t ch : utf16) { @@ -343,7 +343,7 @@ EncodeFromUTF16Tmpl(utf16, out); } -template <class C> +template <typename C> void EncodeBinaryTmpl(span<uint8_t> in, C* out) { out->push_back(kExpectedConversionToBase64Tag); uint64_t byte_length = static_cast<uint64_t>(in.size_bytes()); @@ -366,7 +366,7 @@ // bit wide length, plus a 32 bit length for that string. constexpr std::ptrdiff_t kEncodedEnvelopeHeaderSize = 1 + 1 + sizeof(uint32_t); -template <class C> +template <typename C> void EncodeDoubleTmpl(double value, C* out) { // The additional_info=27 indicates 64 bits for the double follow. // See RFC 7049 Section 2.3, Table 1. @@ -389,7 +389,7 @@ // cbor::EnvelopeEncoder - for wrapping submessages // ============================================================================= -template <class C> +template <typename C> void EncodeStartTmpl(C* out, std::size_t& byte_size_pos) { assert(byte_size_pos == 0); out->push_back(kInitialByteForEnvelope); @@ -406,7 +406,7 @@ EncodeStartTmpl<std::string>(out, byte_size_pos_); } -template <class C> +template <typename C> bool EncodeStopTmpl(C* out, std::size_t& byte_size_pos) { assert(byte_size_pos != 0); // The byte size is the size of the payload, that is, all the @@ -436,7 +436,7 @@ // ============================================================================= namespace { -template <class C> +template <typename C> class CBOREncoder : public StreamingParserHandler { public: CBOREncoder(C* out, Status* status) : out_(out), status_(status) { @@ -938,6 +938,56 @@ } out->HandleError(Status{Error::CBOR_TRAILING_JUNK, tokenizer.Status().pos}); } + +// ============================================================================= +// cbor::AppendString8EntryToMap - for limited in-place editing of messages +// ============================================================================= + +template <typename C> +Status AppendString8EntryToCBORMapTmpl(span<uint8_t> string8_key, + span<uint8_t> string8_value, + C* cbor) { + span<uint8_t> bytes(reinterpret_cast<const uint8_t*>(cbor->data()), + cbor->size()); + CBORTokenizer tokenizer(bytes); + if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) + return tokenizer.Status(); + if (tokenizer.TokenTag() != CBORTokenTag::ENVELOPE) + return Status(Error::CBOR_INVALID_ENVELOPE, 0); + std::ptrdiff_t envelope_size = tokenizer.GetEnvelopeContents().size(); + std::size_t old_size = cbor->size(); + if (old_size != std::size_t(envelope_size) + kEncodedEnvelopeHeaderSize) + return Status(Error::CBOR_INVALID_ENVELOPE, 0); + if (envelope_size == 0 || + (tokenizer.GetEnvelopeContents()[0] != EncodeIndefiniteLengthMapStart())) + return Status(Error::CBOR_MAP_START_EXPECTED, kEncodedEnvelopeHeaderSize); + if (cbor->back() != EncodeStop()) + return Status(Error::CBOR_MAP_STOP_EXPECTED, cbor->size() - 1); + cbor->pop_back(); + EncodeString8(string8_key, cbor); + EncodeString8(string8_value, cbor); + cbor->push_back(EncodeStop()); + std::size_t new_envelope_size = envelope_size + (cbor->size() - old_size); + if (new_envelope_size > std::numeric_limits<uint32_t>::max()) + return Status(Error::CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED, 0); + std::size_t size_pos = cbor->size() - new_envelope_size - sizeof(uint32_t); + uint8_t* out = reinterpret_cast<uint8_t*>(&cbor->at(size_pos)); + *(out++) = (new_envelope_size >> 24) & 0xff; + *(out++) = (new_envelope_size >> 16) & 0xff; + *(out++) = (new_envelope_size >> 8) & 0xff; + *(out) = new_envelope_size & 0xff; + return Status(); +} +Status AppendString8EntryToCBORMap(span<uint8_t> string8_key, + span<uint8_t> string8_value, + std::vector<uint8_t>* cbor) { + return AppendString8EntryToCBORMapTmpl(string8_key, string8_value, cbor); +} +Status AppendString8EntryToCBORMap(span<uint8_t> string8_key, + span<uint8_t> string8_value, + std::string* cbor) { + return AppendString8EntryToCBORMapTmpl(string8_key, string8_value, cbor); +} } // namespace cbor namespace json { @@ -948,7 +998,7 @@ namespace { // Prints |value| to |out| with 4 hex digits, most significant chunk first. -template <class C> +template <typename C> void PrintHex(uint16_t value, C* out) { for (int ii = 3; ii >= 0; --ii) { int four_bits = 0xf & (value >> (4 * ii)); @@ -992,7 +1042,7 @@ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz0123456789+/"; -template <class C> +template <typename C> void Base64Encode(const span<uint8_t>& in, C* out) { // The following three cases are based on the tables in the example // section in https://en.wikipedia.org/wiki/Base64. We process three @@ -1025,7 +1075,7 @@ } // Implements a handler for JSON parser events to emit a JSON string. -template <class C> +template <typename C> class JSONEncoder : public StreamingParserHandler { public: JSONEncoder(const Platform* platform, C* out, Status* status) @@ -1911,7 +1961,7 @@ // ============================================================================= // json::ConvertCBORToJSON, json::ConvertJSONToCBOR - for transcoding // ============================================================================= -template <class C> +template <typename C> Status ConvertCBORToJSONTmpl(const Platform& platform, span<uint8_t> cbor, C* json) { @@ -1933,7 +1983,7 @@ return ConvertCBORToJSONTmpl(platform, cbor, json); } -template <class C> +template <typename C> Status ConvertJSONToCBORTmpl(const Platform& platform, span<uint8_t> json, C* cbor) {
diff --git a/third_party/inspector_protocol/lib/encoding_h.template b/third_party/inspector_protocol/lib/encoding_h.template index 5250a89..8f62c9e 100644 --- a/third_party/inspector_protocol/lib/encoding_h.template +++ b/third_party/inspector_protocol/lib/encoding_h.template
@@ -62,11 +62,11 @@ }; template <typename T> -span<T> SpanFromVector(const std::vector<T>& v) { +span<T> SpanFrom(const std::vector<T>& v) { return span<T>(v.data(), v.size()); } -inline span<uint8_t> SpanFromStdString(const std::string& v) { +inline span<uint8_t> SpanFrom(const std::string& v) { return span<uint8_t>(reinterpret_cast<const uint8_t*>(v.data()), v.size()); } @@ -105,6 +105,8 @@ CBOR_STRING8_MUST_BE_7BIT = 0x1c, CBOR_TRAILING_JUNK = 0x1d, CBOR_MAP_START_EXPECTED = 0x1e, + CBOR_MAP_STOP_EXPECTED = 0x1f, + CBOR_ENVELOPE_SIZE_LIMIT_EXCEEDED = 0x20, }; // A status value with position that can be copied. The default status @@ -400,6 +402,20 @@ // that case. void ParseCBOR(span<uint8_t> bytes, StreamingParserHandler* out); +// ============================================================================= +// cbor::AppendString8EntryToMap - for limited in-place editing of messages +// ============================================================================= + +// Modifies the |cbor| message by appending a new key/value entry at the end +// of the map. Patches up the envelope size; Status.ok() iff successful. +// If not successful, |cbor| may be corrupted after this call. +Status AppendString8EntryToCBORMap(span<uint8_t> string8_key, + span<uint8_t> string8_value, + std::vector<uint8_t>* cbor); +Status AppendString8EntryToCBORMap(span<uint8_t> string8_key, + span<uint8_t> string8_value, + std::string* cbor); + namespace internals { // Exposed only for writing tests. int8_t ReadTokenStart(span<uint8_t> bytes, cbor::MajorType* type,
diff --git a/third_party/libusb/BUILD.gn b/third_party/libusb/BUILD.gn index 518114bd9..7989bf8f 100644 --- a/third_party/libusb/BUILD.gn +++ b/third_party/libusb/BUILD.gn
@@ -91,6 +91,10 @@ # Needed on OSX 10.12 to silence a deprecation warning. "OBJC_SILENCE_GC_DEPRECATIONS=1", ] + libs = [ + "CoreFoundation.framework", + "IOKit.framework", + ] } else { sources -= [ "src/libusb/os/darwin_usb.c",
diff --git a/third_party/webxr_test_pages/webxr-samples/input-selection.html b/third_party/webxr_test_pages/webxr-samples/input-selection.html index 9ed63e17..41f931c 100644 --- a/third_party/webxr_test_pages/webxr-samples/input-selection.html +++ b/third_party/webxr_test_pages/webxr-samples/input-selection.html
@@ -61,6 +61,7 @@ import {PbrMaterial} from './js/cottontail/src/materials/pbr.js'; import {BoxBuilder} from './js/cottontail/src/geometry/box-builder.js'; import {mat4, vec3, quat} from './js/cottontail/src/math/gl-matrix.js'; + import {BoundsRenderer} from './js/cottontail/src/nodes/bounds-renderer.js'; // If requested, initialize the WebXR polyfill if (QueryArgs.getBool('allowPolyfill', false)) { @@ -79,6 +80,7 @@ let gl = null; let renderer = null; let scene = new Scene(); + let boundsRenderer = null; if (hideStats) { scene.enableStats(false); } @@ -197,16 +199,28 @@ outputContext: outputCanvas.getContext('xrpresent') }); - session.requestReferenceSpace({ type: 'stationary', subtype: 'floor-level' }).then((refSpace) => { - return refSpace; - }, (e) => { - if (!session.mode.startsWith('immersive')) { - // If we're in inline mode, our underlying platform may not support - // the stationary reference space, but an identity space is guaranteed. - return session.requestReferenceSpace({ type: 'identity' }); + // Same logic for establishing a reference space as in room-scale.html + session.requestReferenceSpace({ type: 'bounded' }).then((refSpace) => { + if (!boundsRenderer) { + boundsRenderer = new BoundsRenderer(refSpace); + scene.addNode(boundsRenderer); } else { - throw e; + boundsRenderer.boundedRefSpace = refSpace; } + return refSpace; + }).catch(() => { + console.log('Falling back to floor-level reference space'); + return session.requestReferenceSpace({ type: 'stationary', subtype: 'floor-level' }).catch((e) => { + if (!session.mode.startsWith('immersive')) { + console.log('Falling back to identity reference space'); + return session.requestReferenceSpace({ type: 'identity' }).then((refSpace) => { + refSpace.originOffset = new XRRigidTransform({y: -1.6}); + return refSpace; + }); + } else { + throw e; + } + }); }).then((refSpace) => { if (session.mode.startsWith('immersive')) { xrImmersiveRefSpace = refSpace; @@ -298,6 +312,18 @@ // Update tracking space origin so that origin + playerOffset == player location in world space vec3.sub(trackingSpaceOriginInWorldSpace, playerInWorldSpaceNew, playerOffsetInWorldSpaceNew); + // Compute the origin offset + quat.identity(invOrientation); + quat.rotateY(invOrientation, invOrientation, -trackingSpaceHeadingDegrees * Math.PI / 180); + vec3.negate(invPosition, trackingSpaceOriginInWorldSpace); + vec3.transformQuat(invPosition, invPosition, invOrientation); + let xform = new XRRigidTransform( + {x: invPosition[0], y: invPosition[1], z: invPosition[2]}, + {x: invOrientation[0], y: invOrientation[1], z: invOrientation[2], w: invOrientation[3]}); + + // Update originOffset to use the teleported player position and orientation + refSpace.originOffset = xform; + console.log('teleport to', trackingSpaceOriginInWorldSpace); } @@ -328,17 +354,6 @@ let session = frame.session; let refSpace = getRefSpace(session); - quat.identity(invOrientation); - quat.rotateY(invOrientation, invOrientation, -trackingSpaceHeadingDegrees * Math.PI / 180); - vec3.negate(invPosition, trackingSpaceOriginInWorldSpace); - vec3.transformQuat(invPosition, invPosition, invOrientation); - let xform = new XRRigidTransform( - {x: invPosition[0], y: invPosition[1], z: invPosition[2]}, - {x: invOrientation[0], y: invOrientation[1], z: invOrientation[2], w: invOrientation[3]}); - - // Update originOffset to use the teleported player position and orientation - refSpace.originOffset = xform; - let pose = frame.getViewerPose(refSpace); scene.startFrame(); session.requestAnimationFrame(onXRFrame);
diff --git a/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/bounds-renderer.js b/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/bounds-renderer.js index 081efa14..3cc43f5 100644 --- a/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/bounds-renderer.js +++ b/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/nodes/bounds-renderer.js
@@ -19,13 +19,13 @@ // SOFTWARE. /* -This file renders a passed in XRStageBounds object and attempts +This file renders a passed in XRBoundedReferenceSpace object and attempts to render geometry on the floor to indicate where the bounds is. -XRStageBounds' `geometry` is a series of XRStageBoundsPoints (in -clockwise-order) with `x` and `z` properties for each. +The bounds `geometry` is a series of DOMPointReadOnlys in +clockwise-order. */ -import {Material} from '../core/material.js'; +import {Material, RENDER_ORDER} from '../core/material.js'; import {Node} from '../core/node.js'; import {Primitive, PrimitiveAttribute} from '../core/primitive.js'; @@ -35,10 +35,12 @@ constructor() { super(); + this.renderOrder = RENDER_ORDER.ADDITIVE; this.state.blend = true; this.state.blendFuncSrc = GL.SRC_ALPHA; this.state.blendFuncDst = GL.ONE; this.state.depthTest = false; + this.state.cullFace = false; } get materialName() { @@ -47,9 +49,10 @@ get vertexSource() { return ` - attribute vec2 POSITION; - + attribute vec3 POSITION; + varying vec3 v_pos; vec4 vertex_main(mat4 proj, mat4 view, mat4 model) { + v_pos = POSITION; return proj * view * model * vec4(POSITION, 1.0); }`; } @@ -57,50 +60,80 @@ get fragmentSource() { return ` precision mediump float; - + varying vec3 v_pos; vec4 fragment_main() { - return vec4(0.0, 1.0, 0.0, 0.3); + return vec4(0.0, 1.0, 0.0, (1.0 - v_pos.y) * 0.5); }`; } } export class BoundsRenderer extends Node { - constructor() { + constructor(refSpace) { super(); - this._stageBounds = null; + this._resetListener = (ev) => { + console.log('Got a reset event'); + this.onReset(this._boundedRefSpace); + }; + + this.boundedRefSpace = refSpace; } onRendererChanged(renderer) { - this.stageBounds = this._stageBounds; + this._material = new BoundsMaterial(); + this.onReset(this._boundedRefSpace); } - get stageBounds() { - return this._stageBounds; + get boundedRefSpace() { + return this._boundedRefSpace; } - set stageBounds(stageBounds) { - if (this._stageBounds) { + set boundedRefSpace(refSpace) { + if (this._boundedRefSpace != refSpace) { + if (this._boundedRefSpace) { + this._boundedRefSpace.removeEventListener('reset', this._resetListener); + } + if (refSpace) { + refSpace.addEventListener('reset', this._resetListener); + } + this.onReset(refSpace); + } + } + + onReset(refSpace) { + if (this._boundedRefSpace) { this.clearRenderPrimitives(); } - this._stageBounds = stageBounds; - if (!stageBounds || stageBounds.length === 0 || !this._renderer) { + this._boundedRefSpace = refSpace; + if (!refSpace || refSpace.boundsGeometry.length === 0 || !this._renderer) { return; } + let geometry = refSpace.boundsGeometry; + let verts = []; let indices = []; // Tessellate the bounding points from XRStageBounds and connect // each point to a neighbor and 0,0,0. - const pointCount = stageBounds.geometry.length; + const pointCount = geometry.length; + let lastIndex = -1; for (let i = 0; i < pointCount; i++) { - const point = stageBounds.geometry[i]; + const point = geometry[i]; verts.push(point.x, 0, point.z); - indices.push(i, i === 0 ? pointCount - 1 : i - 1, pointCount); + verts.push(point.x, 1, point.z); + + lastIndex += 2; + if (i > 0) { + indices.push(lastIndex, lastIndex-1, lastIndex-2); + indices.push(lastIndex-2, lastIndex-1, lastIndex-3); + } } - // Center point - verts.push(0, 0, 0); + + if (pointCount > 1) { + indices.push(1, 0, lastIndex); + indices.push(lastIndex, 0, lastIndex-1); + } let vertexBuffer = this._renderer.createRenderBuffer(GL.ARRAY_BUFFER, new Float32Array(verts)); let indexBuffer = this._renderer.createRenderBuffer(GL.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices)); @@ -112,7 +145,7 @@ let primitive = new Primitive(attribs, indices.length); primitive.setIndexBuffer(indexBuffer); - let renderPrimitive = this._renderer.createRenderPrimitive(primitive, new BoundsMaterial()); + let renderPrimitive = this._renderer.createRenderPrimitive(primitive, this._material); this.addRenderPrimitive(renderPrimitive); } -} +} \ No newline at end of file
diff --git a/third_party/webxr_test_pages/webxr-samples/room-scale.html b/third_party/webxr_test_pages/webxr-samples/room-scale.html index 995c7ba..8b535325 100644 --- a/third_party/webxr_test_pages/webxr-samples/room-scale.html +++ b/third_party/webxr_test_pages/webxr-samples/room-scale.html
@@ -59,6 +59,7 @@ import {QueryArgs} from './js/cottontail/src/util/query-args.js'; import {FallbackHelper} from './js/cottontail/src/util/fallback-helper.js'; import {SkyboxNode} from './js/cottontail/src/nodes/skybox.js'; + import {BoundsRenderer} from './js/cottontail/src/nodes/bounds-renderer.js'; // If requested, initialize the WebXR polyfill if (QueryArgs.getBool('allowPolyfill', false)) { @@ -74,6 +75,7 @@ let gl = null; let renderer = null; let scene = new Scene(); + let boundsRenderer = null; scene.addNode(new Gltf2Node({url: '../media/gltf/camp/camp.gltf'})); scene.addNode(new SkyboxNode({url: '../media/textures/eilenriede-park-2k.png'})); scene.standingStats(true); @@ -133,28 +135,50 @@ outputContext: outputCanvas.getContext('xrpresent') }); - // Get a stage frame of reference, which will align the user's physical - // floor with Y=0 and can provide boundaries that indicate where the - // user can safely walk. If the system can't natively provide stage - // coordinates (for example, with a 3DoF device) then it will return an - // emulated stage, where the view is translated up by a static height so - // that the scene still renders in approximately the right place. - session.requestReferenceSpace({ type: 'stationary', subtype: 'floor-level' }).then((refSpace) => { - return refSpace; - }, (e) => { - if (!session.mode.startsWith('immersive')) { - // If we're in inline mode, our underlying platform may not support - // the stationary reference space, but an identity space is guaranteed. - return session.requestReferenceSpace({ type: 'identity' }); + // Attempt to get a 'bounded' reference space, which will align the + // user's physical floor with Y=0 and provide boundaries that indicate + // where the user can safely walk. + session.requestReferenceSpace({ type: 'bounded' }).then((refSpace) => { + if (!boundsRenderer) { + boundsRenderer = new BoundsRenderer(refSpace); + scene.addNode(boundsRenderer); } else { - throw e; + boundsRenderer.boundedRefSpace = refSpace; } + return refSpace; + }).catch(() => { + // If a bounded reference space isn't supported, fall back to a + // stationary/floor-level reference space. This still provides a + // floor-relative space and will always be supported for + // immersive sessions. It will not, however, provide boundaries + // and generally expects the user to stand in one place. + // If the device doesn't have a way of determining the floor + // level (for example, with a 3DoF device) then it will return + // an emulated floor-level space, where the view is translated + // up by a static height so that the scene still renders in + // approximately the right place. + console.log('Falling back to floor-level reference space'); + return session.requestReferenceSpace({ type: 'stationary', subtype: 'floor-level' }).catch((e) => { + if (!session.mode.startsWith('immersive')) { + // If we're in inline mode, our underlying platform may not support + // the stationary reference space, but an identity space is guaranteed. + console.log('Falling back to identity reference space'); + return session.requestReferenceSpace({ type: 'identity' }).then((refSpace) => { + // If we use an identity reference space we need to scoot the + // origin down a bit to put the camera at approximately the + // right level. (Here we're moving it 1.6 meters, which should + // *very* roughly align us with the eye height of an "average" + // adult human.) + refSpace.originOffset = new XRRigidTransform({y: -1.6}); + return refSpace; + }); + } else { + throw e; + } + }); }).then((refSpace) => { if (session.mode.startsWith('immersive')) { xrImmersiveRefSpace = refSpace; - let boundsRenderer = new BoundsRenderer(); - boundsRenderer.stageBounds = refSpace.bounds; - scene.addNode(boundsRenderer); } else { xrNonImmersiveRefSpace = refSpace; }
diff --git a/tools/android/generate_java_test/OWNERS b/tools/android/generate_java_test/OWNERS new file mode 100644 index 0000000..73ec257 --- /dev/null +++ b/tools/android/generate_java_test/OWNERS
@@ -0,0 +1 @@ +yzjr@chromium.org
diff --git a/tools/android/generate_java_test/generate_java_test.py b/tools/android/generate_java_test/generate_java_test.py new file mode 100755 index 0000000..250a37e2 --- /dev/null +++ b/tools/android/generate_java_test/generate_java_test.py
@@ -0,0 +1,340 @@ +#!/usr/bin/python +# 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. +''' +This script helps to generate Java instrumentation tests and/or Unit test +(robolectric) for new feature Other than that, it helps to add your source +file (foo.java) and test files (footest.java) to gn (java_sources.gni) +Also, it will generate OWNER file with your ldap@chromium.org if it doesn't exit + +Where to run? +Anywhere in the repo as the tool can find the abstract paths. + +How to run? sample: +If you are building the following example like +"chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java" + +Use command: +python generate_java_test.py --instrumentation --unittest --source \ +"chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java" + -i, --instrumentation generate instrumentation test file + -u, --unittest generate unittest file + Default will generate both of them + -s, --source source file with path [must have] + +What do you get? +- test files created +- gn file updated +- OWNER created + +What do you need to do? +- Write TESTs! + + +''' +from __future__ import print_function + +import argparse +import datetime +import os +import re +import bisect + +# Below sessions are contents for test files +this_year = str(datetime.datetime.now().year) + +_INST_TEST_FILE = '''// Copyright %s The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// generate_java_test.py + +package %s; + +import org.junit.runner.RunWith; + +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.ui.DummyUiActivityTestCase; + +/** Integration tests for %s. */ +@RunWith(ChromeJUnit4ClassRunner.class) +public class %sTest extends DummyUiActivityTestCase { +} +''' + +_UNIT_TEST_FILE = '''// Copyright %s The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// generate_java_test.py + +package %s; + +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; + +/** Unit tests for %s. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class %sUnitTest { +} + +''' + +# End or contents + +# Set root to be "src/" like src/tools/android/gn_java_test/../../../ +root_path = os.path.abspath(os.path.dirname(__file__)) + "/../../../" + +# path of gni files +javatest_gni = os.path.join(root_path, + "chrome/android/chrome_test_java_sources.gni") +junittest_gni = os.path.join( + root_path, "chrome/android/chrome_junit_test_java_sources.gni") + +# Help message if the user use wrong arguments +HELP_MESSAGE = ''' +Wrong --source pattern! Please use the sample below +generate_create_test.py --unittest --source \ +chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java +''' + + +# used for better logging +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + + +def failmsg(s): + return "%s%s%s" % (bcolors.FAIL, s, bcolors.ENDC) + + +def infomsg(s): + return "%s%s%s" % (bcolors.OKBLUE, s, bcolors.ENDC) + + +def warningmsg(s): + return "%s%s%s" % (bcolors.WARNING, s, bcolors.ENDC) + + +# ----------------- APIs and main function are below ----------------------# + + +# Verify if source file exist, return () if it doesn't exist, +# otherwise, return (package_name, file_name) +def GetPackageAndFile(source): + if not os.path.exists(os.path.join(root_path, source)): + print(failmsg("%s%s Does not exist!" % (root_path, source))) + return () +#TODO(yzjr): Will add support for components under chrome/android/features +#crbug/950783 + matchSource = re.match( + "chrome\/android\/java\/src\/" + + "(org\/chromium\/chrome\/browser\/.*\/?)\/(.*)\.java", source) + + if not matchSource: + print(failmsg(HELP_MESSAGE)) + return () + + package_name = matchSource.group(1) + print(infomsg("Package name: %s" % package_name)) + file_name = matchSource.group(2) + print(infomsg("File name: %s" % file_name)) + return (package_name, file_name) + +# Generate java test file , OWNER and modify corresponding GNI +def CreateJavaTestFile(package_path, file_name): + package_name = package_path.replace('/', '.') + + ins_testfile_path = os.path.join(root_path, 'chrome/android/javatests/src/', + package_path) + ins_testfile = os.path.join(ins_testfile_path, file_name + 'Test.java') + print(infomsg("+++ Creating instrumentation_test file: %s" % ins_testfile)) + + if os.path.exists(ins_testfile): + print(warningmsg("%s already exist!\n" % ins_testfile)) + else: + os.makedirs(os.path.dirname(ins_testfile)) + try: + file = open(ins_testfile, "w") + filecontent = _INST_TEST_FILE % (this_year, package_name, file_name, + file_name) + file.write(filecontent) + file.close() + except Exception as e: + print(warningmsg(e.message)) + # Create Owner file if source code OWNERS exists, otherwise skip + source_ownerfile = os.path.join('chrome/android/java/src/', package_path, + 'OWNERS') + if os.path.exists(os.path.join(root_path, source_ownerfile)): + ins_owner = os.path.join(ins_testfile_path, 'OWNERS') + CreateOwnerFile(ins_owner, source_ownerfile) + # Modify GN file + tag = "chrome_test_java_sources" + txt = 'javatests/src/%s/%sTest.java' % (package_path, file_name) + ModifyGnFile(javatest_gni, tag, txt) + + +# Generate junit test file , OWNER and modify corresponding GNI +def CreateJunitTestFile(package_path, file_name): + package_name = package_path.replace('/', '.') + + unit_testfile_path = os.path.join(root_path, 'chrome/android/junit/src/', + package_path) + unit_testfile = os.path.join(unit_testfile_path, file_name + "UnitTest.java") + print(infomsg("+++ Creating unit test file: %s" % unit_testfile)) + + if os.path.exists(unit_testfile): + print(warningmsg("%s already exist!\n" % unit_testfile)) + else: + os.makedirs(os.path.dirname(unit_testfile)) + try: + file = open(unit_testfile, "w") + filecontent = _UNIT_TEST_FILE % (this_year, package_name, file_name, + file_name) + file.write(filecontent) + file.close() + except Exception as e: + print(warningmsg(e.message)) + # Create Owner file if source code OWNERS exists, otherwise skip + source_ownerfile = os.path.join('chrome/android/java/src/', package_path, + 'OWNERS') + if os.path.exists(os.path.join(root_path, source_ownerfile)): + unit_testowner = os.path.join(unit_testfile_path, "OWNERS") + CreateOwnerFile(unit_testowner, source_ownerfile) + # Modify GN file + tag = "chrome_junit_test_java_sources" + txt = 'junit/src/%s/%sUnitTest.java' % (package_path, file_name) + ModifyGnFile(junittest_gni, tag, txt) + +# Create OWNER file if it doesn't exist +def CreateOwnerFile(ownerfile, source_owners): + if os.path.exists(ownerfile): + print(warningmsg("%s already exists!" % ownerfile)) + return + try: + file = open(ownerfile, "w") + file.write("file://" + source_owners) + file.close() + except Exception as e: + print(bcolors.WARNING + e.message + bcolors.ENDC) + +# Modify GN file +def ModifyGnFile(gn_file, tag, txt): + read_lines = [] + filelist = {} + + try: + with open(gn_file) as f: + code = compile(f.read(), "sometempfile.py", 'exec') + exec (code, filelist) + if tag not in filelist: + print(warningmsg("%s is not found\n" % tag)) + return + if txt in filelist[tag]: + print(warningmsg("%s already exists\n" % txt)) + return + + # sorted the list as it might not be sorted from user input + testfiles = sorted(filelist[tag]) + # insert test file to an sorted list + bisect.insort(testfiles, txt) + f.close() + # read file headers with comments or others until tag + with open(gn_file) as f: + for line in f: + stripped = line.strip() + if stripped.startswith(tag): + read_lines.append(line) + for files in testfiles: + read_lines.append(" \"%s\",\n" % files) + # end of tag + read_lines.append(']') + f.close() + with open(gn_file, 'w') as f: + f.write(''.join(read_lines)) + f.close() + except Exception as e: + print(warningmsg("Failed to modify %s because %s" % (gn_file, e.message))) + + +# ******************* Below is main function *********************** +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "-u", "--unittest", help="create unit tests", action="store_true") + parser.add_argument( + "-i", + "--instrumentation", + help="create java instrumentation tests", + action="store_true") + parser.add_argument( + "-s", + "--source", + type=str, + help="source of java code" + + "like chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java", + required=True) + + args = parser.parse_args() + + source_path = GetPackageAndFile(args.source or '') + if not source_path: + exit() + + package_path = source_path[0] + file_name = source_path[1] + + # Add test files to java_sources.gni if they don't exist + ran = False + if args.unittest: + ran = True + CreateJavaTestFile(package_path, file_name) + if args.instrumentation: + ran = True + CreateJunitTestFile(package_path, file_name) + if not ran: # default for both tests + CreateJavaTestFile(package_path, file_name) + CreateJunitTestFile(package_path, file_name) + + +if __name__ == "__main__": + main() +''' + +Test cases for this script: + +* wrong commands * +python generate_java_test.py +python generate_java_test.py -h +python generate_java_test.py --instrumentation +python generate_java_test.py --unittest +python generate_java_test.py --instrumentation --unittest --source\ +"chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java" + +* good commands * +python generate_java_test.py --instrumentation --unittest --source\ +"chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java" +python generate_java_test.py --source\ +"chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java" +python generate_java_test.py --unittest --source\ +"chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java" +python generate_java_test.py --instrumentation --source\ +"chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java" + +* File exists - run twice * +python generate_java_test.py --source\ +"chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java" +python generate_java_test.py --source\ +"chrome/android/java/src/org/chromium/chrome/browser/foo/Foo.java" +'''
diff --git a/tools/chrome_proxy/webdriver/lite_page.py b/tools/chrome_proxy/webdriver/lite_page.py index c9bc029..5c1bf49 100644 --- a/tools/chrome_proxy/webdriver/lite_page.py +++ b/tools/chrome_proxy/webdriver/lite_page.py
@@ -337,6 +337,8 @@ 'NetworkQualityEstimator.Enabled:' 'force_effective_connection_type/2G') test_driver.AddChromeArg( + '--data-reduction-proxy-experiment=force_lite_page') + test_driver.AddChromeArg( '--force-fieldtrials=' 'NetworkQualityEstimator/Enabled/' 'DataReductionProxyPreviewsBlackListTransition/Enabled/')
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 12a060c..ad5b8d8 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -198,7 +198,7 @@ 'Libfuzzer Upload Linux V8-ARM64 ASan Debug': 'libfuzzer_asan_debug_bot_v8_arm64', 'Libfuzzer Upload Linux MSan': 'libfuzzer_msan_release_bot', 'Libfuzzer Upload Linux UBSan': 'libfuzzer_ubsan_release_bot', - 'Libfuzzer Upload Mac ASan': 'libfuzzer_mac_asan_release_bot', + 'Libfuzzer Upload Mac ASan': 'libfuzzer_mac_asan_shared_release_bot', 'Libfuzzer Upload Windows ASan': 'libfuzzer_windows_asan_release_bot', 'MSAN Release (chained origins)': 'msan_release_bot', 'MSAN Release (no origins)': 'msan_no_origins_release_bot', @@ -279,7 +279,7 @@ 'Libfuzzer Upload Linux ASan Debug': 'libfuzzer_asan_debug_bot', 'Libfuzzer Upload Linux MSan': 'libfuzzer_msan_release_bot', 'Libfuzzer Upload Linux UBSan': 'libfuzzer_ubsan_release_bot', - 'Libfuzzer Upload Mac ASan': 'libfuzzer_mac_asan_release_bot', + 'Libfuzzer Upload Mac ASan': 'libfuzzer_mac_asan_shared_release_bot', 'Libfuzzer Upload Windows ASan': 'libfuzzer_windows_asan_release_bot', 'Linux ARM': 'release_bot_arm', 'Linux remote_run Builder': 'release_bot', @@ -1660,8 +1660,8 @@ 'libfuzzer', 'ubsan_security', 'release_bot', 'chromeos_codecs', 'pdf_xfa', 'disable_nacl', 'optimize_for_fuzzing', ], - 'libfuzzer_mac_asan_release_bot': [ - 'libfuzzer', 'asan', 'release_bot', 'chrome_with_codecs', 'pdf_xfa', 'disable_nacl', 'optimize_for_fuzzing', + 'libfuzzer_mac_asan_shared_release_bot': [ + 'libfuzzer', 'asan', 'shared_release_bot', 'chrome_with_codecs', 'pdf_xfa', 'disable_nacl', 'optimize_for_fuzzing', ], # Note that because of optimize_for_fuzzing, Windows cannot share a config
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 5a64aee9..4267bc9 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -8976,6 +8976,9 @@ </enum> <enum name="ContentSuggestionsBreakingNewsMessageAction"> + <obsolete> + Removed 04/2019. Breaking News feature removed. + </obsolete> <int value="0" label="No action"/> <int value="1" label="Invalid action"/> <int value="2" label="Push-by-value"/> @@ -8996,6 +8999,9 @@ </enum> <enum name="ContentSuggestionsBreakingNewsTokenValidationOutcome"> + <obsolete> + Removed 04/2019. Breaking News feature removed. + </obsolete> <int value="0" label="Token invalid"/> <int value="1" label="Token revalidated"/> </enum> @@ -9329,6 +9335,21 @@ <int value="11" label="Misc, Not Seen"/> </enum> +<enum name="ContextualSearchCardTag"> + <int value="0" label="None"/> + <int value="1" label="CT_OTHER"/> + <int value="2" label="CT_HAS_ENTITY"/> + <int value="3" label="CT_BUSINESS"/> + <int value="4" label="CT_PRODUCT"/> + <int value="5" label="CT_CONTACT"/> + <int value="6" label="CT_EMAIL"/> + <int value="7" label="CT_LOCATION"/> + <int value="8" label="CT_URL"/> + <int value="9" label="CT_DEFINITION"/> + <int value="10" label="CT_TRANSLATE"/> + <int value="11" label="CT_CONTEXTUAL_DEFINITION"/> +</enum> + <enum name="ContextualSearchEnterClosedStateChange"> <int value="0" label="From Other"/> <int value="1" label="From Peeked (back press)"/> @@ -45764,6 +45785,8 @@ <int value="2" label="SchemaMetadataMissing"/> <int value="3" label="SchemaMetadataWrongVersion"/> <int value="4" label="ComponentMetadataMissing"/> + <int value="5" label="FetchedMetadataMissing"/> + <int value="6" label="ComponentAndFetchedMetadataMissing"/> </enum> <enum name="PreviewsHintCacheLevelDBStoreStatus">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index ff022a9..848d08f 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -4588,7 +4588,8 @@ <histogram name="Apps.StateTransition.AnimationSmoothness" units="%"> <!-- Name completed by histogram_suffixes name="TabletOrClamshellMode" and - name="EnterOrExitOverview" --> + name="EnterOrExitOverview" and + name="AppListTargetState" --> <owner>newcomer@chromium.org</owner> <summary> @@ -57449,8 +57450,9 @@ Computed based on OS data. - WARNING: Not reliable on Android, see https://crbug.com/875400. Consider - using Memory.RenderProcessHost.Count.* instead. + WARNINGS: Not reliable on Android, see https://crbug.com/875400. Ignores + processes that do not host a widget, see https://crbug.com/949977#c36. + Consider using Memory.RenderProcessHost.Count.* instead. </summary> </histogram> @@ -74756,6 +74758,9 @@ <histogram name="NewTabPage.ContentSuggestions.BreakingNews.ReceivedMessageAction" enum="ContentSuggestionsBreakingNewsMessageAction"> + <obsolete> + Removed 04/2019. Breaking News feature removed. + </obsolete> <owner>mamir@chromium.org</owner> <summary> Android: Action of a received message. An action can be either push-by-value @@ -74767,6 +74772,9 @@ <histogram name="NewTabPage.ContentSuggestions.BreakingNews.SubscriptionRequestStatus" enum="ContentSuggestionsStatusCode"> + <obsolete> + Removed 04/2019. Breaking News feature removed. + </obsolete> <owner>vitaliii@chromium.org</owner> <summary> Android: The result of a subscription request for breaking news at the @@ -74778,6 +74786,9 @@ <histogram name="NewTabPage.ContentSuggestions.BreakingNews.TimeSinceLastTokenValidation" units="ms"> + <obsolete> + Removed 04/2019. Breaking News feature removed. + </obsolete> <owner>vitaliii@chromium.org</owner> <summary> Android: Time between a token validation and the last successful token @@ -74790,6 +74801,9 @@ <histogram name="NewTabPage.ContentSuggestions.BreakingNews.TokenRetrievalResult" enum="InstanceIDResult"> + <obsolete> + Removed 04/2019. Breaking News feature removed. + </obsolete> <owner>vitaliii@chromium.org</owner> <summary> Android: The result of our inquiry to InstanceID to receive the current @@ -74801,6 +74815,9 @@ <histogram name="NewTabPage.ContentSuggestions.BreakingNews.UnsubscriptionRequestStatus" enum="ContentSuggestionsStatusCode"> + <obsolete> + Removed 04/2019. Breaking News feature removed. + </obsolete> <owner>vitaliii@chromium.org</owner> <summary> Android: The result of an unsubscription request for breaking news at the @@ -74812,6 +74829,9 @@ <histogram name="NewTabPage.ContentSuggestions.BreakingNews.WasTokenValidBeforeValidation" enum="ContentSuggestionsBreakingNewsTokenValidationOutcome"> + <obsolete> + Removed 04/2019. Breaking News feature removed. + </obsolete> <owner>vitaliii@chromium.org</owner> <summary> Android: Whether a token validation detected an invalid token. This is @@ -106275,6 +106295,10 @@ <histogram name="SBClientDownload.ZipFileLocalFileHeadersSkipped" units="count" expires_after="M75"> + <obsolete> + Deprecated 04/19. This approach to measuring platform-dependent extraction + does not work, so the data was not useful. + </obsolete> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -108937,6 +108961,17 @@ </summary> </histogram> +<histogram name="Search.ContextualSearch.CardTag" + enum="ContextualSearchCardTag" expires_after="M78"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + The type of card returned in the Search Term Resolution Response from the + server when a search is resolved in response to a Tap gesture that uses + surrounding text to determine the best search. Implemented for Android. + </summary> +</histogram> + <histogram name="Search.ContextualSearch.OutcomesDuration" units="days" expires_after="M75"> <owner>donnd@chromium.org</owner> @@ -142267,6 +142302,17 @@ <affected-histogram name="Apps.AppsInFolders"/> </histogram_suffixes> +<histogram_suffixes name="AppListTargetState" separator="."> + <suffix name="Close.ClamshellMode" label="Closing the app list"/> + <suffix name="FullscreenAllApps.ClamshellMode" + label="Fullscreen and showing all apps"/> + <suffix name="FullscreenSearch.ClamshellMode" + label="Fullscreen with search results"/> + <suffix name="Half.ClamshellMode" label="Half-visible state of the app list"/> + <suffix name="Peeking.ClamshellMode" label="Peek state of the app list"/> + <affected-histogram name="Apps.StateTransition.AnimationSmoothness"/> +</histogram_suffixes> + <histogram_suffixes name="AppUIComponent" separator="."> <suffix name="AppGrid" label="App - Fullscreen Launcher"/> <suffix name="Desktop" label="Desktop"/>
diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml index 4daf41f9..68ad6632 100644 --- a/tools/metrics/rappor/rappor.xml +++ b/tools/metrics/rappor/rappor.xml
@@ -277,6 +277,9 @@ </rappor-metric> <rappor-metric name="BackgroundSync.Register.Origin" type="UMA_RAPPOR_TYPE"> + <obsolete> + No longer being logged. + </obsolete> <owner>jkarlin@chromium.org</owner> <summary> The eTLD+1 of a URL which registered a Background Sync event.
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index cceb961f..21a57a3 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -1061,6 +1061,51 @@ </metric> </event> +<event name="BackgroundSyncCompleted"> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> + <owner>peter@chromium.org</owner> + <summary> + Logged when a Background Sync one-shot registration is completed. + </summary> + <metric name="MaxAttempts"> + <summary> + Integer value of the maximum number of allowed retries. + </summary> + </metric> + <metric name="NumAttempts"> + <summary> + Integer value of the number of retries / sync events dispatched. + </summary> + </metric> + <metric name="Status"> + <summary> + The enum value of the completion status, defined in + blink::ServiceWorkerStatusCode. + </summary> + </metric> +</event> + +<event name="BackgroundSyncRegistered"> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> + <owner>peter@chromium.org</owner> + <summary> + Logged when a one-shot Background Sync registration is created. + </summary> + <metric name="CanFire"> + <summary> + Boolean for whether a sync event can be immediately dispatched for this + registration. + </summary> + </metric> + <metric name="IsReregistered"> + <summary> + Boolean for whether this is a duplicate registration. + </summary> + </metric> +</event> + <event name="Blink.UpdateTime"> <owner>schenney@chromium.org</owner> <summary>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 4c543874..4a8095f 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -125,7 +125,7 @@ <item id="gcm_checkin" hash_code="65957842" type="0" content_hash_code="98259579" os_list="linux,windows" file_path="google_apis/gcm/engine/checkin_request.cc"/> <item id="gcm_connection_factory" hash_code="29057242" type="0" content_hash_code="75279835" os_list="linux,windows" file_path="google_apis/gcm/engine/connection_factory_impl.cc"/> <item id="gcm_registration" hash_code="61656965" type="0" content_hash_code="113670632" os_list="linux,windows" file_path="google_apis/gcm/engine/registration_request.cc"/> - <item id="gcm_subscription" hash_code="56434025" type="0" content_hash_code="61632174" os_list="linux,windows" file_path="components/ntp_snippets/breaking_news/subscription_json_request.cc"/> + <item id="gcm_subscription" hash_code="56434025" type="0" deprecated="2019-04-10" content_hash_code="61632174" file_path=""/> <item id="gcm_unregistration" hash_code="119542033" type="0" content_hash_code="30144127" os_list="linux,windows" file_path="google_apis/gcm/engine/unregistration_request.cc"/> <item id="geo_language_provider" hash_code="52821843" type="1" second_id="96590038" content_hash_code="65327456" os_list="linux,windows" semantics_fields="1" policy_fields="3,4" file_path="components/language/content/browser/geo_language_provider.cc"/> <item id="google_url_tracker" hash_code="5492492" type="0" content_hash_code="54474899" os_list="linux,windows" file_path="components/google/core/browser/google_url_tracker.cc"/>
diff --git a/ui/accessibility/platform/DEPS b/ui/accessibility/platform/DEPS index d457dd7d..301ade0 100644 --- a/ui/accessibility/platform/DEPS +++ b/ui/accessibility/platform/DEPS
@@ -1,5 +1,8 @@ specific_include_rules = { - "atk_util_auralinux_x11.cc": [ + "atk_util_auralinux_x11\.cc": [ "+ui/events/x", + ], + "ax_platform_node_win\.cc": [ + "+skia/ext", ] }
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index 5195d07..78f1e3f 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -290,6 +290,25 @@ return GetData().GetString16Attribute(attribute, value); } +bool AXPlatformNodeBase::HasInheritedStringAttribute( + ax::mojom::StringAttribute attribute) const { + const AXPlatformNodeBase* current_node = this; + + do { + if (!current_node->delegate_) { + return false; + } + + if (current_node->GetData().HasStringAttribute(attribute)) { + return true; + } + + current_node = FromNativeViewAccessible(current_node->GetParent()); + } while (current_node); + + return false; +} + const std::string& AXPlatformNodeBase::GetInheritedStringAttribute( ax::mojom::StringAttribute attribute) const { const AXPlatformNodeBase* current_node = this; @@ -309,11 +328,41 @@ return base::EmptyString(); } -const base::string16 AXPlatformNodeBase::GetInheritedString16Attribute( +base::string16 AXPlatformNodeBase::GetInheritedString16Attribute( ax::mojom::StringAttribute attribute) const { return base::UTF8ToUTF16(GetInheritedStringAttribute(attribute)); } +bool AXPlatformNodeBase::GetInheritedStringAttribute( + ax::mojom::StringAttribute attribute, + std::string* value) const { + const AXPlatformNodeBase* current_node = this; + + do { + if (!current_node->delegate_) { + return false; + } + + if (current_node->GetData().GetStringAttribute(attribute, value)) { + return true; + } + + current_node = FromNativeViewAccessible(current_node->GetParent()); + } while (current_node); + + return false; +} + +bool AXPlatformNodeBase::GetInheritedString16Attribute( + ax::mojom::StringAttribute attribute, + base::string16* value) const { + std::string value_utf8; + if (!GetInheritedStringAttribute(attribute, &value_utf8)) + return false; + *value = base::UTF8ToUTF16(value_utf8); + return true; +} + bool AXPlatformNodeBase::HasIntListAttribute( ax::mojom::IntListAttribute attribute) const { if (!delegate_)
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h index 3cbca68..4c94aaa 100644 --- a/ui/accessibility/platform/ax_platform_node_base.h +++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -100,10 +100,15 @@ base::string16* value) const; base::string16 GetString16Attribute( ax::mojom::StringAttribute attribute) const; + bool HasInheritedStringAttribute(ax::mojom::StringAttribute attribute) const; const std::string& GetInheritedStringAttribute( ax::mojom::StringAttribute attribute) const; - const base::string16 GetInheritedString16Attribute( + base::string16 GetInheritedString16Attribute( ax::mojom::StringAttribute attribute) const; + bool GetInheritedStringAttribute(ax::mojom::StringAttribute attribute, + std::string* value) const; + bool GetInheritedString16Attribute(ax::mojom::StringAttribute attribute, + base::string16* value) const; bool HasIntListAttribute(ax::mojom::IntListAttribute attribute) const; const std::vector<int32_t>& GetIntListAttribute(
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc index 4ce4355..7c85556 100644 --- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -1546,28 +1546,48 @@ text_data.AddIntAttribute(ax::mojom::IntAttribute::kTextStrikethroughStyle, 2); text_data.AddIntAttribute(ax::mojom::IntAttribute::kTextUnderlineStyle, 3); + text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor, + 0xDEADBEEFU); + text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU); + text_data.AddStringAttribute(ax::mojom::StringAttribute::kLanguage, "fr-CA"); + text_data.SetTextDirection(ax::mojom::TextDirection::kRtl); text_data.SetName("some text"); - ui::AXNodeData more_text_data; - more_text_data.id = 3; - more_text_data.role = ax::mojom::Role::kStaticText; - more_text_data.AddState(ax::mojom::State::kInvisible); - more_text_data.SetName("more text"); + ui::AXNodeData heading_data; + heading_data.id = 3; + heading_data.role = ax::mojom::Role::kHeading; + heading_data.AddIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel, 6); + heading_data.child_ids = {4}; + + ui::AXNodeData heading_text_data; + heading_text_data.id = 4; + heading_text_data.role = ax::mojom::Role::kStaticText; + heading_text_data.AddState(ax::mojom::State::kInvisible); + heading_text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor, + 0xDEADBEEFU); + heading_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, + 0xDEADC0DEU); + heading_text_data.SetTextDirection(ax::mojom::TextDirection::kRtl); + heading_text_data.SetName("more text"); ui::AXNodeData mark_data; - mark_data.id = 4; + mark_data.id = 5; mark_data.role = ax::mojom::Role::kMark; - mark_data.child_ids = {5}; + mark_data.child_ids = {6}; ui::AXNodeData mark_text_data; - mark_text_data.id = 5; + mark_text_data.id = 6; mark_text_data.role = ax::mojom::Role::kStaticText; + mark_text_data.AddIntAttribute(ax::mojom::IntAttribute::kBackgroundColor, + 0xDEADBEEFU); + mark_text_data.AddIntAttribute(ax::mojom::IntAttribute::kColor, 0xDEADC0DEU); + mark_text_data.SetTextDirection(ax::mojom::TextDirection::kRtl); mark_text_data.SetName("marked text"); ui::AXNodeData root_data; root_data.id = 1; root_data.role = ax::mojom::Role::kRootWebArea; - root_data.child_ids = {2, 3, 4}; + root_data.child_ids = {2, 3, 5}; ui::AXTreeUpdate update; ui::AXTreeData tree_data; @@ -1577,15 +1597,19 @@ update.root_id = root_data.id; update.nodes.push_back(root_data); update.nodes.push_back(text_data); - update.nodes.push_back(more_text_data); + update.nodes.push_back(heading_data); + update.nodes.push_back(heading_text_data); update.nodes.push_back(mark_data); update.nodes.push_back(mark_text_data); Init(update); AXNodePosition::SetTreeForTesting(tree_.get()); + AXTreeManagerMap::GetInstance().AddTreeManager(tree_data.tree_id, this); AXNode* root_node = GetRootNode(); AXNode* text_node = root_node->children()[0]; + AXNode* heading_node = root_node->children()[1]; + AXNode* heading_text_node = heading_node->children()[0]; AXNode* mark_node = root_node->children()[2]; AXNode* mark_text_node = mark_node->children()[0]; @@ -1593,6 +1617,9 @@ GetTextRangeProviderFromTextNode(document_range_provider, root_node); ComPtr<ITextRangeProvider> text_range_provider; GetTextRangeProviderFromTextNode(text_range_provider, text_node); + ComPtr<ITextRangeProvider> heading_text_range_provider; + GetTextRangeProviderFromTextNode(heading_text_range_provider, + heading_text_node); ComPtr<ITextRangeProvider> mark_text_range_provider; GetTextRangeProviderFromTextNode(mark_text_range_provider, mark_text_node); @@ -1607,6 +1634,26 @@ base::win::ScopedVariant expected_variant; + // SkColor is ARGB, COLORREF is 0BGR + expected_variant.Set(static_cast<int32_t>(0x00EFBEADU)); + EXPECT_UIA_TEXTATTRIBUTE_EQ(text_range_provider, + UIA_BackgroundColorAttributeId, expected_variant); + EXPECT_UIA_TEXTATTRIBUTE_EQ(document_range_provider, + UIA_BackgroundColorAttributeId, expected_variant); + expected_variant.Reset(); + + { + base::win::ScopedVariant lang_variant; + EXPECT_HRESULT_SUCCEEDED(text_range_provider->GetAttributeValue( + UIA_CultureAttributeId, lang_variant.Receive())); + + EXPECT_EQ(lang_variant.type(), VT_I4); + const LCID lcid = V_I4(lang_variant.ptr()); + EXPECT_EQ(LANG_FRENCH, PRIMARYLANGID(lcid)); + EXPECT_EQ(SUBLANG_FRENCH_CANADIAN, SUBLANGID(lcid)); + EXPECT_EQ(SORT_DEFAULT, SORTIDFROMLCID(lcid)); + } + base::string16 font_name = base::UTF8ToUTF16("sans"); expected_variant.Set(SysAllocString(font_name.c_str())); EXPECT_UIA_TEXTATTRIBUTE_EQ(text_range_provider, UIA_FontNameAttributeId, @@ -1618,6 +1665,14 @@ expected_variant); expected_variant.Reset(); + // SkColor is ARGB, COLORREF is 0BGR + expected_variant.Set(static_cast<int32_t>(0x00DEC0ADU)); + EXPECT_UIA_TEXTATTRIBUTE_EQ(text_range_provider, + UIA_ForegroundColorAttributeId, expected_variant); + EXPECT_UIA_TEXTATTRIBUTE_EQ(document_range_provider, + UIA_ForegroundColorAttributeId, expected_variant); + expected_variant.Reset(); + expected_variant.Set(false); EXPECT_UIA_TEXTATTRIBUTE_EQ(text_range_provider, UIA_IsHiddenAttributeId, expected_variant); @@ -1625,7 +1680,6 @@ EXPECT_UIA_TEXTATTRIBUTE_EQ(document_range_provider, UIA_IsHiddenAttributeId, expected_mixed_variant); - expected_variant.Reset(); expected_variant.Set(TextDecorationLineStyle::TextDecorationLineStyle_Dot); EXPECT_UIA_TEXTATTRIBUTE_EQ(text_range_provider, UIA_OverlineStyleAttributeId, @@ -1648,11 +1702,25 @@ expected_variant); expected_variant.Reset(); + expected_variant.Set(static_cast<int32_t>(StyleId_Heading6)); + EXPECT_UIA_TEXTATTRIBUTE_EQ(heading_text_range_provider, + UIA_StyleIdAttributeId, expected_variant); + expected_variant.Reset(); + style_name = base::UTF8ToUTF16("mark"); expected_variant.Set(SysAllocString(style_name.c_str())); EXPECT_UIA_TEXTATTRIBUTE_EQ(mark_text_range_provider, UIA_StyleNameAttributeId, expected_variant); expected_variant.Reset(); + + expected_variant.Set( + static_cast<int32_t>(FlowDirections::FlowDirections_RightToLeft)); + EXPECT_UIA_TEXTATTRIBUTE_EQ( + text_range_provider, UIA_TextFlowDirectionsAttributeId, expected_variant); + EXPECT_UIA_TEXTATTRIBUTE_EQ(document_range_provider, + UIA_TextFlowDirectionsAttributeId, + expected_variant); + expected_variant.Reset(); } TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderSelect) {
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index ffe54e4..308e1ee 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -21,6 +21,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/enum_variant.h" #include "base/win/scoped_variant.h" +#include "skia/ext/skia_utils_win.h" #include "third_party/iaccessible2/ia2_api_all.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/accessibility/accessibility_switches.h" @@ -4032,10 +4033,21 @@ } switch (attribute_id) { + case UIA_BackgroundColorAttributeId: + V_VT(result) = VT_I4; + V_I4(result) = + GetIntAttributeAsCOLORREF(ax::mojom::IntAttribute::kBackgroundColor); + break; + case UIA_CultureAttributeId: + return GetCultureAttributeAsVariant(result); case UIA_FontNameAttributeId: V_VT(result) = VT_BSTR; V_BSTR(result) = GetFontNameAttributeAsBSTR(); break; + case UIA_ForegroundColorAttributeId: + V_VT(result) = VT_I4; + V_I4(result) = GetIntAttributeAsCOLORREF(ax::mojom::IntAttribute::kColor); + break; case UIA_IsHiddenAttributeId: V_VT(result) = VT_BOOL; V_BOOL(result) = IsInvisibleOrIgnored() ? VARIANT_TRUE : VARIANT_FALSE; @@ -4054,11 +4066,20 @@ V_VT(result) = VT_BSTR; V_BSTR(result) = GetStyleNameAttributeAsBSTR(); break; + case UIA_StyleIdAttributeId: + V_VT(result) = VT_I4; + V_I4(result) = ComputeUIAStyleId(); + break; case UIA_UnderlineStyleAttributeId: V_VT(result) = VT_I4; V_I4(result) = GetUIATextDecorationStyle( ax::mojom::IntAttribute::kTextUnderlineStyle); break; + case UIA_TextFlowDirectionsAttributeId: + V_VT(result) = VT_I4; + V_I4(result) = + TextDirectionToFlowDirections(GetData().GetTextDirection()); + break; default: V_VT(result) = VT_UNKNOWN; return ::UiaGetReservedNotSupportedValue(&V_UNKNOWN(result)); @@ -4067,6 +4088,96 @@ return S_OK; } +HRESULT AXPlatformNodeWin::GetCultureAttributeAsVariant(VARIANT* result) const { + const base::string16 language = + GetInheritedString16Attribute(ax::mojom::StringAttribute::kLanguage); + const LCID lcid = + LocaleNameToLCID(language.c_str(), LOCALE_ALLOW_NEUTRAL_NAMES); + if (!lcid) + return E_FAIL; + + V_VT(result) = VT_I4; + V_I4(result) = lcid; + return S_OK; +} + +COLORREF AXPlatformNodeWin::GetIntAttributeAsCOLORREF( + ax::mojom::IntAttribute attribute) const { + const SkColor color = GetIntAttribute(attribute); + return skia::SkColorToCOLORREF(color); +} + +LONG AXPlatformNodeWin::ComputeUIAStyleId() const { + const AXPlatformNodeBase* current_node = this; + do { + switch (current_node->GetData().role) { + case ax::mojom::Role::kHeading: + return AXHierarchicalLevelToUIAStyleId(current_node->GetIntAttribute( + ax::mojom::IntAttribute::kHierarchicalLevel)); + case ax::mojom::Role::kListItem: + // TODO: In a following change, introduce enum ax::mojom::ListStyle, + // then return either |StyleId_NumberedList| or |StyleId_BulletedList|. + // The enum will also be used to implement UIA_BulletStyleAttributeId. + break; + case ax::mojom::Role::kMark: + return StyleId_Custom; + case ax::mojom::Role::kBlockquote: + return StyleId_Quote; + default: + break; + } + current_node = FromNativeViewAccessible(current_node->GetParent()); + } while (current_node); + + return StyleId_Normal; +} + +// static +LONG AXPlatformNodeWin::AXHierarchicalLevelToUIAStyleId( + int32_t hierarchical_level) { + switch (hierarchical_level) { + case 0: + return StyleId_Normal; + case 1: + return StyleId_Heading1; + case 2: + return StyleId_Heading2; + case 3: + return StyleId_Heading3; + case 4: + return StyleId_Heading4; + case 5: + return StyleId_Heading5; + case 6: + return StyleId_Heading6; + case 7: + return StyleId_Heading7; + case 8: + return StyleId_Heading8; + case 9: + return StyleId_Heading9; + default: + return StyleId_Custom; + } +} + +// static +FlowDirections AXPlatformNodeWin::TextDirectionToFlowDirections( + ax::mojom::TextDirection text_direction) { + switch (text_direction) { + case ax::mojom::TextDirection::kNone: + return FlowDirections::FlowDirections_Default; + case ax::mojom::TextDirection::kLtr: + return FlowDirections::FlowDirections_Default; + case ax::mojom::TextDirection::kRtl: + return FlowDirections::FlowDirections_RightToLeft; + case ax::mojom::TextDirection::kTtb: + return FlowDirections::FlowDirections_Vertical; + case ax::mojom::TextDirection::kBtt: + return FlowDirections::FlowDirections_BottomToTop; + } +} + // IRawElementProviderSimple support methods. bool AXPlatformNodeWin::IsPatternProviderSupported(PATTERNID pattern_id) {
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h index 7efa9ec..fb243c264 100644 --- a/ui/accessibility/platform/ax_platform_node_win.h +++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -996,7 +996,6 @@ REFIID riid, void** object) override; - public: // Support method for ITextRangeProvider::GetAttributeValue HRESULT GetTextAttributeValue(TEXTATTRIBUTEID attribute_id, VARIANT* result); @@ -1197,6 +1196,21 @@ // Helper method for mutating the ISelectionItemProvider selected state HRESULT ISelectionItemProviderSetSelected(bool selected); + // + // Getters for UIA GetTextAttributeValue + // + + // Lookup the LCID for the language this node is using + HRESULT GetCultureAttributeAsVariant(VARIANT* result) const; + // Converts an int attribute to a COLORREF + COLORREF GetIntAttributeAsCOLORREF(ax::mojom::IntAttribute attribute) const; + // Helper to get the UIA StyleId enumeration for this node + LONG ComputeUIAStyleId() const; + // Converts IntAttribute::kHierarchicalLevel to UIA StyleId enumeration + static LONG AXHierarchicalLevelToUIAStyleId(int32_t hierarchical_level); + // Convert mojom TextDirection to UIA FlowDirections enumeration + static FlowDirections TextDirectionToFlowDirections(ax::mojom::TextDirection); + bool IsAncestorComboBox(); // Helper method for getting the horizontal scroll percent.
diff --git a/ui/webui/resources/cr_polymer_resources.grdp b/ui/webui/resources/cr_polymer_resources.grdp index a3a9519..8ec07eb4a 100644 --- a/ui/webui/resources/cr_polymer_resources.grdp +++ b/ui/webui/resources/cr_polymer_resources.grdp
@@ -6,6 +6,9 @@ <structure name="IDR_WEBUI_HTML_ACTION_LINK_CSS" file="html/action_link_css.html" type="chrome_html" compress="gzip" /> + <structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_ROW_BEHAVIOR" + file="html/cr/ui/focus_row_behavior.html" type="chrome_html" + compress="gzip" /> <structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_WITHOUT_INK" file="html/cr/ui/focus_without_ink.html" type="chrome_html" compress="gzip" /> @@ -38,6 +41,9 @@ <structure name="IDR_WEBUI_JS_I18N_BEHAVIOR" file="js/i18n_behavior.js" type="chrome_html" compress="gzip" /> + <structure name="IDR_WEBUI_JS_CR_UI_FOCUS_ROW_BEHAVIOR" + file="js/cr/ui/focus_row_behavior.js" type="chrome_html" + compress="gzip" /> <structure name="IDR_WEBUI_JS_CR_UI_FOCUS_WITHOUT_INK" file="js/cr/ui/focus_without_ink.js" type="chrome_html" compress="gzip" />
diff --git a/ui/webui/resources/webui_resources.grd b/ui/webui/resources/webui_resources.grd index e9b4dbbd..c1125ae 100644 --- a/ui/webui/resources/webui_resources.grd +++ b/ui/webui/resources/webui_resources.grd
@@ -312,9 +312,6 @@ <structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_ROW" file="html/cr/ui/focus_row.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_HTML_CR_UI_FOCUS_ROW_BEHAVIOR" - file="html/cr/ui/focus_row_behavior.html" type="chrome_html" - compress="gzip" /> <structure name="IDR_WEBUI_HTML_CR_UI_LIST" file="html/cr/ui/list.html" type="chrome_html" compress="gzip" /> @@ -429,9 +426,6 @@ <structure name="IDR_WEBUI_JS_CR_UI_FOCUS_ROW" file="js/cr/ui/focus_row.js" type="chrome_html" compress="gzip" /> - <structure name="IDR_WEBUI_JS_CR_UI_FOCUS_ROW_BEHAVIOR" - file="js/cr/ui/focus_row_behavior.js" type="chrome_html" - compress="gzip" /> <structure name="IDR_WEBUI_JS_CR_UI_LIST" file="js/cr/ui/list.js" type="chrome_html" compress="gzip" /> <structure name="IDR_WEBUI_JS_CR_UI_LIST_ITEM"