diff --git a/DEPS b/DEPS index 289b0748..bd7999e 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # 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': '60c05f98aa22d89e4ef25acb4799936f5df3cff2', + 'skia_revision': 'e305cc1f2a44e47d6a0dcc0ff34e2692349aed5d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '1d6a302d9693e0e1fa2eb029fa82347609f1e57c', + 'v8_revision': '285b9f5a26decb9cc11e14e2101ed707a321b542', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -52,7 +52,7 @@ # 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': 'c31b7411af0b804650744dba97de7d86e1a959f2', + 'angle_revision': 'd9671226c7ddc129173d0558ae8862352fb5a277', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'a9caab94c1f16929e5acf2676117224617d80f53', + 'pdfium_revision': '0d73909e89a5c93917b9cb73fe5c03c484f2793d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'c78686903901261433d5abf72d94f0052524b5c7', + 'catapult_revision': '6a5ce5c1dff46439e735135316e21b7355dde479', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/ash/common/shelf/app_list_shelf_item_delegate.cc b/ash/common/shelf/app_list_shelf_item_delegate.cc index 7f7c3db7..e56cf5c 100644 --- a/ash/common/shelf/app_list_shelf_item_delegate.cc +++ b/ash/common/shelf/app_list_shelf_item_delegate.cc
@@ -55,10 +55,6 @@ return NULL; } -bool AppListShelfItemDelegate::IsDraggable() { - return false; -} - bool AppListShelfItemDelegate::CanPin() const { return true; }
diff --git a/ash/common/shelf/app_list_shelf_item_delegate.h b/ash/common/shelf/app_list_shelf_item_delegate.h index f46289f..04520e7d 100644 --- a/ash/common/shelf/app_list_shelf_item_delegate.h +++ b/ash/common/shelf/app_list_shelf_item_delegate.h
@@ -26,7 +26,6 @@ const ui::Event& event) override; base::string16 GetTitle() override; ShelfMenuModel* CreateApplicationMenu(int event_flags) override; - bool IsDraggable() override; bool CanPin() const override; void Close() override;
diff --git a/ash/common/shelf/shelf_controller.cc b/ash/common/shelf/shelf_controller.cc index ecc96e2..a027b98 100644 --- a/ash/common/shelf/shelf_controller.cc +++ b/ash/common/shelf/shelf_controller.cc
@@ -114,11 +114,6 @@ return new ShelfMenuModelMus(this); } - bool IsDraggable() override { - NOTIMPLEMENTED(); - return false; - } - void Close() override { NOTIMPLEMENTED(); } mojom::ShelfItemDelegateAssociatedPtr delegate_;
diff --git a/ash/common/shelf/shelf_item_delegate.h b/ash/common/shelf/shelf_item_delegate.h index 8cd6c11..ab13a83 100644 --- a/ash/common/shelf/shelf_item_delegate.h +++ b/ash/common/shelf/shelf_item_delegate.h
@@ -63,9 +63,6 @@ // |event_flags| specifies the flags of the event which triggered this menu. virtual ShelfMenuModel* CreateApplicationMenu(int event_flags) = 0; - // Whether the launcher item is draggable. - virtual bool IsDraggable() = 0; - // Closes all windows associated with this item. virtual void Close() = 0; };
diff --git a/ash/common/shelf/shelf_view.cc b/ash/common/shelf/shelf_view.cc index 311b498f..f85e154 100644 --- a/ash/common/shelf/shelf_view.cc +++ b/ash/common/shelf/shelf_view.cc
@@ -798,9 +798,7 @@ if (index == -1 || view_model_->view_size() <= 1) return; // View is being deleted, ignore request. - ShelfItemDelegate* item_delegate = - model_->GetShelfItemDelegate(model_->items()[index].id); - if (!item_delegate->IsDraggable()) + if (view == GetAppListButton()) return; // View is not draggable, ignore request. // Only when the repost event occurs on the same shelf item, we should ignore @@ -1104,14 +1102,6 @@ return; } - // If the item is no longer draggable, bail out. - ShelfItemDelegate* item_delegate = - model_->GetShelfItemDelegate(model_->items()[start_drag_index_].id); - if (!item_delegate->IsDraggable()) { - CancelDrag(-1); - return; - } - // Move the view to the front so that it appears on top of other views. ReorderChildView(drag_view_, -1); bounds_animator_->StopAnimatingView(drag_view_); @@ -1120,18 +1110,13 @@ } void ShelfView::ContinueDrag(const ui::LocatedEvent& event) { + DCHECK(dragging()); + DCHECK(drag_view_); // Due to a syncing operation the application might have been removed. // Bail if it is gone. int current_index = view_model_->GetIndexOfView(drag_view_); DCHECK_NE(-1, current_index); - ShelfItemDelegate* item_delegate = - model_->GetShelfItemDelegate(model_->items()[current_index].id); - if (!item_delegate->IsDraggable()) { - CancelDrag(-1); - return; - } - // If this is not a drag and drop host operation and not the app list item, // check if the item got ripped off the shelf - if it did we are done. if (!drag_and_drop_shelf_id_ && @@ -1184,14 +1169,11 @@ target_index = std::min(indices.second, std::max(target_index, indices.first)); - int first_draggable_item = 0; - while (first_draggable_item < static_cast<int>(model_->items().size()) && - !model_->GetShelfItemDelegate(model_->items()[first_draggable_item].id) - ->IsDraggable()) { - first_draggable_item++; - } - + // The app list button is always first, and it is the only non-draggable item. + int first_draggable_item = model_->GetItemIndexForType(TYPE_APP_LIST) + 1; + DCHECK_EQ(1, first_draggable_item); target_index = std::max(target_index, first_draggable_item); + DCHECK_LT(target_index, model_->item_count()); if (target_index == current_index) return;
diff --git a/ash/common/shelf/shelf_window_watcher.cc b/ash/common/shelf/shelf_window_watcher.cc index 92bfe9a1..b4087c2 100644 --- a/ash/common/shelf/shelf_window_watcher.cc +++ b/ash/common/shelf/shelf_window_watcher.cc
@@ -100,6 +100,11 @@ void ShelfWindowWatcher::UserWindowObserver::OnWindowVisibilityChanged( WmWindow* window, bool visible) { + // OnWindowVisibilityChanged() is called for descendants too. We only care + // about changes to the visibility of windows we know about. + if (!window_watcher_->observed_user_windows_.IsObserving(window)) + return; + // The tooltip behavior for panel windows depends on the panel visibility. window_watcher_->OnUserWindowPropertyChanged(window); }
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.cc b/ash/common/shelf/shelf_window_watcher_item_delegate.cc index d0679cc..844a3b8 100644 --- a/ash/common/shelf/shelf_window_watcher_item_delegate.cc +++ b/ash/common/shelf/shelf_window_watcher_item_delegate.cc
@@ -64,10 +64,6 @@ return nullptr; } -bool ShelfWindowWatcherItemDelegate::IsDraggable() { - return true; -} - bool ShelfWindowWatcherItemDelegate::CanPin() const { return GetShelfItemType(id_) != TYPE_APP_PANEL; }
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.h b/ash/common/shelf/shelf_window_watcher_item_delegate.h index edb0afb..d1049bbe 100644 --- a/ash/common/shelf/shelf_window_watcher_item_delegate.h +++ b/ash/common/shelf/shelf_window_watcher_item_delegate.h
@@ -25,7 +25,6 @@ const ui::Event& event) override; base::string16 GetTitle() override; ShelfMenuModel* CreateApplicationMenu(int event_flags) override; - bool IsDraggable() override; bool CanPin() const override; void Close() override;
diff --git a/ash/common/shelf/shelf_window_watcher_unittest.cc b/ash/common/shelf/shelf_window_watcher_unittest.cc index 6e772bc..1a8e5ce 100644 --- a/ash/common/shelf/shelf_window_watcher_unittest.cc +++ b/ash/common/shelf/shelf_window_watcher_unittest.cc
@@ -307,4 +307,30 @@ EXPECT_EQ(1, model_->item_count()); } +TEST_F(ShelfWindowWatcherTest, DontCreateShelfEntriesForChildWindows) { + const int initial_item_count = model_->item_count(); + + WmWindow* window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, + ui::LAYER_NOT_DRAWN); + window->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_APP); + WmShell::Get() + ->GetPrimaryRootWindow() + ->GetChildByShellWindowId(kShellWindowId_DefaultContainer) + ->AddChild(window); + window->Show(); + EXPECT_EQ(initial_item_count + 1, model_->item_count()); + + WmWindow* child_window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, + ui::LAYER_NOT_DRAWN); + child_window->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_APP); + window->AddChild(child_window); + child_window->Show(); + // |child_window| should not result in adding a new entry. + EXPECT_EQ(initial_item_count + 1, model_->item_count()); + + child_window->Destroy(); + window->Destroy(); + EXPECT_EQ(initial_item_count, model_->item_count()); +} + } // namespace ash
diff --git a/ash/common/system/chromeos/network/network_state_list_detailed_view.cc b/ash/common/system/chromeos/network/network_state_list_detailed_view.cc index 699caa6..05ce6f1 100644 --- a/ash/common/system/chromeos/network/network_state_list_detailed_view.cc +++ b/ash/common/system/chromeos/network/network_state_list_detailed_view.cc
@@ -497,7 +497,6 @@ : UMA_STATUS_AREA_CONNECT_TO_CONFIGURED_NETWORK); chromeos::NetworkConnect::Get()->ConnectToNetworkId(network->guid()); } - owner()->system_tray()->CloseSystemBubble(); } void NetworkStateListDetailedView::CreateExtraTitleRowButtons() {
diff --git a/ash/common/system/chromeos/network/vpn_list_view.cc b/ash/common/system/chromeos/network/vpn_list_view.cc index a66d03ca..6dccf46 100644 --- a/ash/common/system/chromeos/network/vpn_list_view.cc +++ b/ash/common/system/chromeos/network/vpn_list_view.cc
@@ -18,6 +18,7 @@ #include "ash/common/system/tray/hover_highlight_view.h" #include "ash/common/system/tray/system_menu_button.h" #include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/throbber_view.h" #include "ash/common/system/tray/tray_constants.h" #include "ash/common/system/tray/tray_popup_label_button.h" #include "ash/common/system/tray/tray_popup_utils.h" @@ -193,6 +194,10 @@ }; void UpdateFromNetworkState(const chromeos::NetworkState* network); + void SetupConnectedItemMd(const base::string16& text, + const gfx::ImageSkia& image); + void SetupConnectingItemMd(const base::string16& text, + const gfx::ImageSkia& image); const std::string service_path_; @@ -282,16 +287,22 @@ // the network list in the UI has not been updated yet. return; } - RemoveAllChildViews(true); disconnect_button_ = nullptr; - AddIconAndLabel( - network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST), - network_icon::GetLabelForNetwork(network, network_icon::ICON_TYPE_LIST), - IsConnectedOrConnecting(network)); - if (IsConnectedOrConnecting(network)) { - if (UseMd()) { + gfx::ImageSkia image = + network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST); + base::string16 label = + network_icon::GetLabelForNetwork(network, network_icon::ICON_TYPE_LIST); + if (UseMd()) { + if (network->IsConnectedState()) + SetupConnectedItemMd(label, image); + else if (network->IsConnectingState()) + SetupConnectingItemMd(label, image); + else + AddIconAndLabel(image, label, false); + + if (network->IsConnectedState()) { disconnect_button_ = TrayPopupUtils::CreateTrayPopupButton( this, l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECT)); tri_view()->AddView(TriView::Container::END, disconnect_button_); @@ -299,17 +310,16 @@ tri_view()->SetContainerBorder( TriView::Container::END, views::CreateEmptyBorder(0, 0, 0, kTrayPopupButtonEndMargin)); - } else { + } + } else { + AddIconAndLabel(image, label, IsConnectedOrConnecting(network)); + if (IsConnectedOrConnecting(network)) { disconnect_button_ = new DisconnectButton(this); AddChildView(disconnect_button_); SetBorder(views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 3)); - } - } else { - if (!UseMd()) + } else { SetBorder(views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0)); - } - - if (!UseMd()) { + } // The icon and the disconnect button are always set to their preferred // size. All remaining space is used for the network name. views::BoxLayout* layout = new views::BoxLayout( @@ -321,6 +331,28 @@ Layout(); } +// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. +void VPNListNetworkEntry::SetupConnectedItemMd(const base::string16& text, + const gfx::ImageSkia& image) { + AddIconAndLabels( + image, text, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED)); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::CAPTION); + style.set_color_style(TrayPopupItemStyle::ColorStyle::CONNECTED); + style.SetupLabel(sub_text_label()); +} + +// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. +void VPNListNetworkEntry::SetupConnectingItemMd(const base::string16& text, + const gfx::ImageSkia& image) { + AddIconAndLabels( + image, text, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING)); + ThrobberView* throbber = new ThrobberView; + throbber->Start(); + AddRightView(throbber); +} + } // namespace VPNListView::VPNListView(NetworkListDelegate* delegate) : delegate_(delegate) {
diff --git a/ash/common/test/test_shelf_item_delegate.cc b/ash/common/test/test_shelf_item_delegate.cc index 985a705f..e7d9cca2 100644 --- a/ash/common/test/test_shelf_item_delegate.cc +++ b/ash/common/test/test_shelf_item_delegate.cc
@@ -10,7 +10,7 @@ namespace test { TestShelfItemDelegate::TestShelfItemDelegate(WmWindow* window) - : window_(window), is_draggable_(true) {} + : window_(window) {} TestShelfItemDelegate::~TestShelfItemDelegate() {} @@ -34,10 +34,6 @@ return nullptr; } -bool TestShelfItemDelegate::IsDraggable() { - return is_draggable_; -} - bool TestShelfItemDelegate::CanPin() const { return true; }
diff --git a/ash/common/test/test_shelf_item_delegate.h b/ash/common/test/test_shelf_item_delegate.h index 8eb7564..dac15e1 100644 --- a/ash/common/test/test_shelf_item_delegate.h +++ b/ash/common/test/test_shelf_item_delegate.h
@@ -21,22 +21,17 @@ explicit TestShelfItemDelegate(WmWindow* window); ~TestShelfItemDelegate() override; - void set_is_draggable(bool is_draggable) { is_draggable_ = is_draggable; } - // ShelfItemDelegate: ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; base::string16 GetTitle() override; ShelfMenuModel* CreateApplicationMenu(int event_flags) override; - bool IsDraggable() override; bool CanPin() const override; void Close() override; private: WmWindow* window_; - bool is_draggable_; - DISALLOW_COPY_AND_ASSIGN(TestShelfItemDelegate); };
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index 3f4fc96..d5be149 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -439,13 +439,23 @@ } } + // Simulate a mouse press event on the shelf's view at |view_index|. + views::View* SimulateViewPressed(ShelfView::Pointer pointer, int view_index) { + views::View* view = test_api_->GetViewAt(view_index); + ui::MouseEvent pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(), + view->GetBoundsInScreen().origin(), + ui::EventTimeForNow(), 0, 0); + shelf_view_->PointerPressedOnButton(view, pointer, pressed_event); + return view; + } + + // Similar to SimulateViewPressed, but the index must not be for the app list, + // since the app list button is not a ShelfButton. ShelfButton* SimulateButtonPressed(ShelfView::Pointer pointer, int button_index) { + EXPECT_NE(TYPE_APP_LIST, model_->items()[button_index].type); ShelfButton* button = test_api_->GetButton(button_index); - ui::MouseEvent click_event(ui::ET_MOUSE_PRESSED, gfx::Point(), - button->GetBoundsInScreen().origin(), - ui::EventTimeForNow(), 0, 0); - shelf_view_->PointerPressedOnButton(button, pointer, click_event); + EXPECT_EQ(button, SimulateViewPressed(pointer, button_index)); return button; } @@ -496,8 +506,8 @@ int from_index, int to_index, bool progressively) { - views::View* to = test_api_->GetButton(to_index); - views::View* from = test_api_->GetButton(from_index); + views::View* to = test_api_->GetViewAt(to_index); + views::View* from = test_api_->GetViewAt(from_index); int dist_x = to->x() - from->x(); int dist_y = to->y() - from->y(); if (progressively) { @@ -520,7 +530,7 @@ int button_index, int destination_index, bool progressively) { - views::View* button = SimulateButtonPressed(pointer, button_index); + views::View* button = SimulateViewPressed(pointer, button_index); if (!progressively) { ContinueDrag(button, pointer, button_index, destination_index, false); @@ -1165,26 +1175,30 @@ ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); } -// Check that whether the ash behaves correctly if not draggable -// item are in front of the shelf. +// Ensure the app list button cannot be dragged and other items cannot be +// dragged in front of the app list button. TEST_F(ShelfViewTest, DragWithNotDraggableItemInFront) { + // The expected id order is initialized as: 1, 2, 3, 4, 5, 6, 7 std::vector<std::pair<ShelfID, views::View*>> id_map; SetupForDragTest(&id_map); + ASSERT_EQ(TYPE_APP_LIST, model_->items()[0].type); - (static_cast<TestShelfItemDelegate*>( - model_->GetShelfItemDelegate(id_map[1].first))) - ->set_is_draggable(false); - (static_cast<TestShelfItemDelegate*>( - model_->GetShelfItemDelegate(id_map[2].first))) - ->set_is_draggable(false); + // Ensure that the app list button cannot be dragged. + // The expected id order is unchanged: 1, 2, 3, 4, 5, 6, 7 + ASSERT_NO_FATAL_FAILURE(DragAndVerify(0, 1, shelf_view_, id_map)); + ASSERT_NO_FATAL_FAILURE(DragAndVerify(0, 2, shelf_view_, id_map)); + ASSERT_NO_FATAL_FAILURE(DragAndVerify(0, 5, shelf_view_, id_map)); - ASSERT_NO_FATAL_FAILURE(DragAndVerify(3, 1, shelf_view_, id_map)); - ASSERT_NO_FATAL_FAILURE(DragAndVerify(3, 2, shelf_view_, id_map)); - - std::rotate(id_map.begin() + 3, id_map.begin() + 4, id_map.begin() + 5); - ASSERT_NO_FATAL_FAILURE(DragAndVerify(4, 1, shelf_view_, id_map)); - std::rotate(id_map.begin() + 3, id_map.begin() + 5, id_map.begin() + 6); - ASSERT_NO_FATAL_FAILURE(DragAndVerify(5, 1, shelf_view_, id_map)); + // Ensure that items cannot be dragged in front of the app list button. + // Attempting to do so will order buttons immediately after the app list. + // Dragging the second button in front should no-op: 1, 2, 3, 4, 5, 6, 7 + ASSERT_NO_FATAL_FAILURE(DragAndVerify(1, 0, shelf_view_, id_map)); + // Dragging the third button in front should yield: 1, 3, 2, 4, 5, 6, 7 + std::rotate(id_map.begin() + 1, id_map.begin() + 2, id_map.begin() + 3); + ASSERT_NO_FATAL_FAILURE(DragAndVerify(2, 0, shelf_view_, id_map)); + // Dragging the sixth button in front should yield: 1, 6, 3, 2, 4, 5, 7 + std::rotate(id_map.begin() + 1, id_map.begin() + 5, id_map.begin() + 6); + ASSERT_NO_FATAL_FAILURE(DragAndVerify(5, 0, shelf_view_, id_map)); } // Check that clicking first on one item and then dragging another works as
diff --git a/ash/shell/window_watcher_shelf_item_delegate.cc b/ash/shell/window_watcher_shelf_item_delegate.cc index 9ac9c15b..1a73dea7 100644 --- a/ash/shell/window_watcher_shelf_item_delegate.cc +++ b/ash/shell/window_watcher_shelf_item_delegate.cc
@@ -40,10 +40,6 @@ return nullptr; } -bool WindowWatcherShelfItemDelegate::IsDraggable() { - return true; -} - bool WindowWatcherShelfItemDelegate::CanPin() const { return true; }
diff --git a/ash/shell/window_watcher_shelf_item_delegate.h b/ash/shell/window_watcher_shelf_item_delegate.h index 8c713861..879e95f 100644 --- a/ash/shell/window_watcher_shelf_item_delegate.h +++ b/ash/shell/window_watcher_shelf_item_delegate.h
@@ -26,7 +26,6 @@ const ui::Event& event) override; base::string16 GetTitle() override; ShelfMenuModel* CreateApplicationMenu(int event_flags) override; - bool IsDraggable() override; bool CanPin() const override; void Close() override;
diff --git a/ash/test/shelf_view_test_api.cc b/ash/test/shelf_view_test_api.cc index c9ff178c..92afe5db 100644 --- a/ash/test/shelf_view_test_api.cc +++ b/ash/test/shelf_view_test_api.cc
@@ -50,9 +50,13 @@ ShelfButton* ShelfViewTestAPI::GetButton(int index) { // App list button is not a ShelfButton. if (shelf_view_->model_->items()[index].type == ash::TYPE_APP_LIST) - return NULL; + return nullptr; - return static_cast<ShelfButton*>(shelf_view_->view_model_->view_at(index)); + return static_cast<ShelfButton*>(GetViewAt(index)); +} + +views::View* ShelfViewTestAPI::GetViewAt(int index) { + return shelf_view_->view_model_->view_at(index); } int ShelfViewTestAPI::GetFirstVisibleIndex() {
diff --git a/ash/test/shelf_view_test_api.h b/ash/test/shelf_view_test_api.h index 52aa27a..b32121f 100644 --- a/ash/test/shelf_view_test_api.h +++ b/ash/test/shelf_view_test_api.h
@@ -5,7 +5,6 @@ #ifndef ASH_TEST_SHELF_VIEW_TEST_API_H_ #define ASH_TEST_SHELF_VIEW_TEST_API_H_ -#include "ash/common/shelf/shelf_item_delegate.h" #include "ash/common/shelf/shelf_item_types.h" #include "base/macros.h" @@ -21,6 +20,7 @@ namespace views { class Button; class InkDrop; +class View; } namespace ash { @@ -43,9 +43,13 @@ // Number of icons displayed. int GetButtonCount(); - // Retrieve the button at |index|. + // Retrieve the button at |index|, doesn't support the app list button, + // because the app list button is not a ShelfButton. ShelfButton* GetButton(int index); + // Retrieve the view at |index|. + views::View* GetViewAt(int index); + // First visible button index. int GetFirstVisibleIndex();
diff --git a/base/BUILD.gn b/base/BUILD.gn index 244aec4..0c4b35fa 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1235,16 +1235,18 @@ "synchronization/read_write_lock_nacl.cc", ] - # Add stuff that doesn't work in NaCl. - sources += [ - # PartitionAlloc uses SpinLock, which doesn't work in NaCl (see below). - "allocator/partition_allocator/address_space_randomization.cc", - "allocator/partition_allocator/address_space_randomization.h", - "allocator/partition_allocator/page_allocator.cc", - "allocator/partition_allocator/page_allocator.h", - "allocator/partition_allocator/partition_alloc.cc", - "allocator/partition_allocator/partition_alloc.h", - ] + if (!is_ios) { + # Add stuff that doesn't work in NaCl. + sources += [ + # PartitionAlloc uses SpinLock, which doesn't work in NaCl (see below). + "allocator/partition_allocator/address_space_randomization.cc", + "allocator/partition_allocator/address_space_randomization.h", + "allocator/partition_allocator/page_allocator.cc", + "allocator/partition_allocator/page_allocator.h", + "allocator/partition_allocator/partition_alloc.cc", + "allocator/partition_allocator/partition_alloc.h", + ] + } } # SpinLock uses inline assembly that doesn't work on NaCl, and for which there @@ -1807,7 +1809,6 @@ test("base_unittests") { sources = [ - "allocator/partition_allocator/partition_alloc_unittest.cc", "allocator/tcmalloc_unittest.cc", "android/application_status_listener_unittest.cc", "android/content_uri_utils_unittest.cc", @@ -2171,6 +2172,8 @@ set_sources_assignment_filter(sources_assignment_filter) # TODO(GYP): dep on copy_test_data_ios action. + } else { + sources += [ "allocator/partition_allocator/partition_alloc_unittest.cc" ] } if (is_mac) {
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni index df12be9..13b4506 100644 --- a/build/config/compiler/compiler.gni +++ b/build/config/compiler/compiler.gni
@@ -44,6 +44,20 @@ # Whether or not we should turn on incremental WPO. Only affects the VS # Windows build. use_incremental_wpo = false + + # Root directory that will store the MSVC link repro. This should only be + # used for debugging purposes on the builders where a MSVC linker flakyness + # has been observed. The targets for which a link repro should be generated + # should add somethink like this to their configuration: + # if (linkrepro_root_dir != "") { + # ldflags = ["/LINKREPRO:" + linkrepro_root_dir + "/" + target_name] + # } + # + # Note that doing a link repro uses a lot of disk space and slows down the + # build, so this shouldn't be enabled on too many targets. + # + # See crbug.com/669854. + linkrepro_root_dir = "" } declare_args() {
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn index 10e617b..8efa40c 100644 --- a/build/toolchain/win/BUILD.gn +++ b/build/toolchain/win/BUILD.gn
@@ -272,6 +272,16 @@ command = "cmd /c $python_path $tool_wrapper_path delete-file $pdbname && $command" } + if (linkrepro_root_dir != "") { + # Create the directory that will receive the link repro for this target + # if needed. Note that this will create one directory per link target + # even if this target doesn't generate a link repro. This is necessary + # because the linker doesn't generate the directory specified to the + # /LINKREPRO flag if it doesn't exist. + linkrepro_dir = "$linkrepro_root_dir\\{{target_output_name}}" + command = "cmd /c mkdir $linkrepro_dir && $command" + } + default_output_extension = ".exe" default_output_dir = "{{root_out_dir}}" description = "LINK {{output}}"
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc index b94d1464..defa0ba 100644 --- a/cc/blink/web_display_item_list_impl.cc +++ b/cc/blink/web_display_item_list_impl.cc
@@ -71,10 +71,9 @@ } void WebDisplayItemListImpl::appendClipPathItem(const SkPath& clip_path, - SkClipOp clip_op, bool antialias) { display_item_list_->CreateAndAppendPairedBeginItem<cc::ClipPathDisplayItem>( - clip_path, clip_op, antialias); + clip_path, antialias); } void WebDisplayItemListImpl::appendEndClipPathItem() {
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h index 9ef08b0e9..e97ee45 100644 --- a/cc/blink/web_display_item_list_impl.h +++ b/cc/blink/web_display_item_list_impl.h
@@ -12,7 +12,6 @@ #include "third_party/WebKit/public/platform/WebDisplayItemList.h" #include "third_party/WebKit/public/platform/WebVector.h" #include "third_party/skia/include/core/SkBlendMode.h" -#include "third_party/skia/include/core/SkClipOp.h" #include "ui/gfx/geometry/point_f.h" class SkColorFilter; @@ -48,7 +47,6 @@ const blink::WebVector<SkRRect>& rounded_clip_rects) override; void appendEndClipItem() override; void appendClipPathItem(const SkPath& clip_path, - SkClipOp clip_op, bool antialias) override; void appendEndClipPathItem() override; void appendFloatClipItem(const blink::WebFloatRect& clip_rect) override;
diff --git a/cc/playback/clip_path_display_item.cc b/cc/playback/clip_path_display_item.cc index 5b5240d..5d18b3b7 100644 --- a/cc/playback/clip_path_display_item.cc +++ b/cc/playback/clip_path_display_item.cc
@@ -16,10 +16,9 @@ namespace cc { ClipPathDisplayItem::ClipPathDisplayItem(const SkPath& clip_path, - SkClipOp clip_op, bool antialias) : DisplayItem(CLIP_PATH) { - SetNew(clip_path, clip_op, antialias); + SetNew(clip_path, antialias); } ClipPathDisplayItem::ClipPathDisplayItem(const proto::DisplayItem& proto) @@ -27,7 +26,6 @@ DCHECK_EQ(proto::DisplayItem::Type_ClipPath, proto.type()); const proto::ClipPathDisplayItem& details = proto.clip_path_item(); - SkClipOp clip_op = SkClipOpFromProto(details.clip_op()); bool antialias = details.antialias(); SkPath clip_path; @@ -37,17 +35,15 @@ DCHECK_EQ(details.clip_path().size(), bytes_read); } - SetNew(clip_path, clip_op, antialias); + SetNew(clip_path, antialias); } ClipPathDisplayItem::~ClipPathDisplayItem() { } void ClipPathDisplayItem::SetNew(const SkPath& clip_path, - SkClipOp clip_op, bool antialias) { clip_path_ = clip_path; - clip_op_ = clip_op; antialias_ = antialias; } @@ -55,7 +51,6 @@ proto->set_type(proto::DisplayItem::Type_ClipPath); proto::ClipPathDisplayItem* details = proto->mutable_clip_path_item(); - details->set_clip_op(SkClipOpToProto(clip_op_)); details->set_antialias(antialias_); // Just use skia's serialization method for the SkPath for now. @@ -70,7 +65,7 @@ void ClipPathDisplayItem::Raster(SkCanvas* canvas, SkPicture::AbortCallback* callback) const { canvas->save(); - canvas->clipPath(clip_path_, clip_op_, antialias_); + canvas->clipPath(clip_path_, antialias_); } void ClipPathDisplayItem::AsValueInto(
diff --git a/cc/playback/clip_path_display_item.h b/cc/playback/clip_path_display_item.h index f8ea8ab6..33e648e 100644 --- a/cc/playback/clip_path_display_item.h +++ b/cc/playback/clip_path_display_item.h
@@ -12,7 +12,6 @@ #include "base/memory/ptr_util.h" #include "cc/base/cc_export.h" #include "cc/playback/display_item.h" -#include "third_party/skia/include/core/SkClipOp.h" #include "third_party/skia/include/core/SkPath.h" class SkCanvas; @@ -21,7 +20,7 @@ class CC_EXPORT ClipPathDisplayItem : public DisplayItem { public: - ClipPathDisplayItem(const SkPath& path, SkClipOp clip_op, bool antialias); + ClipPathDisplayItem(const SkPath& path, bool antialias); explicit ClipPathDisplayItem(const proto::DisplayItem& proto); ~ClipPathDisplayItem() override; @@ -39,10 +38,9 @@ int ApproximateOpCount() const { return 1; } private: - void SetNew(const SkPath& path, SkClipOp clip_op, bool antialias); + void SetNew(const SkPath& path, bool antialias); SkPath clip_path_; - SkClipOp clip_op_; bool antialias_; };
diff --git a/cc/playback/display_item_list_unittest.cc b/cc/playback/display_item_list_unittest.cc index 64dc0b3..9196dfc 100644 --- a/cc/playback/display_item_list_unittest.cc +++ b/cc/playback/display_item_list_unittest.cc
@@ -200,8 +200,7 @@ // Build the ClipPathDisplayItem. SkPath path; path.addCircle(5.f, 5.f, 2.f, SkPath::Direction::kCW_Direction); - list->CreateAndAppendPairedBeginItem<ClipPathDisplayItem>( - path, SkClipOp::kIntersect, false); + list->CreateAndAppendPairedBeginItem<ClipPathDisplayItem>(path, false); // Build the second DrawingDisplayItem. AppendSecondSerializationTestPicture(list, layer_size);
diff --git a/cc/proto/skia_conversions.cc b/cc/proto/skia_conversions.cc index 72397de08..74a7af2 100644 --- a/cc/proto/skia_conversions.cc +++ b/cc/proto/skia_conversions.cc
@@ -26,30 +26,6 @@ } // namespace -SkClipOp SkClipOpFromProto(proto::SkClipOp::Op op) { - switch (op) { - case proto::SkClipOp::DIFFERENCE_: - return SkClipOp::kDifference; - case proto::SkClipOp::INTERSECT: - return SkClipOp::kIntersect; - default: - break; - } - return SkClipOp::kDifference; -} - -proto::SkClipOp::Op SkClipOpToProto(SkClipOp op) { - switch (op) { - case SkClipOp::kDifference: - return proto::SkClipOp::DIFFERENCE_; - case SkClipOp::kIntersect: - return proto::SkClipOp::INTERSECT; - default: - break; - } - return proto::SkClipOp::DIFFERENCE_; -} - SkBlendMode SkXfermodeModeFromProto(proto::SkXfermode::Mode mode) { switch (mode) { case proto::SkXfermode::CLEAR_:
diff --git a/cc/proto/skia_conversions.h b/cc/proto/skia_conversions.h index e92e1ae..33429f3 100644 --- a/cc/proto/skia_conversions.h +++ b/cc/proto/skia_conversions.h
@@ -21,9 +21,6 @@ // TODO(dtrainor): Move these to a class and make them static // (crbug.com/548432). -CC_EXPORT SkClipOp SkClipOpFromProto(proto::SkClipOp::Op op); -CC_EXPORT proto::SkClipOp::Op SkClipOpToProto(SkClipOp op); - CC_EXPORT SkBlendMode SkXfermodeModeFromProto(proto::SkXfermode::Mode mode); CC_EXPORT proto::SkXfermode::Mode SkXfermodeModeToProto(SkBlendMode mode);
diff --git a/cc/proto/skia_conversions_unittest.cc b/cc/proto/skia_conversions_unittest.cc index bc6ddba2..2eba14c 100644 --- a/cc/proto/skia_conversions_unittest.cc +++ b/cc/proto/skia_conversions_unittest.cc
@@ -11,24 +11,11 @@ #include "cc/proto/skxfermode.pb.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBlendMode.h" -#include "third_party/skia/include/core/SkClipOp.h" #include "third_party/skia/include/core/SkRRect.h" namespace cc { namespace { -TEST(SkiaProtoConversionsTest, SerializeDeserializeSkClipOp) { - // explicitly list the clipops, as this list will be reduced overtime - // as skia constricts the valid ops for clipping - // https://bugs.chromium.org/p/skia/issues/detail?id=3191 - const SkClipOp ops[] = { - SkClipOp::kDifference, SkClipOp::kIntersect, - }; - for (SkClipOp op : ops) { - EXPECT_EQ(op, SkClipOpFromProto(SkClipOpToProto(op))); - } -} - TEST(SkiaProtoConversionsTest, SerializeDeserializeSkXfermodeMode) { for (size_t i = 0; i < static_cast<size_t>(SkBlendMode::kLastMode); i++) { SkBlendMode mode = static_cast<SkBlendMode>(i);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BackgroundSyncLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/BackgroundSyncLauncher.java index 312dd77..4bbbb4c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/BackgroundSyncLauncher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/BackgroundSyncLauncher.java
@@ -24,7 +24,7 @@ /** * The {@link BackgroundSyncLauncher} singleton is created and owned by the C++ browser. It * registers interest in waking up the browser the next time the device goes online after the - * browser closes via the {@link #setLaunchWhenNextOnline} method. + * browser closes via the {@link #launchBrowserIfStopped} method. * * Thread model: This class is to be run on the UI thread only. */ @@ -50,6 +50,9 @@ */ private static boolean sGCMEnabled = true; + @VisibleForTesting + protected AsyncTask<Void, Void, Void> mLaunchBrowserIfStoppedTask; + /** * Create a BackgroundSyncLauncher object, which is owned by C++. * @param context The app context. @@ -79,18 +82,21 @@ * Callback for {@link #shouldLaunchBrowserIfStopped}. The run method is invoked on the UI * thread. */ - public static interface ShouldLaunchCallback { public void run(Boolean shouldLaunch); } + public interface ShouldLaunchCallback { void run(Boolean shouldLaunch); } /** * Returns whether the browser should be launched when the device next goes online. * This is set by C++ and reset to false each time {@link BackgroundSyncLauncher}'s singleton is * created (the native browser is started). This call is asynchronous and will run the callback * on the UI thread when complete. - * @param context The application context. - * @param sharedPreferences The shared preferences. + * + * {@link AsyncTask} is necessary as the browser process will not have warmed up the + * {@link SharedPreferences} before it is used here. This is likely the first usage of + * {@link ContextUtils#getAppSharedPreferences}. + * + * @param callback The callback after fetching prefs. */ - protected static void shouldLaunchBrowserIfStopped( - final Context context, final ShouldLaunchCallback callback) { + protected static void shouldLaunchBrowserIfStopped(final ShouldLaunchCallback callback) { new AsyncTask<Void, Void, Boolean>() { @Override protected Boolean doInBackground(Void... params) { @@ -101,7 +107,7 @@ protected void onPostExecute(Boolean shouldLaunch) { callback.run(shouldLaunch); } - }.execute(); + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } /** @@ -110,15 +116,16 @@ * This method is called by C++ as background sync registrations are added and removed. When the * {@link BackgroundSyncLauncher} singleton is created (on browser start), this is called to * remove any pre-existing scheduled tasks. - * @param context The application context. + * + * See {@link #shouldLaunchBrowserIfStopped} for {@link AsyncTask}. + * * @param shouldLaunch Whether or not to launch the browser in the background. * @param minDelayMs The minimum time to wait before checking on the browser process. */ @VisibleForTesting @CalledByNative - protected void launchBrowserIfStopped( - final Context context, final boolean shouldLaunch, final long minDelayMs) { - new AsyncTask<Void, Void, Void>() { + protected void launchBrowserIfStopped(final boolean shouldLaunch, final long minDelayMs) { + mLaunchBrowserIfStoppedTask = new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { SharedPreferences prefs = ContextUtils.getAppSharedPreferences(); @@ -133,7 +140,7 @@ if (shouldLaunch) { RecordHistogram.recordBooleanHistogram( "BackgroundSync.LaunchTask.ScheduleSuccess", - scheduleLaunchTask(context, mScheduler, minDelayMs)); + scheduleLaunchTask(mScheduler, minDelayMs)); } else { RecordHistogram.recordBooleanHistogram( "BackgroundSync.LaunchTask.CancelSuccess", @@ -141,7 +148,7 @@ } } } - }.execute(); + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } /** @@ -154,7 +161,7 @@ protected BackgroundSyncLauncher(Context context) { mScheduler = GcmNetworkManager.getInstance(context); - launchBrowserIfStopped(context, false, 0); + launchBrowserIfStopped(false, 0); } private static boolean canUseGooglePlayServices(Context context) { @@ -188,8 +195,7 @@ return !sGCMEnabled; } - private static boolean scheduleLaunchTask( - Context context, GcmNetworkManager scheduler, long minDelayMs) { + private static boolean scheduleLaunchTask(GcmNetworkManager scheduler, long minDelayMs) { // Google Play Services may not be up to date, if the application was not installed through // the Play Store. In this case, scheduling the task will fail silently. final long minDelaySecs = minDelayMs / 1000; @@ -252,11 +258,11 @@ // without delay and let the browser reschedule if necessary. // TODO(iclelland): If this fails, report the failure via UMA (not now, // since the browser is not running, but on next startup.) - scheduleLaunchTask(context, scheduler, 0); + scheduleLaunchTask(scheduler, 0); } } }; - BackgroundSyncLauncher.shouldLaunchBrowserIfStopped(context, callback); + BackgroundSyncLauncher.shouldLaunchBrowserIfStopped(callback); } @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java index e561effc..e2ffdab4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java
@@ -40,7 +40,7 @@ } /** - * Called to open a given download item that is downloaded by the android DownloadManager. + * Called to open a particular download item. Falls back to opening Download Home. * @param context Context of the receiver. * @param intent Intent from the android DownloadManager. */ @@ -51,24 +51,22 @@ DownloadManagerService.openDownloadsPage(context); return; } + long id = ids[0]; DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); Uri uri = manager.getUriForDownloadedFile(id); if (uri == null) { - // Open the downloads page DownloadManagerService.openDownloadsPage(context); - } else { - String downloadFilename = IntentUtils.safeGetStringExtra( - intent, DownloadNotificationService.EXTRA_DOWNLOAD_FILE_PATH); - boolean isSupportedMimeType = IntentUtils.safeGetBooleanExtra( - intent, DownloadNotificationService.EXTRA_IS_SUPPORTED_MIME_TYPE, false); - Intent launchIntent = DownloadManagerService.getLaunchIntentFromDownloadId( - context, downloadFilename, id, isSupportedMimeType); - if (!DownloadUtils.fireOpenIntentForDownload(context, launchIntent)) { - DownloadManagerService.openDownloadsPage(context); - } + return; } + + String downloadFilename = IntentUtils.safeGetStringExtra( + intent, DownloadNotificationService.EXTRA_DOWNLOAD_FILE_PATH); + boolean isSupportedMimeType = IntentUtils.safeGetBooleanExtra( + intent, DownloadNotificationService.EXTRA_IS_SUPPORTED_MIME_TYPE, false); + DownloadManagerService.openDownloadedContent( + context, downloadFilename, isSupportedMimeType, id); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java index 53c112e..e7230bb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -982,6 +982,7 @@ * @param isSupportedMimeType Whether the MIME type is supported by browser. * @return the intent to launch for the given download item. */ + @Nullable static Intent getLaunchIntentFromDownloadId( Context context, @Nullable String filePath, long downloadId, boolean isSupportedMimeType) { @@ -1021,29 +1022,36 @@ context, intent, true); } + /** See {@link #openDownloadedContent(Context, String, boolean, long)}. */ + protected void openDownloadedContent(final DownloadInfo downloadInfo, final long downloadId) { + openDownloadedContent(mContext, downloadInfo.getFilePath(), + isSupportedMimeType(downloadInfo.getMimeType()), downloadId); + } + /** - * Launch the intent for a given download item. + * Launch the intent for a given download item, or Download Home if that's not possible. * TODO(qinmin): Move this to DownloadManagerDelegate. * - * @param downloadInfo Info about the downloaded item. - * @param downloadId ID of the download item in DownloadManager. + * @param context Context to use. + * @param filePath Path to the downloaded item. + * @param isSupportedMimeType MIME type of the downloaded item. + * @param downloadId ID of the download item in DownloadManager. */ - protected void openDownloadedContent(final DownloadInfo downloadInfo, final long downloadId) { - final boolean isSupportedMimeType = isSupportedMimeType(downloadInfo.getMimeType()); + protected static void openDownloadedContent(final Context context, final String filePath, + final boolean isSupportedMimeType, final long downloadId) { new AsyncTask<Void, Void, Intent>() { @Override public Intent doInBackground(Void... params) { return getLaunchIntentFromDownloadId( - mContext, downloadInfo.getFilePath(), downloadId, isSupportedMimeType); + context, filePath, downloadId, isSupportedMimeType); } @Override protected void onPostExecute(Intent intent) { - if (intent == null) return; - - Context context = ContextUtils.getApplicationContext(); - if (ExternalNavigationDelegateImpl.resolveIntent(context, intent, true)) { - DownloadUtils.fireOpenIntentForDownload(context, intent); + if (intent == null + || !ExternalNavigationDelegateImpl.resolveIntent(context, intent, true) + || !DownloadUtils.fireOpenIntentForDownload(context, intent)) { + openDownloadsPage(context); } } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -1559,7 +1567,7 @@ @Override public void broadcastDownloadAction(DownloadItem downloadItem, String action) { Intent intent = DownloadNotificationService.buildActionIntent(mContext, action, - downloadItem.getId(), downloadItem.getDownloadInfo().getFileName(), false); + downloadItem.getId(), downloadItem.getDownloadInfo().getFileName()); mContext.sendBroadcast(intent); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java index b0840924..ceed07d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -268,19 +268,21 @@ int percentage, long timeRemainingInMillis, long startTime, boolean isOffTheRecord, boolean canDownloadWhileMetered, boolean isOfflinePage, boolean isDownloadPending) { if (mStopPostingProgressNotifications) return; + String contentText = mContext.getResources().getString(isDownloadPending ? R.string.download_notification_pending : R.string.download_started); int resId = isDownloadPending ? android.R.drawable.stat_sys_download_done : android.R.drawable.stat_sys_download; - NotificationCompat.Builder builder = buildNotification( - resId, fileName, contentText); - boolean indeterminate = (percentage == INVALID_DOWNLOAD_PERCENTAGE) || isDownloadPending; + NotificationCompat.Builder builder = buildNotification(resId, fileName, contentText); builder.setOngoing(true); - // Avoid moving animations while download is not downloading. + builder.setPriority(Notification.PRIORITY_HIGH); + + // Avoid animations while the download isn't progressing. + boolean indeterminate = (percentage == INVALID_DOWNLOAD_PERCENTAGE) || isDownloadPending; if (!isDownloadPending) { builder.setProgress(100, percentage, indeterminate); } - builder.setPriority(Notification.PRIORITY_HIGH); + if (!indeterminate && !isOfflinePage) { String duration = formatRemainingTime(mContext, timeRemainingInMillis); if (Build.VERSION.CODENAME.equals("N") @@ -291,22 +293,33 @@ } } int notificationId = getNotificationId(downloadGuid); + if (startTime > 0) builder.setWhen(startTime); + + // Clicking on an in-progress download sends the user to see all their downloads. + Intent downloadHomeIntent = buildActionIntent( + mContext, DownloadManager.ACTION_NOTIFICATION_CLICKED, null, null); + builder.setContentIntent(PendingIntent.getBroadcast( + mContext, notificationId, downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT)); + builder.setAutoCancel(false); + + Intent pauseIntent = buildActionIntent( + mContext, ACTION_DOWNLOAD_PAUSE, downloadGuid, fileName); + builder.addAction(R.drawable.ic_media_control_pause, + mContext.getResources().getString(R.string.download_notification_pause_button), + buildPendingIntent(pauseIntent, notificationId)); + + Intent cancelIntent = buildActionIntent( + mContext, ACTION_DOWNLOAD_CANCEL, downloadGuid, fileName); + builder.addAction(R.drawable.btn_close_white, + mContext.getResources().getString(R.string.download_notification_cancel_button), + buildPendingIntent(cancelIntent, notificationId)); + + updateNotification(notificationId, builder.build()); + int itemType = isOfflinePage ? DownloadSharedPreferenceEntry.ITEM_TYPE_OFFLINE_PAGE : DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD; addOrReplaceSharedPreferenceEntry(new DownloadSharedPreferenceEntry(notificationId, isOffTheRecord, canDownloadWhileMetered, downloadGuid, fileName, itemType, true)); - if (startTime > 0) builder.setWhen(startTime); - Intent cancelIntent = buildActionIntent( - mContext, ACTION_DOWNLOAD_CANCEL, downloadGuid, fileName, isOfflinePage); - builder.addAction(R.drawable.btn_close_white, - mContext.getResources().getString(R.string.download_notification_cancel_button), - buildPendingIntent(cancelIntent, notificationId)); - Intent pauseIntent = buildActionIntent( - mContext, ACTION_DOWNLOAD_PAUSE, downloadGuid, fileName, isOfflinePage); - builder.addAction(R.drawable.ic_media_control_pause, - mContext.getResources().getString(R.string.download_notification_pause_button), - buildPendingIntent(pauseIntent, notificationId)); - updateNotification(notificationId, builder.build()); if (!mDownloadsInProgress.contains(downloadGuid)) { mDownloadsInProgress.add(downloadGuid); } @@ -357,23 +370,35 @@ mDownloadsInProgress.remove(downloadGuid); return; } + String contentText = mContext.getResources().getString( R.string.download_notification_paused); NotificationCompat.Builder builder = buildNotification( android.R.drawable.ic_media_pause, entry.fileName, contentText); - Intent cancelIntent = buildActionIntent(mContext, ACTION_DOWNLOAD_CANCEL, - entry.downloadGuid, entry.fileName, entry.isOfflinePage()); - Intent dismissIntent = new Intent(cancelIntent); - dismissIntent.putExtra(EXTRA_NOTIFICATION_DISMISSED, true); - builder.setDeleteIntent(buildPendingIntent(dismissIntent, entry.notificationId)); - builder.addAction(R.drawable.btn_close_white, - mContext.getResources().getString(R.string.download_notification_cancel_button), - buildPendingIntent(cancelIntent, entry.notificationId)); + + // Clicking on an in-progress download sends the user to see all their downloads. + Intent downloadHomeIntent = buildActionIntent( + mContext, DownloadManager.ACTION_NOTIFICATION_CLICKED, null, null); + builder.setContentIntent(PendingIntent.getBroadcast(mContext, entry.notificationId, + downloadHomeIntent, PendingIntent.FLAG_UPDATE_CURRENT)); + builder.setAutoCancel(false); + Intent resumeIntent = buildActionIntent(mContext, ACTION_DOWNLOAD_RESUME, - entry.downloadGuid, entry.fileName, entry.isOfflinePage()); + entry.downloadGuid, entry.fileName); builder.addAction(R.drawable.ic_get_app_white_24dp, mContext.getResources().getString(R.string.download_notification_resume_button), buildPendingIntent(resumeIntent, entry.notificationId)); + + Intent cancelIntent = buildActionIntent(mContext, ACTION_DOWNLOAD_CANCEL, + entry.downloadGuid, entry.fileName); + builder.addAction(R.drawable.btn_close_white, + mContext.getResources().getString(R.string.download_notification_cancel_button), + buildPendingIntent(cancelIntent, entry.notificationId)); + + Intent dismissIntent = new Intent(cancelIntent); + dismissIntent.putExtra(EXTRA_NOTIFICATION_DISMISSED, true); + builder.setDeleteIntent(buildPendingIntent(dismissIntent, entry.notificationId)); + updateNotification(entry.notificationId, builder.build()); // Update the SharedPreference entry with the new isAutoResumable value. addOrReplaceSharedPreferenceEntry(new DownloadSharedPreferenceEntry(entry.notificationId, @@ -405,7 +430,7 @@ Intent intent; if (isOfflinePage) { intent = buildActionIntent( - mContext, ACTION_DOWNLOAD_OPEN, downloadGuid, fileName, isOfflinePage); + mContext, ACTION_DOWNLOAD_OPEN, downloadGuid, fileName); } else { intent = new Intent(DownloadManager.ACTION_NOTIFICATION_CLICKED); long[] idArray = {systemDownloadId}; @@ -490,10 +515,9 @@ * @param action Download action to perform. * @param downloadGuid GUID of the download. * @param fileName Name of the download file. - * @param isOfflinePage Whether the intent is for offline page download. */ static Intent buildActionIntent(Context context, String action, String downloadGuid, - String fileName, boolean isOfflinePage) { + String fileName) { ComponentName component = new ComponentName( context.getPackageName(), DownloadBroadcastReceiver.class.getName()); Intent intent = new Intent(action);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java index 82382d0..ff98a16 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemWrapper.java
@@ -395,7 +395,11 @@ return false; } - if (mItem.getDownloadInfo().state() == DownloadState.CANCELLED) { + int state = mItem.getDownloadInfo().state(); + if ((state == DownloadState.INTERRUPTED && !mItem.getDownloadInfo().isResumable()) + || state == DownloadState.CANCELLED) { + // Mocks don't include showing cancelled/unresumable downloads. Might need to if + // undeletable files become a big issue. return false; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java index dd5b3d9..8c9d1875 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
@@ -209,6 +209,15 @@ } @Override + public boolean onLongClick(View view) { + if (mItem != null && mItem.isComplete()) { + return super.onLongClick(view); + } else { + return true; + } + } + + @Override public void setChecked(boolean checked) { super.setChecked(checked); updateIconView();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java index db39d63..26e21a9b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java
@@ -4,8 +4,10 @@ package org.chromium.chrome.browser.payments; +import android.content.Context; import android.text.TextUtils; +import org.chromium.chrome.R; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.payments.ui.PaymentOption; @@ -16,6 +18,7 @@ */ public class AutofillContact extends PaymentOption { private final AutofillProfile mProfile; + private final Context mContext; @Nullable private String mPayerName; @Nullable private String mPayerPhone; @Nullable private String mPayerEmail; @@ -23,21 +26,23 @@ /** * Builds contact details. * - * @param profile The autofill profile where this contact data lives. - * @param name The payer name. If not empty, this will be the primary label. - * @param phone The phone number. If name is empty, this will be the primary label. - * @param email The email address. If name and phone are empty, this will be the primary - * label. - * @param isComplete Whether the data in this contact can be sent to the merchant as-is. If - * false, user needs to add more information here. + * @param context The application context. + * @param profile The autofill profile where this contact data lives. + * @param name The payer name. If not empty, this will be the primary label. + * @param phone The phone number. If name is empty, this will be the primary label. + * @param email The email address. If name and phone are empty, this will be the + * primary label. + * @param completionStatus The completion status of this contact. */ - public AutofillContact(AutofillProfile profile, @Nullable String name, - @Nullable String phone, @Nullable String email, boolean isComplete) { + public AutofillContact(Context context, AutofillProfile profile, @Nullable String name, + @Nullable String phone, @Nullable String email, + @ContactEditor.CompletionStatus int completionStatus) { super(profile.getGUID(), null, null, null, null); + mContext = context; mProfile = profile; - mIsComplete = isComplete; mIsEditable = true; setContactInfo(profile.getGUID(), name, phone, email); + updateCompletionStatus(completionStatus); } /** @return Payer name. Null if the merchant did not request it or data is incomplete. */ @@ -73,8 +78,8 @@ */ public void completeContact(String guid, @Nullable String name, @Nullable String phone, @Nullable String email) { - mIsComplete = true; setContactInfo(guid, name, phone, email); + updateCompletionStatus(ContactEditor.COMPLETE); } private void setContactInfo(String guid, @Nullable String name, @@ -92,4 +97,33 @@ mPayerPhone == null ? null : mPayerEmail); } } + + private void updateCompletionStatus(int completionStatus) { + mIsComplete = completionStatus == ContactEditor.COMPLETE; + + switch (completionStatus) { + case ContactEditor.COMPLETE: + mEditMessage = null; + mEditTitle = mContext.getString(R.string.payments_edit_contact_details_label); + break; + case ContactEditor.INVALID_NAME: + mEditMessage = mContext.getString(R.string.payments_name_required); + mEditTitle = mContext.getString(R.string.payments_add_name); + break; + case ContactEditor.INVALID_EMAIL: + mEditMessage = mContext.getString(R.string.payments_email_required); + mEditTitle = mContext.getString(R.string.payments_add_email); + break; + case ContactEditor.INVALID_PHONE_NUMBER: + mEditMessage = mContext.getString(R.string.payments_phone_number_required); + mEditTitle = mContext.getString(R.string.payments_add_phone_number); + break; + case ContactEditor.INVALID_MULTIPLE_FIELDS: + mEditMessage = mContext.getString(R.string.payments_more_information_required); + mEditTitle = mContext.getString(R.string.payments_add_more_information); + break; + default: + assert false : "Invalid completion status code"; + } + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java index 7924e096..ad65b79 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.payments; +import android.support.annotation.IntDef; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import android.util.Patterns; @@ -16,6 +17,8 @@ import org.chromium.chrome.browser.payments.ui.EditorFieldModel.EditorFieldValidator; import org.chromium.chrome.browser.payments.ui.EditorModel; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.HashSet; import java.util.Set; @@ -25,6 +28,20 @@ * Contact information editor. */ public class ContactEditor extends EditorBase<AutofillContact> { + @IntDef({INVALID_NAME, INVALID_EMAIL, INVALID_PHONE_NUMBER, INVALID_MULTIPLE_FIELDS}) + @Retention(RetentionPolicy.SOURCE) + public @interface CompletionStatus {} + /** Can be sent to the merchant as-is without editing first. */ + public static final int COMPLETE = 0; + /** The contact name is missing. */ + public static final int INVALID_NAME = 1; + /** The contact email is invalid or missing. */ + public static final int INVALID_EMAIL = 2; + /** The contact phone number is invalid or missing. */ + public static final int INVALID_PHONE_NUMBER = 3; + /** Multiple fields are invalid or missing. */ + public static final int INVALID_MULTIPLE_FIELDS = 4; + private final boolean mRequestPayerName; private final boolean mRequestPayerPhone; private final boolean mRequestPayerEmail; @@ -53,19 +70,39 @@ } /** - * Returns whether the following contact information can be sent to the merchant as-is without - * editing first. + * Returns the contact completion status with the given name, phone and email. * * @param name The payer name to check. * @param phone The phone number to check. * @param email The email address to check. - * @return Whether the contact information is complete. + * @return The completion status. */ - public boolean isContactInformationComplete( + @CompletionStatus + public int checkContactCompletionStatus( @Nullable String name, @Nullable String phone, @Nullable String email) { - return (!mRequestPayerName || !TextUtils.isEmpty(name)) - && (!mRequestPayerPhone || getPhoneValidator().isValid(phone)) - && (!mRequestPayerEmail || getEmailValidator().isValid(email)); + int invalidFieldCount = 0; + int completionStatus = COMPLETE; + + if (mRequestPayerName && TextUtils.isEmpty(name)) { + invalidFieldCount++; + completionStatus = INVALID_NAME; + } + + if (mRequestPayerPhone && !getPhoneValidator().isValid(phone)) { + invalidFieldCount++; + completionStatus = INVALID_PHONE_NUMBER; + } + + if (mRequestPayerEmail && !getEmailValidator().isValid(email)) { + invalidFieldCount++; + completionStatus = INVALID_EMAIL; + } + + if (invalidFieldCount > 1) { + completionStatus = INVALID_MULTIPLE_FIELDS; + } + + return completionStatus; } /** @@ -101,7 +138,9 @@ super.edit(toEdit, callback); final AutofillContact contact = toEdit == null - ? new AutofillContact(new AutofillProfile(), null, null, null, false) : toEdit; + ? new AutofillContact(mContext, new AutofillProfile(), null, null, null, + INVALID_MULTIPLE_FIELDS) + : toEdit; final EditorFieldModel nameField = mRequestPayerName ? EditorFieldModel.createTextInput(EditorFieldModel.INPUT_TYPE_HINT_PERSON_NAME, @@ -129,9 +168,10 @@ contact.getPayerEmail()) : null; - EditorModel editor = new EditorModel( - mContext.getString(toEdit == null ? R.string.payments_add_contact_details_label - : R.string.payments_edit_contact_details_label)); + EditorModel editor = new EditorModel(toEdit == null + ? mContext.getString(R.string.payments_add_contact_details_label) + : toEdit.getEditTitle()); + if (nameField != null) editor.addField(nameField); if (phoneField != null) editor.addField(phoneField); if (emailField != null) editor.addField(emailField);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index 8916012..f0b64a2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -431,9 +431,11 @@ if (!uniqueContactInfos.contains(uniqueContactInfo)) { uniqueContactInfos.add(uniqueContactInfo); - boolean isComplete = mContactEditor.isContactInformationComplete(name, - phone, email); - contacts.add(new AutofillContact(profile, name, phone, email, isComplete)); + @ContactEditor.CompletionStatus + int completionStatus = + mContactEditor.checkContactCompletionStatus(name, phone, email); + contacts.add(new AutofillContact( + mContext, profile, name, phone, email, completionStatus)); } } }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index bdbff378..7796f00 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2618,10 +2618,10 @@ <message name="IDS_PAYMENTS_ADD_VALID_CARD_NUMBER" desc="The title of the dialog for user to add valid payment card number."> Add valid card number </message> - <message name="IDS_PAYMENTS_MORE_INFORMATION_REQUIRED" desc="The label to indicate more information is required for payment card."> + <message name="IDS_PAYMENTS_MORE_INFORMATION_REQUIRED" desc="The label to indicate more information is required for payment card or shipping address or contact info."> More information required </message> - <message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title of the dialog for user to add more information to payment card."> + <message name="IDS_PAYMENTS_ADD_MORE_INFORMATION" desc="The title of the dialog for user to add more information to payment card or shipping address or contact info."> Add more information </message> <message name="IDS_PAYMENTS_EDIT_CARD" desc="The title of the dialog for user to edit payment card."> @@ -2630,10 +2630,10 @@ <message name="IDS_PAYMENTS_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]"> Exp: <ph name="EXPIRATION_MONTH">%1$s<ex>06</ex></ph>/<ph name="EXPIRATION_YEAR">%2$s<ex>17</ex></ph> </message> - <message name="IDS_PAYMENTS_PHONE_NUMBER_REQUIRED" desc="The label to indicate phone number is required in the shipping address. This phone number can be used, for example, if there's a problem with shipping a package to its destination."> + <message name="IDS_PAYMENTS_PHONE_NUMBER_REQUIRED" desc="The label to indicate phone number is required in the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination."> Phone number required </message> - <message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address. This phone number can be used, for example, if there's a problem with shipping a package to its destination."> + <message name="IDS_PAYMENTS_ADD_PHONE_NUMBER" desc="The title of the dialog for user to add phone number to the shipping address or contact info. This phone number can be used, for example, if there's a problem with shipping a package to its destination."> Add phone number </message> <message name="IDS_PAYMENTS_RECIPIENT_REQUIRED" desc="The label to indicate recipient is required in the shipping address. The recipient could be a person or institute name identifies the receiver of the shipping package."> @@ -2648,6 +2648,18 @@ <message name="IDS_PAYMENTS_ADD_VALID_ADDRESS" desc="The title of the dialog for user to add valid shipping address. For example, missing state or city name."> Add valid address </message> + <message name="IDS_PAYMENTS_EMAIL_REQUIRED" desc="The label to indicate email is required for the contact details. This email can be used to contact the payer."> + Email required + </message> + <message name="IDS_PAYMENTS_ADD_EMAIL" desc="The title of the dialog for user to add email to the contact details. This email can be used to contact the payer."> + Add email + </message> + <message name="IDS_PAYMENTS_NAME_REQUIRED" desc="The label to indicate name is required for the contact details. This name could be a person or institute name of the payer."> + Name required + </message> + <message name="IDS_PAYMENTS_ADD_NAME" desc="The title of the dialog for user to add name to the contact details. This name could be a person or institute name of the payer."> + Add name + </message> <message name="IDS_PAYMENTS_ORDER_SUMMARY_LABEL" desc="The title of the section that shows the summary of the order, including names and prices of individual line items, i.e. the bill."> Order summary </message>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BackgroundSyncLauncherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BackgroundSyncLauncherTest.java index f26d62d..2b1f41f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/BackgroundSyncLauncherTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BackgroundSyncLauncherTest.java
@@ -13,6 +13,7 @@ import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.RetryOnFailure; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Semaphore; /** @@ -51,7 +52,7 @@ } }; - BackgroundSyncLauncher.shouldLaunchBrowserIfStopped(mContext, callback); + BackgroundSyncLauncher.shouldLaunchBrowserIfStopped(callback); try { // Wait on the callback to be called. semaphore.acquire(); @@ -61,6 +62,16 @@ return mShouldLaunchResult; } + private void waitForLaunchBrowserTask() { + try { + mLauncher.mLaunchBrowserIfStoppedTask.get(); + } catch (InterruptedException e) { + fail("Launch task was interrupted"); + } catch (ExecutionException e) { + fail("Launch task had execution exception"); + } + } + @SmallTest @Feature({"BackgroundSync"}) @RetryOnFailure @@ -81,9 +92,11 @@ @RetryOnFailure public void testSetLaunchWhenNextOnline() { assertFalse(shouldLaunchBrowserIfStoppedSync()); - mLauncher.launchBrowserIfStopped(mContext, true, 0); + mLauncher.launchBrowserIfStopped(true, 0); + waitForLaunchBrowserTask(); assertTrue(shouldLaunchBrowserIfStoppedSync()); - mLauncher.launchBrowserIfStopped(mContext, false, 0); + mLauncher.launchBrowserIfStopped(false, 0); + waitForLaunchBrowserTask(); assertFalse(shouldLaunchBrowserIfStoppedSync()); } @@ -91,7 +104,8 @@ @Feature({"BackgroundSync"}) @RetryOnFailure public void testNewLauncherDisablesNextOnline() { - mLauncher.launchBrowserIfStopped(mContext, true, 0); + mLauncher.launchBrowserIfStopped(true, 0); + waitForLaunchBrowserTask(); assertTrue(shouldLaunchBrowserIfStoppedSync()); // Simulate restarting the browser by deleting the launcher and creating a new one.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java index f98ea70..cafa5a00 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java
@@ -10,18 +10,55 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.autofill.AutofillTestHelper; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; -import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import java.util.ArrayList; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; /** * A payment integration test for a merchant that requests contact details and a user that has - * 5 contact detail options. + * multiple contact detail options. */ public class PaymentRequestMultipleContactDetailsTest extends PaymentRequestTestBase { + private static final AutofillProfile[] AUTOFILL_PROFILES = { + // Incomplete (no phone) profile. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "Bart Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "", "bart@simpson.com", ""), + + // Incomplete (no email) profile. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "Homer Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "555 123-4567", "", ""), + + // Complete profile. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "Lisa Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "555 123-4567", "lisa@simpson.com", ""), + + // Complete profile. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "Maggie Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "555 123-4567", "maggie@simpson.com", ""), + + // Incomplete (no phone and email) profile. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, + "Marge Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", + "90210", "", "US", "", "", ""), + + // Incomplete (no name) profile. + new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, "", + "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US", + "555 123-4567", "marge@simpson.com", ""), + + }; + + private AutofillProfile[] mProfilesToAdd; + private int[] mCountsToSet; + private int[] mDatesToSet; + public PaymentRequestMultipleContactDetailsTest() { - // The merchant requests both a phone number and an email address. + // The merchant requests a name, a phone number and an email address. super("payment_request_contact_details_test.html"); } @@ -29,48 +66,17 @@ public void onMainActivityStarted() throws InterruptedException, ExecutionException, TimeoutException { AutofillTestHelper helper = new AutofillTestHelper(); - // Create an incomplete (no phone) profile with the highest frecency score. - String guid1 = helper.setProfile( - new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, - "Bart Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", - "90210", "", "US", "", "bart@simpson.com", "")); - // Create an incomplete (no phone) profile with a the second highest frecency score. - String guid2 = helper.setProfile( - new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, - "Homer Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", - "90210", "", "US", "", "homer@simpson.com", "")); + // Add the profiles. + ArrayList<String> guids = new ArrayList<>(); + for (int i = 0; i < mProfilesToAdd.length; i++) { + guids.add(helper.setProfile(mProfilesToAdd[i])); + } - // Create a complete profile with a middle frecency score. - String guid3 = helper.setProfile( - new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, - "Lisa Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", - "90210", "", "US", "555 123-4567", "lisa@simpson.com", "")); - - // Create a complete profile with the second lowest frecency score. - String guid4 = helper.setProfile( - new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, - "Maggie Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", - "90210", "", "US", "555 123-4567", "maggie@simpson.com", "")); - - // Create an incomplete profile with the lowest frecency score. - String guid5 = helper.setProfile( - new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */, - "Marge Simpson", "Acme Inc.", "123 Main", "California", "Los Angeles", "", - "90210", "", "US", "", "marge@simpson.com", "")); - - // Create a credit card associated with the fourth profile. - helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe", - "4111111111111111", "1111", "12", "2050", "visa", R.drawable.pr_visa, - guid4, "" /* serverId */)); - - // Set the use stats so that profile1 has the highest frecency score, profile2 the second - // highest, profile 3 the third lowest, profile4 the second lowest and profile 5 the lowest. - helper.setProfileUseStatsForTesting(guid1, 20, 5000); - helper.setProfileUseStatsForTesting(guid2, 15, 5000); - helper.setProfileUseStatsForTesting(guid3, 10, 5000); - helper.setProfileUseStatsForTesting(guid4, 5, 5000); - helper.setProfileUseStatsForTesting(guid5, 1, 1); + // Set up the profile use stats. + for (int i = 0; i < guids.size(); i++) { + helper.setProfileUseStatsForTesting(guids.get(i), mCountsToSet[i], mDatesToSet[i]); + } } /** @@ -82,14 +88,50 @@ @Feature({"Payments"}) public void testContactDetailsSuggestionOrdering() throws InterruptedException, ExecutionException, TimeoutException { - triggerUIAndWait(mReadyToPay); + // Set the use stats so that profile[0] has the highest frecency score, profile[1] the + // second highest, profile[2] the third lowest, profile[3] the second lowest and profile[4] + // the lowest. + mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[0], AUTOFILL_PROFILES[1], + AUTOFILL_PROFILES[2], AUTOFILL_PROFILES[3], AUTOFILL_PROFILES[4]}; + mCountsToSet = new int[] {20, 15, 10, 5, 1}; + mDatesToSet = new int[] {5000, 5000, 5000, 5000, 1}; + + triggerUIAndWait(mReadyForInput); clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); assertEquals(4, getNumberOfContactDetailSuggestions()); assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com", getContactDetailsSuggestionLabel(0)); assertEquals("Maggie Simpson\n555 123-4567\nmaggie@simpson.com", getContactDetailsSuggestionLabel(1)); - assertEquals("Bart Simpson\nbart@simpson.com", getContactDetailsSuggestionLabel(2)); - assertEquals("Homer Simpson\nhomer@simpson.com", getContactDetailsSuggestionLabel(3)); + assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required", + getContactDetailsSuggestionLabel(2)); + assertEquals( + "Homer Simpson\n555 123-4567\nEmail required", getContactDetailsSuggestionLabel(3)); + } + + /** + * Make sure the information required message has been displayed for incomplete contact details + * correctly. + */ + @MediumTest + @Feature({"Payments"}) + public void testContactDetailsEditRequiredMessage() + throws InterruptedException, ExecutionException, TimeoutException { + mProfilesToAdd = new AutofillProfile[] {AUTOFILL_PROFILES[0], AUTOFILL_PROFILES[1], + AUTOFILL_PROFILES[4], AUTOFILL_PROFILES[5]}; + mCountsToSet = new int[] {15, 10, 5, 1}; + mDatesToSet = new int[] {5000, 5000, 5000, 5000}; + + triggerUIAndWait(mReadyForInput); + clickInContactInfoAndWait(R.id.payments_section, mReadyForInput); + assertEquals(4, getNumberOfContactDetailSuggestions()); + assertEquals("Bart Simpson\nbart@simpson.com\nPhone number required", + getContactDetailsSuggestionLabel(0)); + assertEquals( + "Homer Simpson\n555 123-4567\nEmail required", getContactDetailsSuggestionLabel(1)); + assertEquals( + "Marge Simpson\nMore information required", getContactDetailsSuggestionLabel(2)); + assertEquals("555 123-4567\nmarge@simpson.com\nName required", + getContactDetailsSuggestionLabel(3)); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java index 34c652f..8f83831 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
@@ -10,7 +10,6 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.blink_public.platform.WebDisplayMode; import org.chromium.chrome.browser.ChromeSwitches; @@ -187,7 +186,6 @@ */ @MediumTest @Feature({"WebApk"}) - @DisabledTest(message = "crbug.com/673385") public void testCanonicalUrlsDifferentShouldUpgrade() throws Exception { // URL canonicalization should replace "%62" with 'b'. CreationData creationData = defaultCreationData(mTestServer);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java index 48c1d10e..32d9d2d0 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java
@@ -4,11 +4,19 @@ package org.chromium.chrome.browser.payments; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; +import org.robolectric.ParameterizedRobolectricTestRunner; +import org.robolectric.ParameterizedRobolectricTestRunner.Parameters; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; @@ -18,7 +26,8 @@ /** * Unit tests for the AutofillContact class. */ -@RunWith(Parameterized.class) +@RunWith(ParameterizedRobolectricTestRunner.class) +@Config(sdk = 21, manifest = Config.NONE) public class AutofillContactTest { @Parameters public static Collection<Object[]> data() { @@ -62,6 +71,9 @@ }); } + private static final String IMCOMPLETE_MESSAGE = "incomplete"; + + private final Context mContext; private final String mPayerName; private final String mPayerPhone; private final String mPayerEmail; @@ -77,6 +89,8 @@ boolean isComplete, String expectedLabel, String expectedSublabel, String expectedTertiaryLabel, String expectedPayerName, String expectedPayerPhone, String expectedPayerEmail) { + mContext = spy(RuntimeEnvironment.application); + doReturn(IMCOMPLETE_MESSAGE).when(mContext).getString(anyInt()); mPayerName = payerName; mPayerPhone = payerPhone; mPayerEmail = payerEmail; @@ -92,8 +106,9 @@ @Test public void test() { AutofillProfile profile = new AutofillProfile(); - AutofillContact contact = - new AutofillContact(profile, mPayerName, mPayerPhone, mPayerEmail, mIsComplete); + AutofillContact contact = new AutofillContact(mContext, profile, mPayerName, mPayerPhone, + mPayerEmail, + mIsComplete ? ContactEditor.COMPLETE : ContactEditor.INVALID_MULTIPLE_FIELDS); Assert.assertEquals( mIsComplete ? "Contact should be complete" : "Contact should be incomplete", @@ -124,5 +139,11 @@ "Sublabel should be " + expectedSublabel, expectedSublabel, actual.getSublabel()); Assert.assertEquals("TertiaryLabel should be " + expectedTertiaryLabel, expectedTertiaryLabel, actual.getTertiaryLabel()); + + Assert.assertEquals("EditTitle should be " + IMCOMPLETE_MESSAGE, IMCOMPLETE_MESSAGE, + actual.getEditTitle()); + String editMessage = actual.isComplete() ? null : IMCOMPLETE_MESSAGE; + Assert.assertEquals( + "EditMessage should be " + editMessage, editMessage, actual.getEditMessage()); } }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 21b02760..5f638f6 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -6341,12 +6341,6 @@ <message name="IDS_FLAG_DISABLE_TAB_FOR_DESKTOP_SHARE_DESCRIPTION" desc="Description for the flag to disable tab for desktop share."> This flag controls whether users can choose a tab for desktop share. </message> - <message name="IDS_FLAG_DISABLE_DESKTOP_CAPTURE_PICKER_NEW_UI" desc="Title for the flag to disable desktop capture picker window new UI."> - Disable Desktop Capture Picker Window New UI. - </message> - <message name="IDS_FLAG_DISABLE_DESKTOP_CAPTURE_PICKER_NEW_UI_DESCRIPTION" desc="Description for the flag to disable desktop capture picker window new UI."> - This flag controls whether we show the old or new UI for desktop capture picker window. - </message> <message name="IDS_TRACE_UPLOAD_URL_CHOICE_OTHER"> Other </message> @@ -14045,9 +14039,6 @@ Share Your Screen </message> </if> - <message name="IDS_DESKTOP_MEDIA_PICKER_TITLE_DEPRECATED" desc="Title for the window picker dialog shown when desktop capture is requested by an app."> - Share your screen - <ph name="APP_NAME">$1<ex>Google Hangouts</ex></ph> - </message> <message name="IDS_DESKTOP_MEDIA_PICKER_TEXT" desc="Text for the window picker dialog shown when desktop capture is requested by an app to be used by the app itself."> <ph name="APP_NAME">$1<ex>Google Hangouts</ex></ph> wants to share the contents of your screen. Choose what you'd like to share. </message> @@ -14056,16 +14047,7 @@ </message> <message name="IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE" desc="Text for the checkbox on the window picker dialog, when checked, audio will be shared, otherwise just video sharing"> Share audio - </message> - <message name="IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_MAC" desc="Tooltip text for the checkbox on the window picker dialog, explaining why the checkbox to share audio is disabled"> - To share audio, select a tab. - </message> - <message name="IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_WINDOW" desc="Tooltip text for the checkbox on the window picker dialog, explaining why the checkbox to share audio is disabled"> - To share audio, select a tab or entire screen. - </message> - <message name="IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_NONE" desc="Tooltip text for the checkbox on the window picker dialog, explaining why the checkbox for audio sharing is disabled"> - Please select what to share first. - </message> + </message> <message name="IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_SCREEN" desc="Text for the button on the window picker dialog, clicking which takes one to full screen sharing"> Your Entire Screen </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index b9c75e6..bd607776 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -473,8 +473,11 @@ <message name="IDS_SETTINGS_BLUETOOTH_PAIR_DEVICE" desc="Name of the settings page for pairing bluetooth devices."> Pair Bluetooth Device </message> - <message name="IDS_SETTINGS_BLUETOOTH_ENABLE" desc="Label for control to enable or disable bluetooth."> - Enable Bluetooth + <message name="IDS_SETTINGS_BLUETOOTH_ENABLED" desc="Label for bluetooth section when enabled."> + Bluetooth enabled + </message> + <message name="IDS_SETTINGS_BLUETOOTH_DISABLED" desc="Label for bluetooth section when disabled."> + Bluetooth disabled </message> <message name="IDS_SETTINGS_BLUETOOTH_EXPAND_ACCESSIBILITY_LABEL" desc="Label for the button that toggles showing available bluetooth devices. Only visible by screen reader software."> Show available bluetooth devices @@ -825,10 +828,10 @@ printer name </message> <message name="IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTERS_NEARBY_TITLE" desc="Text for the title of the dialog that is used to add nearby printers."> - Add printers nearby + Add a nearby printer </message> <message name="IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTERS_MANUALLY_TITLE" desc="Text for the title of the dialog that is used to manually add a printer instead of automatically finding ones nearby."> - Add printers manually + Add a printer manually </message> <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_TITLE" desc="Text for the title of the Printer Details subpage."> Printer details
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 4ff6479ef..828c551 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -533,8 +533,6 @@ "manifest/manifest_icon_downloader.h", "manifest/manifest_icon_selector.cc", "manifest/manifest_icon_selector.h", - "media/combined_desktop_media_list.cc", - "media/combined_desktop_media_list.h", "media/media_access_handler.h", "media/media_device_id_salt.cc", "media/media_device_id_salt.h", @@ -2159,6 +2157,8 @@ "download/notification/download_notification_manager.h", "media/public_session_media_access_handler.cc", "media/public_session_media_access_handler.h", + "media/webrtc/public_session_tab_capture_access_handler.cc", + "media/webrtc/public_session_tab_capture_access_handler.h", "memory/memory_kills_histogram.h", "memory/memory_kills_monitor.cc", "memory/memory_kills_monitor.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index b71af7e..9abac3d 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1816,11 +1816,6 @@ {"tab-for-desktop-share", IDS_FLAG_DISABLE_TAB_FOR_DESKTOP_SHARE, IDS_FLAG_DISABLE_TAB_FOR_DESKTOP_SHARE_DESCRIPTION, kOsAll, SINGLE_VALUE_TYPE(extensions::switches::kDisableTabForDesktopShare)}, - {"disable-desktop-capture-picker-new-ui", - IDS_FLAG_DISABLE_DESKTOP_CAPTURE_PICKER_NEW_UI, - IDS_FLAG_DISABLE_DESKTOP_CAPTURE_PICKER_NEW_UI_DESCRIPTION, kOsAll, - SINGLE_VALUE_TYPE( - extensions::switches::kDisableDesktopCapturePickerNewUI)}, #endif // ENABLE_EXTENSIONS #if defined(OS_ANDROID) {"enable-ntp-snippets", IDS_FLAGS_ENABLE_NTP_SNIPPETS_NAME,
diff --git a/chrome/browser/android/background_sync_launcher_android.cc b/chrome/browser/android/background_sync_launcher_android.cc index 0b13a14..bac2de6 100644 --- a/chrome/browser/android/background_sync_launcher_android.cc +++ b/chrome/browser/android/background_sync_launcher_android.cc
@@ -44,8 +44,7 @@ JNIEnv* env = base::android::AttachCurrentThread(); Java_BackgroundSyncLauncher_launchBrowserIfStopped( - env, java_launcher_, base::android::GetApplicationContext(), - launch_when_next_online, min_delay_ms); + env, java_launcher_, launch_when_next_online, min_delay_ms); } // static
diff --git a/chrome/browser/android/vr_shell/vr_compositor.cc b/chrome/browser/android/vr_shell/vr_compositor.cc index 9d5d05e2..882236f 100644 --- a/chrome/browser/android/vr_shell/vr_compositor.cc +++ b/chrome/browser/android/vr_shell/vr_compositor.cc
@@ -54,8 +54,9 @@ compositor_->SetSurface(nullptr); } -void VrCompositor::SetWindowBounds(int width, int height) { - compositor_->SetWindowBounds(gfx::Size(width, height)); +void VrCompositor::SetWindowBounds(gfx::Size size) { + bounds_ = size; + compositor_->SetWindowBounds(bounds_); } void VrCompositor::SurfaceChanged(jobject surface) {
diff --git a/chrome/browser/android/vr_shell/vr_compositor.h b/chrome/browser/android/vr_shell/vr_compositor.h index a9c559a..a0e87202 100644 --- a/chrome/browser/android/vr_shell/vr_compositor.h +++ b/chrome/browser/android/vr_shell/vr_compositor.h
@@ -10,6 +10,7 @@ #include "base/android/scoped_java_ref.h" #include "base/macros.h" #include "content/public/browser/android/compositor_client.h" +#include "ui/gfx/geometry/size.h" typedef unsigned int SkColor; @@ -34,7 +35,8 @@ ~VrCompositor() override; void SurfaceDestroyed(); - void SetWindowBounds(int width, int height); + void SetWindowBounds(gfx::Size size); + gfx::Size GetWindowBounds() { return bounds_; } void SurfaceChanged(jobject surface); void SetLayer(content::WebContents* web_contents); @@ -44,6 +46,7 @@ private: std::unique_ptr<content::Compositor> compositor_; + gfx::Size bounds_; cc::Layer* layer_ = nullptr; cc::Layer* layer_parent_ = nullptr;
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc index f12b8667..36861751 100644 --- a/chrome/browser/android/vr_shell/vr_shell.cc +++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -179,28 +179,6 @@ g_instance = nullptr; } -void VrShell::SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num) { - GLThread* thread = static_cast<GLThread*>(gl_thread_.get()); - if (thread->GetVrShellGlUnsafe()) { - thread->GetVrShellGlUnsafe()->SetGvrPoseForWebVr(pose, pose_num); - } -} - -void VrShell::SetWebVRRenderSurfaceSize(int width, int height) { - GLThread* thread = static_cast<GLThread*>(gl_thread_.get()); - if (thread->GetVrShellGlUnsafe()) { - thread->GetVrShellGlUnsafe()->SetWebVRRenderSurfaceSize(width, height); - } -} - -gvr::Sizei VrShell::GetWebVRCompositorSurfaceSize() { - GLThread* thread = static_cast<GLThread*>(gl_thread_.get()); - if (thread->GetVrShellGlUnsafe()) { - return thread->GetVrShellGlUnsafe()->GetWebVRCompositorSurfaceSize(); - } - return gvr::Sizei(); -} - void VrShell::OnTriggerEvent(JNIEnv* env, const JavaParamRef<jobject>& obj) { GLThread* thread = static_cast<GLThread*>(gl_thread_.get()); @@ -260,6 +238,23 @@ } } +void VrShell::SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num) { + GLThread* thread = static_cast<GLThread*>(gl_thread_.get()); + thread->task_runner()->PostTask( + FROM_HERE, base::Bind(&VrShellGl::SetGvrPoseForWebVr, + thread->GetVrShellGl(), pose, pose_num)); +} + +void VrShell::SetWebVRRenderSurfaceSize(int width, int height) { + // TODO(klausw,crbug.com/655722): Change the GVR render size and set the WebVR + // render surface size. +} + +gvr::Sizei VrShell::GetWebVRCompositorSurfaceSize() { + const gfx::Size& size = content_compositor_->GetWindowBounds(); + return {size.width(), size.height()}; +} + void VrShell::SetWebVRSecureOrigin(bool secure_origin) { // TODO(cjgrant): Align this state with the logic that drives the omnibox. html_interface_->SetWebVRSecureOrigin(secure_origin); @@ -270,10 +265,9 @@ void VrShell::UpdateWebVRTextureBounds(const gvr::Rectf& left_bounds, const gvr::Rectf& right_bounds) { GLThread* thread = static_cast<GLThread*>(gl_thread_.get()); - if (thread->GetVrShellGlUnsafe()) { - thread->GetVrShellGlUnsafe()->UpdateWebVRTextureBounds(left_bounds, - right_bounds); - } + thread->task_runner()->PostTask( + FROM_HERE, base::Bind(&VrShellGl::UpdateWebVRTextureBounds, + thread->GetVrShellGl(), left_bounds, right_bounds)); } // TODO(mthiesse): Do not expose GVR API outside of GL thread. @@ -308,7 +302,7 @@ FROM_HERE, base::Bind(&VrShellGl::ContentPhysicalBoundsChanged, thread->GetVrShellGl(), width, height))); - content_compositor_->SetWindowBounds(width, height); + content_compositor_->SetWindowBounds(gfx::Size(width, height)); } void VrShell::UIBoundsChanged(JNIEnv* env, @@ -322,7 +316,7 @@ FROM_HERE, base::Bind(&VrShellGl::UIPhysicalBoundsChanged, thread->GetVrShellGl(), width, height)); - ui_compositor_->SetWindowBounds(width, height); + ui_compositor_->SetWindowBounds(gfx::Size(width, height)); } UiScene* VrShell::GetScene() { @@ -412,24 +406,24 @@ ui_input_manager_.reset(); ui_contents_ = nullptr; // TODO(mthiesse): Handle web contents being destroyed. - ForceExitVR(); + ForceExitVr(); } void VrShell::ContentWebContentsDestroyed() { content_input_manager_.reset(); main_contents_ = nullptr; // TODO(mthiesse): Handle web contents being destroyed. - ForceExitVR(); + ForceExitVr(); } void VrShell::ContentWasHidden() { // Ensure we don't continue sending input to it. content_input_manager_.reset(); // TODO(mthiesse): Handle web contents being hidden. - ForceExitVR(); + ForceExitVr(); } -void VrShell::ForceExitVR() { +void VrShell::ForceExitVr() { delegate_->ForceExitVr(); }
diff --git a/chrome/browser/android/vr_shell/vr_shell.h b/chrome/browser/android/vr_shell/vr_shell.h index bd41379..1eacb3f 100644 --- a/chrome/browser/android/vr_shell/vr_shell.h +++ b/chrome/browser/android/vr_shell/vr_shell.h
@@ -131,7 +131,7 @@ void ContentFrameWasResized(bool width_changed); - void ForceExitVR(); + void ForceExitVr(); private: ~VrShell() override;
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc index a2ac615..16c0614 100644 --- a/chrome/browser/android/vr_shell/vr_shell_gl.cc +++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -214,25 +214,25 @@ if (gl::GetGLImplementation() == gl::kGLImplementationNone && !gl::init::InitializeGLOneOff()) { LOG(ERROR) << "gl::init::InitializeGLOneOff failed"; - ForceExitVR(); + ForceExitVr(); return false; } surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size()); if (!surface_.get()) { LOG(ERROR) << "gl::init::CreateOffscreenGLSurface failed"; - ForceExitVR(); + ForceExitVr(); return false; } context_ = gl::init::CreateGLContext(nullptr, surface_.get(), gl::GLContextAttribs()); if (!context_.get()) { LOG(ERROR) << "gl::init::CreateGLContext failed"; - ForceExitVR(); + ForceExitVr(); return false; } if (!context_->MakeCurrent(surface_.get())) { LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; - ForceExitVR(); + ForceExitVr(); return false; } @@ -317,7 +317,6 @@ // For kFramePrimaryBuffer (primary VrShell and WebVR content) specs.push_back(gvr_api_->CreateBufferSpec()); render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); - render_size_primary_vrshell_ = render_size_primary_; // For kFrameHeadlockedBuffer (for WebVR insecure content warning). // Set this up at fixed resolution, the (smaller) FOV gets set below. @@ -610,25 +609,6 @@ // DrawVrShell if needed. buffer_viewport_list_->SetToRecommendedBufferViewports(); - // TODO(klausw): Fix this. Resizing buffers here leads to webVR mode showing - // nothing but a black screen. -// if (vr_shell_->GetUiInterface()->GetMode() == UiInterface::Mode::WEB_VR) { -// // If needed, resize the primary buffer for use with WebVR. -// if (render_size_primary_ != render_size_primary_webvr_) { -// if (!render_size_primary_webvr_.width) { -// VLOG(2) << "WebVR rendering size not known yet, dropping frame"; -// return; -// } -// render_size_primary_ = render_size_primary_webvr_; -// swap_chain_->ResizeBuffer(kFramePrimaryBuffer, render_size_primary_); -// } -// } else { -// if (render_size_primary_ != render_size_primary_vrshell_) { -// render_size_primary_ = render_size_primary_vrshell_; -// swap_chain_->ResizeBuffer(kFramePrimaryBuffer, render_size_primary_); -// } -// } - gvr::Frame frame = swap_chain_->AcquireFrame(); gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; @@ -755,13 +735,6 @@ } } -void VrShellGl::SetWebVRRenderSurfaceSize(int width, int height) { - render_size_primary_webvr_.width = width; - render_size_primary_webvr_.height = height; - // TODO(klausw,crbug.com/655722): set the WebVR render surface size here once - // we have that. -} - gvr::Sizei VrShellGl::GetWebVRCompositorSurfaceSize() { // This is a stopgap while we're using the WebVR compositor rendering path. // TODO(klausw,crbug.com/655722): Remove this method and member once we're @@ -1005,9 +978,9 @@ task_runner_->PostDelayedTask(FROM_HERE, draw_task_.callback(), target - now); } -void VrShellGl::ForceExitVR() { +void VrShellGl::ForceExitVr() { main_thread_task_runner_->PostTask( - FROM_HERE, base::Bind(&VrShell::ForceExitVR, weak_vr_shell_)); + FROM_HERE, base::Bind(&VrShell::ForceExitVr, weak_vr_shell_)); } } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.h b/chrome/browser/android/vr_shell/vr_shell_gl.h index 2720dd89..85e25a1 100644 --- a/chrome/browser/android/vr_shell/vr_shell_gl.h +++ b/chrome/browser/android/vr_shell/vr_shell_gl.h
@@ -75,7 +75,6 @@ const gvr::Rectf& right_bounds); gvr::GvrApi* gvr_api(); void SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num); - void SetWebVRRenderSurfaceSize(int width, int height); gvr::Sizei GetWebVRCompositorSurfaceSize(); UiScene* GetScene() { return scene_.get(); } @@ -107,7 +106,7 @@ const base::TimeDelta interval); void ScheduleNextDrawFrame(); - void ForceExitVR(); + void ForceExitVr(); // samplerExternalOES texture data for UI content image. int ui_texture_id_ = 0; @@ -137,12 +136,6 @@ gvr::Sizei render_size_primary_; gvr::Sizei render_size_headlocked_; - // Intended size for the primary render buffer by UI mode. - // For WebVR, a size of 0x0 is used to indicate "not yet ready" - // to suppress rendering while still initializing. - gvr::Sizei render_size_primary_webvr_ = device::kInvalidRenderTargetSize; - gvr::Sizei render_size_primary_vrshell_; - std::unique_ptr<VrShellRenderer> vr_shell_renderer_; bool touch_pending_ = false;
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc index 8486fd7d..05459124 100644 --- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc +++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
@@ -451,9 +451,10 @@ // access to page content, which we can't allow. // "declarativeContent", - // Allow, but either (1) ask user for confirmation or (2) return blank - // capture. - // "desktopCapture", + // User is prompted when an extension requests desktopCapture whether they + // want to allow it. The request is made through + // chrome.desktopCapture.chooseDesktopMedia call. + "desktopCapture", // Haven't checked in detail what this does, but messing with devtools // usually comes with the ability to access page content. @@ -626,9 +627,9 @@ // Enumerates removable storage. "system.storage", - // Provides access to screen contents, so block. Alternatively, (1) prompt - // for user consent or (2) return blank capture. - // "tabCapture", + // User is prompted (allow/deny) when an extension requests tabCapture. The + // request is made via chrome.tabCapture.capture call. + "tabCapture", // Privacy sensitive URL access. // "tabs",
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc index cb42c268..301e4aa 100644 --- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc +++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -840,6 +840,19 @@ nullptr); } } + + if (policy.has_device_wallpaper_image()) { + const em::DeviceWallpaperImageProto& container( + policy.device_wallpaper_image()); + if (container.has_device_wallpaper_image()) { + std::unique_ptr<base::DictionaryValue> dict_val = + base::DictionaryValue::From( + base::JSONReader::Read(container.device_wallpaper_image())); + policies->Set(key::kDeviceWallpaperImage, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, + std::move(dict_val), nullptr); + } + } } } // namespace
diff --git a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto index cd897005..50ce9a6 100644 --- a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto +++ b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
@@ -754,6 +754,12 @@ repeated string login_apps = 1; } +// The url and hash that specified in JSON format that can be used to set the +// device-level wallpaper on the login screen before any user logs in. +message DeviceWallpaperImageProto { + optional string device_wallpaper_image = 1; +} + message ChromeDeviceSettingsProto { optional DevicePolicyRefreshRateProto device_policy_refresh_rate = 1; optional UserWhitelistProto user_whitelist = 2; @@ -808,4 +814,5 @@ 45; optional LoginAppsProto login_apps = 46; optional NetworkThrottlingEnabledProto network_throttling = 47; + optional DeviceWallpaperImageProto device_wallpaper_image = 48; }
diff --git a/chrome/browser/chromeos/power/freezer_cgroup_process_manager.cc b/chrome/browser/chromeos/power/freezer_cgroup_process_manager.cc index af1fd7e..9c20edb 100644 --- a/chrome/browser/chromeos/power/freezer_cgroup_process_manager.cc +++ b/chrome/browser/chromeos/power/freezer_cgroup_process_manager.cc
@@ -34,7 +34,9 @@ explicit FileWorker(scoped_refptr<base::SequencedTaskRunner> file_thread) : ui_thread_(content::BrowserThread::GetTaskRunnerForThread( content::BrowserThread::UI)), - file_thread_(file_thread) { + file_thread_(file_thread), + enabled_(false), + froze_successfully_(false) { DCHECK(ui_thread_->RunsTasksOnCurrentThread()); } @@ -78,7 +80,8 @@ return; } - WriteCommandToFile(kFreezeCommand, to_be_frozen_state_path_); + froze_successfully_ = + WriteCommandToFile(kFreezeCommand, to_be_frozen_state_path_); } void ThawRenderers(ResultCallback callback) { @@ -91,6 +94,13 @@ } bool result = WriteCommandToFile(kThawCommand, to_be_frozen_state_path_); + + // TODO(derat): For now, lie and report success if thawing failed but + // freezing also failed previously. Remove after weird EBADF and ENOENT + // problems tracked at http://crbug.com/661310 are fixed. + if (!result && !froze_successfully_) + result = true; + ui_thread_->PostTask(FROM_HERE, base::Bind(callback, result)); } @@ -128,6 +138,10 @@ bool enabled_; + // True iff FreezeRenderers() wrote its command successfully the last time it + // was called. + bool froze_successfully_; + DISALLOW_COPY_AND_ASSIGN(FileWorker); };
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc index 6775222e..05a60523c1 100644 --- a/chrome/browser/chromeos/settings/device_settings_provider.cc +++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" +#include "base/json/json_reader.h" #include "base/logging.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" @@ -64,6 +65,7 @@ kDeviceDisabledMessage, kDeviceOwner, kDeviceQuirksDownloadEnabled, + kDeviceWallpaperImage, kDisplayRotationDefault, kExtensionCacheSize, kHeartbeatEnabled, @@ -523,6 +525,14 @@ kDeviceQuirksDownloadEnabled, policy.quirks_download_enabled().quirks_download_enabled()); } + + if (policy.has_device_wallpaper_image() && + policy.device_wallpaper_image().has_device_wallpaper_image()) { + std::unique_ptr<base::DictionaryValue> dict_val = + base::DictionaryValue::From(base::JSONReader::Read( + policy.device_wallpaper_image().device_wallpaper_image())); + new_values_cache->SetValue(kDeviceWallpaperImage, std::move(dict_val)); + } } void DecodeLogUploadPolicies(const em::ChromeDeviceSettingsProto& policy,
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_store.cc b/chrome/browser/extensions/api/content_settings/content_settings_store.cc index 3df22217..a3d28d9d 100644 --- a/chrome/browser/extensions/api/content_settings/content_settings_store.cc +++ b/chrome/browser/extensions/api/content_settings/content_settings_store.cc
@@ -4,15 +4,14 @@ #include "chrome/browser/extensions/api/content_settings/content_settings_store.h" +#include <algorithm> #include <memory> #include <set> #include <utility> -#include <vector> #include "base/debug/alias.h" #include "base/logging.h" #include "base/memory/ptr_util.h" -#include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/values.h" #include "chrome/browser/extensions/api/content_settings/content_settings_api_constants.h" @@ -36,8 +35,10 @@ namespace keys = content_settings_api_constants; struct ContentSettingsStore::ExtensionEntry { - // Extension id + // Extension id. std::string id; + // Installation time. + base::Time install_time; // Whether extension is enabled in the profile. bool enabled; // Content settings. @@ -53,7 +54,6 @@ } ContentSettingsStore::~ContentSettingsStore() { - base::STLDeleteValues(&entries_); } std::unique_ptr<RuleIterator> ContentSettingsStore::GetRuleIterator( @@ -61,16 +61,14 @@ const content_settings::ResourceIdentifier& identifier, bool incognito) const { std::vector<std::unique_ptr<RuleIterator>> iterators; - // Iterate the extensions based on install time (last installed extensions - // first). - ExtensionEntryMap::const_reverse_iterator entry_it; // The individual |RuleIterators| shouldn't lock; pass |lock_| to the // |ConcatenationIterator| in a locked state. std::unique_ptr<base::AutoLock> auto_lock(new base::AutoLock(lock_)); - for (entry_it = entries_.rbegin(); entry_it != entries_.rend(); ++entry_it) { - auto* entry = entry_it->second; + // Iterate the extensions based on install time (most-recently installed + // items first). + for (const auto& entry : entries_) { if (!entry->enabled) continue; @@ -128,13 +126,23 @@ const base::Time& install_time, bool is_enabled) { base::AutoLock lock(lock_); - ExtensionEntryMap::iterator i = FindEntry(ext_id); - ExtensionEntry* entry; + auto i = FindIterator(ext_id); + ExtensionEntry* entry = nullptr; if (i != entries_.end()) { - entry = i->second; + entry = i->get(); } else { entry = new ExtensionEntry; - entries_.insert(std::make_pair(install_time, entry)); + entry->install_time = install_time; + + // Insert in reverse-chronological order to maintain the invariant. + auto unique_entry = base::WrapUnique(entry); + auto location = + std::upper_bound(entries_.begin(), entries_.end(), unique_entry, + [](const std::unique_ptr<ExtensionEntry>& a, + const std::unique_ptr<ExtensionEntry>& b) { + return a->install_time > b->install_time; + }); + entries_.insert(location, std::move(unique_entry)); } entry->id = ext_id; @@ -147,14 +155,13 @@ bool notify_incognito = false; { base::AutoLock lock(lock_); - ExtensionEntryMap::iterator i = FindEntry(ext_id); + auto i = FindIterator(ext_id); if (i == entries_.end()) return; - notify = !i->second->settings.empty(); - notify_incognito = !i->second->incognito_persistent_settings.empty() || - !i->second->incognito_session_only_settings.empty(); + notify = !(*i)->settings.empty(); + notify_incognito = !(*i)->incognito_persistent_settings.empty() || + !(*i)->incognito_session_only_settings.empty(); - delete i->second; entries_.erase(i); } if (notify) @@ -169,14 +176,15 @@ bool notify_incognito = false; { base::AutoLock lock(lock_); - ExtensionEntryMap::const_iterator i = FindEntry(ext_id); - if (i == entries_.end()) + ExtensionEntry* entry = FindEntry(ext_id); + if (!entry) return; - notify = !i->second->settings.empty(); - notify_incognito = !i->second->incognito_persistent_settings.empty() || - !i->second->incognito_session_only_settings.empty(); - i->second->enabled = is_enabled; + notify = !entry->settings.empty(); + notify_incognito = !entry->incognito_persistent_settings.empty() || + !entry->incognito_session_only_settings.empty(); + + entry->enabled = is_enabled; } if (notify) NotifyOfContentSettingChanged(ext_id, false); @@ -187,46 +195,34 @@ OriginIdentifierValueMap* ContentSettingsStore::GetValueMap( const std::string& ext_id, ExtensionPrefsScope scope) { - ExtensionEntryMap::const_iterator i = FindEntry(ext_id); - if (i != entries_.end()) { - switch (scope) { - case kExtensionPrefsScopeRegular: - return &(i->second->settings); - case kExtensionPrefsScopeRegularOnly: - // TODO(bauerb): Implement regular-only content settings. - NOTREACHED(); - return NULL; - case kExtensionPrefsScopeIncognitoPersistent: - return &(i->second->incognito_persistent_settings); - case kExtensionPrefsScopeIncognitoSessionOnly: - return &(i->second->incognito_session_only_settings); - } - } - return NULL; + const OriginIdentifierValueMap* result = + static_cast<const ContentSettingsStore*>(this)->GetValueMap(ext_id, + scope); + return const_cast<OriginIdentifierValueMap*>(result); } const OriginIdentifierValueMap* ContentSettingsStore::GetValueMap( const std::string& ext_id, ExtensionPrefsScope scope) const { - ExtensionEntryMap::const_iterator i = FindEntry(ext_id); - if (i == entries_.end()) - return NULL; + ExtensionEntry* entry = FindEntry(ext_id); + if (!entry) + return nullptr; switch (scope) { case kExtensionPrefsScopeRegular: - return &(i->second->settings); + return &(entry->settings); case kExtensionPrefsScopeRegularOnly: // TODO(bauerb): Implement regular-only content settings. NOTREACHED(); - return NULL; + return nullptr; case kExtensionPrefsScopeIncognitoPersistent: - return &(i->second->incognito_persistent_settings); + return &(entry->incognito_persistent_settings); case kExtensionPrefsScopeIncognitoSessionOnly: - return &(i->second->incognito_session_only_settings); + return &(entry->incognito_session_only_settings); } NOTREACHED(); - return NULL; + return nullptr; } void ContentSettingsStore::ClearContentSettingsForExtension( @@ -375,24 +371,22 @@ BrowserThread::CurrentlyOn(BrowserThread::UI); } -ContentSettingsStore::ExtensionEntryMap::iterator -ContentSettingsStore::FindEntry(const std::string& ext_id) { - ExtensionEntryMap::iterator i; - for (i = entries_.begin(); i != entries_.end(); ++i) { - if (i->second->id == ext_id) - return i; - } - return entries_.end(); +ContentSettingsStore::ExtensionEntry* ContentSettingsStore::FindEntry( + const std::string& ext_id) const { + auto iter = + std::find_if(entries_.begin(), entries_.end(), + [ext_id](const std::unique_ptr<ExtensionEntry>& entry) { + return entry->id == ext_id; + }); + return iter == entries_.end() ? nullptr : iter->get(); } -ContentSettingsStore::ExtensionEntryMap::const_iterator -ContentSettingsStore::FindEntry(const std::string& ext_id) const { - ExtensionEntryMap::const_iterator i; - for (i = entries_.begin(); i != entries_.end(); ++i) { - if (i->second->id == ext_id) - return i; - } - return entries_.end(); +ContentSettingsStore::ExtensionEntries::iterator +ContentSettingsStore::FindIterator(const std::string& ext_id) { + return std::find_if(entries_.begin(), entries_.end(), + [ext_id](const std::unique_ptr<ExtensionEntry>& entry) { + return entry->id == ext_id; + }); } } // namespace extensions
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_store.h b/chrome/browser/extensions/api/content_settings/content_settings_store.h index f0f9e39..0567613 100644 --- a/chrome/browser/extensions/api/content_settings/content_settings_store.h +++ b/chrome/browser/extensions/api/content_settings/content_settings_store.h
@@ -6,7 +6,9 @@ #define CHROME_BROWSER_EXTENSIONS_API_CONTENT_SETTINGS_CONTENT_SETTINGS_STORE_H_ #include <map> +#include <memory> #include <string> +#include <vector> #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -112,7 +114,9 @@ struct ExtensionEntry; - typedef std::multimap<base::Time, ExtensionEntry*> ExtensionEntryMap; + // A list of the entries, maintained in reverse-chronological order (most- + // recently installed items first) to facilitate search. + using ExtensionEntries = std::vector<std::unique_ptr<ExtensionEntry>>; virtual ~ContentSettingsStore(); @@ -129,10 +133,11 @@ bool OnCorrectThread(); - ExtensionEntryMap::iterator FindEntry(const std::string& ext_id); - ExtensionEntryMap::const_iterator FindEntry(const std::string& ext_id) const; + ExtensionEntry* FindEntry(const std::string& ext_id) const; + ExtensionEntries::iterator FindIterator(const std::string& ext_id); - ExtensionEntryMap entries_; + // The entries. + ExtensionEntries entries_; base::ObserverList<Observer, false> observers_;
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc index 6d22232e..ec9cdc3 100644 --- a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc +++ b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
@@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/command_line.h" #include "base/macros.h" +#include "base/strings/stringprintf.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/helper.h" #include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h" @@ -167,10 +168,11 @@ service_test_(nullptr), device_test_(nullptr) {} - bool RunNetworkingSubtest(const std::string& subtest) { - return RunExtensionSubtest("networking_private/chromeos", - "main.html?" + subtest, - kFlagEnableFileAccess | kFlagLoadAsComponent); + bool RunNetworkingSubtest(const std::string& test) { + const std::string arg = + base::StringPrintf("{\"test\": \"%s\"}", test.c_str()); + return RunPlatformAppTestWithArg("networking_private/chromeos", + arg.c_str()); } void SetUpInProcessBrowserTestFixture() override { @@ -713,4 +715,11 @@ EXPECT_TRUE(RunNetworkingSubtest("cellularSimPuk")) << message_; } +// Tests subset of networking API for the networking API alias - to verify that +// using API methods and event does not cause access exceptions (due to +// missing permissions). +IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, Alias) { + EXPECT_TRUE(RunPlatformAppTest("networking_private/alias")) << message_; +} + } // namespace
diff --git a/chrome/browser/media/combined_desktop_media_list.cc b/chrome/browser/media/combined_desktop_media_list.cc deleted file mode 100644 index 8ef6f8c..0000000 --- a/chrome/browser/media/combined_desktop_media_list.cc +++ /dev/null
@@ -1,130 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/media/combined_desktop_media_list.h" - -CombinedDesktopMediaList::CombinedDesktopMediaList( - std::vector<std::unique_ptr<DesktopMediaList>>& media_lists) - : media_lists_(std::move(media_lists)) { - DCHECK(media_lists_.size()); -} - -CombinedDesktopMediaList::~CombinedDesktopMediaList() {} - -void CombinedDesktopMediaList::SetUpdatePeriod(base::TimeDelta period) { - for (const auto& list : media_lists_) - list->SetUpdatePeriod(period); -} - -void CombinedDesktopMediaList::SetThumbnailSize( - const gfx::Size& thumbnail_size) { - for (const auto& list : media_lists_) - list->SetThumbnailSize(thumbnail_size); -} - -void CombinedDesktopMediaList::SetViewDialogWindowId( - content::DesktopMediaID dialog_id) { - for (const auto& list : media_lists_) - list->SetViewDialogWindowId(dialog_id); -} - -void CombinedDesktopMediaList::StartUpdating( - DesktopMediaListObserver* observer) { - observer_ = observer; - for (const auto& list : media_lists_) - list->StartUpdating(this); -} - -int CombinedDesktopMediaList::GetSourceCount() const { - int count = 0; - for (const auto& list : media_lists_) - count += list->GetSourceCount(); - - return count; -} - -const DesktopMediaList::Source& CombinedDesktopMediaList::GetSource( - int index) const { - for (const auto& list : media_lists_) { - int count = list->GetSourceCount(); - if (index < count) - return list->GetSource(index); - - index -= count; - } - - NOTREACHED(); - return media_lists_[0]->GetSource(0); -} - -void CombinedDesktopMediaList::OnSourceAdded(DesktopMediaList* list, - int index) { - int count = 0; - for (const auto& cur_list : media_lists_) { - if (cur_list.get() == list) { - observer_->OnSourceAdded(this, count + index); - return; - } - count += cur_list->GetSourceCount(); - } - - NOTREACHED(); -} - -void CombinedDesktopMediaList::OnSourceRemoved(DesktopMediaList* list, - int index) { - int count = 0; - for (const auto& cur_list : media_lists_) { - if (cur_list.get() == list) { - observer_->OnSourceRemoved(this, count + index); - return; - } - count += cur_list->GetSourceCount(); - } - - NOTREACHED(); -} - -void CombinedDesktopMediaList::OnSourceMoved(DesktopMediaList* list, - int old_index, - int new_index) { - int count = 0; - for (const auto& cur_list : media_lists_) { - if (cur_list.get() == list) { - observer_->OnSourceMoved(this, count + old_index, count + new_index); - return; - } - count += cur_list->GetSourceCount(); - } - - NOTREACHED(); -} - -void CombinedDesktopMediaList::OnSourceNameChanged(DesktopMediaList* list, - int index) { - int count = 0; - for (const auto& cur_list : media_lists_) { - if (cur_list.get() == list) { - observer_->OnSourceNameChanged(this, count + index); - return; - } - count += cur_list->GetSourceCount(); - } - - NOTREACHED(); -} - -void CombinedDesktopMediaList::OnSourceThumbnailChanged(DesktopMediaList* list, - int index) { - int count = 0; - for (const auto& cur_list : media_lists_) { - if (cur_list.get() == list) { - observer_->OnSourceThumbnailChanged(this, count + index); - return; - } - count += cur_list->GetSourceCount(); - } - - NOTREACHED(); -}
diff --git a/chrome/browser/media/combined_desktop_media_list.h b/chrome/browser/media/combined_desktop_media_list.h deleted file mode 100644 index 9e100e3..0000000 --- a/chrome/browser/media/combined_desktop_media_list.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_MEDIA_COMBINED_DESKTOP_MEDIA_LIST_H_ -#define CHROME_BROWSER_MEDIA_COMBINED_DESKTOP_MEDIA_LIST_H_ - -#include <memory> -#include <vector> - -#include "chrome/browser/media/webrtc/desktop_media_list.h" -#include "chrome/browser/media/webrtc/desktop_media_list_observer.h" - -// The combined desktop media list of one or multiple input DesktopMediaLists. -// The combined list is the concatenation of the input lists. The front of -// combined list will be filled with the first input list, then follows with -// the second one and so on. -class CombinedDesktopMediaList : public DesktopMediaList, - public DesktopMediaListObserver { - public: - explicit CombinedDesktopMediaList( - std::vector<std::unique_ptr<DesktopMediaList>>& media_lists); - ~CombinedDesktopMediaList() override; - - // DesktopMediaList interface. - void SetUpdatePeriod(base::TimeDelta period) override; - void SetThumbnailSize(const gfx::Size& thumbnail_size) override; - void SetViewDialogWindowId(content::DesktopMediaID dialog_id) override; - void StartUpdating(DesktopMediaListObserver* observer) override; - int GetSourceCount() const override; - const Source& GetSource(int index) const override; - - private: - // DesktopMediaListObserver interface. - void OnSourceAdded(DesktopMediaList* list, int index) override; - void OnSourceRemoved(DesktopMediaList* list, int index) override; - void OnSourceMoved(DesktopMediaList* list, - int old_index, - int new_index) override; - void OnSourceNameChanged(DesktopMediaList* list, int index) override; - void OnSourceThumbnailChanged(DesktopMediaList* list, int index) override; - - std::vector<std::unique_ptr<DesktopMediaList>> media_lists_; - - DesktopMediaListObserver* observer_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(CombinedDesktopMediaList); -}; - -#endif // CHROME_BROWSER_MEDIA_COMBINED_DESKTOP_MEDIA_LIST_H_
diff --git a/chrome/browser/media/combined_desktop_media_list_unittest.cc b/chrome/browser/media/combined_desktop_media_list_unittest.cc deleted file mode 100644 index 7f5d6c0..0000000 --- a/chrome/browser/media/combined_desktop_media_list_unittest.cc +++ /dev/null
@@ -1,387 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/media/combined_desktop_media_list.h" - -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/media/webrtc/desktop_media_list_base.h" -#include "chrome/browser/media/webrtc/desktop_media_list_observer.h" -#include "content/public/test/test_browser_thread.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/image/image_skia.h" - -using testing::DoAll; -using content::DesktopMediaID; - -static const int kThumbnailSize = 50; -static const int kDefaultSourceCount = 2; - -// Create a greyscale image with certain size and grayscale value. -gfx::ImageSkia CreateGrayscaleImage(gfx::Size size, uint8_t greyscale_value) { - SkBitmap result; - result.allocN32Pixels(size.width(), size.height(), true); - - result.lockPixels(); - uint8_t* pixels_data = reinterpret_cast<uint8_t*>(result.getPixels()); - - // Set greyscale value for all pixels. - for (int y = 0; y < result.height(); ++y) { - for (int x = 0; x < result.width(); ++x) { - pixels_data[result.rowBytes() * y + x * result.bytesPerPixel()] = - greyscale_value; - pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 1] = - greyscale_value; - pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 2] = - greyscale_value; - pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 3] = - 0xff; - } - } - - result.unlockPixels(); - - return gfx::ImageSkia::CreateFrom1xBitmap(result); -} - -// Fake Implementation of DesktopMediaListBase. -class FakeDesktopMediaListBaseImpl : public DesktopMediaListBase { - public: - explicit FakeDesktopMediaListBaseImpl(DesktopMediaID::Type type) - : DesktopMediaListBase(base::TimeDelta()), - media_type_(type) { - SetThumbnailSize(gfx::Size(kThumbnailSize, kThumbnailSize)); - - for (int i = 0; i < kDefaultSourceCount; ++i) - AddFakeSource(i, base::UTF8ToUTF16("Test media"), i); - } - - ~FakeDesktopMediaListBaseImpl() override {} - - void AddFakeSource(int index, base::string16 title, int greyscale_value) { - DesktopMediaID id(media_type_, index + 1); - fake_sources_.push_back(DesktopMediaListBase::SourceDescription(id, title)); - fake_thumbnails_.push_back( - CreateGrayscaleImage(gfx::Size(10, 10), greyscale_value)); - current_thumbnail_map_[id.id] = greyscale_value; - } - - void RemoveFakeSource(int index) { - if (static_cast<size_t>(index) >= fake_sources_.size()) - return; - - current_thumbnail_map_.erase(fake_sources_[index].id.id); - fake_sources_.erase(fake_sources_.begin() + index); - fake_thumbnails_.erase(fake_thumbnails_.begin() + index); - } - - void Refresh() override { - UpdateSourcesList(fake_sources_); - - // Update thumbnails. - for (size_t i = 0; i < fake_sources_.size(); i++) { - // only update when a thumbnail is added or changed. - const int id = fake_sources_[i].id.id; - if (!refreshed_thumbnail_map_.count(id) || - (refreshed_thumbnail_map_[id] != current_thumbnail_map_[id])) { - UpdateSourceThumbnail(fake_sources_[i].id, fake_thumbnails_[i]); - } - } - refreshed_thumbnail_map_ = current_thumbnail_map_; - } - - std::vector<DesktopMediaListBase::SourceDescription> fake_sources_; - std::vector<gfx::ImageSkia> fake_thumbnails_; - DesktopMediaID::Type media_type_; - // The current and last refrehed maps of source id and thumbnail's greyscale. - // They are used for detect the thumbnail add or change. - std::map<int, int> current_thumbnail_map_, refreshed_thumbnail_map_; - - DISALLOW_COPY_AND_ASSIGN(FakeDesktopMediaListBaseImpl); -}; - -class MockObserver : public DesktopMediaListObserver { - public: - MOCK_METHOD2(OnSourceAdded, void(DesktopMediaList* list, int index)); - MOCK_METHOD2(OnSourceRemoved, void(DesktopMediaList* list, int index)); - MOCK_METHOD3(OnSourceMoved, - void(DesktopMediaList* list, int old_index, int new_index)); - MOCK_METHOD2(OnSourceNameChanged, void(DesktopMediaList* list, int index)); - MOCK_METHOD2(OnSourceThumbnailChanged, - void(DesktopMediaList* list, int index)); - - void VerifyAndClearExpectations() { - testing::Mock::VerifyAndClearExpectations(this); - } -}; - -ACTION_P2(CheckListSize, list, expected_list_size) { - EXPECT_EQ(expected_list_size, list->GetSourceCount()); -} - -ACTION_P(QuitMessageLoop, message_loop) { - message_loop->task_runner()->PostTask( - FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); -} - -class CombinedDesktopMediaListTest : public testing::Test { - public: - CombinedDesktopMediaListTest() - : ui_thread_(content::BrowserThread::UI, &message_loop_) { - list1_ = new FakeDesktopMediaListBaseImpl(DesktopMediaID::TYPE_SCREEN); - list2_ = new FakeDesktopMediaListBaseImpl(DesktopMediaID::TYPE_WINDOW); - - std::unique_ptr<DesktopMediaList> list1(list1_); - std::unique_ptr<DesktopMediaList> list2(list2_); - - std::vector<std::unique_ptr<DesktopMediaList>> lists; - lists.push_back(std::move(list1)); - lists.push_back(std::move(list2)); - - combined_list_.reset(new CombinedDesktopMediaList(lists)); - } - - // StartUpdating() and verify the first call of refresh(). - void InitializeAndVerify() { - { - testing::InSequence dummy; - - // list1_'s refresh. - for (int i = 0; i < kDefaultSourceCount; ++i) { - EXPECT_CALL(observer_, OnSourceAdded(combined_list_.get(), i)) - .WillOnce(CheckListSize(combined_list_.get(), i + 1)); - } - - for (int i = 0; i < kDefaultSourceCount; ++i) { - EXPECT_CALL(observer_, - OnSourceThumbnailChanged(combined_list_.get(), i)); - } - - // list2_'s refresh. - for (int i = kDefaultSourceCount; i < 2 * kDefaultSourceCount; ++i) { - EXPECT_CALL(observer_, OnSourceAdded(combined_list_.get(), i)) - .WillOnce(CheckListSize(combined_list_.get(), i + 1)); - } - - for (int i = kDefaultSourceCount; i < 2 * kDefaultSourceCount - 1; ++i) { - EXPECT_CALL(observer_, - OnSourceThumbnailChanged(combined_list_.get(), i)); - } - - EXPECT_CALL(observer_, - OnSourceThumbnailChanged(combined_list_.get(), - 2 * kDefaultSourceCount - 1)) - .WillOnce(QuitMessageLoop(&message_loop_)); - } - - combined_list_->StartUpdating(&observer_); - base::RunLoop().Run(); - - // list1_'s sources. - for (int i = 0; i < kDefaultSourceCount; ++i) { - EXPECT_EQ(combined_list_->GetSource(i).id.type, - content::DesktopMediaID::TYPE_SCREEN); - EXPECT_EQ(combined_list_->GetSource(i).id.id, i + 1); - } - - // list2_'s sources. - for (int i = kDefaultSourceCount; i < 2 * kDefaultSourceCount; i++) { - EXPECT_EQ(combined_list_->GetSource(i).id.type, - content::DesktopMediaID::TYPE_WINDOW); - EXPECT_EQ(combined_list_->GetSource(i).id.id, - i - kDefaultSourceCount + 1); - } - - observer_.VerifyAndClearExpectations(); - } - - protected: - // Must be listed before |combined_list_|, so it's destroyed last. - MockObserver observer_; - FakeDesktopMediaListBaseImpl* list1_; - FakeDesktopMediaListBaseImpl* list2_; - std::unique_ptr<CombinedDesktopMediaList> combined_list_; - - base::MessageLoop message_loop_; - content::TestBrowserThread ui_thread_; - - DISALLOW_COPY_AND_ASSIGN(CombinedDesktopMediaListTest); -}; - -TEST_F(CombinedDesktopMediaListTest, AddSource) { - InitializeAndVerify(); - - int index = kDefaultSourceCount; - list1_->AddFakeSource(index, base::UTF8ToUTF16("Test media"), index); - - EXPECT_CALL(observer_, OnSourceAdded(combined_list_.get(), index)) - .WillOnce( - CheckListSize(combined_list_.get(), 2 * kDefaultSourceCount + 1)); - EXPECT_CALL(observer_, OnSourceThumbnailChanged(combined_list_.get(), index)) - .WillOnce(QuitMessageLoop(&message_loop_)); - - list1_->Refresh(); - base::RunLoop().Run(); - - list2_->AddFakeSource(index, base::UTF8ToUTF16("Test media"), index); - - EXPECT_CALL(observer_, - OnSourceAdded(combined_list_.get(), 2 * kDefaultSourceCount + 1)) - .WillOnce( - CheckListSize(combined_list_.get(), 2 * kDefaultSourceCount + 2)); - EXPECT_CALL(observer_, OnSourceThumbnailChanged(combined_list_.get(), - 2 * kDefaultSourceCount + 1)) - .WillOnce(QuitMessageLoop(&message_loop_)); - - list2_->Refresh(); - base::RunLoop().Run(); - - // Verify last source for list1_ and first source for list2_. - EXPECT_EQ(combined_list_->GetSource(index).id.type, - content::DesktopMediaID::TYPE_SCREEN); - EXPECT_EQ(combined_list_->GetSource(index).id.id, index + 1); - EXPECT_EQ(combined_list_->GetSource(index + 1).id.type, - content::DesktopMediaID::TYPE_WINDOW); - EXPECT_EQ(combined_list_->GetSource(index + 1).id.id, 1); -} - -TEST_F(CombinedDesktopMediaListTest, RemoveSource) { - InitializeAndVerify(); - - int index = kDefaultSourceCount - 1; - list1_->RemoveFakeSource(index); - - EXPECT_CALL(observer_, OnSourceRemoved(combined_list_.get(), index)) - .WillOnce(DoAll( - CheckListSize(combined_list_.get(), 2 * kDefaultSourceCount - 1), - QuitMessageLoop(&message_loop_))); - - list1_->Refresh(); - base::RunLoop().Run(); - - list2_->RemoveFakeSource(index); - - EXPECT_CALL(observer_, OnSourceRemoved(combined_list_.get(), - 2 * kDefaultSourceCount - 2)) - .WillOnce(DoAll( - CheckListSize(combined_list_.get(), 2 * kDefaultSourceCount - 2), - QuitMessageLoop(&message_loop_))); - - list2_->Refresh(); - base::RunLoop().Run(); - - // Verify last source for list1_ and first source for list2_. - EXPECT_EQ(combined_list_->GetSource(index - 1).id.type, - content::DesktopMediaID::TYPE_SCREEN); - EXPECT_EQ(combined_list_->GetSource(index - 1).id.id, index); - EXPECT_EQ(combined_list_->GetSource(index).id.type, - content::DesktopMediaID::TYPE_WINDOW); - EXPECT_EQ(combined_list_->GetSource(index).id.id, 1); -} - -TEST_F(CombinedDesktopMediaListTest, MoveSource) { - InitializeAndVerify(); - - // Swap sources. - list1_->RemoveFakeSource(kDefaultSourceCount - 1); - list1_->RemoveFakeSource(kDefaultSourceCount - 2); - list1_->AddFakeSource(kDefaultSourceCount - 1, - base::UTF8ToUTF16("Test media"), - kDefaultSourceCount - 1); - list1_->AddFakeSource(kDefaultSourceCount - 2, - base::UTF8ToUTF16("Test media"), - kDefaultSourceCount - 2); - - EXPECT_CALL(observer_, - OnSourceMoved(combined_list_.get(), kDefaultSourceCount - 1, - kDefaultSourceCount - 2)) - .WillOnce(QuitMessageLoop(&message_loop_)); - - list1_->Refresh(); - base::RunLoop().Run(); - - // Swap sources. - list2_->RemoveFakeSource(kDefaultSourceCount - 1); - list2_->RemoveFakeSource(kDefaultSourceCount - 2); - list2_->AddFakeSource(kDefaultSourceCount - 1, - base::UTF8ToUTF16("Test media"), - kDefaultSourceCount - 1); - list2_->AddFakeSource(kDefaultSourceCount - 2, - base::UTF8ToUTF16("Test media"), - kDefaultSourceCount - 2); - - EXPECT_CALL(observer_, - OnSourceMoved(combined_list_.get(), 2 * kDefaultSourceCount - 1, - 2 * kDefaultSourceCount - 2)) - .WillOnce(QuitMessageLoop(&message_loop_)); - - list2_->Refresh(); - base::RunLoop().Run(); -} - -TEST_F(CombinedDesktopMediaListTest, UpdateTitle) { - InitializeAndVerify(); - - // Change title. - list1_->RemoveFakeSource(kDefaultSourceCount - 1); - list1_->AddFakeSource(kDefaultSourceCount - 1, - base::UTF8ToUTF16("New test media"), - kDefaultSourceCount - 1); - - EXPECT_CALL(observer_, OnSourceNameChanged(combined_list_.get(), - kDefaultSourceCount - 1)) - .WillOnce(QuitMessageLoop(&message_loop_)); - - list1_->Refresh(); - base::RunLoop().Run(); - - // Change title. - list2_->RemoveFakeSource(kDefaultSourceCount - 1); - list2_->AddFakeSource(kDefaultSourceCount - 1, - base::UTF8ToUTF16("New test media"), - kDefaultSourceCount - 1); - - EXPECT_CALL(observer_, OnSourceNameChanged(combined_list_.get(), - 2 * kDefaultSourceCount - 1)) - .WillOnce(QuitMessageLoop(&message_loop_)); - - list2_->Refresh(); - base::RunLoop().Run(); - - EXPECT_EQ(combined_list_->GetSource(kDefaultSourceCount - 1).name, - base::UTF8ToUTF16("New test media")); - EXPECT_EQ(combined_list_->GetSource(2 * kDefaultSourceCount - 1).name, - base::UTF8ToUTF16("New test media")); -} - -TEST_F(CombinedDesktopMediaListTest, UpdateThumbnail) { - InitializeAndVerify(); - - // Change thumbnail. - list1_->RemoveFakeSource(kDefaultSourceCount - 1); - list1_->AddFakeSource(kDefaultSourceCount - 1, - base::UTF8ToUTF16("Test media"), 100); - - EXPECT_CALL(observer_, OnSourceThumbnailChanged(combined_list_.get(), - kDefaultSourceCount - 1)) - .WillOnce(QuitMessageLoop(&message_loop_)); - - list1_->Refresh(); - base::RunLoop().Run(); - - // Change thumbnail. - list2_->RemoveFakeSource(kDefaultSourceCount - 1); - list2_->AddFakeSource(kDefaultSourceCount - 1, - base::UTF8ToUTF16("Test media"), 100); - - EXPECT_CALL(observer_, OnSourceThumbnailChanged(combined_list_.get(), - 2 * kDefaultSourceCount - 1)) - .WillOnce(QuitMessageLoop(&message_loop_)); - - list2_->Refresh(); - base::RunLoop().Run(); -}
diff --git a/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc b/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc index b856588..cf79263 100644 --- a/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc +++ b/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc
@@ -37,6 +37,7 @@ #if defined(OS_CHROMEOS) #include "ash/shell.h" #include "chrome/browser/media/public_session_media_access_handler.h" +#include "chrome/browser/media/webrtc/public_session_tab_capture_access_handler.h" #endif // defined(OS_CHROMEOS) #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -92,8 +93,13 @@ media_access_handlers_.push_back(new ExtensionMediaAccessHandler()); #endif media_access_handlers_.push_back(new DesktopCaptureAccessHandler()); +#if defined(OS_CHROMEOS) + // Wrapper around TabCaptureAccessHandler used in Public Sessions. + media_access_handlers_.push_back(new PublicSessionTabCaptureAccessHandler()); +#else media_access_handlers_.push_back(new TabCaptureAccessHandler()); #endif +#endif media_access_handlers_.push_back(new PermissionBubbleMediaAccessHandler()); }
diff --git a/chrome/browser/media/webrtc/public_session_tab_capture_access_handler.cc b/chrome/browser/media/webrtc/public_session_tab_capture_access_handler.cc new file mode 100644 index 0000000..65e2d33 --- /dev/null +++ b/chrome/browser/media/webrtc/public_session_tab_capture_access_handler.cc
@@ -0,0 +1,143 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/media/webrtc/public_session_tab_capture_access_handler.h" + +#include <utility> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/ptr_util.h" +#include "chromeos/login/login_state.h" +#include "content/public/browser/web_contents.h" +#include "extensions/common/extension.h" +#include "extensions/common/permissions/manifest_permission_set.h" +#include "extensions/common/permissions/permission_set.h" +#include "extensions/common/url_pattern_set.h" + +namespace { + +// Returns true if we're in a Public Session. +bool IsPublicSession() { + return chromeos::LoginState::IsInitialized() && + chromeos::LoginState::Get()->IsPublicSessionUser(); +} + +} // namespace + +PublicSessionTabCaptureAccessHandler::PublicSessionTabCaptureAccessHandler() {} + +PublicSessionTabCaptureAccessHandler::~PublicSessionTabCaptureAccessHandler() {} + +bool PublicSessionTabCaptureAccessHandler::SupportsStreamType( + const content::MediaStreamType type, + const extensions::Extension* extension) { + return tab_capture_access_handler_.SupportsStreamType(type, extension); +} + +bool PublicSessionTabCaptureAccessHandler::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const extensions::Extension* extension) { + return tab_capture_access_handler_.CheckMediaAccessPermission( + web_contents, security_origin, type, extension); +} + +void PublicSessionTabCaptureAccessHandler::HandleRequest( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const extensions::Extension* extension) { + // This class handles requests for Public Sessions only, outside of them just + // pass the request through to the original class. + if (!IsPublicSession() || !extension) { + return tab_capture_access_handler_.HandleRequest(web_contents, request, + callback, extension); + } + + UserChoice& user_choice = user_choice_cache_[extension->id()]; + + if ((request.audio_type != content::MEDIA_TAB_AUDIO_CAPTURE && + request.video_type != content::MEDIA_TAB_VIDEO_CAPTURE) || + !user_choice.NeedsPrompting()) { + return ChainHandleRequest(web_contents, request, callback, extension); + } + + user_choice.SetPrompted(); + + extensions::APIPermissionSet new_apis; + new_apis.insert(extensions::APIPermission::kTabCapture); + auto permission_set = base::MakeUnique<extensions::PermissionSet>( + new_apis, extensions::ManifestPermissionSet(), + extensions::URLPatternSet(), extensions::URLPatternSet()); + auto prompt = base::MakeUnique<ExtensionInstallPrompt>(web_contents); + + prompt->ShowDialog( + base::Bind(&PublicSessionTabCaptureAccessHandler::ResolvePermissionPrompt, + base::Unretained(this), web_contents, request, callback, + extension), + extension, + nullptr, // Uses the extension icon. + base::MakeUnique<ExtensionInstallPrompt::Prompt>( + ExtensionInstallPrompt::PERMISSIONS_PROMPT), + std::move(permission_set), + ExtensionInstallPrompt::GetDefaultShowDialogCallback()); + + extension_install_prompt_map_[extension->id()] = std::move(prompt); +} + +void PublicSessionTabCaptureAccessHandler::ChainHandleRequest( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const extensions::Extension* extension) { + DCHECK(IsPublicSession() && extension); + const UserChoice& user_choice = user_choice_cache_[extension->id()]; + content::MediaStreamRequest request_copy(request); + + // If the user denied tab capture, here the request gets filtered out before + // being passed on to the actual implementation. + if (!user_choice.IsAllowed()) { + request_copy.audio_type = content::MEDIA_NO_SERVICE; + request_copy.video_type = content::MEDIA_NO_SERVICE; + } + + // Pass the request through to the original class. + tab_capture_access_handler_.HandleRequest(web_contents, request_copy, + callback, extension); +} + +void PublicSessionTabCaptureAccessHandler::ResolvePermissionPrompt( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const extensions::Extension* extension, + ExtensionInstallPrompt::Result prompt_result) { + // Dispose of the prompt as it's not needed anymore. + extension_install_prompt_map_.erase(extension->id()); + + bool allowed = prompt_result == ExtensionInstallPrompt::Result::ACCEPTED; + UserChoice& user_choice = user_choice_cache_[extension->id()]; + + user_choice.Set(allowed); + + ChainHandleRequest(web_contents, request, callback, extension); +} + +bool PublicSessionTabCaptureAccessHandler::UserChoice::IsAllowed() const { + return tab_capture_allowed_; +} + +bool PublicSessionTabCaptureAccessHandler::UserChoice::NeedsPrompting() const { + return !tab_capture_prompted_; +} + +void PublicSessionTabCaptureAccessHandler::UserChoice::Set(bool allowed) { + tab_capture_allowed_ = allowed; +} + +void PublicSessionTabCaptureAccessHandler::UserChoice::SetPrompted() { + tab_capture_prompted_ = true; +}
diff --git a/chrome/browser/media/webrtc/public_session_tab_capture_access_handler.h b/chrome/browser/media/webrtc/public_session_tab_capture_access_handler.h new file mode 100644 index 0000000..a22dfad --- /dev/null +++ b/chrome/browser/media/webrtc/public_session_tab_capture_access_handler.h
@@ -0,0 +1,85 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_MEDIA_WEBRTC_PUBLIC_SESSION_TAB_CAPTURE_ACCESS_HANDLER_H_ +#define CHROME_BROWSER_MEDIA_WEBRTC_PUBLIC_SESSION_TAB_CAPTURE_ACCESS_HANDLER_H_ + +#include "base/macros.h" +#include "chrome/browser/extensions/extension_install_prompt.h" +#include "chrome/browser/media/capture_access_handler_base.h" +#include "chrome/browser/media/webrtc/tab_capture_access_handler.h" +#include "content/public/common/media_stream_request.h" +#include "extensions/common/extension_id.h" + +// MediaAccessHandler for TabCapture API in Public Sessions. This class is +// implemented as a wrapper around TabCaptureAccessHandler. It allows for finer +// access control to the TabCapture manifest permission feature inside of Public +// Sessions. +// +// In Public Sessions, extensions (and apps) are force-installed by admin policy +// so the user does not get a chance to review the permissions for these +// extensions. This is not acceptable from a security/privacy standpoint, so +// when an extension uses the TabCapture API for the first time, we show the +// user a dialog where they can choose whether to allow the extension access to +// the API. +// +// TODO(isandrk): Refactor common code out of this class and +// PublicSessionMediaAccessHandler (crbug.com/672620). +class PublicSessionTabCaptureAccessHandler : public CaptureAccessHandlerBase { + public: + PublicSessionTabCaptureAccessHandler(); + ~PublicSessionTabCaptureAccessHandler() override; + + // MediaAccessHandler implementation. + bool SupportsStreamType(const content::MediaStreamType type, + const extensions::Extension* extension) override; + bool CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const extensions::Extension* extension) override; + void HandleRequest(content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const extensions::Extension* extension) override; + + private: + // Helper function used to chain the HandleRequest call into the original + // inside of TabCaptureAccessHandler. + void ChainHandleRequest(content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const extensions::Extension* extension); + + // Function used to resolve user decision regarding allowing tab capture. + void ResolvePermissionPrompt(content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const extensions::Extension* extension, + ExtensionInstallPrompt::Result prompt_result); + + // Class used to cache user choice regarding allowing tab capture. + class UserChoice { + public: + // Helper function for checking if tab capture is allowed by user choice. + bool IsAllowed() const; + // Helper function which returns true if user choice wasn't prompted yet. + bool NeedsPrompting() const; + void Set(bool allowed); + void SetPrompted(); + + private: + bool tab_capture_prompted_ = false; + bool tab_capture_allowed_ = false; + }; + + std::map<extensions::ExtensionId, UserChoice> user_choice_cache_; + std::map<extensions::ExtensionId, std::unique_ptr<ExtensionInstallPrompt>> + extension_install_prompt_map_; + TabCaptureAccessHandler tab_capture_access_handler_; + + DISALLOW_COPY_AND_ASSIGN(PublicSessionTabCaptureAccessHandler); +}; + +#endif // CHROME_BROWSER_MEDIA_WEBRTC_PUBLIC_SESSION_TAB_CAPTURE_ACCESS_HANDLER_H_
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index 8220c23..4426c62 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -905,3 +905,30 @@ IN_PROC_BROWSER_TEST_F(PDFExtensionTest, RedirectsFailInPlugin) { RunTestsInFile("redirects_fail_test.js", "test.pdf"); } + +// Test that even if a different tab is selected when a navigation occurs, +// the correct tab still gets navigated (see crbug.com/672563). +IN_PROC_BROWSER_TEST_F(PDFExtensionTest, NavigationOnCorrectTab) { + GURL test_pdf_url(embedded_test_server()->GetURL("/pdf/test.pdf")); + content::WebContents* guest_contents = LoadPdfGetGuestContents(test_pdf_url); + ASSERT_TRUE(guest_contents); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL("about:blank"), + WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB | + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + content::WebContents* active_web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_NE(web_contents, active_web_contents); + + ASSERT_TRUE(content::ExecuteScript( + guest_contents, + "viewer.navigator_.navigate(" + " 'www.example.com', Navigator.WindowOpenDisposition.CURRENT_TAB);")); + + EXPECT_TRUE(web_contents->GetController().GetPendingEntry()); + EXPECT_FALSE(active_web_contents->GetController().GetPendingEntry()); +}
diff --git a/chrome/browser/resources/pdf/navigator.js b/chrome/browser/resources/pdf/navigator.js index ba6b7e0e8..15c4518e 100644 --- a/chrome/browser/resources/pdf/navigator.js +++ b/chrome/browser/resources/pdf/navigator.js
@@ -7,10 +7,11 @@ /** * Creates a new NavigatorDelegate for calling browser-specific functions to * do the actual navigating. - * @param {boolean} isInTab Indicates if the PDF viewer is displayed in a tab. + * @param {number} tabId The tab ID of the PDF viewer or -1 if the viewer is + * not displayed in a tab. */ -function NavigatorDelegate(isInTab) { - this.isInTab_ = isInTab; +function NavigatorDelegate(tabId) { + this.tabId_ = tabId; } /** @@ -38,8 +39,8 @@ navigateInCurrentTab: function(url) { // When the PDFviewer is inside a browser tab, prefer the tabs API because // it can navigate from one file:// URL to another. - if (chrome.tabs && this.isInTab_) - chrome.tabs.update({url: url}); + if (chrome.tabs && this.tabId_ != -1) + chrome.tabs.update(this.tabId_, {url: url}); else window.location.href = url; },
diff --git a/chrome/browser/resources/pdf/pdf.js b/chrome/browser/resources/pdf/pdf.js index 8db8ba16..118c50b 100644 --- a/chrome/browser/resources/pdf/pdf.js +++ b/chrome/browser/resources/pdf/pdf.js
@@ -246,10 +246,10 @@ document.addEventListener('mousemove', this.handleMouseEvent_.bind(this)); document.addEventListener('mouseout', this.handleMouseEvent_.bind(this)); - var isInTab = this.browserApi_.getStreamInfo().tabId != -1; + var tabId = this.browserApi_.getStreamInfo().tabId; this.navigator_ = new Navigator( this.originalUrl_, this.viewport_, this.paramsParser_, - new NavigatorDelegate(isInTab)); + new NavigatorDelegate(tabId)); this.viewportScroller_ = new ViewportScroller(this.viewport_, this.plugin_, window);
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html index 48478b52..b978357 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -41,8 +41,9 @@ <neon-animatable route-path="default"> <div class="settings-box first" actionable on-tap="toggleDeviceListExpanded_"> - <iron-icon icon="settings:bluetooth"></iron-icon> - <span class="middle">$i18n{bluetoothEnable}</span> + <iron-icon icon="[[getIcon_(bluetoothEnabled_, deviceConnected_)]]"> + </iron-icon> + <span class="middle">[[getTitle_(bluetoothEnabled_)]]</span> <cr-policy-pref-indicator pref="[[prefs.cros.device.allow_bluetooth]]" hidden="[[prefs.cros.device.allow_bluetooth.value]]">
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js index f716551..35054c2 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -62,6 +62,12 @@ adapterState_: Object, /** + * Whether or not a bluetooth device is connected. + * @private + */ + deviceConnected_: Boolean, + + /** * The ordered list of bluetooth devices. * @type {!Array<!chrome.bluetooth.Device>} * @private @@ -134,6 +140,8 @@ }, }, + observers: ['deviceListChanged_(deviceList_.*)'], + /** * Listener for chrome.bluetooth.onAdapterStateChanged events. * @type {function(!chrome.bluetooth.AdapterState)|undefined} @@ -219,11 +227,43 @@ }, /** @private */ + deviceListChanged_: function() { + for (let device of this.deviceList_) { + if (device.connected) { + this.deviceConnected_ = true; + return; + } + } + this.deviceConnected_ = false; + }, + + /** @private */ selectedItemChanged_: function() { if (this.selectedItem_) this.connectDevice_(this.selectedItem_); }, + /** + * @return {string} + * @private + */ + getIcon_: function() { + if (!this.bluetoothEnabled_) + return 'settings:bluetooth-disabled'; + if (this.deviceConnected_) + return 'settings:bluetooth-connected'; + return 'settings:bluetooth'; + }, + + /** + * @return {string} + * @private + */ + getTitle_: function() { + return this.i18n( + this.bluetoothEnabled_ ? 'bluetoothEnabled' : 'bluetoothDisabled'); + }, + /** @private */ toggleDeviceListExpanded_: function() { this.deviceListExpanded_ = !this.deviceListExpanded_;
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html index 1724407..a3ca875 100644 --- a/chrome/browser/resources/settings/icons.html +++ b/chrome/browser/resources/settings/icons.html
@@ -34,6 +34,8 @@ <if expr="chromeos"> <g id="battery-charging-full"><path d="M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33v15.33C7 21.4 7.6 22 8.33 22h7.33c.74 0 1.34-.6 1.34-1.33V5.33C17 4.6 16.4 4 15.67 4zM11 20v-5.5H9L13 7v5.5h2L11 20z"></path></g> <g id="bluetooth"><path d="M17.71 7.71L12 2h-1v7.59L6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 11 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM13 5.83l1.88 1.88L13 9.59V5.83zm1.88 10.46L13 18.17v-3.76l1.88 1.88z"></path></g> + <g id="bluetooth-connected"><path d="M7 12l-2-2-2 2 2 2 2-2zm10.71-4.29L12 2h-1v7.59L6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 11 14.41V22h1l5.71-5.71-4.3-4.29 4.3-4.29zM13 5.83l1.88 1.88L13 9.59V5.83zm1.88 10.46L13 18.17v-3.76l1.88 1.88zM19 10l-2 2 2 2 2-2-2-2z"></path></g> + <g id="bluetooth-disabled"><path d="M13 5.83l1.88 1.88-1.6 1.6 1.41 1.41 3.02-3.02L12 2h-1v5.03l2 2v-3.2zM5.41 4L4 5.41 10.59 12 5 17.59 6.41 19 11 14.41V22h1l4.29-4.29 2.3 2.29L20 18.59 5.41 4zM13 18.17v-3.76l1.88 1.88L13 18.17z"></path></g> <g id="brightness-1"><circle cx="12" cy="12" r="10"></circle></g> </if> <if expr="not chromeos">
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc index 6ab540b..4c7cfe2 100644 --- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc +++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -8,6 +8,7 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/path_service.h" +#include "base/strings/string_piece.h" #include "base/test/histogram_tester.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/subresource_filter/test_ruleset_publisher.h" @@ -31,6 +32,12 @@ const char kSubresourceFilterPromptHistogram[] = "SubresourceFilter.Prompt.NumVisibility"; +GURL GetURLWithFragment(const GURL& url, base::StringPiece fragment) { + GURL::Replacements replacements; + replacements.SetRefStr(fragment); + return url.ReplaceComponents(replacements); +} + } // namespace namespace subresource_filter { @@ -96,15 +103,32 @@ return nullptr; } - bool WasScriptResourceLoaded(content::RenderFrameHost* rfh) { + bool WasParsedScriptElementLoaded(content::RenderFrameHost* rfh) { DCHECK(rfh); - bool script_resource_was_loaded; + bool script_resource_was_loaded = false; EXPECT_TRUE(content::ExecuteScriptAndExtractBool( rfh, "domAutomationController.send(!!document.scriptExecuted)", &script_resource_was_loaded)); return script_resource_was_loaded; } + bool IsDynamicScriptElementLoaded(content::RenderFrameHost* rfh) { + DCHECK(rfh); + bool script_resource_was_loaded = false; + EXPECT_TRUE(content::ExecuteScriptAndExtractBool( + rfh, "insertScriptElementAndReportSuccess()", + &script_resource_was_loaded)); + return script_resource_was_loaded; + } + + void InsertDynamicFrameWithScript() { + bool frame_was_loaded = false; + ASSERT_TRUE(content::ExecuteScriptAndExtractBool( + web_contents()->GetMainFrame(), "insertFrameWithScriptAndNotify()", + &frame_was_loaded)); + ASSERT_TRUE(frame_was_loaded); + } + void SetRulesetToDisallowURLsWithPathSuffix(const std::string& suffix) { ASSERT_NO_FATAL_FAILURE( test_ruleset_publisher_.SetRulesetToDisallowURLsWithPathSuffix(suffix)); @@ -122,17 +146,37 @@ ASSERT_NO_FATAL_FAILURE(SetRulesetToDisallowURLsWithPathSuffix( "suffix-that-does-not-match-anything")); ui_test_utils::NavigateToURL(browser(), url); - EXPECT_TRUE(WasScriptResourceLoaded(web_contents()->GetMainFrame())); + EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame())); ASSERT_NO_FATAL_FAILURE( SetRulesetToDisallowURLsWithPathSuffix("included_script.js")); ui_test_utils::NavigateToURL(browser(), url); - EXPECT_FALSE(WasScriptResourceLoaded(web_contents()->GetMainFrame())); + EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame())); // The main frame document should never be filtered. SetRulesetToDisallowURLsWithPathSuffix("frame_with_included_script.html"); ui_test_utils::NavigateToURL(browser(), url); - EXPECT_TRUE(WasScriptResourceLoaded(web_contents()->GetMainFrame())); + EXPECT_TRUE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame())); +} + +// There should be no document-level de-/reactivation happening on the renderer +// side as a result of an in-page navigation. +IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, + DocumentActivationOutlivesSamePageNavigation) { + GURL url(GetTestUrl("subresource_filter/frame_with_delayed_script.html")); + ASSERT_NO_FATAL_FAILURE( + SetRulesetToDisallowURLsWithPathSuffix("included_script.js")); + ui_test_utils::NavigateToURL(browser(), url); + + // Deactivation would already detected by the IsDynamicScriptElementLoaded + // line alone. To ensure no reactivation, which would muddy up recorded + // histograms, also set a ruleset that allows everything. If there was + // reactivation, then this new ruleset would be picked up, once again causing + // the IsDynamicScriptElementLoaded check to fail. + ASSERT_NO_FATAL_FAILURE(SetRulesetToDisallowURLsWithPathSuffix( + "suffix-that-does-not-match-anything")); + ui_test_utils::NavigateToURL(browser(), GetURLWithFragment(url, "ref")); + EXPECT_FALSE(IsDynamicScriptElementLoaded(web_contents()->GetMainFrame())); } IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, SubFrameActivation) { @@ -146,11 +190,29 @@ for (const char* subframe_name : kSubframeNames) { content::RenderFrameHost* frame = FindFrameByName(subframe_name); ASSERT_TRUE(frame); - EXPECT_FALSE(WasScriptResourceLoaded(frame)); + EXPECT_FALSE(WasParsedScriptElementLoaded(frame)); } tester.ExpectBucketCount(kSubresourceFilterPromptHistogram, true, 1); } +// The page-level activation state on the browser-side should not be reset when +// a same-page navigation starts in the main frame. Verify this by dynamically +// inserting a subframe afterwards, and still expecting activation. +IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, + PageLevelActivationOutlivesSamePageNavigation) { + GURL url(GetTestUrl("subresource_filter/frame_set.html")); + ASSERT_NO_FATAL_FAILURE( + SetRulesetToDisallowURLsWithPathSuffix("included_script.js")); + ui_test_utils::NavigateToURL(browser(), url); + + ui_test_utils::NavigateToURL(browser(), GetURLWithFragment(url, "ref")); + + ASSERT_NO_FATAL_FAILURE(InsertDynamicFrameWithScript()); + content::RenderFrameHost* dynamic_frame = FindFrameByName("dynamic"); + ASSERT_TRUE(dynamic_frame); + EXPECT_FALSE(WasParsedScriptElementLoaded(dynamic_frame)); +} + IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, PRE_MainFrameActivationOnStartup) { SetRulesetToDisallowURLsWithPathSuffix("included_script.js"); @@ -162,7 +224,7 @@ // Verify that the ruleset persisted in the previous session is used for this // page load right after start-up. ui_test_utils::NavigateToURL(browser(), url); - EXPECT_FALSE(WasScriptResourceLoaded(web_contents()->GetMainFrame())); + EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame())); } IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, @@ -172,7 +234,9 @@ GURL url(GetTestUrl("subresource_filter/frame_set.html")); base::HistogramTester tester; ui_test_utils::NavigateToURL(browser(), url); - EXPECT_TRUE(ExecuteScript(FindFrameByName("three"), "runny()")); + tester.ExpectBucketCount(kSubresourceFilterPromptHistogram, true, 1); + // Check that the bubble is not shown again for this navigation. + EXPECT_FALSE(IsDynamicScriptElementLoaded(FindFrameByName("three"))); tester.ExpectBucketCount(kSubresourceFilterPromptHistogram, true, 1); // Check that bubble is shown for new navigation. ui_test_utils::NavigateToURL(browser(), url);
diff --git a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc index 0626cb6..886c2a4 100644 --- a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc +++ b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
@@ -48,10 +48,6 @@ namespace { -std::string TabNodeIdToTag(const std::string& machine_tag, int tab_node_id) { - return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id); -} - class SessionNotificationObserver { public: SessionNotificationObserver() @@ -132,7 +128,7 @@ std::map<int, SyncedTabDelegate*> tab_overrides_; std::map<int, SessionID::id_type> tab_id_overrides_; const SyncedWindowDelegate* const wrapped_; - SessionID::id_type session_id_override_ = TabNodePool::kInvalidTabID; + SessionID::id_type session_id_override_ = -1; }; class TestSyncedWindowDelegatesGetter : public SyncedWindowDelegatesGetter { @@ -403,10 +399,6 @@ return sessions_client_shim_.get(); } - TabNodePool* GetTabPool() { - return &manager()->session_tracker_.local_tab_pool_; - } - syncer::SyncPrefs* sync_prefs() { return sync_prefs_.get(); } SyncedWindowDelegatesGetter* get_synced_window_getter() { @@ -510,32 +502,40 @@ namespace { -// A SyncedTabDelegate fake for testing. It simulates a normal -// SyncedTabDelegate with a proper WebContents. For a SyncedTabDelegate without -// a WebContents, see PlaceholderTabDelegate below. class SyncedTabDelegateFake : public SyncedTabDelegate { public: - SyncedTabDelegateFake() {} + SyncedTabDelegateFake() + : current_entry_index_(0), is_supervised_(false), sync_id_(-1) {} ~SyncedTabDelegateFake() override {} - // SyncedTabDelegate overrides. bool IsInitialBlankNavigation() const override { // This differs from NavigationControllerImpl, which has an initial blank // NavigationEntry. return GetEntryCount() == 0; } int GetCurrentEntryIndex() const override { return current_entry_index_; } + void set_current_entry_index(int i) { + current_entry_index_ = i; + } + + void AppendEntry(std::unique_ptr<content::NavigationEntry> entry) { + entries_.push_back(std::move(entry)); + } + GURL GetVirtualURLAtIndex(int i) const override { if (static_cast<size_t>(i) >= entries_.size()) return GURL(); return entries_[i]->GetVirtualURL(); } + GURL GetFaviconURLAtIndex(int i) const override { return GURL(); } + ui::PageTransition GetTransitionAtIndex(int i) const override { if (static_cast<size_t>(i) >= entries_.size()) return ui::PAGE_TRANSITION_LINK; return entries_[i]->GetTransitionType(); } + void GetSerializedNavigationAtIndex( int i, sessions::SerializedNavigationEntry* serialized_entry) const override { @@ -545,9 +545,17 @@ sessions::ContentSerializedNavigationBuilder::FromNavigationEntry( i, *entries_[i]); } + int GetEntryCount() const override { return entries_.size(); } - SessionID::id_type GetWindowId() const override { return window_id_; } - SessionID::id_type GetSessionId() const override { return tab_id_; } + + SessionID::id_type GetWindowId() const override { + return SessionID::id_type(); + } + + SessionID::id_type GetSessionId() const override { + return SessionID::id_type(); + } + bool IsBeingDestroyed() const override { return false; } std::string GetExtensionAppId() const override { return std::string(); } bool ProfileIsSupervised() const override { return is_supervised_; } @@ -556,23 +564,6 @@ GetBlockedNavigations() const override { return &blocked_navigations_; } - bool IsPlaceholderTab() const override { return false; } - int GetSyncId() const override { return sync_id_; } - void SetSyncId(int sync_id) override { sync_id_ = sync_id; } - bool ShouldSync(SyncSessionsClient* sessions_client) override { - return false; - } - - void AppendEntry(std::unique_ptr<content::NavigationEntry> entry) { - entries_.push_back(std::move(entry)); - } - - void set_current_entry_index(int i) { current_entry_index_ = i; } - - void SetWindowId(SessionID::id_type window_id) { window_id_ = window_id; } - - void SetSessionId(SessionID::id_type id) { tab_id_ = id; } - void set_blocked_navigations( std::vector<const content::NavigationEntry*>* navs) { for (auto* entry : *navs) { @@ -583,101 +574,31 @@ blocked_navigations_.push_back(std::move(serialized_entry)); } } + bool IsPlaceholderTab() const override { return true; } + + // Session sync related methods. + int GetSyncId() const override { return sync_id_; } + void SetSyncId(int sync_id) override { sync_id_ = sync_id; } + + bool ShouldSync(SyncSessionsClient* sessions_client) override { + return false; + } void reset() { current_entry_index_ = 0; - sync_id_ = TabNodePool::kInvalidTabNodeID; + sync_id_ = -1; entries_.clear(); } private: - int current_entry_index_ = 0; - bool is_supervised_ = false; - int sync_id_ = -1; - SessionID::id_type tab_id_ = 0; - SessionID::id_type window_id_ = 0; + int current_entry_index_; + bool is_supervised_; + int sync_id_; std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>> blocked_navigations_; std::vector<std::unique_ptr<content::NavigationEntry>> entries_; }; -// A placeholder delegate. These delegates have no WebContents, simulating a tab -// that has been restored without bringing its state fully into memory (for -// example on Android), or where the tab's contents have been evicted from -// memory. See SyncedTabDelegate::IsPlaceHolderTab for more info. -class PlaceholderTabDelegate : public SyncedTabDelegate { - public: - PlaceholderTabDelegate(SessionID::id_type session_id, int sync_id) - : session_id_(session_id), sync_id_(sync_id) {} - ~PlaceholderTabDelegate() override {} - - // SyncedTabDelegate overrides. - SessionID::id_type GetSessionId() const override { return session_id_; } - int GetSyncId() const override { return sync_id_; } - void SetSyncId(int sync_id) override { sync_id_ = sync_id; } - bool IsPlaceholderTab() const override { return true; } - - // Everything else is invalid to invoke as it depends on a valid WebContents. - SessionID::id_type GetWindowId() const override { - NOTREACHED(); - return 0; - } - bool IsBeingDestroyed() const override { - NOTREACHED(); - return false; - } - std::string GetExtensionAppId() const override { - NOTREACHED(); - return ""; - } - bool IsInitialBlankNavigation() const override { - NOTREACHED(); - return false; - } - int GetCurrentEntryIndex() const override { - NOTREACHED(); - return 0; - } - int GetEntryCount() const override { - NOTREACHED(); - return 0; - } - GURL GetVirtualURLAtIndex(int i) const override { - NOTREACHED(); - return GURL(); - } - GURL GetFaviconURLAtIndex(int i) const override { - NOTREACHED(); - return GURL(); - } - ui::PageTransition GetTransitionAtIndex(int i) const override { - NOTREACHED(); - return ui::PageTransition(); - } - void GetSerializedNavigationAtIndex( - int i, - sessions::SerializedNavigationEntry* serialized_entry) const override { - NOTREACHED(); - } - bool ProfileIsSupervised() const override { - NOTREACHED(); - return false; - } - const std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>>* - GetBlockedNavigations() const override { - NOTREACHED(); - return nullptr; - } - bool ShouldSync(SyncSessionsClient* sessions_client) override { - NOTREACHED(); - return false; - } - - private: - SessionID::id_type session_id_; - int sync_id_; -}; - } // namespace static const base::Time kTime0 = base::Time::FromInternalValue(100); @@ -1032,37 +953,29 @@ // Ensure model association associates the pre-existing tabs. TEST_F(SessionsSyncManagerTest, SwappedOutOnRestore) { - const char kFoo1[] = "http://foo1/"; - const char kFoo2[] = "http://foo2/"; - const char kBar1[] = "http://bar1/"; - const char kBar2[] = "http://bar2/"; - const char kBaz1[] = "http://baz1/"; - const char kBaz2[] = "http://baz2/"; + AddTab(browser(), GURL("http://foo1")); + NavigateAndCommitActiveTab(GURL("http://foo2")); + AddTab(browser(), GURL("http://bar1")); + NavigateAndCommitActiveTab(GURL("http://bar2")); + AddTab(browser(), GURL("http://baz1")); + NavigateAndCommitActiveTab(GURL("http://baz2")); const int kRestoredTabId = 1337; const int kNewTabId = 2468; - // AddTab inserts at index 0, so go in reverse order (tab 3 -> tab 1). - AddTab(browser(), GURL(kBaz1)); - NavigateAndCommitActiveTab(GURL(kBaz2)); - AddTab(browser(), GURL(kBar1)); - NavigateAndCommitActiveTab(GURL(kBar2)); - AddTab(browser(), GURL(kFoo1)); - NavigateAndCommitActiveTab(GURL(kFoo2)); - syncer::SyncDataList in; syncer::SyncChangeList out; InitWithSyncDataTakeOutput(in, &out); - // Should be one header add, 3 tab adds, one header update. - ASSERT_EQ(5U, out.size()); + // Should be one header add, 3 tab add/update pairs, one header update. + ASSERT_EQ(8U, out.size()); // For input, we set up: // * one "normal" fully loaded tab - // * one placeholder tab with no WebContents and a tab_id change - // * one placeholder tab with no WebContents and no tab_id change - sync_pb::EntitySpecifics t0_entity = out[1].sync_data().GetSpecifics(); - sync_pb::EntitySpecifics t1_entity = out[2].sync_data().GetSpecifics(); - sync_pb::EntitySpecifics t2_entity = out[3].sync_data().GetSpecifics(); + // * one "frozen" tab with no WebContents and a tab_id change + // * one "frozen" tab with no WebContents and no tab_id change + sync_pb::EntitySpecifics t0_entity = out[2].sync_data().GetSpecifics(); + sync_pb::EntitySpecifics t1_entity = out[4].sync_data().GetSpecifics(); + sync_pb::EntitySpecifics t2_entity = out[6].sync_data().GetSpecifics(); t1_entity.mutable_session()->mutable_tab()->set_tab_id(kRestoredTabId); in.push_back(CreateRemoteData(t0_entity)); in.push_back(CreateRemoteData(t1_entity)); @@ -1073,8 +986,9 @@ const std::set<const SyncedWindowDelegate*>& windows = manager()->synced_window_delegates_getter()->GetSyncedWindowDelegates(); ASSERT_EQ(1U, windows.size()); - PlaceholderTabDelegate t1_override(kNewTabId, 1); - PlaceholderTabDelegate t2_override(t2_entity.session().tab().tab_id(), 2); + SyncedTabDelegateFake t1_override, t2_override; + t1_override.SetSyncId(1); // No WebContents by default. + t2_override.SetSyncId(2); // No WebContents by default. SyncedWindowDelegateOverride window_override(*windows.begin()); window_override.OverrideTabAt(1, &t1_override, kNewTabId); window_override.OverrideTabAt(2, &t2_override, @@ -1092,66 +1006,50 @@ new syncer::SyncErrorFactoryMock())); // There should be two changes, one for the fully associated tab, and - // one each for the tab_id updates to t1 and t2. - ASSERT_EQ(3U, FilterOutLocalHeaderChanges(&out)->size()); + // one for the tab_id update to t1. t2 shouldn't need to be updated. + ASSERT_EQ(2U, FilterOutLocalHeaderChanges(&out)->size()); EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type()); - EXPECT_EQ(kFoo2, out[0] - .sync_data() - .GetSpecifics() - .session() - .tab() - .navigation(1) - .virtual_url()); - EXPECT_EQ(SyncChange::ACTION_UPDATE, out[1].change_type()); EXPECT_EQ(kNewTabId, out[1].sync_data().GetSpecifics().session().tab().tab_id()); - EXPECT_EQ(kBar2, out[1] - .sync_data() - .GetSpecifics() - .session() - .tab() - .navigation(1) - .virtual_url()); - EXPECT_EQ(SyncChange::ACTION_UPDATE, out[2].change_type()); - EXPECT_EQ(t2_entity.session().tab().tab_id(), - out[2].sync_data().GetSpecifics().session().tab().tab_id()); - EXPECT_EQ(kBaz2, out[2] - .sync_data() - .GetSpecifics() - .session() - .tab() - .navigation(1) - .virtual_url()); + // Verify TabLinks. + SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_; + ASSERT_EQ(3U, tab_map.size()); + int t2_tab_id = t2_entity.session().tab().tab_id(); + EXPECT_EQ(2, tab_map.find(t2_tab_id)->second->tab_node_id()); + EXPECT_EQ(1, tab_map.find(kNewTabId)->second->tab_node_id()); + int t0_tab_id = out[0].sync_data().GetSpecifics().session().tab().tab_id(); + EXPECT_EQ(0, tab_map.find(t0_tab_id)->second->tab_node_id()); + // TODO(tim): Once bug 337057 is fixed, we can issue an OnLocalTabModified + // from here (using an override similar to above) to return a new tab id + // and verify that we don't see any node creations in the SyncChangeProcessor + // (similar to how SessionsSyncManagerTest.OnLocalTabModified works.) } // Ensure model association updates the window ID for tabs whose window's ID has // changed. TEST_F(SessionsSyncManagerTest, WindowIdUpdatedOnRestore) { - const char kFoo1[] = "http://foo1/"; - const char kFoo2[] = "http://foo2/"; const int kNewWindowId = 1337; syncer::SyncDataList in; syncer::SyncChangeList out; // Set up one tab and start sync with it. - AddTab(browser(), GURL(kFoo1)); - NavigateAndCommitActiveTab(GURL(kFoo2)); + AddTab(browser(), GURL("http://foo1")); + NavigateAndCommitActiveTab(GURL("http://foo2")); InitWithSyncDataTakeOutput(in, &out); - // Should be one header add, 1 tab add, and one header update. - ASSERT_EQ(3U, out.size()); - const sync_pb::EntitySpecifics t0_entity = out[1].sync_data().GetSpecifics(); - ASSERT_TRUE(t0_entity.session().has_tab()); + // Should be one header add, 1 tab add/update pair, and one header update. + ASSERT_EQ(4U, out.size()); + const sync_pb::EntitySpecifics t0_entity = out[2].sync_data().GetSpecifics(); in.push_back(CreateRemoteData(t0_entity)); out.clear(); manager()->StopSyncing(syncer::SESSIONS); - // Override the tab with a placeholder tab delegate. - PlaceholderTabDelegate t0_override(t0_entity.session().tab().tab_id(), - t0_entity.session().tab_node_id()); + // SyncedTabDelegateFake is a placeholder (no WebContents) by default. + SyncedTabDelegateFake t0_override; + t0_override.SetSyncId(t0_entity.session().tab_node_id()); // Set up the window override with the new window ID and placeholder tab. const std::set<const SyncedWindowDelegate*>& windows = @@ -1180,13 +1078,6 @@ EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type()); EXPECT_EQ(kNewWindowId, out[0].sync_data().GetSpecifics().session().tab().window_id()); - EXPECT_EQ(kFoo2, out[0] - .sync_data() - .GetSpecifics() - .session() - .tab() - .navigation(1) - .virtual_url()); } // Tests MergeDataAndStartSyncing with sync data but no local data. @@ -1249,8 +1140,7 @@ syncer::SyncChangeList output; InitWithSyncDataTakeOutput(foreign_data, &output); - // Should be one header add, 1 tab add, and one header update. - ASSERT_EQ(3U, output.size()); + ASSERT_EQ(4U, output.size()); // Verify the local header. EXPECT_TRUE(output[0].IsValid()); @@ -1278,12 +1168,12 @@ } EXPECT_EQ(SyncChange::ACTION_ADD, output[1].change_type()); EXPECT_EQ(SyncChange::ACTION_UPDATE, output[2].change_type()); - EXPECT_TRUE(output[1].sync_data().GetSpecifics().session().has_tab()); + EXPECT_TRUE(output[2].sync_data().GetSpecifics().session().has_tab()); // Verify the header was updated to reflect window state. - EXPECT_TRUE(output[2].IsValid()); - EXPECT_EQ(SyncChange::ACTION_UPDATE, output[2].change_type()); - const SyncData data_2(output[2].sync_data()); + EXPECT_TRUE(output[3].IsValid()); + EXPECT_EQ(SyncChange::ACTION_UPDATE, output[3].change_type()); + const SyncData data_2(output[3].sync_data()); EXPECT_EQ(manager()->current_machine_tag(), syncer::SyncDataLocal(data_2).GetTag()); const sync_pb::SessionSpecifics& specifics2(data_2.GetSpecifics().session()); @@ -1326,9 +1216,7 @@ syncer::SyncChangeList output1; InitWithSyncDataTakeOutput(foreign_data1, &output1); - - // 1 header add, one tab add, one header update. - ASSERT_EQ(3U, output1.size()); + ASSERT_EQ(4U, output1.size()); // Add a second window to the foreign session. // TODO(tim): Bug 98892. Add local window too when observers are hooked up. @@ -1419,10 +1307,10 @@ tag, tab_nums1, &tabs)); // Update associator with the session's meta node, window, and tabs. - manager()->UpdateTrackerWithSpecifics(meta, base::Time()); + manager()->UpdateTrackerWithForeignSession(meta, base::Time()); for (std::vector<sync_pb::SessionSpecifics>::iterator iter = tabs.begin(); iter != tabs.end(); ++iter) { - manager()->UpdateTrackerWithSpecifics(*iter, base::Time()); + manager()->UpdateTrackerWithForeignSession(*iter, base::Time()); } ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions)); ASSERT_EQ(1U, foreign_sessions.size()); @@ -1434,7 +1322,7 @@ EXPECT_EQ(5U, changes.size()); std::set<std::string> expected_tags(&tag, &tag + 1); for (int i = 0; i < 5; i++) - expected_tags.insert(TabNodeIdToTag(tag, i)); + expected_tags.insert(TabNodePool::TabIdToTag(tag, i)); for (int i = 0; i < 5; i++) { SCOPED_TRACE(changes[i].ToString()); @@ -1557,32 +1445,40 @@ // committing the NavigationEntry. The first notification results in a tab // we don't associate although we do update the header node. The second // notification triggers association of the tab, and the subsequent window - // update. So we should see 3 changes at the SyncChangeProcessor. - ASSERT_EQ(3U, out.size()); + // update. So we should see 4 changes at the SyncChangeProcessor. + ASSERT_EQ(4U, out.size()); EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type()); ASSERT_TRUE(out[0].sync_data().GetSpecifics().session().has_header()); EXPECT_EQ(SyncChange::ACTION_ADD, out[1].change_type()); int tab_node_id = out[1].sync_data().GetSpecifics().session().tab_node_id(); - EXPECT_EQ(TabNodeIdToTag(manager()->current_machine_tag(), tab_node_id), + EXPECT_EQ(TabNodePool::TabIdToTag( + manager()->current_machine_tag(), tab_node_id), syncer::SyncDataLocal(out[1].sync_data()).GetTag()); EXPECT_EQ(SyncChange::ACTION_UPDATE, out[2].change_type()); - EXPECT_EQ(SyncChange::ACTION_UPDATE, out[2].change_type()); - ASSERT_TRUE(out[2].sync_data().GetSpecifics().session().has_header()); + ASSERT_TRUE(out[2].sync_data().GetSpecifics().session().has_tab()); + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[3].change_type()); + ASSERT_TRUE(out[3].sync_data().GetSpecifics().session().has_header()); // Verify the actual content. const sync_pb::SessionHeader& session_header = - out[2].sync_data().GetSpecifics().session().header(); + out[3].sync_data().GetSpecifics().session().header(); ASSERT_EQ(1, session_header.window_size()); EXPECT_EQ(1, session_header.window(0).tab_size()); const sync_pb::SessionTab& tab1 = - out[1].sync_data().GetSpecifics().session().tab(); + out[2].sync_data().GetSpecifics().session().tab(); ASSERT_EQ(1, tab1.navigation_size()); EXPECT_EQ(foo1.spec(), tab1.navigation(0).virtual_url()); // Verify TabNodePool integrity. - EXPECT_EQ(1U, GetTabPool()->Capacity()); - EXPECT_TRUE(GetTabPool()->Empty()); + EXPECT_EQ(1U, manager()->local_tab_pool_.Capacity()); + EXPECT_TRUE(manager()->local_tab_pool_.Empty()); + + // Verify TabLinks. + SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_; + ASSERT_EQ(1U, tab_map.size()); + int tab_id = out[2].sync_data().GetSpecifics().session().tab().tab_id(); + EXPECT_EQ(tab_node_id, tab_map.find(tab_id)->second->tab_node_id()); } // Test that receiving a session delete from sync removes the session @@ -1726,8 +1622,7 @@ manager()->session_tracker_.LookupSessionTab(session_tag, 2, &tab)); std::set<int> tab_node_ids; - manager()->session_tracker_.LookupForeignTabNodeIds(session_tag, - &tab_node_ids); + manager()->session_tracker_.LookupTabNodeIds(session_tag, &tab_node_ids); EXPECT_EQ(6U, tab_node_ids.size()); EXPECT_TRUE(tab_node_ids.find(tab1A.tab_node_id()) != tab_node_ids.end()); EXPECT_TRUE(tab_node_ids.find(tab1B.tab_node_id()) != tab_node_ids.end()); @@ -1743,8 +1638,7 @@ manager()->ProcessSyncChanges(FROM_HERE, changes); tab_node_ids.clear(); - manager()->session_tracker_.LookupForeignTabNodeIds(session_tag, - &tab_node_ids); + manager()->session_tracker_.LookupTabNodeIds(session_tag, &tab_node_ids); EXPECT_EQ(3U, tab_node_ids.size()); EXPECT_TRUE(tab_node_ids.find(tab1C.tab_node_id()) != tab_node_ids.end()); EXPECT_TRUE(tab_node_ids.find(tab2A.tab_node_id()) != tab_node_ids.end()); @@ -1782,8 +1676,7 @@ output.clear(); std::set<int> tab_node_ids; - manager()->session_tracker_.LookupForeignTabNodeIds(session_tag, - &tab_node_ids); + manager()->session_tracker_.LookupTabNodeIds(session_tag, &tab_node_ids); EXPECT_EQ(2U, tab_node_ids.size()); EXPECT_TRUE(tab_node_ids.find(tab_node_id_shared) != tab_node_ids.end()); EXPECT_TRUE(tab_node_ids.find(tab_node_id_unique) != tab_node_ids.end()); @@ -1793,8 +1686,7 @@ manager()->ProcessSyncChanges(FROM_HERE, changes); tab_node_ids.clear(); - manager()->session_tracker_.LookupForeignTabNodeIds(session_tag, - &tab_node_ids); + manager()->session_tracker_.LookupTabNodeIds(session_tag, &tab_node_ids); EXPECT_EQ(1U, tab_node_ids.size()); EXPECT_TRUE(tab_node_ids.find(tab_node_id_unique) != tab_node_ids.end()); @@ -1802,45 +1694,34 @@ EXPECT_EQ(1U, output.size()); } -TEST_F(SessionsSyncManagerTest, AssociationReusesNodes) { +// TODO(shashishekhar): "Move this to TabNodePool unittests." +TEST_F(SessionsSyncManagerTest, SaveUnassociatedNodesForReassociation) { syncer::SyncChangeList changes; - AddTab(browser(), GURL("http://foo1")); - InitWithSyncDataTakeOutput(syncer::SyncDataList(), &changes); - ASSERT_EQ(3U, changes.size()); // Header add, tab add, header update. - ASSERT_TRUE(changes[1].sync_data().GetSpecifics().session().has_tab()); - int tab_node_id = - changes[1].sync_data().GetSpecifics().session().tab_node_id(); + InitWithNoSyncData(); - // Pass back the previous tab and header nodes at association, along with a - // second tab node (with a rewritten tab node id). - syncer::SyncDataList in; - in.push_back( - CreateRemoteData(changes[2].sync_data().GetSpecifics())); // Header node. - sync_pb::SessionSpecifics new_tab( - changes[1].sync_data().GetSpecifics().session()); - new_tab.set_tab_node_id(tab_node_id + 1); - in.push_back(CreateRemoteData(new_tab)); // New tab node. - in.push_back(CreateRemoteData( - changes[1].sync_data().GetSpecifics())); // Old tab node. + std::string local_tag = manager()->current_machine_tag(); + // Create a free node and then dissassociate sessions so that it ends up + // unassociated. + manager()->local_tab_pool_.GetFreeTabNode(&changes); + + // Update the tab_id of the node, so that it is considered a valid + // unassociated node otherwise it will be mistaken for a corrupted node and + // will be deleted before being added to the tab node pool. + sync_pb::EntitySpecifics entity(changes[0].sync_data().GetSpecifics()); + entity.mutable_session()->mutable_tab()->set_tab_id(1); + SyncData d = CreateRemoteData(entity); + syncer::SyncDataList in(&d, &d + 1); changes.clear(); - - // Reassociate (with the same single tab/window open). - manager()->StopSyncing(syncer::SESSIONS); - syncer::SyncMergeResult result = manager()->MergeDataAndStartSyncing( + SessionsSyncManager manager2(GetSyncSessionsClient(), sync_prefs(), + local_device(), NewDummyRouter(), + base::Closure(), base::Closure()); + syncer::SyncMergeResult result = manager2.MergeDataAndStartSyncing( syncer::SESSIONS, in, std::unique_ptr<syncer::SyncChangeProcessor>( new TestSyncProcessorStub(&changes)), std::unique_ptr<syncer::SyncErrorFactory>( new syncer::SyncErrorFactoryMock())); ASSERT_FALSE(result.error().IsSet()); - - // No tab entities should be deleted. The original (lower) tab node id should - // be reused for association. - FilterOutLocalHeaderChanges(&changes); - ASSERT_EQ(1U, changes.size()); - EXPECT_EQ(SyncChange::ACTION_UPDATE, changes[0].change_type()); - EXPECT_TRUE(changes[0].sync_data().GetSpecifics().session().has_tab()); - EXPECT_EQ(tab_node_id, - changes[0].sync_data().GetSpecifics().session().tab_node_id()); + EXPECT_TRUE(FilterOutLocalHeaderChanges(&changes)->empty()); } TEST_F(SessionsSyncManagerTest, MergeDeletesCorruptNode) { @@ -1848,19 +1729,16 @@ InitWithNoSyncData(); std::string local_tag = manager()->current_machine_tag(); - int tab_node_id = TabNodePool::kInvalidTabNodeID; - GetTabPool()->GetTabNodeForTab(0, &tab_node_id); - sync_pb::SessionSpecifics specifics; - specifics.set_session_tag(local_tag); - specifics.set_tab_node_id(tab_node_id); - SyncData d = CreateRemoteData(specifics); + int tab_node_id = manager()->local_tab_pool_.GetFreeTabNode(&changes); + SyncData d = CreateRemoteData(changes[0].sync_data().GetSpecifics()); syncer::SyncDataList in(&d, &d + 1); + changes.clear(); TearDown(); SetUp(); InitWithSyncDataTakeOutput(in, &changes); EXPECT_EQ(1U, FilterOutLocalHeaderChanges(&changes)->size()); EXPECT_EQ(SyncChange::ACTION_DELETE, changes[0].change_type()); - EXPECT_EQ(TabNodeIdToTag(local_tag, tab_node_id), + EXPECT_EQ(TabNodePool::TabIdToTag(local_tag, tab_node_id), syncer::SyncDataLocal(changes[0].sync_data()).GetTag()); } @@ -1929,7 +1807,7 @@ // Go to a sync-interesting URL. NavigateAndCommitActiveTab(GURL("http://foo2")); - EXPECT_EQ(2U, out.size()); // Tab add and header update. + EXPECT_EQ(3U, out.size()); // Tab add, update, and header update. EXPECT_TRUE( base::StartsWith(syncer::SyncDataLocal(out[0].sync_data()).GetTag(), @@ -1939,9 +1817,18 @@ out[0].sync_data().GetSpecifics().session().session_tag()); EXPECT_EQ(SyncChange::ACTION_ADD, out[0].change_type()); - EXPECT_TRUE(out[1].IsValid()); + EXPECT_TRUE( + base::StartsWith(syncer::SyncDataLocal(out[1].sync_data()).GetTag(), + manager()->current_machine_tag(), + base::CompareCase::SENSITIVE)); + EXPECT_EQ(manager()->current_machine_tag(), + out[1].sync_data().GetSpecifics().session().session_tag()); + EXPECT_TRUE(out[1].sync_data().GetSpecifics().session().has_tab()); EXPECT_EQ(SyncChange::ACTION_UPDATE, out[1].change_type()); - const SyncData data(out[1].sync_data()); + + EXPECT_TRUE(out[2].IsValid()); + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[2].change_type()); + const SyncData data(out[2].sync_data()); EXPECT_EQ(manager()->current_machine_tag(), syncer::SyncDataLocal(data).GetTag()); const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session()); @@ -1973,17 +1860,17 @@ AddTab(browser(), bar1); NavigateAndCommitActiveTab(bar2); - // One add for each AddTab. + // One add, one update for each AddTab. // One update for each NavigateAndCommit. - // = 4 total tab updates. + // = 6 total tab updates. // One header update corresponding to each of those. // = 6 total header updates. - // 10 total updates. - ASSERT_EQ(10U, out.size()); + // 12 total updates. + ASSERT_EQ(12U, out.size()); // Verify the tab node creations and updates to ensure the SyncProcessor // sees the right operations. - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 12; i++) { SCOPED_TRACE(i); EXPECT_TRUE(out[i].IsValid()); const SyncData data(out[i].sync_data()); @@ -1992,30 +1879,40 @@ base::CompareCase::SENSITIVE)); const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session()); EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag()); - if (i % 5 == 0) { + if (i % 6 == 0) { // First thing on an AddTab is a no-op header update for parented tab. EXPECT_EQ(header.SerializeAsString(), data.GetSpecifics().SerializeAsString()); EXPECT_EQ(manager()->current_machine_tag(), syncer::SyncDataLocal(data).GetTag()); - } else if (i % 5 == 1) { - // Next, the tab should be added. + } else if (i % 6 == 1) { + // Next, the TabNodePool should create the tab node. EXPECT_EQ(SyncChange::ACTION_ADD, out[i].change_type()); - EXPECT_EQ(TabNodeIdToTag(manager()->current_machine_tag(), - data.GetSpecifics().session().tab_node_id()), + EXPECT_EQ(TabNodePool::TabIdToTag( + manager()->current_machine_tag(), + data.GetSpecifics().session().tab_node_id()), syncer::SyncDataLocal(data).GetTag()); - } else if (i % 5 == 2) { + } else if (i % 6 == 2) { + // Then we see the tab update to the URL. + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type()); + EXPECT_EQ(TabNodePool::TabIdToTag( + manager()->current_machine_tag(), + data.GetSpecifics().session().tab_node_id()), + syncer::SyncDataLocal(data).GetTag()); + ASSERT_TRUE(specifics.has_tab()); + } else if (i % 6 == 3) { // The header needs to be updated to reflect the new window state. EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type()); EXPECT_TRUE(specifics.has_header()); - } else if (i % 5 == 3) { + } else if (i % 6 == 4) { // Now we move on to NavigateAndCommit. Update the tab. EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type()); - EXPECT_EQ(TabNodeIdToTag(manager()->current_machine_tag(), - data.GetSpecifics().session().tab_node_id()), + EXPECT_EQ(TabNodePool::TabIdToTag( + manager()->current_machine_tag(), + data.GetSpecifics().session().tab_node_id()), syncer::SyncDataLocal(data).GetTag()); ASSERT_TRUE(specifics.has_tab()); - } else if (i % 5 == 4) { + } else if (i % 6 == 5) { // The header needs to be updated to reflect the new window state. EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type()); ASSERT_TRUE(specifics.has_header()); @@ -2032,33 +1929,25 @@ // ASSERT_TRUEs above allow us to dive in freely here. // Verify first tab. const sync_pb::SessionTab& tab1_1 = - out[1].sync_data().GetSpecifics().session().tab(); + out[2].sync_data().GetSpecifics().session().tab(); ASSERT_EQ(1, tab1_1.navigation_size()); EXPECT_EQ(foo1.spec(), tab1_1.navigation(0).virtual_url()); const sync_pb::SessionTab& tab1_2 = - out[3].sync_data().GetSpecifics().session().tab(); + out[4].sync_data().GetSpecifics().session().tab(); ASSERT_EQ(2, tab1_2.navigation_size()); EXPECT_EQ(foo1.spec(), tab1_2.navigation(0).virtual_url()); EXPECT_EQ(foo2.spec(), tab1_2.navigation(1).virtual_url()); // Verify second tab. const sync_pb::SessionTab& tab2_1 = - out[6].sync_data().GetSpecifics().session().tab(); + out[8].sync_data().GetSpecifics().session().tab(); ASSERT_EQ(1, tab2_1.navigation_size()); EXPECT_EQ(bar1.spec(), tab2_1.navigation(0).virtual_url()); const sync_pb::SessionTab& tab2_2 = - out[8].sync_data().GetSpecifics().session().tab(); + out[10].sync_data().GetSpecifics().session().tab(); ASSERT_EQ(2, tab2_2.navigation_size()); EXPECT_EQ(bar1.spec(), tab2_2.navigation(0).virtual_url()); EXPECT_EQ(bar2.spec(), tab2_2.navigation(1).virtual_url()); - - // Verify tab delegates have Sync ids. - std::set<const SyncedWindowDelegate*> window_delegates = - get_synced_window_getter()->GetSyncedWindowDelegates(); - // Sync ids are in reverse order because tabs are inserted at the beginning - // of the tab list. - EXPECT_EQ(1, (*window_delegates.begin())->GetTabAt(0)->GetSyncId()); - EXPECT_EQ(0, (*window_delegates.begin())->GetTabAt(1)->GetSyncId()); } // Check that if a tab becomes uninteresting (for example no syncable URLs), @@ -2076,21 +1965,21 @@ // Add an interesting tab. AddTab(browser(), kValidUrl); - // No-op header update, tab creation, header update. - ASSERT_EQ(3U, out.size()); + // No-op header update, tab creation, tab update, header update. + ASSERT_EQ(4U, out.size()); // The last two are the interesting updates. - ASSERT_TRUE(out[1].sync_data().GetSpecifics().session().has_tab()); - EXPECT_EQ(kValidUrl.spec(), out[1] + ASSERT_TRUE(out[2].sync_data().GetSpecifics().session().has_tab()); + EXPECT_EQ(kValidUrl.spec(), out[2] .sync_data() .GetSpecifics() .session() .tab() .navigation(0) .virtual_url()); - ASSERT_TRUE(out[2].sync_data().GetSpecifics().session().has_header()); + ASSERT_TRUE(out[3].sync_data().GetSpecifics().session().has_header()); ASSERT_EQ(1, - out[2].sync_data().GetSpecifics().session().header().window_size()); - ASSERT_EQ(1, out[2] + out[3].sync_data().GetSpecifics().session().header().window_size()); + ASSERT_EQ(1, out[3] .sync_data() .GetSpecifics() .session() @@ -2126,7 +2015,7 @@ syncer::SyncChangeList out; InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out); - ASSERT_EQ(4U, out.size()); // Header creation, add two tabs, header update + ASSERT_EQ(6U, out.size()); // Check that this machine's data is not included in the foreign windows. std::vector<const SyncedSession*> foreign_sessions; @@ -2147,7 +2036,7 @@ EXPECT_EQ(0, header_s.window_size()); // Verify the tab node creations and updates with content. - for (int i = 1; i < 3; i++) { + for (int i = 1; i < 5; i++) { EXPECT_TRUE(out[i].IsValid()); const SyncData data(out[i].sync_data()); EXPECT_TRUE(base::StartsWith(syncer::SyncDataLocal(data).GetTag(), @@ -2155,13 +2044,18 @@ base::CompareCase::SENSITIVE)); const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session()); EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag()); - EXPECT_EQ(SyncChange::ACTION_ADD, out[i].change_type()); + if (i % 2 == 1) { + EXPECT_EQ(SyncChange::ACTION_ADD, out[i].change_type()); + } else { + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type()); + EXPECT_TRUE(specifics.has_tab()); + } } // Verify the header was updated to reflect new window state. - EXPECT_TRUE(out[3].IsValid()); - EXPECT_EQ(SyncChange::ACTION_UPDATE, out[3].change_type()); - const SyncData data_2(out[3].sync_data()); + EXPECT_TRUE(out[5].IsValid()); + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[5].change_type()); + const SyncData data_2(out[5].sync_data()); EXPECT_EQ(manager()->current_machine_tag(), syncer::SyncDataLocal(data_2).GetTag()); const sync_pb::SessionSpecifics& specifics2(data_2.GetSpecifics().session()); @@ -2170,13 +2064,19 @@ const sync_pb::SessionHeader& header_s2 = specifics2.header(); EXPECT_EQ(1, header_s2.window_size()); - // Verify tab delegates have Sync ids. - std::set<const SyncedWindowDelegate*> window_delegates = - get_synced_window_getter()->GetSyncedWindowDelegates(); - // Sync ids are in same order as tabs because the association happens after - // the tabs are opened (and therefore iterates through same order). - EXPECT_EQ(0, (*window_delegates.begin())->GetTabAt(0)->GetSyncId()); - EXPECT_EQ(1, (*window_delegates.begin())->GetTabAt(1)->GetSyncId()); + // Verify TabLinks. + SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_; + ASSERT_EQ(2U, tab_map.size()); + // Tabs are ordered by sessionid in tab_map, so should be able to traverse + // the tree based on order of tabs created + SessionsSyncManager::TabLinksMap::iterator iter = tab_map.begin(); + ASSERT_EQ(2, iter->second->tab()->GetEntryCount()); + EXPECT_EQ(GURL("http://foo1"), iter->second->tab()->GetVirtualURLAtIndex(0)); + EXPECT_EQ(GURL("http://foo2"), iter->second->tab()->GetVirtualURLAtIndex(1)); + iter++; + ASSERT_EQ(2, iter->second->tab()->GetEntryCount()); + EXPECT_EQ(GURL("http://bar1"), iter->second->tab()->GetVirtualURLAtIndex(0)); + EXPECT_EQ(GURL("http://bar2"), iter->second->tab()->GetVirtualURLAtIndex(1)); } TEST_F(SessionsSyncManagerTest, ForeignSessionModifiedTime) { @@ -2279,7 +2179,8 @@ for (int i = 1; i < 5; i++) { EXPECT_EQ(SyncChange::ACTION_DELETE, output[i].change_type()); const SyncData data(output[i].sync_data()); - EXPECT_EQ(TabNodeIdToTag(tag1, i), syncer::SyncDataLocal(data).GetTag()); + EXPECT_EQ(TabNodePool::TabIdToTag(tag1, i), + syncer::SyncDataLocal(data).GetTag()); } ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions)); @@ -2402,8 +2303,7 @@ syncer::SyncChangeList out; InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out); - ASSERT_EQ(3U, out.size()); // Header ADD, tab ADD, header UPDATE. - out.clear(); + ASSERT_EQ(4U, out.size()); // Header, tab ADD, tab UPDATE, header UPDATE. // To simulate WebContents swap during prerendering, create new WebContents // and swap with old WebContents. @@ -2424,28 +2324,24 @@ old_web_contents.get()); browser()->tab_strip_model()->ReplaceWebContentsAt(index, new_web_contents); - ASSERT_EQ(4U, out.size()); - EXPECT_EQ(SyncChange::ACTION_ADD, out[0].change_type()); - out.clear(); + ASSERT_EQ(9U, out.size()); + EXPECT_EQ(SyncChange::ACTION_ADD, out[4].change_type()); + EXPECT_EQ(SyncChange::ACTION_UPDATE, out[5].change_type()); - // Navigate away. +1 tab updates, 1 header update. + // Navigate away. NavigateAndCommitActiveTab(GURL("http://bar2")); // Delete old WebContents. This should not crash. - // +1 no-op header update. old_web_contents.reset(); // Try more navigations and verify output size. This can also reveal // bugs (leaks) on memcheck bots if the SessionSyncManager // didn't properly clean up the tab pool or session tracker. - // +1 tab updates, 1 header update. NavigateAndCommitActiveTab(GURL("http://bar3")); - // +1 no-op header update, tab add, header update. AddTab(browser(), GURL("http://bar4")); - // +1 tab update, header update. NavigateAndCommitActiveTab(GURL("http://bar5")); - ASSERT_EQ(10U, out.size()); + ASSERT_EQ(19U, out.size()); } // Test that NOTIFICATION_FOREIGN_SESSION_UPDATED is sent when processing
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 44a84a8..39c851b5 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -2055,8 +2055,6 @@ "views/desktop_capture/desktop_media_picker_views.h", "views/desktop_capture/desktop_media_source_view.cc", "views/desktop_capture/desktop_media_source_view.h", - "views/desktop_media_picker_views_deprecated.cc", - "views/desktop_media_picker_views_deprecated.h", "views/dropdown_bar_host_aura.cc", "views/frame/browser_non_client_frame_view_factory_views.cc", "views/ime/ime_window_frame_view.cc", @@ -2344,8 +2342,6 @@ "cocoa/media_picker/desktop_media_picker_cocoa.mm", "cocoa/media_picker/desktop_media_picker_controller.h", "cocoa/media_picker/desktop_media_picker_controller.mm", - "cocoa/media_picker/desktop_media_picker_controller_deprecated.h", - "cocoa/media_picker/desktop_media_picker_controller_deprecated.mm", "cocoa/media_picker/desktop_media_picker_item.h", "cocoa/media_picker/desktop_media_picker_item.mm", "cocoa/native_window_tracker_cocoa.h",
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc index 203c9566..0f62d9a 100644 --- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
@@ -220,10 +220,6 @@ return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); } -bool AppShortcutLauncherItemController::IsDraggable() { - return true; -} - bool AppShortcutLauncherItemController::CanPin() const { return GetPinnableForAppID(app_id(), launcher_controller()->profile()) == AppListControllerDelegate::PIN_EDITABLE;
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h index 36f8da17..cdb443d1b 100644 --- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
@@ -50,7 +50,6 @@ const ui::Event& event) override; base::string16 GetTitle() override; ash::ShelfMenuModel* CreateApplicationMenu(int event_flags) override; - bool IsDraggable() override; bool CanPin() const override; void Close() override;
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc index 705cb2f9..ad03c18 100644 --- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
@@ -136,10 +136,6 @@ app_id()); } -bool AppWindowLauncherItemController::IsDraggable() { - return true; -} - bool AppWindowLauncherItemController::CanPin() const { return GetPinnableForAppID(app_id(), launcher_controller()->profile()) == AppListControllerDelegate::PIN_EDITABLE;
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h index 79118bb9..eb5ac33 100644 --- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
@@ -51,7 +51,6 @@ ash::ShelfItemDelegate::PerformedAction ItemSelected( const ui::Event& event) override; base::string16 GetTitle() override; - bool IsDraggable() override; bool CanPin() const override; void Close() override;
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc index f4e3b88..2faae28 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
@@ -60,10 +60,6 @@ return nullptr; } -bool ArcAppDeferredLauncherItemController::IsDraggable() { - return false; -} - void ArcAppDeferredLauncherItemController::Close() { if (host_) host_->Close(app_id());
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h index 42c5f6c..189932c 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h
@@ -38,7 +38,6 @@ base::string16 GetTitle() override; bool CanPin() const override; ash::ShelfMenuModel* CreateApplicationMenu(int event_flags) override; - bool IsDraggable() override; void Close() override; // LauncherItemController overrides:
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc index 99e2b2bf..3c70a37a 100644 --- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -230,10 +230,6 @@ return new LauncherApplicationMenuItemModel(GetApplicationList(event_flags)); } -bool BrowserShortcutLauncherItemController::IsDraggable() { - return true; -} - bool BrowserShortcutLauncherItemController::CanPin() const { return true; }
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h index e0a822310..c76876c 100644 --- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
@@ -52,7 +52,6 @@ const ui::Event& event) override; base::string16 GetTitle() override; ash::ShelfMenuModel* CreateApplicationMenu(int event_flags) override; - bool IsDraggable() override; bool CanPin() const override; void Close() override;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc index 7ed4d39..1fc13581 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -279,7 +279,6 @@ ash::ShelfMenuModel* CreateApplicationMenu(int event_flags) override { return NULL; } - bool IsDraggable() override { return false; } bool CanPin() const override { return GetPinnableForAppID(app_id(), launcher_controller()->profile()) == AppListControllerDelegate::PIN_EDITABLE;
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h index 0fa7153..05ed3f0 100644 --- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h +++ b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h
@@ -10,7 +10,6 @@ #import "base/mac/scoped_nsobject.h" #include "chrome/browser/media/webrtc/desktop_media_picker.h" -@class DesktopMediaPickerControllerDeprecated; @class DesktopMediaPickerController; // Cocoa's DesktopMediaPicker implementation. @@ -32,9 +31,6 @@ const DoneCallback& done_callback) override; private: - base::scoped_nsobject<DesktopMediaPickerControllerDeprecated> - controller_deprecated_; - base::scoped_nsobject<DesktopMediaPickerController> controller_; };
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm index 8f197be..d777da4 100644 --- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm +++ b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm
@@ -6,10 +6,7 @@ #include <utility> -#include "base/command_line.h" -#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.h" #import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.h" -#include "extensions/common/switches.h" DesktopMediaPickerCocoa::DesktopMediaPickerCocoa() { } @@ -28,21 +25,6 @@ std::unique_ptr<DesktopMediaList> tab_list, bool request_audio, const DoneCallback& done_callback) { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - extensions::switches::kDisableDesktopCapturePickerNewUI)) { - controller_deprecated_.reset([[DesktopMediaPickerControllerDeprecated alloc] - initWithScreenList:std::move(screen_list) - windowList:std::move(window_list) - tabList:std::move(tab_list) - parent:parent - callback:done_callback - appName:app_name - targetName:target_name - requestAudio:request_audio]); - [controller_deprecated_ showWindow:nil]; - return; - } - controller_.reset([[DesktopMediaPickerController alloc] initWithScreenList:std::move(screen_list) windowList:std::move(window_list)
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm index 9fa47f0..5a660e5 100644 --- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm +++ b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm
@@ -10,7 +10,7 @@ #include "base/command_line.h" #import "base/mac/bundle_locations.h" #include "base/strings/sys_string_conversions.h" -#include "chrome/browser/media/combined_desktop_media_list.h" +#include "chrome/browser/media/webrtc/desktop_media_list.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.h b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.h deleted file mode 100644 index 48c8df9..0000000 --- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_CONTROLLER_DEPRECATED_H_ -#define CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_CONTROLLER_DEPRECATED_H_ - -#import <Cocoa/Cocoa.h> -#import <Quartz/Quartz.h> - -#include <memory> - -#include "base/callback.h" -#import "base/mac/scoped_nsobject.h" -#include "base/strings/string16.h" -#include "chrome/browser/media/webrtc/desktop_media_list.h" -#include "chrome/browser/media/webrtc/desktop_media_picker.h" -#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_bridge.h" - -// A controller for the Desktop Media Picker. Presents the user with a list of -// media sources for screen-capturing, and reports the result. -@interface DesktopMediaPickerControllerDeprecated - : NSWindowController<NSWindowDelegate, DesktopMediaPickerObserver> { - @private - // The image browser view to present sources to the user (thumbnails and - // names). - base::scoped_nsobject<IKImageBrowserView> sourceBrowser_; - - // The button used to confirm the selection. - NSButton* shareButton_; // weak; owned by contentView - - // The button used to cancel and close the dialog. - NSButton* cancelButton_; // weak; owned by contentView - - // The checkbox for audio share. - // |audioShareState_| records the state when check box is disabled. - base::scoped_nsobject<NSButton> audioShareCheckbox_; - NSCellStateValue audioShareState_; - - // Provides source information (including thumbnails) to fill up |items_| and - // to render in |sourceBrowser_|. - std::unique_ptr<DesktopMediaList> media_list_; - - // To be called with the user selection. - DesktopMediaPicker::DoneCallback doneCallback_; - - // Array of |DesktopMediaPickerItem| used as data for |sourceBrowser_|. - base::scoped_nsobject<NSMutableArray> items_; - - // C++ bridge to use as an observer to |media_list_|, that forwards obj-c - // notifications to this object. - std::unique_ptr<DesktopMediaPickerBridge> bridge_; - - // Used to create |DesktopMediaPickerItem|s with unique IDs. - int lastImageUID_; -} - -// Designated initializer. -// To show the dialog, use |NSWindowController|'s |showWindow:|. -// |callback| will be called to report the user's selection. -// |appName| will be used to format the dialog's title and the label, where it -// appears as the initiator of the request. -// |targetName| will be used to format the dialog's label and appear as the -// consumer of the requested stream. -- (id)initWithScreenList:(std::unique_ptr<DesktopMediaList>)screen_list - windowList:(std::unique_ptr<DesktopMediaList>)window_list - tabList:(std::unique_ptr<DesktopMediaList>)tab_list - parent:(NSWindow*)parent - callback:(const DesktopMediaPicker::DoneCallback&)callback - appName:(const base::string16&)appName - targetName:(const base::string16&)targetName - requestAudio:(bool)requestAudio; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_MEDIA_PICKER_DESKTOP_MEDIA_PICKER_CONTROLLER_DEPRECATED_H_
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.mm b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.mm deleted file mode 100644 index d22e58684..0000000 --- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.mm +++ /dev/null
@@ -1,443 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.h" - -#include <utility> - -#include "base/bind.h" -#include "base/command_line.h" -#import "base/mac/bundle_locations.h" -#include "base/strings/sys_string_conversions.h" -#include "chrome/browser/media/combined_desktop_media_list.h" -#import "chrome/browser/ui/cocoa/key_equivalent_constants.h" -#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_item.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/grit/generated_resources.h" -#include "components/strings/grit/components_strings.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_delegate.h" -#import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h" -#import "ui/base/cocoa/flipped_view.h" -#import "ui/base/cocoa/window_size_constants.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/image/image_skia_util_mac.h" - -namespace { - -const int kInitialContentWidth = 620; -const int kMinimumContentWidth = 500; -const int kMinimumContentHeight = 390; -const int kThumbnailWidth = 150; -const int kThumbnailHeight = 150; -const int kFramePadding = 20; -const int kControlSpacing = 10; -const int kExcessButtonPadding = 6; - -} // namespace - -@interface DesktopMediaPickerControllerDeprecated (Private) - -// Populate the window with controls and views. -- (void)initializeContentsWithAppName:(const base::string16&)appName; - -// Create a |NSTextField| with label traits given |width|. Frame height is -// automatically adjusted to fit. -- (NSTextField*)createTextFieldWithText:(NSString*)text - frameWidth:(CGFloat)width; - -// Create a button with |title|, with size adjusted to fit. -- (NSButton*)createButtonWithTitle:(NSString*)title; - -// Report result by invoking |doneCallback_|. The callback is invoked only on -// the first call to |reportResult:|. Subsequent calls will be no-ops. -- (void)reportResult:(content::DesktopMediaID)sourceID; - -// Action handlers. -- (void)sharePressed:(id)sender; -- (void)cancelPressed:(id)sender; - -@end - -@implementation DesktopMediaPickerControllerDeprecated - -- (id)initWithScreenList:(std::unique_ptr<DesktopMediaList>)screen_list - windowList:(std::unique_ptr<DesktopMediaList>)window_list - tabList:(std::unique_ptr<DesktopMediaList>)tab_list - parent:(NSWindow*)parent - callback:(const DesktopMediaPicker::DoneCallback&)callback - appName:(const base::string16&)appName - targetName:(const base::string16&)targetName - requestAudio:(bool)requestAudio { - const NSUInteger kStyleMask = - NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask; - base::scoped_nsobject<NSWindow> window([[NSWindow alloc] - initWithContentRect:ui::kWindowSizeDeterminedLater - styleMask:kStyleMask - backing:NSBackingStoreBuffered - defer:NO]); - - if ((self = [super initWithWindow:window])) { - [parent addChildWindow:window ordered:NSWindowAbove]; - [window setDelegate:self]; - [self initializeContentsWithAppName:appName - targetName:targetName - requestAudio:requestAudio]; - std::vector<std::unique_ptr<DesktopMediaList>> media_lists; - if (screen_list) - media_lists.push_back(std::move(screen_list)); - - if (window_list) - media_lists.push_back(std::move(window_list)); - - if (tab_list) - media_lists.push_back(std::move(tab_list)); - - if (media_lists.size() > 1) - media_list_.reset(new CombinedDesktopMediaList(media_lists)); - else - media_list_ = std::move(media_lists[0]); - media_list_->SetViewDialogWindowId(content::DesktopMediaID( - content::DesktopMediaID::TYPE_WINDOW, [window windowNumber])); - doneCallback_ = callback; - items_.reset([[NSMutableArray alloc] init]); - bridge_.reset(new DesktopMediaPickerBridge(self)); - } - return self; -} - -- (void)dealloc { - [shareButton_ setTarget:nil]; - [cancelButton_ setTarget:nil]; - [sourceBrowser_ setDelegate:nil]; - [sourceBrowser_ setDataSource:nil]; - [[self window] close]; - [super dealloc]; -} - -- (void)initializeContentsWithAppName:(const base::string16&)appName - targetName:(const base::string16&)targetName - requestAudio:(bool)requestAudio { - // Use flipped coordinates to facilitate manual layout. - const CGFloat kPaddedWidth = kInitialContentWidth - (kFramePadding * 2); - base::scoped_nsobject<FlippedView> content( - [[FlippedView alloc] initWithFrame:NSZeroRect]); - [[self window] setContentView:content]; - NSPoint origin = NSMakePoint(kFramePadding, kFramePadding); - - // Set the dialog's title. - NSString* titleText = l10n_util::GetNSStringF( - IDS_DESKTOP_MEDIA_PICKER_TITLE_DEPRECATED, appName); - [[self window] setTitle:titleText]; - - // Set the dialog's description. - NSString* descriptionText; - if (appName == targetName) { - descriptionText = - l10n_util::GetNSStringF(IDS_DESKTOP_MEDIA_PICKER_TEXT, appName); - } else { - descriptionText = l10n_util::GetNSStringF( - IDS_DESKTOP_MEDIA_PICKER_TEXT_DELEGATED, appName, targetName); - } - NSTextField* description = - [self createTextFieldWithText:descriptionText frameWidth:kPaddedWidth]; - [description setFrameOrigin:origin]; - [content addSubview:description]; - origin.y += NSHeight([description frame]) + kControlSpacing; - - // Create the image browser. - sourceBrowser_.reset([[IKImageBrowserView alloc] initWithFrame:NSZeroRect]); - NSUInteger cellStyle = IKCellsStyleShadowed | IKCellsStyleTitled; - [sourceBrowser_ setDelegate:self]; - [sourceBrowser_ setDataSource:self]; - [sourceBrowser_ setCellsStyleMask:cellStyle]; - [sourceBrowser_ setCellSize:NSMakeSize(kThumbnailWidth, kThumbnailHeight)]; - [sourceBrowser_ setAllowsMultipleSelection:NO]; - - // Create a scroll view to host the image browser. - NSRect imageBrowserScrollFrame = - NSMakeRect(origin.x, origin.y, kPaddedWidth, 350); - base::scoped_nsobject<NSScrollView> imageBrowserScroll( - [[NSScrollView alloc] initWithFrame:imageBrowserScrollFrame]); - [imageBrowserScroll setHasVerticalScroller:YES]; - [imageBrowserScroll setDocumentView:sourceBrowser_]; - [imageBrowserScroll setBorderType:NSBezelBorder]; - [imageBrowserScroll - setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [content addSubview:imageBrowserScroll]; - origin.y += NSHeight(imageBrowserScrollFrame) + kControlSpacing; - - // Create a checkbox for audio sharing. - if (requestAudio) { - audioShareCheckbox_.reset([[NSButton alloc] initWithFrame:NSZeroRect]); - [audioShareCheckbox_ setFrameOrigin:origin]; - [audioShareCheckbox_ - setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin]; - [audioShareCheckbox_ setButtonType:NSSwitchButton]; - audioShareState_ = NSOnState; - [audioShareCheckbox_ - setTitle:l10n_util::GetNSString(IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE)]; - [audioShareCheckbox_ sizeToFit]; - [audioShareCheckbox_ setEnabled:NO]; - [audioShareCheckbox_ - setToolTip:l10n_util::GetNSString( - IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_MAC)]; - [content addSubview:audioShareCheckbox_]; - origin.y += NSHeight([audioShareCheckbox_ frame]) + kControlSpacing; - } - - // Create the share button. - shareButton_ = - [self createButtonWithTitle:l10n_util::GetNSString( - IDS_DESKTOP_MEDIA_PICKER_SHARE)]; - origin.x = kInitialContentWidth - kFramePadding - - (NSWidth([shareButton_ frame]) - kExcessButtonPadding); - [shareButton_ setEnabled:NO]; - [shareButton_ setFrameOrigin:origin]; - [shareButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; - [shareButton_ setTarget:self]; - [shareButton_ setKeyEquivalent:kKeyEquivalentReturn]; - [shareButton_ setAction:@selector(sharePressed:)]; - [content addSubview:shareButton_]; - - // Create the cancel button. - cancelButton_ = - [self createButtonWithTitle:l10n_util::GetNSString(IDS_CANCEL)]; - origin.x -= kControlSpacing + - (NSWidth([cancelButton_ frame]) - (kExcessButtonPadding * 2)); - [cancelButton_ setFrameOrigin:origin]; - [cancelButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin]; - [cancelButton_ setTarget:self]; - [cancelButton_ setKeyEquivalent:kKeyEquivalentEscape]; - [cancelButton_ setAction:@selector(cancelPressed:)]; - [content addSubview:cancelButton_]; - origin.y += - kFramePadding + (NSHeight([cancelButton_ frame]) - kExcessButtonPadding); - - // Resize window to fit. - [[[self window] contentView] setAutoresizesSubviews:NO]; - [[self window] setContentSize:NSMakeSize(kInitialContentWidth, origin.y)]; - [[self window] setContentMinSize:NSMakeSize(kMinimumContentWidth, - kMinimumContentHeight)]; - [[[self window] contentView] setAutoresizesSubviews:YES]; - - // Make sourceBrowser_ get keyboard focus. - [[self window] makeFirstResponder:sourceBrowser_]; -} - -- (void)showWindow:(id)sender { - // Signal the media_list to start sending thumbnails. |bridge_| is used as the - // observer, and will forward notifications to this object. - media_list_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight)); - media_list_->StartUpdating(bridge_.get()); - - [self.window center]; - [super showWindow:sender]; -} - -- (void)reportResult:(content::DesktopMediaID)sourceID { - if (doneCallback_.is_null()) { - return; - } - - sourceID.audio_share = [audioShareCheckbox_ isEnabled] && - [audioShareCheckbox_ state] == NSOnState; - - // If the media source is an tab, activate it. - if (sourceID.type == content::DesktopMediaID::TYPE_WEB_CONTENTS) { - content::WebContents* tab = content::WebContents::FromRenderFrameHost( - content::RenderFrameHost::FromID( - sourceID.web_contents_id.render_process_id, - sourceID.web_contents_id.main_render_frame_id)); - if (tab) - tab->GetDelegate()->ActivateContents(tab); - } - - // Notify the |callback_| asynchronously because it may release the - // controller. - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(doneCallback_, sourceID)); - doneCallback_.Reset(); -} - -- (void)sharePressed:(id)sender { - NSIndexSet* indexes = [sourceBrowser_ selectionIndexes]; - NSUInteger selectedIndex = [indexes firstIndex]; - DesktopMediaPickerItem* item = [items_ objectAtIndex:selectedIndex]; - [self reportResult:[item sourceID]]; - [self close]; -} - -- (void)cancelPressed:(id)sender { - [self reportResult:content::DesktopMediaID()]; - [self close]; -} - -- (NSTextField*)createTextFieldWithText:(NSString*)text - frameWidth:(CGFloat)width { - NSRect frame = NSMakeRect(0, 0, width, 1); - base::scoped_nsobject<NSTextField> textField( - [[NSTextField alloc] initWithFrame:frame]); - [textField setEditable:NO]; - [textField setSelectable:YES]; - [textField setDrawsBackground:NO]; - [textField setBezeled:NO]; - [textField setStringValue:text]; - [textField setFont:[NSFont systemFontOfSize:13]]; - [textField setAutoresizingMask:NSViewWidthSizable]; - [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField]; - return textField.autorelease(); -} - -- (NSButton*)createButtonWithTitle:(NSString*)title { - base::scoped_nsobject<NSButton> button( - [[NSButton alloc] initWithFrame:NSZeroRect]); - [button setButtonType:NSMomentaryPushInButton]; - [button setBezelStyle:NSRoundedBezelStyle]; - [button setTitle:title]; - [GTMUILocalizerAndLayoutTweaker sizeToFitView:button]; - return button.autorelease(); -} - -#pragma mark NSWindowDelegate - -- (void)windowWillClose:(NSNotification*)notification { - // Report the result if it hasn't been reported yet. |reportResult:| ensures - // that the result is only reported once. - [self reportResult:content::DesktopMediaID()]; - - // Remove self from the parent. - NSWindow* window = [self window]; - [[window parentWindow] removeChildWindow:window]; -} - -#pragma mark IKImageBrowserDataSource - -- (NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView*)browser { - return [items_ count]; -} - -- (id)imageBrowser:(IKImageBrowserView*)browser itemAtIndex:(NSUInteger)index { - return [items_ objectAtIndex:index]; -} - -#pragma mark IKImageBrowserDelegate - -- (void)imageBrowser:(IKImageBrowserView*)browser - cellWasDoubleClickedAtIndex:(NSUInteger)index { - DesktopMediaPickerItem* item = [items_ objectAtIndex:index]; - [self reportResult:[item sourceID]]; - [self close]; -} - -- (void)imageBrowserSelectionDidChange:(IKImageBrowserView*)browser { - NSIndexSet* indexes = [sourceBrowser_ selectionIndexes]; - - // Enable or disable the OK button based on whether we have a selection. - [shareButton_ setEnabled:([indexes count] > 0)]; - - // Enable or disable the checkbox based on whether we can support audio for - // the selected source. - // On Mac, the checkbox will enabled for tab sharing, namely - // TYPE_WEB_CONTENTS. - if ([indexes count] == 0) { - if ([audioShareCheckbox_ isEnabled]) { - [audioShareCheckbox_ setEnabled:NO]; - audioShareState_ = [audioShareCheckbox_ state]; - [audioShareCheckbox_ setState:NSOffState]; - } - [audioShareCheckbox_ - setToolTip:l10n_util::GetNSString( - IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_MAC)]; - return; - } - - NSUInteger selectedIndex = [indexes firstIndex]; - DesktopMediaPickerItem* item = [items_ objectAtIndex:selectedIndex]; - switch ([item sourceID].type) { - case content::DesktopMediaID::TYPE_SCREEN: - case content::DesktopMediaID::TYPE_WINDOW: - if ([audioShareCheckbox_ isEnabled]) { - [audioShareCheckbox_ setEnabled:NO]; - audioShareState_ = [audioShareCheckbox_ state]; - [audioShareCheckbox_ setState:NSOffState]; - } - [audioShareCheckbox_ - setToolTip:l10n_util::GetNSString( - IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_MAC)]; - break; - case content::DesktopMediaID::TYPE_WEB_CONTENTS: - if (![audioShareCheckbox_ isEnabled]) { - [audioShareCheckbox_ setEnabled:YES]; - [audioShareCheckbox_ setState:audioShareState_]; - } - [audioShareCheckbox_ setToolTip:@""]; - break; - case content::DesktopMediaID::TYPE_NONE: - NOTREACHED(); - } -} - -#pragma mark DesktopMediaPickerObserver - -- (void)sourceAddedForList:(DesktopMediaList*)list atIndex:(int)index { - const DesktopMediaList::Source& source = media_list_->GetSource(index); - NSString* imageTitle = base::SysUTF16ToNSString(source.name); - base::scoped_nsobject<DesktopMediaPickerItem> item( - [[DesktopMediaPickerItem alloc] initWithSourceId:source.id - imageUID:++lastImageUID_ - imageTitle:imageTitle]); - [items_ insertObject:item atIndex:index]; - [sourceBrowser_ reloadData]; - - NSString* autoselectSource = base::SysUTF8ToNSString( - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kAutoSelectDesktopCaptureSource)); - - if ([autoselectSource isEqualToString:imageTitle]) { - [self reportResult:[item sourceID]]; - [self close]; - } -} - -- (void)sourceRemovedForList:(DesktopMediaList*)list atIndex:(int)index { - if ([[sourceBrowser_ selectionIndexes] containsIndex:index]) { - // Selected item was removed. Clear selection. - [sourceBrowser_ setSelectionIndexes:[NSIndexSet indexSet] - byExtendingSelection:FALSE]; - } - [items_ removeObjectAtIndex:index]; - [sourceBrowser_ reloadData]; -} - -- (void)sourceMovedForList:(DesktopMediaList*)list - from:(int)oldIndex - to:(int)newIndex { - base::scoped_nsobject<DesktopMediaPickerItem> item( - [[items_ objectAtIndex:oldIndex] retain]); - [items_ removeObjectAtIndex:oldIndex]; - [items_ insertObject:item atIndex:newIndex]; - [sourceBrowser_ reloadData]; -} - -- (void)sourceNameChangedForList:(DesktopMediaList*)list atIndex:(int)index { - DesktopMediaPickerItem* item = [items_ objectAtIndex:index]; - const DesktopMediaList::Source& source = media_list_->GetSource(index); - [item setImageTitle:base::SysUTF16ToNSString(source.name)]; - [sourceBrowser_ reloadData]; -} - -- (void)sourceThumbnailChangedForList:(DesktopMediaList*)list - atIndex:(int)index { - const DesktopMediaList::Source& source = media_list_->GetSource(index); - NSImage* image = gfx::NSImageFromImageSkia(source.thumbnail); - - DesktopMediaPickerItem* item = [items_ objectAtIndex:index]; - [item setImageRepresentation:image]; - [sourceBrowser_ reloadData]; -} - -@end // @interface DesktopMediaPickerController
diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated_unittest.mm b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated_unittest.mm deleted file mode 100644 index 5f2345c..0000000 --- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated_unittest.mm +++ /dev/null
@@ -1,259 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.h" - -#include "base/bind.h" -#include "base/run_loop.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/media/webrtc/desktop_media_list_observer.h" -#include "chrome/browser/media/webrtc/fake_desktop_media_list.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "testing/gtest_mac.h" - -@interface DesktopMediaPickerControllerDeprecated (ExposedForTesting) -- (IKImageBrowserView*)sourceBrowser; -- (NSButton*)shareButton; -- (NSButton*)audioShareCheckbox; -- (NSArray*)items; -@end - -@implementation DesktopMediaPickerControllerDeprecated (ExposedForTesting) -- (IKImageBrowserView*)sourceBrowser { - return sourceBrowser_; -} - -- (NSButton*)shareButton { - return shareButton_; -} - -- (NSButton*)cancelButton { - return cancelButton_; -} - -- (NSButton*)audioShareCheckbox { - return audioShareCheckbox_; -} - -- (NSArray*)items { - return items_; -} -@end - -class DesktopMediaPickerControllerDeprecatedTest : public CocoaTest { - public: - DesktopMediaPickerControllerDeprecatedTest() {} - - void SetUp() override { - CocoaTest::SetUp(); - - screen_list_ = new FakeDesktopMediaList(); - window_list_ = new FakeDesktopMediaList(); - tab_list_ = new FakeDesktopMediaList(); - - DesktopMediaPicker::DoneCallback callback = - base::Bind(&DesktopMediaPickerControllerDeprecatedTest::OnResult, - base::Unretained(this)); - - controller_.reset([[DesktopMediaPickerControllerDeprecated alloc] - initWithScreenList:std::unique_ptr<DesktopMediaList>(screen_list_) - windowList:std::unique_ptr<DesktopMediaList>(window_list_) - tabList:std::unique_ptr<DesktopMediaList>(tab_list_) - parent:nil - callback:callback - appName:base::ASCIIToUTF16("Screenshare Test") - targetName:base::ASCIIToUTF16("https://foo.com") - requestAudio:true]); - } - - void TearDown() override { - controller_.reset(); - CocoaTest::TearDown(); - } - - bool WaitForCallback() { - if (!callback_called_) { - base::RunLoop().RunUntilIdle(); - } - return callback_called_; - } - - protected: - void OnResult(content::DesktopMediaID source) { - EXPECT_FALSE(callback_called_); - callback_called_ = true; - source_reported_ = source; - } - - content::TestBrowserThreadBundle thread_bundle_; - bool callback_called_ = false; - content::DesktopMediaID source_reported_; - FakeDesktopMediaList* screen_list_ = nullptr; - FakeDesktopMediaList* window_list_ = nullptr; - FakeDesktopMediaList* tab_list_ = nullptr; - base::scoped_nsobject<DesktopMediaPickerControllerDeprecated> controller_; -}; - -TEST_F(DesktopMediaPickerControllerDeprecatedTest, ShowAndDismiss) { - [controller_ showWindow:nil]; - - window_list_->AddSource(0); - window_list_->AddSource(1); - window_list_->SetSourceThumbnail(1); - - NSArray* items = [controller_ items]; - EXPECT_EQ(2U, [items count]); - EXPECT_NSEQ(@"0", [[items objectAtIndex:0] imageTitle]); - EXPECT_EQ(nil, [[items objectAtIndex:0] imageRepresentation]); - EXPECT_NSEQ(@"1", [[items objectAtIndex:1] imageTitle]); - EXPECT_TRUE([[items objectAtIndex:1] imageRepresentation] != nil); -} - -TEST_F(DesktopMediaPickerControllerDeprecatedTest, ClickShare) { - [controller_ showWindow:nil]; - - window_list_->AddSource(0); - window_list_->SetSourceThumbnail(0); - window_list_->AddSource(1); - window_list_->SetSourceThumbnail(1); - - EXPECT_EQ(2U, [[controller_ items] count]); - EXPECT_FALSE([[controller_ shareButton] isEnabled]); - - NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:1]; - [[controller_ sourceBrowser] setSelectionIndexes:indexSet - byExtendingSelection:NO]; - EXPECT_TRUE([[controller_ shareButton] isEnabled]); - - [[controller_ shareButton] performClick:nil]; - EXPECT_TRUE(WaitForCallback()); - EXPECT_EQ(window_list_->GetSource(1).id, source_reported_); -} - -TEST_F(DesktopMediaPickerControllerDeprecatedTest, ClickCancel) { - [controller_ showWindow:nil]; - - window_list_->AddSource(0); - window_list_->SetSourceThumbnail(0); - window_list_->AddSource(1); - window_list_->SetSourceThumbnail(1); - - [[controller_ cancelButton] performClick:nil]; - EXPECT_TRUE(WaitForCallback()); - EXPECT_EQ(content::DesktopMediaID(), source_reported_); -} - -TEST_F(DesktopMediaPickerControllerDeprecatedTest, CloseWindow) { - [controller_ showWindow:nil]; - - window_list_->AddSource(0); - window_list_->SetSourceThumbnail(0); - window_list_->AddSource(1); - window_list_->SetSourceThumbnail(1); - - [controller_ close]; - EXPECT_TRUE(WaitForCallback()); - EXPECT_EQ(content::DesktopMediaID(), source_reported_); -} - -TEST_F(DesktopMediaPickerControllerDeprecatedTest, UpdateThumbnail) { - [controller_ showWindow:nil]; - - window_list_->AddSource(0); - window_list_->SetSourceThumbnail(0); - window_list_->AddSource(1); - window_list_->SetSourceThumbnail(1); - - NSArray* items = [controller_ items]; - EXPECT_EQ(2U, [items count]); - NSUInteger version = [[items objectAtIndex:0] imageVersion]; - - window_list_->SetSourceThumbnail(0); - EXPECT_NE(version, [[items objectAtIndex:0] imageVersion]); -} - -TEST_F(DesktopMediaPickerControllerDeprecatedTest, UpdateName) { - [controller_ showWindow:nil]; - - window_list_->AddSource(0); - window_list_->SetSourceThumbnail(0); - window_list_->AddSource(1); - window_list_->SetSourceThumbnail(1); - - NSArray* items = [controller_ items]; - EXPECT_EQ(2U, [items count]); - NSUInteger version = [[items objectAtIndex:0] imageVersion]; - - window_list_->SetSourceThumbnail(0); - EXPECT_NE(version, [[items objectAtIndex:0] imageVersion]); -} - -TEST_F(DesktopMediaPickerControllerDeprecatedTest, RemoveSource) { - [controller_ showWindow:nil]; - - window_list_->AddSource(0); - window_list_->AddSource(1); - window_list_->AddSource(2); - window_list_->SetSourceName(1, base::ASCIIToUTF16("foo")); - - NSArray* items = [controller_ items]; - EXPECT_EQ(3U, [items count]); - EXPECT_NSEQ(@"foo", [[items objectAtIndex:1] imageTitle]); -} - -TEST_F(DesktopMediaPickerControllerDeprecatedTest, MoveSource) { - [controller_ showWindow:nil]; - - window_list_->AddSource(0); - window_list_->AddSource(1); - window_list_->SetSourceName(1, base::ASCIIToUTF16("foo")); - NSArray* items = [controller_ items]; - EXPECT_NSEQ(@"foo", [[items objectAtIndex:1] imageTitle]); - - window_list_->MoveSource(1, 0); - EXPECT_NSEQ(@"foo", [[items objectAtIndex:0] imageTitle]); - - window_list_->MoveSource(0, 1); - EXPECT_NSEQ(@"foo", [[items objectAtIndex:1] imageTitle]); -} - -// Make sure the audio share checkbox' state reacts correctly with -// the source selection. Namely the checkbox is enabled only for tab -// sharing on Mac. -TEST_F(DesktopMediaPickerControllerDeprecatedTest, AudioShareCheckboxState) { - [controller_ showWindow:nil]; - - screen_list_->AddSourceByFullMediaID( - content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0)); - window_list_->AddSourceByFullMediaID( - content::DesktopMediaID(content::DesktopMediaID::TYPE_WINDOW, 1)); - tab_list_->AddSourceByFullMediaID( - content::DesktopMediaID(content::DesktopMediaID::TYPE_WEB_CONTENTS, 2)); - - NSButton* checkbox = [controller_ audioShareCheckbox]; - EXPECT_EQ(NO, [checkbox isEnabled]); - - NSIndexSet* index_set = [NSIndexSet indexSetWithIndex:0]; - [checkbox setEnabled:YES]; - [[controller_ sourceBrowser] setSelectionIndexes:index_set - byExtendingSelection:NO]; - EXPECT_EQ(NO, [checkbox isEnabled]); - - index_set = [NSIndexSet indexSetWithIndex:1]; - [checkbox setEnabled:YES]; - [[controller_ sourceBrowser] setSelectionIndexes:index_set - byExtendingSelection:NO]; - EXPECT_EQ(NO, [checkbox isEnabled]); - - index_set = [NSIndexSet indexSetWithIndex:2]; - [[controller_ sourceBrowser] setSelectionIndexes:index_set - byExtendingSelection:NO]; - EXPECT_EQ(YES, [checkbox isEnabled]); - - index_set = [NSIndexSet indexSet]; - [[controller_ sourceBrowser] setSelectionIndexes:index_set - byExtendingSelection:NO]; - EXPECT_EQ(NO, [checkbox isEnabled]); -}
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc index d5bd241..ef876004 100644 --- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc +++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -5,13 +5,11 @@ #include "chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h" #include "base/callback.h" -#include "base/command_line.h" #include "chrome/browser/media/webrtc/desktop_media_list.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h" #include "chrome/browser/ui/views/desktop_capture/desktop_media_source_view.h" -#include "chrome/browser/ui/views/desktop_media_picker_views_deprecated.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "components/constrained_window/constrained_window_views.h" @@ -20,7 +18,6 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents_delegate.h" -#include "extensions/common/switches.h" #include "ui/aura/window_tree_host.h" #include "ui/base/l10n/l10n_util.h" #include "ui/events/keycodes/keyboard_codes.h" @@ -445,10 +442,5 @@ // static std::unique_ptr<DesktopMediaPicker> DesktopMediaPicker::Create() { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - extensions::switches::kDisableDesktopCapturePickerNewUI)) { - return std::unique_ptr<DesktopMediaPicker>( - new deprecated::DesktopMediaPickerViews()); - } return std::unique_ptr<DesktopMediaPicker>(new DesktopMediaPickerViews()); }
diff --git a/chrome/browser/ui/views/desktop_media_picker_views_deprecated.cc b/chrome/browser/ui/views/desktop_media_picker_views_deprecated.cc deleted file mode 100644 index 44a76ee..0000000 --- a/chrome/browser/ui/views/desktop_media_picker_views_deprecated.cc +++ /dev/null
@@ -1,666 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "desktop_media_picker_views_deprecated.h" - -#include <stddef.h> -#include <utility> - -#include "base/callback.h" -#include "base/command_line.h" -#include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" -#include "chrome/browser/media/combined_desktop_media_list.h" -#include "chrome/browser/media/webrtc/desktop_media_list.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/grit/generated_resources.h" -#include "components/constrained_window/constrained_window_views.h" -#include "components/strings/grit/components_strings.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/web_contents_delegate.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/events/event_constants.h" -#include "ui/events/keycodes/keyboard_codes.h" -#include "ui/gfx/canvas.h" -#include "ui/native_theme/native_theme.h" -#include "ui/views/background.h" -#include "ui/views/bubble/bubble_frame_view.h" -#include "ui/views/controls/button/checkbox.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/layout_constants.h" -#include "ui/views/widget/widget.h" -#include "ui/views/window/dialog_client_view.h" -#include "ui/wm/core/shadow_types.h" - -using content::DesktopMediaID; - -namespace { - -const int kThumbnailWidth = 160; -const int kThumbnailHeight = 100; -const int kThumbnailMargin = 10; -const int kLabelHeight = 40; -const int kListItemWidth = kThumbnailMargin * 2 + kThumbnailWidth; -const int kListItemHeight = - kThumbnailMargin * 2 + kThumbnailHeight + kLabelHeight; -const int kListColumns = 3; -const int kTotalListWidth = kListColumns * kListItemWidth; - -const int kDesktopMediaSourceViewGroupId = 1; - -const char kDesktopMediaSourceViewClassName[] = - "DesktopMediaPicker_DesktopMediaSourceView"; - -#if !defined(USE_ASH) -DesktopMediaID::Id AcceleratedWidgetToDesktopMediaId( - gfx::AcceleratedWidget accelerated_widget) { -#if defined(OS_WIN) - return reinterpret_cast<DesktopMediaID::Id>(accelerated_widget); -#else - return static_cast<DesktopMediaID::Id>(accelerated_widget); -#endif -} -#endif - -int GetMediaListViewHeightForRows(size_t rows) { - return kListItemHeight * rows; -} - -} // namespace - -namespace deprecated { - -DesktopMediaSourceView::DesktopMediaSourceView(DesktopMediaListView* parent, - DesktopMediaID source_id) - : parent_(parent), - source_id_(source_id), - image_view_(new views::ImageView()), - label_(new views::Label()), - selected_(false) { - AddChildView(image_view_); - AddChildView(label_); - SetFocusBehavior(FocusBehavior::ALWAYS); -} - -DesktopMediaSourceView::~DesktopMediaSourceView() {} - -void DesktopMediaSourceView::SetName(const base::string16& name) { - label_->SetText(name); -} - -void DesktopMediaSourceView::SetThumbnail(const gfx::ImageSkia& thumbnail) { - image_view_->SetImage(thumbnail); -} - -void DesktopMediaSourceView::SetSelected(bool selected) { - if (selected == selected_) - return; - selected_ = selected; - - if (selected) { - // Unselect all other sources. - Views neighbours; - parent()->GetViewsInGroup(GetGroup(), &neighbours); - for (Views::iterator i(neighbours.begin()); i != neighbours.end(); ++i) { - if (*i != this) { - DCHECK_EQ((*i)->GetClassName(), kDesktopMediaSourceViewClassName); - DesktopMediaSourceView* source_view = - static_cast<DesktopMediaSourceView*>(*i); - source_view->SetSelected(false); - } - } - - const SkColor bg_color = GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor); - set_background(views::Background::CreateSolidBackground(bg_color)); - - parent_->OnSelectionChanged(); - } else { - set_background(NULL); - } - - SchedulePaint(); -} - -const char* DesktopMediaSourceView::GetClassName() const { - return kDesktopMediaSourceViewClassName; -} - -void DesktopMediaSourceView::Layout() { - image_view_->SetBounds(kThumbnailMargin, kThumbnailMargin, kThumbnailWidth, - kThumbnailHeight); - label_->SetBounds(kThumbnailMargin, kThumbnailHeight + kThumbnailMargin, - kThumbnailWidth, kLabelHeight); -} - -views::View* DesktopMediaSourceView::GetSelectedViewForGroup(int group) { - Views neighbours; - parent()->GetViewsInGroup(group, &neighbours); - if (neighbours.empty()) - return NULL; - - for (Views::iterator i(neighbours.begin()); i != neighbours.end(); ++i) { - DCHECK_EQ((*i)->GetClassName(), kDesktopMediaSourceViewClassName); - DesktopMediaSourceView* source_view = - static_cast<DesktopMediaSourceView*>(*i); - if (source_view->selected_) - return source_view; - } - return NULL; -} - -bool DesktopMediaSourceView::IsGroupFocusTraversable() const { - return false; -} - -void DesktopMediaSourceView::OnPaint(gfx::Canvas* canvas) { - View::OnPaint(canvas); - if (HasFocus()) { - gfx::Rect bounds(GetLocalBounds()); - bounds.Inset(kThumbnailMargin / 2, kThumbnailMargin / 2); - canvas->DrawFocusRect(bounds); - } -} - -void DesktopMediaSourceView::OnFocus() { - View::OnFocus(); - SetSelected(true); - ScrollRectToVisible(gfx::Rect(size())); - // We paint differently when focused. - SchedulePaint(); -} - -void DesktopMediaSourceView::OnBlur() { - View::OnBlur(); - // We paint differently when focused. - SchedulePaint(); -} - -bool DesktopMediaSourceView::OnMousePressed(const ui::MouseEvent& event) { - if (event.GetClickCount() == 1) { - RequestFocus(); - } else if (event.GetClickCount() == 2) { - RequestFocus(); - parent_->OnDoubleClick(); - } - return true; -} - -void DesktopMediaSourceView::OnGestureEvent(ui::GestureEvent* event) { - if (event->type() == ui::ET_GESTURE_TAP && - event->details().tap_count() == 2) { - RequestFocus(); - parent_->OnDoubleClick(); - event->SetHandled(); - return; - } - - // Detect tap gesture using ET_GESTURE_TAP_DOWN so the view also gets focused - // on the long tap (when the tap gesture starts). - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - RequestFocus(); - event->SetHandled(); - } -} - -DesktopMediaListView::DesktopMediaListView( - DesktopMediaPickerDialogView* parent, - std::unique_ptr<DesktopMediaList> media_list) - : parent_(parent), media_list_(std::move(media_list)), weak_factory_(this) { - media_list_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight)); - SetFocusBehavior(FocusBehavior::ALWAYS); -} - -DesktopMediaListView::~DesktopMediaListView() {} - -void DesktopMediaListView::StartUpdating(DesktopMediaID dialog_window_id) { - media_list_->SetViewDialogWindowId(dialog_window_id); - media_list_->StartUpdating(this); -} - -void DesktopMediaListView::OnSelectionChanged() { - parent_->OnSelectionChanged(); -} - -void DesktopMediaListView::OnDoubleClick() { - parent_->OnDoubleClick(); -} - -DesktopMediaSourceView* DesktopMediaListView::GetSelection() { - for (int i = 0; i < child_count(); ++i) { - DesktopMediaSourceView* source_view = - static_cast<DesktopMediaSourceView*>(child_at(i)); - DCHECK_EQ(source_view->GetClassName(), kDesktopMediaSourceViewClassName); - if (source_view->is_selected()) - return source_view; - } - return NULL; -} - -gfx::Size DesktopMediaListView::GetPreferredSize() const { - int total_rows = (child_count() + kListColumns - 1) / kListColumns; - return gfx::Size(kTotalListWidth, GetMediaListViewHeightForRows(total_rows)); -} - -void DesktopMediaListView::Layout() { - int x = 0; - int y = 0; - - for (int i = 0; i < child_count(); ++i) { - if (x + kListItemWidth > kTotalListWidth) { - x = 0; - y += kListItemHeight; - } - - View* source_view = child_at(i); - source_view->SetBounds(x, y, kListItemWidth, kListItemHeight); - - x += kListItemWidth; - } - - y += kListItemHeight; - SetSize(gfx::Size(kTotalListWidth, y)); -} - -bool DesktopMediaListView::OnKeyPressed(const ui::KeyEvent& event) { - int position_increment = 0; - switch (event.key_code()) { - case ui::VKEY_UP: - position_increment = -kListColumns; - break; - case ui::VKEY_DOWN: - position_increment = kListColumns; - break; - case ui::VKEY_LEFT: - position_increment = -1; - break; - case ui::VKEY_RIGHT: - position_increment = 1; - break; - default: - return false; - } - - if (position_increment != 0) { - DesktopMediaSourceView* selected = GetSelection(); - DesktopMediaSourceView* new_selected = NULL; - - if (selected) { - int index = GetIndexOf(selected); - int new_index = index + position_increment; - if (new_index >= child_count()) - new_index = child_count() - 1; - else if (new_index < 0) - new_index = 0; - if (index != new_index) { - new_selected = - static_cast<DesktopMediaSourceView*>(child_at(new_index)); - } - } else if (has_children()) { - new_selected = static_cast<DesktopMediaSourceView*>(child_at(0)); - } - - if (new_selected) { - GetFocusManager()->SetFocusedView(new_selected); - } - - return true; - } - - return false; -} - -void DesktopMediaListView::OnSourceAdded(DesktopMediaList* list, int index) { - const DesktopMediaList::Source& source = media_list_->GetSource(index); - DesktopMediaSourceView* source_view = - new DesktopMediaSourceView(this, source.id); - source_view->SetName(source.name); - source_view->SetGroup(kDesktopMediaSourceViewGroupId); - AddChildViewAt(source_view, index); - - PreferredSizeChanged(); - - if (child_count() % kListColumns == 1) - parent_->OnMediaListRowsChanged(); - - std::string autoselect_source = - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kAutoSelectDesktopCaptureSource); - if (!autoselect_source.empty() && - base::ASCIIToUTF16(autoselect_source) == source.name) { - // Select, then accept and close the dialog when we're done adding sources. - source_view->OnFocus(); - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&DesktopMediaListView::AcceptSelection, - weak_factory_.GetWeakPtr())); - } -} - -void DesktopMediaListView::OnSourceRemoved(DesktopMediaList* list, int index) { - DesktopMediaSourceView* view = - static_cast<DesktopMediaSourceView*>(child_at(index)); - DCHECK(view); - DCHECK_EQ(view->GetClassName(), kDesktopMediaSourceViewClassName); - bool was_selected = view->is_selected(); - RemoveChildView(view); - delete view; - - if (was_selected) - OnSelectionChanged(); - - PreferredSizeChanged(); - - if (child_count() % kListColumns == 0) - parent_->OnMediaListRowsChanged(); -} - -void DesktopMediaListView::OnSourceMoved(DesktopMediaList* list, - int old_index, - int new_index) { - DesktopMediaSourceView* view = - static_cast<DesktopMediaSourceView*>(child_at(old_index)); - ReorderChildView(view, new_index); - PreferredSizeChanged(); -} - -void DesktopMediaListView::OnSourceNameChanged(DesktopMediaList* list, - int index) { - const DesktopMediaList::Source& source = media_list_->GetSource(index); - DesktopMediaSourceView* source_view = - static_cast<DesktopMediaSourceView*>(child_at(index)); - source_view->SetName(source.name); -} - -void DesktopMediaListView::OnSourceThumbnailChanged(DesktopMediaList* list, - int index) { - const DesktopMediaList::Source& source = media_list_->GetSource(index); - DesktopMediaSourceView* source_view = - static_cast<DesktopMediaSourceView*>(child_at(index)); - source_view->SetThumbnail(source.thumbnail); -} - -void DesktopMediaListView::AcceptSelection() { - OnSelectionChanged(); - OnDoubleClick(); -} - -DesktopMediaPickerDialogView::DesktopMediaPickerDialogView( - content::WebContents* parent_web_contents, - gfx::NativeWindow context, - DesktopMediaPickerViews* parent, - const base::string16& app_name, - const base::string16& target_name, - std::unique_ptr<DesktopMediaList> screen_list, - std::unique_ptr<DesktopMediaList> window_list, - std::unique_ptr<DesktopMediaList> tab_list, - bool request_audio) - : parent_(parent), - app_name_(app_name), - description_label_(new views::Label()), - audio_share_checkbox_(nullptr), - audio_share_checked_(true), - sources_scroll_view_(views::ScrollView::CreateScrollViewWithBorder()) { - std::vector<std::unique_ptr<DesktopMediaList>> media_lists; - if (screen_list) - media_lists.push_back(std::move(screen_list)); - if (window_list) - media_lists.push_back(std::move(window_list)); - if (tab_list) - media_lists.push_back(std::move(tab_list)); - - std::unique_ptr<DesktopMediaList> media_list; - if (media_lists.size() > 1) - media_list.reset(new CombinedDesktopMediaList(media_lists)); - else - media_list = std::move(media_lists[0]); - - DCHECK(media_list != nullptr); - sources_list_view_ = new DesktopMediaListView(this, std::move(media_list)); - - // TODO(estade): we should be getting the inside-border spacing by default as - // a DialogDelegateView subclass, via default BubbleFrameView content margins. - SetLayoutManager(new views::BoxLayout( - views::BoxLayout::kVertical, views::kButtonHEdgeMarginNew, - views::kPanelVertMargin, views::kLabelToControlVerticalSpacing)); - - if (app_name == target_name) { - description_label_->SetText( - l10n_util::GetStringFUTF16(IDS_DESKTOP_MEDIA_PICKER_TEXT, app_name)); - } else { - description_label_->SetText(l10n_util::GetStringFUTF16( - IDS_DESKTOP_MEDIA_PICKER_TEXT_DELEGATED, app_name, target_name)); - } - description_label_->SetMultiLine(true); - description_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - AddChildView(description_label_); - - sources_scroll_view_->SetContents(sources_list_view_); - sources_scroll_view_->ClipHeightTo(GetMediaListViewHeightForRows(1), - GetMediaListViewHeightForRows(2)); - AddChildView(sources_scroll_view_); - - if (request_audio) { - audio_share_checkbox_ = new views::Checkbox( - l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE)); - AddChildView(audio_share_checkbox_); - audio_share_checkbox_->SetEnabled(false); - audio_share_checkbox_->SetTooltipText(l10n_util::GetStringUTF16( - IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_NONE)); - } - - // If |parent_web_contents| is set and it's not a background page then the - // picker will be shown modal to the web contents. Otherwise the picker is - // shown in a separate window. - views::Widget* widget = NULL; - bool modal_dialog = - parent_web_contents && - !parent_web_contents->GetDelegate()->IsNeverVisible(parent_web_contents); - if (modal_dialog) { - widget = - constrained_window::ShowWebModalDialogViews(this, parent_web_contents); - } else { - widget = DialogDelegate::CreateDialogWidget(this, context, NULL); - widget->Show(); - } - - // If the picker is not modal to the calling web contents then it is displayed - // in its own top-level window, so in that case it needs to be filtered out of - // the list of top-level windows available for capture, and to achieve that - // the Id is passed to DesktopMediaList. - DesktopMediaID dialog_window_id; - if (!modal_dialog) { - dialog_window_id = DesktopMediaID::RegisterAuraWindow( - DesktopMediaID::TYPE_WINDOW, widget->GetNativeWindow()); - - // Set native window ID if the windows is outside Ash. -#if !defined(USE_ASH) - dialog_window_id.id = AcceleratedWidgetToDesktopMediaId( - widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget()); -#endif - } - - sources_list_view_->StartUpdating(dialog_window_id); -} - -DesktopMediaPickerDialogView::~DesktopMediaPickerDialogView() {} - -void DesktopMediaPickerDialogView::DetachParent() { - parent_ = NULL; -} - -gfx::Size DesktopMediaPickerDialogView::GetPreferredSize() const { - static const size_t kDialogViewWidth = 600; - return gfx::Size(kDialogViewWidth, GetHeightForWidth(kDialogViewWidth)); -} - -ui::ModalType DesktopMediaPickerDialogView::GetModalType() const { - return ui::MODAL_TYPE_CHILD; -} - -base::string16 DesktopMediaPickerDialogView::GetWindowTitle() const { - return l10n_util::GetStringFUTF16( - IDS_DESKTOP_MEDIA_PICKER_TITLE_DEPRECATED, app_name_); -} - -bool DesktopMediaPickerDialogView::IsDialogButtonEnabled( - ui::DialogButton button) const { - if (button == ui::DIALOG_BUTTON_OK) - return sources_list_view_->GetSelection() != NULL; - return true; -} - -views::View* DesktopMediaPickerDialogView::GetInitiallyFocusedView() { - return sources_list_view_; -} - -base::string16 DesktopMediaPickerDialogView::GetDialogButtonLabel( - ui::DialogButton button) const { - return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK - ? IDS_DESKTOP_MEDIA_PICKER_SHARE - : IDS_CANCEL); -} - -bool DesktopMediaPickerDialogView::Accept() { - DesktopMediaSourceView* selection = sources_list_view_->GetSelection(); - - // Ok button should only be enabled when a source is selected. - DCHECK(selection); - DesktopMediaID source = selection->source_id(); - source.audio_share = audio_share_checkbox_ && - audio_share_checkbox_->enabled() && - audio_share_checkbox_->checked(); - - // If the media source is an tab, activate it. - if (source.type == DesktopMediaID::TYPE_WEB_CONTENTS) { - content::WebContents* tab = content::WebContents::FromRenderFrameHost( - content::RenderFrameHost::FromID( - source.web_contents_id.render_process_id, - source.web_contents_id.main_render_frame_id)); - if (tab) - tab->GetDelegate()->ActivateContents(tab); - } - - if (parent_) - parent_->NotifyDialogResult(source); - - // Return true to close the window. - return true; -} - -void DesktopMediaPickerDialogView::DeleteDelegate() { - // If the dialog is being closed then notify the parent about it. - if (parent_) - parent_->NotifyDialogResult(DesktopMediaID()); - delete this; -} - -void DesktopMediaPickerDialogView::OnSelectionChanged() { - GetDialogClientView()->UpdateDialogButtons(); - - // Disable the checkbox if we cannot support audio for the selected source. - if (audio_share_checkbox_) { - DesktopMediaSourceView* selection = sources_list_view_->GetSelection(); - - DesktopMediaID source; - if (selection) - source = selection->source_id(); - - if (source.type == DesktopMediaID::TYPE_SCREEN || - source.type == DesktopMediaID::TYPE_WEB_CONTENTS) { - if (!audio_share_checkbox_->enabled()) { - audio_share_checkbox_->SetEnabled(true); - audio_share_checkbox_->SetChecked(audio_share_checked_); - } - audio_share_checkbox_->SetTooltipText(base::string16()); - } else if (source.type == DesktopMediaID::TYPE_WINDOW) { - if (audio_share_checkbox_->enabled()) { - audio_share_checkbox_->SetEnabled(false); - audio_share_checked_ = audio_share_checkbox_->checked(); - audio_share_checkbox_->SetChecked(false); - } - audio_share_checkbox_->SetTooltipText(l10n_util::GetStringUTF16( - IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_WINDOW)); - } else { - NOTREACHED(); - } - } -} - -void DesktopMediaPickerDialogView::OnDoubleClick() { - // This will call Accept() and close the dialog. - GetDialogClientView()->AcceptWindow(); -} - -void DesktopMediaPickerDialogView::OnMediaListRowsChanged() { - gfx::Rect widget_bound = GetWidget()->GetWindowBoundsInScreen(); - - int new_height = widget_bound.height() - sources_scroll_view_->height() + - sources_scroll_view_->GetPreferredSize().height(); - - GetWidget()->CenterWindow(gfx::Size(widget_bound.width(), new_height)); -} - -DesktopMediaListView* DesktopMediaPickerDialogView::GetMediaListViewForTesting() - const { - return sources_list_view_; -} - -DesktopMediaSourceView* -DesktopMediaPickerDialogView::GetMediaSourceViewForTesting(int index) const { - if (sources_list_view_->child_count() <= index) - return NULL; - - return reinterpret_cast<DesktopMediaSourceView*>( - sources_list_view_->child_at(index)); -} - -DesktopMediaPickerViews::DesktopMediaPickerViews() : dialog_(NULL) {} - -DesktopMediaPickerViews::~DesktopMediaPickerViews() { - if (dialog_) { - dialog_->DetachParent(); - dialog_->GetWidget()->Close(); - } -} - -void DesktopMediaPickerViews::Show( - content::WebContents* web_contents, - gfx::NativeWindow context, - gfx::NativeWindow parent, - const base::string16& app_name, - const base::string16& target_name, - std::unique_ptr<DesktopMediaList> screen_list, - std::unique_ptr<DesktopMediaList> window_list, - std::unique_ptr<DesktopMediaList> tab_list, - bool request_audio, - const DoneCallback& done_callback) { - callback_ = done_callback; - dialog_ = new DesktopMediaPickerDialogView( - web_contents, context, this, app_name, target_name, - std::move(screen_list), std::move(window_list), std::move(tab_list), - request_audio); -} - -void DesktopMediaPickerViews::NotifyDialogResult(DesktopMediaID source) { - // Once this method is called the |dialog_| will close and destroy itself. - dialog_->DetachParent(); - dialog_ = NULL; - - DCHECK(!callback_.is_null()); - - // Notify the |callback_| asynchronously because it may need to destroy - // DesktopMediaPicker. - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(callback_, source)); - callback_.Reset(); -} - -} // namespace deprecated
diff --git a/chrome/browser/ui/views/desktop_media_picker_views_deprecated.h b/chrome/browser/ui/views/desktop_media_picker_views_deprecated.h deleted file mode 100644 index 02d0e5c..0000000 --- a/chrome/browser/ui/views/desktop_media_picker_views_deprecated.h +++ /dev/null
@@ -1,210 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_DESKTOP_MEDIA_PICKER_VIEWS_DEPRECATED_H_ -#define CHROME_BROWSER_UI_VIEWS_DESKTOP_MEDIA_PICKER_VIEWS_DEPRECATED_H_ - -#include "base/macros.h" -#include "chrome/browser/media/webrtc/desktop_media_list_observer.h" -#include "chrome/browser/media/webrtc/desktop_media_picker.h" -#include "ui/views/window/dialog_delegate.h" - -namespace views { -class ImageView; -class Label; -class Checkbox; -} // namespace views - -// TODO(qiangchen): Remove this file after new UI is done, and remove related -// resource strings, such as IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_NONE. -namespace deprecated { - -class DesktopMediaPickerDialogView; -class DesktopMediaPickerViews; -class DesktopMediaSourceView; - -// View that shows a list of desktop media sources available from -// DesktopMediaList. -class DesktopMediaListView : public views::View, - public DesktopMediaListObserver { - public: - DesktopMediaListView(DesktopMediaPickerDialogView* parent, - std::unique_ptr<DesktopMediaList> media_list); - ~DesktopMediaListView() override; - - void StartUpdating(content::DesktopMediaID dialog_window_id); - - // Called by DesktopMediaSourceView when selection has changed. - void OnSelectionChanged(); - - // Called by DesktopMediaSourceView when a source has been double-clicked. - void OnDoubleClick(); - - // Returns currently selected source. - DesktopMediaSourceView* GetSelection(); - - // views::View overrides. - gfx::Size GetPreferredSize() const override; - void Layout() override; - bool OnKeyPressed(const ui::KeyEvent& event) override; - - private: - // DesktopMediaList::Observer interface - void OnSourceAdded(DesktopMediaList* list, int index) override; - void OnSourceRemoved(DesktopMediaList* list, int index) override; - void OnSourceMoved(DesktopMediaList* list, - int old_index, - int new_index) override; - void OnSourceNameChanged(DesktopMediaList* list, int index) override; - void OnSourceThumbnailChanged(DesktopMediaList* list, int index) override; - - // Accepts whatever happens to be selected right now. - void AcceptSelection(); - - DesktopMediaPickerDialogView* parent_; - std::unique_ptr<DesktopMediaList> media_list_; - base::WeakPtrFactory<DesktopMediaListView> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(DesktopMediaListView); -}; - -// View used for each item in DesktopMediaListView. Shows a single desktop media -// source as a thumbnail with the title under it. -class DesktopMediaSourceView : public views::View { - public: - DesktopMediaSourceView(DesktopMediaListView* parent, - content::DesktopMediaID source_id); - ~DesktopMediaSourceView() override; - - // Updates thumbnail and title from |source|. - void SetName(const base::string16& name); - void SetThumbnail(const gfx::ImageSkia& thumbnail); - - // Id for the source shown by this View. - const content::DesktopMediaID& source_id() const { return source_id_; } - - // Returns true if the source is selected. - bool is_selected() const { return selected_; } - - // views::View interface. - const char* GetClassName() const override; - void Layout() override; - views::View* GetSelectedViewForGroup(int group) override; - bool IsGroupFocusTraversable() const override; - void OnPaint(gfx::Canvas* canvas) override; - void OnFocus() override; - void OnBlur() override; - bool OnMousePressed(const ui::MouseEvent& event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - - private: - // Updates selection state of the element. If |selected| is true then also - // calls SetSelected(false) for the source view that was selected before that - // (if any). - void SetSelected(bool selected); - - DesktopMediaListView* parent_; - content::DesktopMediaID source_id_; - - views::ImageView* image_view_; - views::Label* label_; - - bool selected_; - - DISALLOW_COPY_AND_ASSIGN(DesktopMediaSourceView); -}; - -// Dialog view used for DesktopMediaPickerViews. -class DesktopMediaPickerDialogView : public views::DialogDelegateView { - public: - DesktopMediaPickerDialogView(content::WebContents* parent_web_contents, - gfx::NativeWindow context, - DesktopMediaPickerViews* parent, - const base::string16& app_name, - const base::string16& target_name, - std::unique_ptr<DesktopMediaList> screen_list, - std::unique_ptr<DesktopMediaList> window_list, - std::unique_ptr<DesktopMediaList> tab_list, - bool request_audio); - ~DesktopMediaPickerDialogView() override; - - // Called by parent (DesktopMediaPickerViews) when it's destroyed. - void DetachParent(); - - // Called by DesktopMediaListView. - void OnSelectionChanged(); - void OnDoubleClick(); - - // views::View overrides. - gfx::Size GetPreferredSize() const override; - - // views::DialogDelegateView overrides. - ui::ModalType GetModalType() const override; - base::string16 GetWindowTitle() const override; - bool IsDialogButtonEnabled(ui::DialogButton button) const override; - views::View* GetInitiallyFocusedView() override; - base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; - bool Accept() override; - void DeleteDelegate() override; - - void OnMediaListRowsChanged(); - - DesktopMediaListView* GetMediaListViewForTesting() const; - DesktopMediaSourceView* GetMediaSourceViewForTesting(int index) const; - - private: - DesktopMediaPickerViews* parent_; - base::string16 app_name_; - - views::Label* description_label_; - - // |audio_share_checked_| records whether the user permits audio, when - // |audio_share_checkbox_| is disabled. - views::Checkbox* audio_share_checkbox_; - bool audio_share_checked_; - - views::ScrollView* sources_scroll_view_; - DesktopMediaListView* sources_list_view_; - - DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerDialogView); -}; - -// Implementation of DesktopMediaPicker for Views. -class DesktopMediaPickerViews : public DesktopMediaPicker { - public: - DesktopMediaPickerViews(); - ~DesktopMediaPickerViews() override; - - void NotifyDialogResult(content::DesktopMediaID source); - - // DesktopMediaPicker overrides. - void Show(content::WebContents* web_contents, - gfx::NativeWindow context, - gfx::NativeWindow parent, - const base::string16& app_name, - const base::string16& target_name, - std::unique_ptr<DesktopMediaList> screen_list, - std::unique_ptr<DesktopMediaList> window_list, - std::unique_ptr<DesktopMediaList> tab_list, - bool request_audio, - const DoneCallback& done_callback) override; - - DesktopMediaPickerDialogView* GetDialogViewForTesting() const { - return dialog_; - } - - private: - DoneCallback callback_; - - // The |dialog_| is owned by the corresponding views::Widget instance. - // When DesktopMediaPickerViews is destroyed the |dialog_| is destroyed - // asynchronously by closing the widget. - DesktopMediaPickerDialogView* dialog_; - - DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerViews); -}; - -} // namespace deprecated - -#endif // CHROME_BROWSER_UI_VIEWS_DESKTOP_MEDIA_PICKER_VIEWS_DEPRECATED_H_
diff --git a/chrome/browser/ui/views/desktop_media_picker_views_deprecated_unittest.cc b/chrome/browser/ui/views/desktop_media_picker_views_deprecated_unittest.cc deleted file mode 100644 index ffc448a..0000000 --- a/chrome/browser/ui/views/desktop_media_picker_views_deprecated_unittest.cc +++ /dev/null
@@ -1,231 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/views/desktop_media_picker_views_deprecated.h" - -#include <utility> - -#include "base/bind.h" -#include "base/run_loop.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/media/webrtc/fake_desktop_media_list.h" -#include "components/web_modal/test_web_contents_modal_dialog_host.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/aura/window.h" -#include "ui/events/event_utils.h" -#include "ui/views/test/scoped_views_test_helper.h" -#include "ui/views/widget/widget.h" -#include "ui/views/window/dialog_client_view.h" -#include "ui/views/window/dialog_delegate.h" - -namespace deprecated { - -class DesktopMediaPickerViewsDeprecatedTest : public testing::Test { - public: - DesktopMediaPickerViewsDeprecatedTest() {} - ~DesktopMediaPickerViewsDeprecatedTest() override {} - - void SetUp() override { - screen_list_ = new FakeDesktopMediaList(); - window_list_ = new FakeDesktopMediaList(); - tab_list_ = new FakeDesktopMediaList(); - std::unique_ptr<FakeDesktopMediaList> screen_list(screen_list_); - std::unique_ptr<FakeDesktopMediaList> window_list(window_list_); - std::unique_ptr<FakeDesktopMediaList> tab_list(tab_list_); - - base::string16 app_name = base::ASCIIToUTF16("foo"); - - picker_views_.reset(new DesktopMediaPickerViews()); - picker_views_->Show( - NULL, test_helper_.GetContext(), NULL, app_name, app_name, - std::move(screen_list), std::move(window_list), std::move(tab_list), - false, base::Bind(&DesktopMediaPickerViewsDeprecatedTest::OnPickerDone, - base::Unretained(this))); - } - - void TearDown() override { - if (GetPickerDialogView()) { - EXPECT_CALL(*this, OnPickerDone(content::DesktopMediaID())); - GetPickerDialogView()->GetWidget()->CloseNow(); - } - } - - DesktopMediaPickerDialogView* GetPickerDialogView() const { - return picker_views_->GetDialogViewForTesting(); - } - - MOCK_METHOD1(OnPickerDone, void(content::DesktopMediaID)); - - protected: - content::TestBrowserThreadBundle thread_bundle_; - views::ScopedViewsTestHelper test_helper_; - FakeDesktopMediaList* screen_list_; - FakeDesktopMediaList* window_list_; - FakeDesktopMediaList* tab_list_; - std::unique_ptr<DesktopMediaPickerViews> picker_views_; -}; - -TEST_F(DesktopMediaPickerViewsDeprecatedTest, - DoneCallbackCalledWhenWindowClosed) { - EXPECT_CALL(*this, OnPickerDone(content::DesktopMediaID())); - - GetPickerDialogView()->GetWidget()->Close(); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(DesktopMediaPickerViewsDeprecatedTest, - DoneCallbackCalledOnOkButtonPressed) { - const int kFakeId = 222; - EXPECT_CALL(*this, OnPickerDone(content::DesktopMediaID( - content::DesktopMediaID::TYPE_WINDOW, kFakeId))); - window_list_->AddSource(kFakeId); - - EXPECT_FALSE( - GetPickerDialogView()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK)); - - GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnFocus(); - EXPECT_TRUE( - GetPickerDialogView()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK)); - - GetPickerDialogView()->GetDialogClientView()->AcceptWindow(); - base::RunLoop().RunUntilIdle(); -} - -// Verifies that a MediaSourceView is selected with mouse left click and -// original selected MediaSourceView gets unselected. -TEST_F(DesktopMediaPickerViewsDeprecatedTest, - SelectMediaSourceViewOnSingleClick) { - window_list_->AddSource(0); - window_list_->AddSource(1); - - DesktopMediaSourceView* source_view_0 = - GetPickerDialogView()->GetMediaSourceViewForTesting(0); - - DesktopMediaSourceView* source_view_1 = - GetPickerDialogView()->GetMediaSourceViewForTesting(1); - - // Both media source views are not selected initially. - EXPECT_FALSE(source_view_0->is_selected()); - EXPECT_FALSE(source_view_1->is_selected()); - - // Source view 0 is selected with mouse click. - ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); - - GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnMousePressed(press); - - EXPECT_TRUE(source_view_0->is_selected()); - EXPECT_FALSE(source_view_1->is_selected()); - - // Source view 1 is selected and source view 0 is unselected with mouse click. - GetPickerDialogView()->GetMediaSourceViewForTesting(1)->OnMousePressed(press); - - EXPECT_FALSE(source_view_0->is_selected()); - EXPECT_TRUE(source_view_1->is_selected()); -} - -TEST_F(DesktopMediaPickerViewsDeprecatedTest, DoneCallbackCalledOnDoubleClick) { - const int kFakeId = 222; - EXPECT_CALL(*this, OnPickerDone(content::DesktopMediaID( - content::DesktopMediaID::TYPE_WINDOW, kFakeId))); - - window_list_->AddSource(kFakeId); - - ui::MouseEvent double_click(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), - ui::EventTimeForNow(), - ui::EF_LEFT_MOUSE_BUTTON | ui::EF_IS_DOUBLE_CLICK, - ui::EF_LEFT_MOUSE_BUTTON); - - GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnMousePressed( - double_click); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(DesktopMediaPickerViewsDeprecatedTest, DoneCallbackCalledOnDoubleTap) { - const int kFakeId = 222; - EXPECT_CALL(*this, OnPickerDone(content::DesktopMediaID( - content::DesktopMediaID::TYPE_WINDOW, kFakeId))); - - window_list_->AddSource(kFakeId); - ui::GestureEventDetails details(ui::ET_GESTURE_TAP); - details.set_tap_count(2); - ui::GestureEvent double_tap(10, 10, 0, base::TimeTicks(), details); - - GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnGestureEvent( - &double_tap); - base::RunLoop().RunUntilIdle(); -} - -TEST_F(DesktopMediaPickerViewsDeprecatedTest, CancelButtonAlwaysEnabled) { - EXPECT_TRUE( - GetPickerDialogView()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL)); -} - -// Verifies that the MediaSourceView is added or removed when |media_list_| is -// updated. -TEST_F(DesktopMediaPickerViewsDeprecatedTest, AddAndRemoveMediaSource) { - // No media source at first. - EXPECT_EQ(NULL, GetPickerDialogView()->GetMediaSourceViewForTesting(0)); - - for (int i = 0; i < 3; ++i) { - window_list_->AddSource(i); - EXPECT_TRUE(GetPickerDialogView()->GetMediaSourceViewForTesting(i)); - } - - for (int i = 2; i >= 0; --i) { - window_list_->RemoveSource(i); - EXPECT_EQ(NULL, GetPickerDialogView()->GetMediaSourceViewForTesting(i)); - } -} - -// Verifies that focusing the MediaSourceView marks it selected and the -// original selected MediaSourceView gets unselected. -TEST_F(DesktopMediaPickerViewsDeprecatedTest, FocusMediaSourceViewToSelect) { - window_list_->AddSource(0); - window_list_->AddSource(1); - - DesktopMediaSourceView* source_view_0 = - GetPickerDialogView()->GetMediaSourceViewForTesting(0); - - DesktopMediaSourceView* source_view_1 = - GetPickerDialogView()->GetMediaSourceViewForTesting(1); - - EXPECT_FALSE(source_view_0->is_selected()); - EXPECT_FALSE(source_view_1->is_selected()); - - source_view_0->OnFocus(); - EXPECT_TRUE(source_view_0->is_selected()); - - // Removing the focus does not undo the selection. - source_view_0->OnBlur(); - EXPECT_TRUE(source_view_0->is_selected()); - - source_view_1->OnFocus(); - EXPECT_FALSE(source_view_0->is_selected()); - EXPECT_TRUE(source_view_1->is_selected()); -} - -TEST_F(DesktopMediaPickerViewsDeprecatedTest, OkButtonDisabledWhenNoSelection) { - window_list_->AddSource(111); - - EXPECT_FALSE( - GetPickerDialogView()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK)); - - GetPickerDialogView()->GetMediaSourceViewForTesting(0)->OnFocus(); - EXPECT_TRUE( - GetPickerDialogView()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK)); - - window_list_->RemoveSource(0); - EXPECT_FALSE( - GetPickerDialogView()->IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK)); -} - -// Verifies that the MediaListView get the initial focus. -TEST_F(DesktopMediaPickerViewsDeprecatedTest, ListViewHasInitialFocus) { - EXPECT_TRUE(GetPickerDialogView()->GetMediaListViewForTesting()->HasFocus()); -} - -} // namespace deprecated
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc index 1b18839..f102bd0 100644 --- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc +++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -579,8 +579,27 @@ bool SimulateMouseDownAndDragStartInLeftFrame() { AssertTestPageIsLoaded(); - if (!SimulateMouseMove(kMiddleOfLeftFrame) || !SimulateMouseDown() || - !SimulateMouseMove(expected_location_of_drag_start_in_left_frame())) + + // Waiting until the mousemove and mousedown events reach the right renderer + // is needed to avoid flakiness reported in https://crbug.com/671445 (which + // has its root cause in https://crbug.com/647378). Once the latter bug + // is fixed, we should no longer need to wait for these events (because + // fixing https://crbug.com/647378 should guarantee that events arrive + // to the renderer in the right order). + DOMDragEventWaiter mouse_move_event_waiter("mousemove", left_frame()); + DOMDragEventWaiter mouse_down_event_waiter("mousedown", left_frame()); + + if (!SimulateMouseMove(kMiddleOfLeftFrame)) + return false; + if (!mouse_move_event_waiter.WaitForNextMatchingEvent(nullptr)) + return false; + + if (!SimulateMouseDown()) + return false; + if (!mouse_down_event_waiter.WaitForNextMatchingEvent(nullptr)) + return false; + + if (!SimulateMouseMove(expected_location_of_drag_start_in_left_frame())) return false; return true; @@ -1139,6 +1158,10 @@ "dragend"})); } +// TODO(paulmeyer): Should test the case of navigation happening in the middle +// of a drag operation, and cross-site drags should be allowed across a +// navigation. + INSTANTIATE_TEST_CASE_P( SameSiteSubframe, DragAndDropBrowserTest, ::testing::Values(false));
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 40ac6f4..63d0c65 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -324,9 +324,10 @@ {"bluetoothAddDevicePageTitle", IDS_SETTINGS_BLUETOOTH_ADD_DEVICE}, {"bluetoothConnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT}, {"bluetoothConnecting", IDS_SETTINGS_BLUETOOTH_CONNECTING}, + {"bluetoothDisabled", IDS_SETTINGS_BLUETOOTH_DISABLED}, {"bluetoothDisconnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT}, {"bluetoothDismiss", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISMISS_ERROR}, - {"bluetoothEnable", IDS_SETTINGS_BLUETOOTH_ENABLE}, + {"bluetoothEnabled", IDS_SETTINGS_BLUETOOTH_ENABLED}, {"bluetoothExpandA11yLabel", IDS_SETTINGS_BLUETOOTH_EXPAND_ACCESSIBILITY_LABEL}, {"bluetoothNoDevices", IDS_OPTIONS_SETTINGS_BLUETOOTH_NO_DEVICES},
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_sandboxed_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_sandboxed_unittest.cc deleted file mode 100644 index 1c8e0ce..0000000 --- a/chrome/common/extensions/manifest_tests/extension_manifests_sandboxed_unittest.cc +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/macros.h" -#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h" -#include "extensions/common/manifest_constants.h" -#include "extensions/common/manifest_handlers/csp_info.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace extensions { - -namespace errors = manifest_errors; - -class SandboxedPagesManifestTest : public ChromeManifestTest { -}; - -TEST_F(SandboxedPagesManifestTest, SandboxedPages) { - // Sandboxed pages specified, no custom CSP value. - scoped_refptr<Extension> extension1( - LoadAndExpectSuccess("sandboxed_pages_valid_1.json")); - - // No sandboxed pages. - scoped_refptr<Extension> extension2( - LoadAndExpectSuccess("sandboxed_pages_valid_2.json")); - - // Sandboxed pages specified with a custom CSP value. - scoped_refptr<Extension> extension3( - LoadAndExpectSuccess("sandboxed_pages_valid_3.json")); - - // Sandboxed pages specified with wildcard, no custom CSP value. - scoped_refptr<Extension> extension4( - LoadAndExpectSuccess("sandboxed_pages_valid_4.json")); - - // Sandboxed pages specified with filename wildcard, no custom CSP value. - scoped_refptr<Extension> extension5( - LoadAndExpectSuccess("sandboxed_pages_valid_5.json")); - - const char kSandboxedCSP[] = - "sandbox allow-scripts allow-forms allow-popups allow-modals"; - const char kDefaultCSP[] = - "script-src 'self' blob: filesystem: chrome-extension-resource:; " - "object-src 'self' blob: filesystem:;"; - const char kCustomSandboxedCSP[] = - "sandbox; script-src: https://www.google.com"; - - EXPECT_EQ( - kSandboxedCSP, - CSPInfo::GetResourceContentSecurityPolicy(extension1.get(), "/test")); - EXPECT_EQ( - kDefaultCSP, - CSPInfo::GetResourceContentSecurityPolicy(extension1.get(), "/none")); - EXPECT_EQ( - kDefaultCSP, - CSPInfo::GetResourceContentSecurityPolicy(extension2.get(), "/test")); - EXPECT_EQ( - kCustomSandboxedCSP, - CSPInfo::GetResourceContentSecurityPolicy(extension3.get(), "/test")); - EXPECT_EQ( - kDefaultCSP, - CSPInfo::GetResourceContentSecurityPolicy(extension3.get(), "/none")); - EXPECT_EQ( - kSandboxedCSP, - CSPInfo::GetResourceContentSecurityPolicy(extension4.get(), "/test")); - EXPECT_EQ(kSandboxedCSP, - CSPInfo::GetResourceContentSecurityPolicy(extension5.get(), - "/path/test.ext")); - EXPECT_EQ( - kDefaultCSP, - CSPInfo::GetResourceContentSecurityPolicy(extension5.get(), "/test")); - - Testcase testcases[] = { - Testcase("sandboxed_pages_invalid_1.json", - errors::kInvalidSandboxedPagesList), - Testcase("sandboxed_pages_invalid_2.json", - errors::kInvalidSandboxedPage), - Testcase("sandboxed_pages_invalid_3.json", - errors::kInvalidSandboxedPagesCSP), - Testcase("sandboxed_pages_invalid_4.json", - errors::kInvalidSandboxedPagesCSP), - Testcase("sandboxed_pages_invalid_5.json", - errors::kInvalidSandboxedPagesCSP) - }; - RunTestcases(testcases, arraysize(testcases), - EXPECT_TYPE_ERROR); -} - -} // namespace extensions
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc index 1f5011b..ec09d43 100644 --- a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc +++ b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
@@ -520,6 +520,15 @@ // Network-related permissions. {IDS_EXTENSION_PROMPT_WARNING_NETWORKING_PRIVATE, + {APIPermission::kNetworkingOnc}, + // Adding networkingPrivate as an optional permission for this rule so + // the permission is removed from the available permission set when the + // next rule (for networkingPrivate permission) is considered - without + // this, IDS_EXTENSION_PROMPT_WARNING_NETWORK_PRIVATE would be duplicated + // for manifests that have both networking.onc and networkingPrivate + // permission. + {APIPermission::kNetworkingPrivate}}, + {IDS_EXTENSION_PROMPT_WARNING_NETWORKING_PRIVATE, {APIPermission::kNetworkingPrivate}, {}}, {IDS_EXTENSION_PROMPT_WARNING_NETWORKING_CONFIG,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index ba77850..ba93142 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3551,7 +3551,6 @@ "../browser/font_family_cache_unittest.cc", "../browser/importer/firefox_profile_lock_unittest.cc", "../browser/importer/profile_writer_unittest.cc", - "../browser/media/combined_desktop_media_list_unittest.cc", "../browser/media/webrtc/tab_desktop_media_list_unittest.cc", "../browser/media_galleries/fileapi/native_media_file_util_unittest.cc", "../browser/media_galleries/gallery_watch_manager_unittest.cc", @@ -4049,7 +4048,6 @@ "../common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc", "../common/extensions/manifest_tests/extension_manifests_portsinpermissions_unittest.cc", "../common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc", - "../common/extensions/manifest_tests/extension_manifests_sandboxed_unittest.cc", "../common/extensions/manifest_tests/extension_manifests_storage_unittest.cc", "../common/extensions/manifest_tests/extension_manifests_ui_unittest.cc", "../common/extensions/manifest_tests/extension_manifests_update_unittest.cc", @@ -4566,7 +4564,6 @@ "../browser/ui/cocoa/location_bar/security_state_bubble_decoration_unittest.mm", "../browser/ui/cocoa/location_bar/selected_keyword_decoration_unittest.mm", "../browser/ui/cocoa/location_bar/zoom_decoration_unittest.mm", - "../browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated_unittest.mm", "../browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm", "../browser/ui/cocoa/menu_button_unittest.mm", "../browser/ui/cocoa/notifications/notification_builder_mac_unittest.mm", @@ -4789,7 +4786,6 @@ # Get these compiling on Mac - see http://crbug.com/657883. "../browser/ui/views/crypto_module_password_dialog_view_unittest.cc", "../browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc", - "../browser/ui/views/desktop_media_picker_views_deprecated_unittest.cc", "../browser/ui/views/first_run_bubble_unittest.cc", ] }
diff --git a/chrome/test/data/drag_and_drop/image_source.html b/chrome/test/data/drag_and_drop/image_source.html index 4c4d05c5..9063b07 100644 --- a/chrome/test/data/drag_and_drop/image_source.html +++ b/chrome/test/data/drag_and_drop/image_source.html
@@ -28,5 +28,7 @@ <img ondragstart="dragstart_handler(event);" ondragend="window.reportDragAndDropEvent(event);" ondragleave="window.reportDragAndDropEvent(event);" + onmousedown="window.reportDragAndDropEvent(event);" + onmousemove="window.reportDragAndDropEvent(event);" src="/image_decoding/droids.jpg"> </body>
diff --git a/chrome/test/data/extensions/api_test/networking_private/alias/manifest.json b/chrome/test/data/extensions/api_test/networking_private/alias/manifest.json new file mode 100644 index 0000000..9f07b55 --- /dev/null +++ b/chrome/test/data/extensions/api_test/networking_private/alias/manifest.json
@@ -0,0 +1,15 @@ +{ + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC74Vbx3EbhPc/FOvn6+HxCjMSml0HdPMiuRjj5a3b+MnRML1iJ9OAgbKUYJ/u3s25/cGq8pNB0NbyupHGEqvqAE7TcNr1mdgs0PWxh2IOI1GKrxlzxpqzQuFmxq5WHKr5RrwZ4/Xq0t/+e8JkvhZdW0jarz/28Jom0gkM5lorsewIDAQAB", + "name": "networking onc extension API interface test", + "version": "0.1", + "manifest_version": 2, + "description": "Test of chrome.networking.onc methods", + "app": { + "background": { + "scripts": ["test.js"] + } + }, + "permissions": [ + "networking.onc" + ] +}
diff --git a/chrome/test/data/extensions/api_test/networking_private/alias/test.js b/chrome/test/data/extensions/api_test/networking_private/alias/test.js new file mode 100644 index 0000000..b724e7b --- /dev/null +++ b/chrome/test/data/extensions/api_test/networking_private/alias/test.js
@@ -0,0 +1,48 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test that verifies that apps with only networking API alias permission +// can invoke API methods and listen to API events without encountering +// API access problems. + +chrome.test.runTests([ + function onlyAliasBindingsPresent() { + chrome.test.assertTrue(!!chrome.networking); + chrome.test.assertTrue(!!chrome.networking.onc); + + chrome.test.assertFalse(!!chrome.networkingPrivate); + chrome.test.succeed(); + }, + function getProperties() { + chrome.networking.onc.getProperties( + 'stub_wifi1_guid', + chrome.test.callbackPass(function(result) { + chrome.test.assertEq('stub_wifi1_guid', result.GUID); + chrome.test.assertEq( + chrome.networking.onc.ConnectionStateType.CONNECTED, + result.ConnectionState); + chrome.test.assertEq('User', result.Source); + })); + }, + function changeConnectionStateAndWaitForNetworksChanged() { + chrome.test.listenOnce( + chrome.networking.onc.onNetworksChanged, + function(networks) { + chrome.test.assertEq(['stub_wifi1_guid'], networks); + }); + chrome.networking.onc.startDisconnect( + 'stub_wifi1_guid', + chrome.test.callbackPass(function() {})); + }, + function verifyConnectionStateChanged() { + chrome.networking.onc.getProperties( + 'stub_wifi1_guid', + chrome.test.callbackPass(function(result) { + chrome.test.assertEq('stub_wifi1_guid', result.GUID); + chrome.test.assertFalse( + result.ConnectionState == + chrome.networking.onc.ConnectionStateType.CONNECTED); + })); + } +]);
diff --git a/chrome/test/data/extensions/api_test/networking_private/chromeos/main.html b/chrome/test/data/extensions/api_test/networking_private/chromeos/main.html deleted file mode 100644 index 8f8039a..0000000 --- a/chrome/test/data/extensions/api_test/networking_private/chromeos/main.html +++ /dev/null
@@ -1,11 +0,0 @@ -<!-- - * Copyright (c) 2013 The Chromium Authors. All rights reserved. Use of this - * source code is governed by a BSD-style license that can be found in the - * LICENSE file. ---> -<script src="test.js"></script> - -<html> -<head><title>networking private component API test</title></head> -<body><h2>chrome.networkingPrivate.* tests</h2></body> -</html>
diff --git a/chrome/test/data/extensions/api_test/networking_private/chromeos/manifest.json b/chrome/test/data/extensions/api_test/networking_private/chromeos/manifest.json index 3c63ae1..89fa8698 100644 --- a/chrome/test/data/extensions/api_test/networking_private/chromeos/manifest.json +++ b/chrome/test/data/extensions/api_test/networking_private/chromeos/manifest.json
@@ -4,6 +4,11 @@ "version": "0.1", "manifest_version": 2, "description": "Test of chrome.networkingPrivate methods", + "app": { + "background": { + "scripts": ["test.js"] + } + }, "permissions": [ "networkingPrivate" ]
diff --git a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js index f6470e2..51c3de1 100644 --- a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js +++ b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js
@@ -711,8 +711,7 @@ var expectedStates = [ConnectionStateType.CONNECTED]; var listener = new privateHelpers.watchForStateChanges(network, expectedStates, done); - chrome.networkingPrivate.startConnect(network, - networkCallbackPass()); + chrome.networkingPrivate.startConnect(network, networkCallbackPass()); }, function onNetworksChangedEventDisconnect() { var network = 'stub_wifi1_guid'; @@ -720,8 +719,7 @@ var expectedStates = [ConnectionStateType.NOT_CONNECTED]; var listener = new privateHelpers.watchForStateChanges(network, expectedStates, done); - chrome.networkingPrivate.startDisconnect(network, - networkCallbackPass()); + chrome.networkingPrivate.startDisconnect(network, networkCallbackPass()); }, function onNetworkListChangedEvent() { // Connecting to wifi2 should set wifi1 to offline. Connected or Connecting @@ -737,8 +735,7 @@ chrome.networkingPrivate.onNetworkListChanged.addListener( listener.listenForChanges); var network = 'stub_wifi2_guid'; - chrome.networkingPrivate.startConnect(network, - networkCallbackPass()); + chrome.networkingPrivate.startConnect(network, networkCallbackPass()); }, function onDeviceStateListChangedEvent() { var listener = callbackPass(function() { @@ -879,7 +876,15 @@ } ]; -var testToRun = window.location.search.substring(1); -chrome.test.runTests(availableTests.filter(function(op) { - return op.name == testToRun; -})); +chrome.test.getConfig(function(config) { + var args = JSON.parse(config.customArg); + var tests = availableTests.filter(function(op) { + return args.test == op.name; + }); + if (tests.length !== 1) { + chrome.test.notifyFail('Test not found ' + args.test); + return; + } + + chrome.test.runTests(tests); +});
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 63b3be9..c065b5c 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3023,6 +3023,19 @@ ] }, + "DeviceWallpaperImage": { + "os": ["chromeos"], + "test_policy": { + "DeviceWallpaperImage": { + "url": "http://localhost/", + "hash": "examplewallpaperhash" + } + }, + "pref_mappings": [ + { "pref": "cros.device_wallpaper_image" } + ] + }, + "----- Chrome Frame policies -------------------------------------------": {}, "ChromeFrameRendererSettings": {
diff --git a/chrome/test/data/subresource_filter/frame_set.html b/chrome/test/data/subresource_filter/frame_set.html index a7f3ea4..0fa699e 100644 --- a/chrome/test/data/subresource_filter/frame_set.html +++ b/chrome/test/data/subresource_filter/frame_set.html
@@ -1,4 +1,16 @@ <html> + <head> + <script type="text/javascript"> + function insertFrameWithScriptAndNotify() { + var frame = document.createElement("iframe"); + frame.name = "dynamic"; + frame.src = "frame_with_included_script.html"; + frame.onload = () => window.domAutomationController.send(true) + frame.onerror = () => window.domAutomationController.send(false) + document.body.appendChild(frame); + } + </script> + </head> <body> <iframe name="one" src="frame_with_included_script.html"></iframe> <iframe name="two" src="frame_with_included_script.html"></iframe>
diff --git a/chrome/test/data/subresource_filter/frame_with_delayed_script.html b/chrome/test/data/subresource_filter/frame_with_delayed_script.html index d7033a31..1b7d4d38 100644 --- a/chrome/test/data/subresource_filter/frame_with_delayed_script.html +++ b/chrome/test/data/subresource_filter/frame_with_delayed_script.html
@@ -1,15 +1,14 @@ <html> <head> <script type="text/javascript"> - function runny() { - var s = document.createElement("script"); - s.type = "text/javascript" - s.src = "included_script.js"; - // Makes sure that the test would non-flakily fail if the subresource - // is allowed to load. - s.async = false; - document.head.appendChild(s); - } + function insertScriptElementAndReportSuccess() { + var s = document.createElement("script"); + s.type = "text/javascript" + s.src = "included_script.js"; + s.onload = () => { window.domAutomationController.send(true); } + s.onerror = () => { window.domAutomationController.send(false); } + document.head.appendChild(s); + } </script> </head> </html>
diff --git a/chromeos/settings/cros_settings_names.cc b/chromeos/settings/cros_settings_names.cc index 094a6c7..dec80cf6d 100644 --- a/chromeos/settings/cros_settings_names.cc +++ b/chromeos/settings/cros_settings_names.cc
@@ -227,4 +227,8 @@ // A list pref storing the apps to install on the login page. const char kLoginApps[] = "cros.device.login_apps"; +// A string pref storing the url and cryptographic hash of the image in JSON +// format allowed to set a device-level wallpaper before any user logs in. +const char kDeviceWallpaperImage[] = "cros.device_wallpaper_image"; + } // namespace chromeos
diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h index 6ffc24db..c8c2ac3a 100644 --- a/chromeos/settings/cros_settings_names.h +++ b/chromeos/settings/cros_settings_names.h
@@ -112,6 +112,8 @@ CHROMEOS_EXPORT extern const char kLoginApps[]; +CHROMEOS_EXPORT extern const char kDeviceWallpaperImage[]; + } // namespace chromeos #endif // CHROMEOS_SETTINGS_CROS_SETTINGS_NAMES_H_
diff --git a/components/browser_sync/abstract_profile_sync_service_test.cc b/components/browser_sync/abstract_profile_sync_service_test.cc index e486261..df49561 100644 --- a/components/browser_sync/abstract_profile_sync_service_test.cc +++ b/components/browser_sync/abstract_profile_sync_service_test.cc
@@ -31,6 +31,11 @@ namespace { +std::unique_ptr<syncer::HttpPostProviderFactory> GetHttpPostProviderFactory( + syncer::CancelationSignal* signal) { + return base::MakeUnique<TestHttpBridgeFactory>(); +} + class SyncEngineForProfileSyncTest : public SyncBackendHostImpl { public: SyncEngineForProfileSyncTest( @@ -41,6 +46,8 @@ const base::Closure& callback); ~SyncEngineForProfileSyncTest() override; + void Initialize(InitParams params) override; + void RequestConfigureSyncer( syncer::ConfigureReason reason, syncer::ModelTypeSet to_download, @@ -49,9 +56,6 @@ ready_task, const base::Closure& retry_callback) override; - protected: - void InitCore(std::unique_ptr<syncer::DoInitializeOptions> options) override; - private: // Invoked at the start of HandleSyncManagerInitializationOnFrontendLoop. // Allows extra initialization work to be performed before the engine comes @@ -77,27 +81,26 @@ SyncEngineForProfileSyncTest::~SyncEngineForProfileSyncTest() {} -void SyncEngineForProfileSyncTest::InitCore( - std::unique_ptr<syncer::DoInitializeOptions> options) { - options->http_bridge_factory = base::MakeUnique<TestHttpBridgeFactory>(); - options->sync_manager_factory = +void SyncEngineForProfileSyncTest::Initialize(InitParams params) { + params.http_factory_getter = base::Bind(&GetHttpPostProviderFactory); + params.sync_manager_factory = base::MakeUnique<syncer::SyncManagerFactoryForProfileSyncTest>(callback_); - options->credentials.email = "testuser@gmail.com"; - options->credentials.sync_token = "token"; - options->credentials.scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope); - options->restored_key_for_bootstrapping.clear(); + params.credentials.email = "testuser@gmail.com"; + params.credentials.sync_token = "token"; + params.credentials.scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope); + params.restored_key_for_bootstrapping.clear(); // It'd be nice if we avoided creating the EngineComponentsFactory in the // first place, but SyncEngine will have created one by now so we must free // it. Grab the switches to pass on first. syncer::EngineComponentsFactory::Switches factory_switches = - options->engine_components_factory->GetSwitches(); - options->engine_components_factory = + params.engine_components_factory->GetSwitches(); + params.engine_components_factory = base::MakeUnique<syncer::TestEngineComponentsFactory>( factory_switches, syncer::EngineComponentsFactory::STORAGE_IN_MEMORY, nullptr); - SyncBackendHostImpl::InitCore(std::move(options)); + SyncBackendHostImpl::Initialize(std::move(params)); } void SyncEngineForProfileSyncTest::RequestConfigureSyncer(
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc index 5103619..0f6339d2 100644 --- a/components/browser_sync/profile_sync_service.cc +++ b/components/browser_sync/profile_sync_service.cc
@@ -20,7 +20,6 @@ #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/metrics/histogram.h" -#include "base/path_service.h" #include "base/profiler/scoped_tracker.h" #include "base/single_thread_task_runner.h" #include "base/strings/stringprintf.h" @@ -169,16 +168,9 @@ false, }; -const base::FilePath::CharType kSyncDataFolderName[] = - FILE_PATH_LITERAL("Sync Data"); const base::FilePath::CharType kLevelDBFolderName[] = FILE_PATH_LITERAL("LevelDB"); -#if defined(OS_WIN) -const base::FilePath::CharType kLoopbackServerBackendFilename[] = - FILE_PATH_LITERAL("profile.pb"); -#endif - // Perform the actual sync data folder deletion. // This should only be called on the sync thread. void DeleteSyncDataFolder(const base::FilePath& directory_path) { @@ -191,42 +183,29 @@ } // namespace ProfileSyncService::InitParams::InitParams() = default; +ProfileSyncService::InitParams::InitParams(InitParams&& other) = default; ProfileSyncService::InitParams::~InitParams() = default; -ProfileSyncService::InitParams::InitParams(InitParams&& other) // NOLINT - : sync_client(std::move(other.sync_client)), - signin_wrapper(std::move(other.signin_wrapper)), - oauth2_token_service(other.oauth2_token_service), - gaia_cookie_manager_service(other.gaia_cookie_manager_service), - start_behavior(other.start_behavior), - network_time_update_callback( - std::move(other.network_time_update_callback)), - base_directory(std::move(other.base_directory)), - url_request_context(std::move(other.url_request_context)), - debug_identifier(std::move(other.debug_identifier)), - channel(other.channel), - blocking_pool(other.blocking_pool) {} ProfileSyncService::ProfileSyncService(InitParams init_params) - : OAuth2TokenService::Consumer("sync"), + : SyncServiceBase(std::move(init_params.sync_client), + std::move(init_params.signin_wrapper), + init_params.channel, + init_params.base_directory, + init_params.debug_identifier), + OAuth2TokenService::Consumer("sync"), last_auth_error_(AuthError::AuthErrorNone()), passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED), - sync_client_(std::move(init_params.sync_client)), - sync_prefs_(sync_client_->GetPrefService()), sync_service_url_( syncer::GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(), init_params.channel)), network_time_update_callback_( std::move(init_params.network_time_update_callback)), - base_directory_(init_params.base_directory), url_request_context_(init_params.url_request_context), - debug_identifier_(std::move(init_params.debug_identifier)), - channel_(init_params.channel), blocking_pool_(init_params.blocking_pool), is_first_time_sync_configure_(false), engine_initialized_(false), sync_disabled_by_admin_(false), is_auth_in_progress_(false), - signin_(std::move(init_params.signin_wrapper)), unrecoverable_error_reason_(ERROR_REASON_UNSET), expect_sync_configuration_aborted_(false), encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()), @@ -241,8 +220,6 @@ gaia_cookie_manager_service_(init_params.gaia_cookie_manager_service), network_resources_(new syncer::HttpBridgeNetworkResources), start_behavior_(init_params.start_behavior), - directory_path_( - base_directory_.Append(base::FilePath(kSyncDataFolderName))), catch_up_configure_in_progress_(false), passphrase_prompt_triggered_by_version_(false), sync_enabled_weak_factory_(this), @@ -519,66 +496,26 @@ return credentials; } -bool ProfileSyncService::ShouldDeleteSyncFolder() { - return !IsFirstSetupComplete(); +syncer::WeakHandle<syncer::JsEventHandler> +ProfileSyncService::GetJsEventHandler() { + return syncer::MakeWeakHandle(sync_js_controller_.AsWeakPtr()); } -void ProfileSyncService::InitializeEngine(bool delete_stale_data) { - if (!engine_) { - NOTREACHED(); - return; - } +syncer::SyncEngine::HttpPostProviderFactoryGetter +ProfileSyncService::MakeHttpPostProviderFactoryGetter() { + return base::Bind(&syncer::NetworkResources::GetHttpPostProviderFactory, + base::Unretained(network_resources_.get()), + url_request_context_, network_time_update_callback_); +} - if (!sync_thread_) { - sync_thread_ = base::MakeUnique<base::Thread>("Chrome_SyncThread"); - base::Thread::Options options; - options.timer_slack = base::TIMER_SLACK_MAXIMUM; - CHECK(sync_thread_->StartWithOptions(options)); - } +std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState> +ProfileSyncService::MoveSavedNigoriState() { + return std::move(saved_nigori_state_); +} - SyncCredentials credentials = GetCredentials(); - - if (delete_stale_data) - ClearStaleErrors(); - - bool enable_local_sync_backend = false; - base::FilePath local_sync_backend_folder = - sync_prefs_.GetLocalSyncBackendDir(); -#if defined(OS_WIN) - enable_local_sync_backend = sync_prefs_.IsLocalSyncEnabled(); - if (local_sync_backend_folder.empty()) { - // TODO(pastarmovj): Add DIR_ROAMING_USER_DATA to PathService to simplify - // this code and move the logic in its right place. See crbug/657810. - CHECK( - base::PathService::Get(base::DIR_APP_DATA, &local_sync_backend_folder)); - local_sync_backend_folder = - local_sync_backend_folder.Append(FILE_PATH_LITERAL("Chrome/User Data")); - } - // This code as it is now will assume the same profile order is present on all - // machines, which is not a given. It is to be defined if only the Default - // profile should get this treatment or all profile as is the case now. The - // solution for now will be to assume profiles are created in the same order - // on all machines and in the future decide if only the Default one should be - // considered roamed. - local_sync_backend_folder = - local_sync_backend_folder.Append(base_directory_.BaseName()); - local_sync_backend_folder = - local_sync_backend_folder.Append(kLoopbackServerBackendFilename); -#endif // defined(OS_WIN) - - SyncEngine::HttpPostProviderFactoryGetter http_post_provider_factory_getter = - base::Bind(&syncer::NetworkResources::GetHttpPostProviderFactory, - base::Unretained(network_resources_.get()), - url_request_context_, network_time_update_callback_); - - engine_->Initialize( - this, sync_thread_->task_runner(), GetJsEventHandler(), sync_service_url_, - local_device_->GetSyncUserAgent(), credentials, delete_stale_data, - enable_local_sync_backend, local_sync_backend_folder, - base::MakeUnique<syncer::SyncManagerFactory>(), - MakeWeakHandle(sync_enabled_weak_factory_.GetWeakPtr()), - base::Bind(syncer::ReportUnrecoverableError, channel_), - http_post_provider_factory_getter, std::move(saved_nigori_state_)); +syncer::WeakHandle<syncer::UnrecoverableErrorHandler> +ProfileSyncService::GetUnrecoverableErrorHandler() { + return syncer::MakeWeakHandle(sync_enabled_weak_factory_.GetWeakPtr()); } bool ProfileSyncService::IsEncryptedDatatypeEnabled() const { @@ -659,9 +596,11 @@ debug_identifier_, invalidator, sync_prefs_.AsWeakPtr(), directory_path_)); - // Initialize the engine. Every time we start up a new SyncEngine, we'll want - // to start from a fresh SyncDB, so delete any old one that might be there. - InitializeEngine(ShouldDeleteSyncFolder()); + // Clear any old errors the first time sync starts. + if (!IsFirstSetupComplete()) + ClearStaleErrors(); + + InitializeEngine(); UpdateFirstSyncTimePref(); @@ -2527,10 +2466,6 @@ return access_token_; } -WeakHandle<syncer::JsEventHandler> ProfileSyncService::GetJsEventHandler() { - return MakeWeakHandle(sync_js_controller_.AsWeakPtr()); -} - syncer::SyncableService* ProfileSyncService::GetSessionsSyncableService() { DCHECK(thread_checker_.CalledOnValidThread()); return sessions_sync_manager_.get();
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h index 3fb2c5b..cf5a8c5 100644 --- a/components/browser_sync/profile_sync_service.h +++ b/components/browser_sync/profile_sync_service.h
@@ -39,7 +39,7 @@ #include "components/sync/driver/data_type_status_table.h" #include "components/sync/driver/startup_controller.h" #include "components/sync/driver/sync_client.h" -#include "components/sync/driver/sync_service.h" +#include "components/sync/driver/sync_service_base.h" #include "components/sync/driver/sync_stopped_reporter.h" #include "components/sync/engine/events/protocol_event_observer.h" #include "components/sync/engine/model_safe_worker.h" @@ -170,8 +170,7 @@ // Once first setup has completed and there are no outstanding // setup-in-progress handles, CanConfigureDataTypes() will return true and // datatype configuration can begin. -class ProfileSyncService : public syncer::SyncService, - public syncer::SyncEngineHost, +class ProfileSyncService : public syncer::SyncServiceBase, public syncer::SyncPrefObserver, public syncer::DataTypeManagerObserver, public syncer::UnrecoverableErrorHandler, @@ -232,8 +231,8 @@ // explicitly defined. struct InitParams { InitParams(); + InitParams(InitParams&& other); ~InitParams(); - InitParams(InitParams&& other); // NOLINT std::unique_ptr<syncer::SyncClient> sync_client; std::unique_ptr<SigninManagerWrapper> signin_wrapper; @@ -588,6 +587,17 @@ // Triggers sync cycle with request to update specified |types|. void RefreshTypesForTest(syncer::ModelTypeSet types); + protected: + // SyncServiceBase implementation. + syncer::SyncCredentials GetCredentials() override; + syncer::WeakHandle<syncer::JsEventHandler> GetJsEventHandler() override; + syncer::SyncEngine::HttpPostProviderFactoryGetter + MakeHttpPostProviderFactoryGetter() override; + std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState> + MoveSavedNigoriState() override; + syncer::WeakHandle<syncer::UnrecoverableErrorHandler> + GetUnrecoverableErrorHandler() override; + private: enum UnrecoverableErrorReason { ERROR_REASON_UNSET, @@ -632,11 +642,6 @@ // to claim ownership of sync thread from engine. void ShutdownImpl(syncer::ShutdownReason reason); - // Return SyncCredentials from the OAuth2TokenService. - syncer::SyncCredentials GetCredentials(); - - virtual syncer::WeakHandle<syncer::JsEventHandler> GetJsEventHandler(); - // Helper method for managing encryption UI. bool IsEncryptedDatatypeEnabled() const; @@ -671,13 +676,6 @@ // token. void RequestAccessToken(); - // Return true if engine should start from a fresh sync DB. - bool ShouldDeleteSyncFolder(); - - // If |delete_sync_data_folder| is true, then this method will delete all - // previous "Sync Data" folders. (useful if the folder is partial/corrupt). - void InitializeEngine(bool delete_sync_data_folder); - // Sets the last synced time to the current time. void UpdateLastSyncedTime(); @@ -770,23 +768,11 @@ // user. GoogleServiceAuthError last_auth_error_; - // Our asynchronous engine to communicate with sync components living on - // other threads. - std::unique_ptr<syncer::SyncEngine> engine_; - // Was the last SYNC_PASSPHRASE_REQUIRED notification sent because it // was required for encryption, decryption with a cached passphrase, or // because a new passphrase is required? syncer::PassphraseRequiredReason passphrase_required_reason_; - // This profile's SyncClient, which abstracts away non-Sync dependencies and - // the Sync API component factory. - std::unique_ptr<syncer::SyncClient> sync_client_; - - // The class that handles getting, setting, and persisting sync - // preferences. - syncer::SyncPrefs sync_prefs_; - // TODO(ncarter): Put this in a profile, once there is UI for it. // This specifies where to find the sync server. const GURL sync_service_url_; @@ -799,19 +785,9 @@ // Callback to update the network time; used for initializing the engine. syncer::NetworkTimeUpdateCallback network_time_update_callback_; - // The path to the base directory under which sync should store its - // information. - base::FilePath base_directory_; - // The request context in which sync should operate. scoped_refptr<net::URLRequestContextGetter> url_request_context_; - // An identifier representing this instance for debugging purposes. - std::string debug_identifier_; - - // The product channel of the embedder. - version_info::Channel channel_; - // Threading context. base::SequencedWorkerPool* blocking_pool_; @@ -838,10 +814,6 @@ // engine to refresh its credentials. bool is_auth_in_progress_; - // Encapsulates user signin - used to set/get the user's authenticated - // email address. - const std::unique_ptr<SigninManagerWrapper> signin_; - // Information describing an unrecoverable error. UnrecoverableErrorReason unrecoverable_error_reason_; std::string unrecoverable_error_message_; @@ -906,12 +878,6 @@ // and association information. syncer::WeakHandle<syncer::DataTypeDebugInfoListener> debug_info_listener_; - // The thread where all the sync operations happen. This thread is kept alive - // until browser shutdown and reused if sync is turned off and on again. It is - // joined during the shutdown process, but there is an abort mechanism in - // place to prevent slow HTTP requests from blocking browser shutdown. - std::unique_ptr<base::Thread> sync_thread_; - // ProfileSyncService uses this service to get access tokens. ProfileOAuth2TokenService* const oauth2_token_service_; @@ -952,9 +918,6 @@ StartBehavior start_behavior_; std::unique_ptr<syncer::StartupController> startup_controller_; - // The full path to the sync data directory. - base::FilePath directory_path_; - std::unique_ptr<syncer::SyncStoppedReporter> sync_stopped_reporter_; // Listens for the system being under memory pressure.
diff --git a/components/browser_sync/profile_sync_service_unittest.cc b/components/browser_sync/profile_sync_service_unittest.cc index a074ec3b..abe8f86 100644 --- a/components/browser_sync/profile_sync_service_unittest.cc +++ b/components/browser_sync/profile_sync_service_unittest.cc
@@ -103,23 +103,7 @@ // to initialized. Allows us to test things that could happen while backend init // is in progress. class SyncEngineNoReturn : public FakeSyncEngine { - void Initialize( - syncer::SyncEngineHost* host, - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner, - const syncer::WeakHandle<syncer::JsEventHandler>& event_handler, - const GURL& service_url, - const std::string& sync_user_agent, - const syncer::SyncCredentials& credentials, - bool delete_sync_data_folder, - bool enable_local_sync_backend, - const base::FilePath& local_sync_backend_folder, - std::unique_ptr<syncer::SyncManagerFactory> sync_manager_factory, - const syncer::WeakHandle<syncer::UnrecoverableErrorHandler>& - unrecoverable_error_handler, - const base::Closure& report_unrecoverable_error_function, - const HttpPostProviderFactoryGetter& http_post_provider_factory_getter, - std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState> - saved_nigori_state) override {} + void Initialize(InitParams params) override {} }; class FakeSyncEngineCollectDeleteDirParam : public FakeSyncEngine { @@ -128,31 +112,9 @@ std::vector<bool>* delete_dir_param) : delete_dir_param_(delete_dir_param) {} - void Initialize( - syncer::SyncEngineHost* host, - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner, - const syncer::WeakHandle<syncer::JsEventHandler>& event_handler, - const GURL& service_url, - const std::string& sync_user_agent, - const syncer::SyncCredentials& credentials, - bool delete_sync_data_folder, - bool enable_local_sync_backend, - const base::FilePath& local_sync_backend_folder, - std::unique_ptr<syncer::SyncManagerFactory> sync_manager_factory, - const syncer::WeakHandle<syncer::UnrecoverableErrorHandler>& - unrecoverable_error_handler, - const base::Closure& report_unrecoverable_error_function, - const HttpPostProviderFactoryGetter& http_post_provider_factory_getter, - std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState> - saved_nigori_state) override { - delete_dir_param_->push_back(delete_sync_data_folder); - FakeSyncEngine::Initialize( - host, std::move(sync_task_runner), event_handler, service_url, - sync_user_agent, credentials, delete_sync_data_folder, - enable_local_sync_backend, local_sync_backend_folder, - std::move(sync_manager_factory), unrecoverable_error_handler, - report_unrecoverable_error_function, http_post_provider_factory_getter, - std::move(saved_nigori_state)); + void Initialize(InitParams params) override { + delete_dir_param_->push_back(params.delete_sync_data_folder); + FakeSyncEngine::Initialize(std::move(params)); } private:
diff --git a/components/cryptauth/remote_device.cc b/components/cryptauth/remote_device.cc index f30aee1..da0a0583 100644 --- a/components/cryptauth/remote_device.cc +++ b/components/cryptauth/remote_device.cc
@@ -4,6 +4,8 @@ #include "components/cryptauth/remote_device.h" +#include "base/base64.h" + namespace cryptauth { RemoteDevice::RemoteDevice() : bluetooth_type(BLUETOOTH_CLASSIC) {} @@ -27,4 +29,19 @@ RemoteDevice::~RemoteDevice() {} +std::string RemoteDevice::GetDeviceId() { + std::string to_return; + base::Base64Encode(public_key, &to_return); + return to_return; +} + +std::string RemoteDevice::GetTruncatedDeviceIdForLogs() { + std::string id = GetDeviceId(); + if (id.length() <= 10) { + return id; + } + + return id.substr(0, 5) + "..." + id.substr(id.length() - 5, id.length()); +} + } // namespace cryptauth
diff --git a/components/cryptauth/remote_device.h b/components/cryptauth/remote_device.h index a484a2a..369bc7f 100644 --- a/components/cryptauth/remote_device.h +++ b/components/cryptauth/remote_device.h
@@ -32,6 +32,14 @@ std::string sign_in_challenge); RemoteDevice(const RemoteDevice& other); ~RemoteDevice(); + + // Returns a unique ID for the device. + std::string GetDeviceId(); + + // Returns a shortened device ID for the purpose of concise logging (device + // IDs are often so long that logs are difficult to read). Note that this + // ID is not guaranteed to be unique, so it should only be used for log. + std::string GetTruncatedDeviceIdForLogs(); }; typedef std::vector<RemoteDevice> RemoteDeviceList;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc index f3374d5..54f7cd7 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -372,6 +372,11 @@ weak_factory_.GetWeakPtr())); } + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kClearDataReductionProxyDataSavings)) { + ClearDataSavingStatistics(); + } + if (delay_.is_zero()) return; @@ -420,11 +425,6 @@ InitListPref(prefs::kDailyHttpReceivedContentLength); InitListPref(prefs::kDailyOriginalContentLengthViaDataReductionProxy); InitListPref(prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabled); - - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kClearDataReductionProxyDataSavings)) { - ClearDataSavingStatistics(); - } } void DataReductionProxyCompressionStats::UpdateDataSavings( @@ -683,29 +683,28 @@ void DataReductionProxyCompressionStats::ClearDataSavingStatistics() { DeleteHistoricalDataUsage(); - list_pref_map_.get( - prefs::kDailyContentLengthHttpsWithDataReductionProxyEnabled)->Clear(); - list_pref_map_ - .get(prefs::kDailyContentLengthLongBypassWithDataReductionProxyEnabled) - ->Clear(); - list_pref_map_ - .get(prefs::kDailyContentLengthShortBypassWithDataReductionProxyEnabled) - ->Clear(); - list_pref_map_ - .get(prefs::kDailyContentLengthUnknownWithDataReductionProxyEnabled) - ->Clear(); - list_pref_map_.get(prefs::kDailyContentLengthViaDataReductionProxy)->Clear(); - list_pref_map_.get(prefs::kDailyContentLengthWithDataReductionProxyEnabled) - ->Clear(); - list_pref_map_.get(prefs::kDailyHttpOriginalContentLength)->Clear(); - list_pref_map_.get(prefs::kDailyHttpReceivedContentLength)->Clear(); - list_pref_map_.get(prefs::kDailyOriginalContentLengthViaDataReductionProxy) - ->Clear(); - list_pref_map_ - .get(prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabled) - ->Clear(); + pref_service_->ClearPref( + prefs::kDailyContentLengthHttpsWithDataReductionProxyEnabled); + pref_service_->ClearPref( + prefs::kDailyContentLengthLongBypassWithDataReductionProxyEnabled); + pref_service_->ClearPref( + prefs::kDailyContentLengthShortBypassWithDataReductionProxyEnabled); + pref_service_->ClearPref( + prefs::kDailyContentLengthUnknownWithDataReductionProxyEnabled); + pref_service_->ClearPref(prefs::kDailyContentLengthViaDataReductionProxy); + pref_service_->ClearPref( + prefs::kDailyContentLengthWithDataReductionProxyEnabled); + pref_service_->ClearPref(prefs::kDailyHttpOriginalContentLength); + pref_service_->ClearPref(prefs::kDailyHttpReceivedContentLength); + pref_service_->ClearPref( + prefs::kDailyOriginalContentLengthViaDataReductionProxy); + pref_service_->ClearPref( + prefs::kDailyOriginalContentLengthWithDataReductionProxyEnabled); - WritePrefs(); + for (DataReductionProxyListPrefMap::iterator iter = list_pref_map_.begin(); + iter != list_pref_map_.end(); ++iter) { + iter->second->Clear(); + } } void DataReductionProxyCompressionStats::DelayedWritePrefs() {
diff --git a/components/data_use_measurement/core/data_use_measurement_unittest.cc b/components/data_use_measurement/core/data_use_measurement_unittest.cc index 31a2784..6f0f66d 100644 --- a/components/data_use_measurement/core/data_use_measurement_unittest.cc +++ b/components/data_use_measurement/core/data_use_measurement_unittest.cc
@@ -70,7 +70,9 @@ } // Creates a test request. - std::unique_ptr<net::URLRequest> CreateTestRequest(bool is_user_request) { + enum RequestKind { kServiceRequest, kUserRequest }; + std::unique_ptr<net::URLRequest> CreateTestRequest( + RequestKind is_user_request) { net::TestDelegate test_delegate; InitializeContext(); net::MockRead reads[] = {net::MockRead("HTTP/1.1 200 OK\r\n" @@ -82,7 +84,7 @@ std::unique_ptr<net::URLRequest> request(context_->CreateRequest( GURL("http://foo.com"), net::DEFAULT_PRIORITY, &test_delegate)); - if (is_user_request) { + if (is_user_request == kUserRequest) { UserRequestUserDataForTesting::MarkAsUserRequest(request.get()); } else { request->SetUserData( @@ -99,7 +101,7 @@ // Sends a request and reports data use attaching either user data or service // data based on |is_user_request|. - void SendRequest(bool is_user_request) { + void SendRequest(RequestKind is_user_request) { std::unique_ptr<net::URLRequest> request = CreateTestRequest(is_user_request); data_use_measurement_.OnBeforeURLRequest(request.get()); @@ -112,7 +114,7 @@ // reflected in proper histograms. void TestForAUserRequest(const std::string& target_dimension) { base::HistogramTester histogram_tester; - SendRequest(true); + SendRequest(kUserRequest); histogram_tester.ExpectTotalCount("DataUse.TrafficSize.User.Downstream." + target_dimension + kConnectionType, 1); @@ -133,7 +135,7 @@ // reflected in proper histograms. void TestForAServiceRequest(const std::string& target_dimension) { base::HistogramTester histogram_tester; - SendRequest(false); + SendRequest(kServiceRequest); histogram_tester.ExpectTotalCount("DataUse.TrafficSize.System.Downstream." + target_dimension + kConnectionType, 1); @@ -200,14 +202,14 @@ TEST_F(DataUseMeasurementTest, DataUseForwarderIsCalled) { EXPECT_FALSE(IsDataUseForwarderCalled()); - SendRequest(true); + SendRequest(kUserRequest); EXPECT_TRUE(IsDataUseForwarderCalled()); } #if defined(OS_ANDROID) TEST_F(DataUseMeasurementTest, AppStateUnknown) { base::HistogramTester histogram_tester; - std::unique_ptr<net::URLRequest> request = CreateTestRequest(true); + std::unique_ptr<net::URLRequest> request = CreateTestRequest(kUserRequest); data_use_measurement_.OnBeforeURLRequest(request.get()); { @@ -243,7 +245,7 @@ TEST_F(DataUseMeasurementTest, TimeOfBackgroundDownstreamBytes) { { - std::unique_ptr<net::URLRequest> request = CreateTestRequest(true); + std::unique_ptr<net::URLRequest> request = CreateTestRequest(kUserRequest); data_use_measurement_.OnBeforeURLRequest(request.get()); base::HistogramTester histogram_tester; data_use_measurement()->OnApplicationStateChange( @@ -261,7 +263,7 @@ { // Create new request when app is in foreground.. base::HistogramTester histogram_tester; - std::unique_ptr<net::URLRequest> request = CreateTestRequest(true); + std::unique_ptr<net::URLRequest> request = CreateTestRequest(kUserRequest); data_use_measurement_.OnBeforeURLRequest(request.get()); data_use_measurement_.OnNetworkBytesSent(*request, 100); data_use_measurement_.OnNetworkBytesReceived(*request, 1000); @@ -274,7 +276,7 @@ } { - std::unique_ptr<net::URLRequest> request = CreateTestRequest(true); + std::unique_ptr<net::URLRequest> request = CreateTestRequest(kUserRequest); data_use_measurement_.OnBeforeURLRequest(request.get()); base::HistogramTester histogram_tester; data_use_measurement()->OnApplicationStateChange( @@ -292,7 +294,7 @@ { // Create new request when app is in background. base::HistogramTester histogram_tester; - std::unique_ptr<net::URLRequest> request = CreateTestRequest(true); + std::unique_ptr<net::URLRequest> request = CreateTestRequest(kUserRequest); data_use_measurement_.OnBeforeURLRequest(request.get()); data_use_measurement_.OnNetworkBytesSent(*request, 100); data_use_measurement_.OnNetworkBytesReceived(*request, 1000); @@ -307,7 +309,8 @@ { // Create new request when app is in background. base::HistogramTester histogram_tester; - std::unique_ptr<net::URLRequest> request = CreateTestRequest(false); + std::unique_ptr<net::URLRequest> request = + CreateTestRequest(kServiceRequest); data_use_measurement_.OnBeforeURLRequest(request.get()); data_use_measurement_.OnNetworkBytesSent(*request, 100); data_use_measurement_.OnNetworkBytesReceived(*request, 1000); @@ -324,7 +327,7 @@ } { - std::unique_ptr<net::URLRequest> request = CreateTestRequest(true); + std::unique_ptr<net::URLRequest> request = CreateTestRequest(kUserRequest); data_use_measurement_.OnBeforeURLRequest(request.get()); base::HistogramTester histogram_tester; data_use_measurement()->OnApplicationStateChange(
diff --git a/components/network_time/network_time_tracker.cc b/components/network_time/network_time_tracker.cc index 89d2ad7..f101774 100644 --- a/components/network_time/network_time_tracker.cc +++ b/components/network_time/network_time_tracker.cc
@@ -534,8 +534,19 @@ base::TimeDelta resolution = base::TimeDelta::FromMilliseconds(1) + base::TimeDelta::FromSeconds(kTimeServerMaxSkewSeconds); + + // Record histograms for the latency of the time query and the time delta + // between time fetches. base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_; UMA_HISTOGRAM_TIMES("NetworkTimeTracker.TimeQueryLatency", latency); + if (!last_fetched_time_.is_null()) { + UMA_HISTOGRAM_CUSTOM_TIMES("NetworkTimeTracker.TimeBetweenFetches", + current_time - last_fetched_time_, + base::TimeDelta::FromHours(1), + base::TimeDelta::FromDays(7), 50); + } + last_fetched_time_ = current_time; + UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks()); return true; }
diff --git a/components/network_time/network_time_tracker.h b/components/network_time/network_time_tracker.h index ea5bbc5..9233647 100644 --- a/components/network_time/network_time_tracker.h +++ b/components/network_time/network_time_tracker.h
@@ -217,6 +217,12 @@ // this NetworkTimeTracker's lifetime. bool time_query_completed_; + // The time that was received from the last network time fetch made by + // CheckTime(). Unlike |network_time_at_least_measurement_|, this time + // is not updated when UpdateNetworkTime() is called. Used for UMA + // metrics. + base::Time last_fetched_time_; + // Callbacks to run when the in-progress time fetch completes. std::vector<base::Closure> fetch_completion_callbacks_;
diff --git a/components/network_time/network_time_tracker_unittest.cc b/components/network_time/network_time_tracker_unittest.cc index 391d87a..747a38a 100644 --- a/components/network_time/network_time_tracker_unittest.cc +++ b/components/network_time/network_time_tracker_unittest.cc
@@ -38,6 +38,8 @@ "NetworkTimeTracker.ClockDivergence.Negative"; const char kWallClockBackwardsHistogram[] = "NetworkTimeTracker.WallClockRanBackwards"; +const char kTimeBetweenFetchesHistogram[] = + "NetworkTimeTracker.TimeBetweenFetches"; } // namespace class NetworkTimeTrackerTest : public ::testing::Test { @@ -813,4 +815,133 @@ tracker_->WaitForFetchForTesting(123123123); } +namespace { + +// NetworkTimeTrackerTest.TimeBetweenFetchesHistogram needs to make several time +// queries that return different times. MultipleGoodTimeResponseHandler is like +// GoodTimeResponseHandler, but returning different times on each of three +// requests that happen in sequence. +// +// See comments inline for how to update the times that are returned. +class MultipleGoodTimeResponseHandler { + public: + MultipleGoodTimeResponseHandler() {} + ~MultipleGoodTimeResponseHandler() {} + + std::unique_ptr<net::test_server::HttpResponse> ResponseHandler( + const net::test_server::HttpRequest& request); + + // Returns the time that is returned in the (i-1)'th response handled by + // ResponseHandler(), or null base::Time() if too many responses have been + // handled. + base::Time GetTimeAtIndex(unsigned int i); + + private: + // |kJsTimes|, |kTimeResponseBodies|, and |kTimeProofHeaders| contain signed + // responses for three subsequent time queries served by + // MultipleGoodTimeResponseHandler. (That is, kJsTimes[i] is the timestamp + // contained in kTimeResponseBodies[i] with signature in kTimeProofHeader[i].) + // NetworkTimeTrackerTest.TimeBetweenFetchesHistogram expects that each + // timestamp is greater than the one before it. + // + // Update as follows: + // + // curl -v http://clients2.google.com/time/1/current?cup2key=1:123123123 + // + // where 1 is the key version and 123123123 is the nonce. Copy the + // response and the x-cup-server-proof header into + // |kTimeResponseBodies| and |kTimeProofHeaders| respectively, and the + // 'current_time_millis' value of the response into |kJsTimes|. + static const double kJsTimes[]; + static const char* kTimeResponseBodies[]; + static const char* kTimeProofHeaders[]; + + // The index into |kJsTimes|, |kTimeResponseBodies|, and + // |kTimeProofHeaders| that will be used in the response in the next + // ResponseHandler() call. + unsigned int next_time_index_ = 0; + + DISALLOW_COPY_AND_ASSIGN(MultipleGoodTimeResponseHandler); +}; + +const double MultipleGoodTimeResponseHandler::kJsTimes[] = {1481653709754, + 1481653820879}; +const char* MultipleGoodTimeResponseHandler::kTimeResponseBodies[] = { + ")]}'\n" + "{\"current_time_millis\":1481653709754,\"server_nonce\":-2." + "7144232419525693E172}", + ")]}'\n" + "{\"current_time_millis\":1481653820879,\"server_nonce\":1." + "8874633267958474E185}"}; +const char* MultipleGoodTimeResponseHandler::kTimeProofHeaders[] = { + "3045022006fdfa882460cd43e15b11d7d35cfc3805b0662c558f6efe54f9bf0c38e80650" + "0221009777817152b6cc1c2b2ea765104a1ab6b87a4da1e87686ae0641c25b23161ea8:" + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "3045022100b6ebcf0f2f5c42bb18bd097a60c4204dd2ed29cad4992b5fdfcf1b32bdfdc6" + "58022005b378c27dd3ddb6edacce39edc8b4ecf189dff5b64ce99975859f6cdc984e20:" + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}; + +std::unique_ptr<net::test_server::HttpResponse> +MultipleGoodTimeResponseHandler::ResponseHandler( + const net::test_server::HttpRequest& request) { + net::test_server::BasicHttpResponse* response = + new net::test_server::BasicHttpResponse(); + + if (next_time_index_ >= + arraysize(MultipleGoodTimeResponseHandler::kJsTimes)) { + response->set_code(net::HTTP_BAD_REQUEST); + return std::unique_ptr<net::test_server::HttpResponse>(response); + } + + response->set_code(net::HTTP_OK); + response->set_content(kTimeResponseBodies[next_time_index_]); + response->AddCustomHeader("x-cup-server-proof", + kTimeProofHeaders[next_time_index_]); + next_time_index_++; + return std::unique_ptr<net::test_server::HttpResponse>(response); +} + +base::Time MultipleGoodTimeResponseHandler::GetTimeAtIndex(unsigned int i) { + if (i >= arraysize(kJsTimes)) + return base::Time(); + return base::Time::FromJsTime(kJsTimes[i]); +} + +} // namespace + +TEST_F(NetworkTimeTrackerTest, TimeBetweenFetchesHistogram) { + MultipleGoodTimeResponseHandler response_handler; + base::HistogramTester histograms; + histograms.ExpectTotalCount(kTimeBetweenFetchesHistogram, 0); + + test_server_->RegisterRequestHandler( + base::Bind(&MultipleGoodTimeResponseHandler::ResponseHandler, + base::Unretained(&response_handler))); + EXPECT_TRUE(test_server_->Start()); + tracker_->SetTimeServerURLForTesting(test_server_->GetURL("/")); + EXPECT_TRUE(tracker_->QueryTimeServiceForTesting()); + tracker_->WaitForFetchForTesting(123123123); + + base::Time out_network_time; + EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE, + tracker_->GetNetworkTime(&out_network_time, nullptr)); + // After the first query, there should be no histogram value because + // there was no delta to record. + histograms.ExpectTotalCount(kTimeBetweenFetchesHistogram, 0); + + // Trigger a second query, which should cause the delta from the first + // query to be recorded. + clock_->Advance(base::TimeDelta::FromHours(1)); + EXPECT_TRUE(tracker_->QueryTimeServiceForTesting()); + tracker_->WaitForFetchForTesting(123123123); + EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE, + tracker_->GetNetworkTime(&out_network_time, nullptr)); + histograms.ExpectTotalCount(kTimeBetweenFetchesHistogram, 1); + histograms.ExpectBucketCount( + kTimeBetweenFetchesHistogram, + (response_handler.GetTimeAtIndex(1) - response_handler.GetTimeAtIndex(0)) + .InMilliseconds(), + 1); +} + } // namespace network_time
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 5a60181..b6f31f85 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -139,7 +139,7 @@ # persistent IDs for all fields (but not for groups!) are needed. These are # specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs, # because doing so would break the deployed wire format! -# For your editing convenience: highest ID currently used: 356 +# For your editing convenience: highest ID currently used: 357 # # Placeholders: # The following placeholder strings are automatically substituted: @@ -9339,6 +9339,38 @@ }, ], }, + { + 'name': 'DeviceWallpaperImage', + 'type': 'external', + 'schema': { + 'type': 'object', + 'properties': { + 'url': { "type": "string" }, + 'hash': { "type": "string" } + }, + }, + 'supported_on': ['chrome_os:57-'], + 'device_only': True, + 'features': { + 'dynamic_refresh': True, + }, + 'example_value': { "url": "https://example.com/device_wallpaper.jpg", "hash": "examplewallpaperexamplewallpaperexamplewallpaperexamplewallpaper" }, + 'max_size': 16777216, + 'id': 357, + 'caption': '''Device wallpaper image''', + 'tags': [], + 'desc': '''Configure device-level wallpaper image that is shown on the login screen if no user has yet signed in to the device. The policy is set by specifying the URL from which the Chrome OS device can download the wallpaper image and a cryptographic hash used to verify the integrity of the download. The image must be in JPEG format, its file size must not exceed 16MB. The URL must be accessible without any authentication. The wallpaper image is downloaded and cached. It will be re-downloaded whenever the URL or the hash changes. + + The policy should be speicified as a string that expresses the URL and hash in JSON format, e.g., + { + "url": "https://example.com/device_wallpaper.jpg", + "hash": "examplewallpaperhash" + } + + If the device wallpaper policy is set, the Chrome OS device will download and use the wallpaper image on the login screen if no user has yet signed in to the device. Once the user logs in, the user's wallpaper policy kicks in. + + If the device wallpaper policy is left not set, it's the user's wallpaper policy to decide what to show if the user's wallpaper policy is set.''', + }, ], 'messages': { # Messages that are not associated to any policies.
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc index b04c52a..5b1ac373 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -159,7 +159,7 @@ void ContentSubresourceFilterDriverFactory::DidStartNavigation( content::NavigationHandle* navigation_handle) { - if (navigation_handle->IsInMainFrame()) { + if (navigation_handle->IsInMainFrame() && !navigation_handle->IsSamePage()) { navigation_chain_.clear(); activation_list_matches_.clear(); navigation_chain_.push_back(navigation_handle->GetURL()); @@ -187,6 +187,7 @@ void ContentSubresourceFilterDriverFactory::ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) { + DCHECK(!navigation_handle->IsSamePage()); content::RenderFrameHost* render_frame_host = navigation_handle->GetRenderFrameHost(); GURL url = navigation_handle->GetURL();
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc index a746256..75db9c7 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -313,7 +313,7 @@ EXPECT_CALL(*driver(), ActivateForProvisionalLoad( ::testing::_, ::testing::_, ::testing::_)) .Times(0); - EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(1); + EXPECT_CALL(*client(), ToggleNotificationVisibility(::testing::_)).Times(0); content::RenderFrameHostTester::For(main_rfh()) ->SimulateNavigationCommit(GURL(kExampleUrl)); ::testing::Mock::VerifyAndClearExpectations(driver());
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/components/subresource_filter/content/renderer/subresource_filter_agent.cc index 64b54b0..05405c0 100644 --- a/components/subresource_filter/content/renderer/subresource_filter_agent.cc +++ b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -143,6 +143,9 @@ void SubresourceFilterAgent::DidCommitProvisionalLoad( bool is_new_navigation, bool is_same_page_navigation) { + if (is_same_page_navigation) + return; + RecordHistogramsOnLoadCommitted(); if (activation_state_for_provisional_load_ != ActivationState::DISABLED && ruleset_dealer_->IsRulesetAvailable()) { @@ -159,6 +162,7 @@ filter_for_last_committed_load_ = filter->AsWeakPtr(); SetSubresourceFilterForCommittedLoad(std::move(filter)); } + activation_state_for_provisional_load_ = ActivationState::DISABLED; }
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc index 29227c0..7839276 100644 --- a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc +++ b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -121,6 +121,13 @@ true /* is_new_navigation */, false /* is_same_page_navigation */); } + void PerformSamePageNavigationWithoutSettingActivationState() { + agent_as_rfo()->DidStartProvisionalLoad(); + agent_as_rfo()->DidCommitProvisionalLoad( + true /* is_new_navigation */, true /* is_same_page_navigation */); + // No DidFinishLoad is called in this case. + } + void StartLoadAndSetActivationState(ActivationState activation_state, bool measure_performance = false) { agent_as_rfo()->DidStartProvisionalLoad(); @@ -238,10 +245,23 @@ ExpectLoadAllowed(kTestSecondURL, true); FinishLoad(); + // In-page navigation should not count as a new load. + ExpectNoSubresourceFilterGetsInjected(); + ExpectNoSignalAboutFirstSubresourceDisallowed(); + PerformSamePageNavigationWithoutSettingActivationState(); + ExpectLoadAllowed(kTestFirstURL, false); + ExpectLoadAllowed(kTestSecondURL, true); + ExpectNoSubresourceFilterGetsInjected(); StartLoadWithoutSettingActivationState(); FinishLoad(); + // Resource loads after the in-page navigation should not be counted toward + // the figures below, as they came after the original page load event. + histogram_tester.ExpectUniqueSample(kSubresourcesTotal, 2, 1); + histogram_tester.ExpectUniqueSample(kSubresourcesEvaluated, 2, 1); + histogram_tester.ExpectUniqueSample(kSubresourcesMatchedRules, 1, 1); + histogram_tester.ExpectUniqueSample(kSubresourcesDisallowed, 1, 1); EXPECT_THAT(histogram_tester.GetAllSamples(kDocumentLoadActivationState), ::testing::ElementsAre( base::Bucket(static_cast<int>(ActivationState::DISABLED), 1), @@ -249,7 +269,7 @@ histogram_tester.ExpectUniqueSample(kDocumentLoadRulesetIsAvailable, 1, 1); } -TEST_F(SubresourceFilterAgentTest, Enabled_HistogramSamples) { +TEST_F(SubresourceFilterAgentTest, Enabled_HistogramSamplesOverTwoLoads) { for (const bool measure_performance : {false, true}) { base::HistogramTester histogram_tester; ASSERT_NO_FATAL_FAILURE(
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn index 6b8a5699..2b290c6 100644 --- a/components/sync/BUILD.gn +++ b/components/sync/BUILD.gn
@@ -150,6 +150,8 @@ "driver/sync_error_controller.h", "driver/sync_service.cc", "driver/sync_service.h", + "driver/sync_service_base.cc", + "driver/sync_service_base.h", "driver/sync_service_observer.cc", "driver/sync_service_observer.h", "driver/sync_service_utils.cc",
diff --git a/components/sync/driver/DEPS b/components/sync/driver/DEPS index a5135a4..ad82970 100644 --- a/components/sync/driver/DEPS +++ b/components/sync/driver/DEPS
@@ -9,6 +9,7 @@ "+components/sync/base", "+components/sync/device_info", "+components/sync/engine", + "+components/sync/js", "+components/sync/model", "+components/sync/protocol", "+components/sync/syncable",
diff --git a/components/sync/driver/glue/sync_backend_host_core.cc b/components/sync/driver/glue/sync_backend_host_core.cc index 9fe765d..ca38894 100644 --- a/components/sync/driver/glue/sync_backend_host_core.cc +++ b/components/sync/driver/glue/sync_backend_host_core.cc
@@ -55,53 +55,6 @@ class EngineComponentsFactory; -DoInitializeOptions::DoInitializeOptions( - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner, - SyncBackendRegistrar* registrar, - const std::vector<scoped_refptr<ModelSafeWorker>>& workers, - const scoped_refptr<ExtensionsActivity>& extensions_activity, - const WeakHandle<JsEventHandler>& event_handler, - const GURL& service_url, - const std::string& sync_user_agent, - std::unique_ptr<HttpPostProviderFactory> http_bridge_factory, - const SyncCredentials& credentials, - const std::string& invalidator_client_id, - std::unique_ptr<SyncManagerFactory> sync_manager_factory, - bool delete_sync_data_folder, - bool enable_local_sync_backend, - const base::FilePath& local_sync_backend_folder, - const std::string& restored_key_for_bootstrapping, - const std::string& restored_keystore_key_for_bootstrapping, - std::unique_ptr<EngineComponentsFactory> engine_components_factory, - const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler, - const base::Closure& report_unrecoverable_error_function, - std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state, - const std::map<ModelType, int64_t>& invalidation_versions) - : sync_task_runner(std::move(sync_task_runner)), - registrar(registrar), - workers(workers), - extensions_activity(extensions_activity), - event_handler(event_handler), - service_url(service_url), - sync_user_agent(sync_user_agent), - http_bridge_factory(std::move(http_bridge_factory)), - credentials(credentials), - invalidator_client_id(invalidator_client_id), - sync_manager_factory(std::move(sync_manager_factory)), - delete_sync_data_folder(delete_sync_data_folder), - enable_local_sync_backend(enable_local_sync_backend), - local_sync_backend_folder(local_sync_backend_folder), - restored_key_for_bootstrapping(restored_key_for_bootstrapping), - restored_keystore_key_for_bootstrapping( - restored_keystore_key_for_bootstrapping), - engine_components_factory(std::move(engine_components_factory)), - unrecoverable_error_handler(unrecoverable_error_handler), - report_unrecoverable_error_function(report_unrecoverable_error_function), - saved_nigori_state(std::move(saved_nigori_state)), - invalidation_versions(invalidation_versions) {} - -DoInitializeOptions::~DoInitializeOptions() {} - SyncBackendHostCore::SyncBackendHostCore( const std::string& name, const base::FilePath& sync_data_folder_path, @@ -366,18 +319,12 @@ last_invalidation_versions_); } -void SyncBackendHostCore::DoInitialize( - std::unique_ptr<DoInitializeOptions> options) { +void SyncBackendHostCore::DoInitialize(SyncEngine::InitParams params) { DCHECK(thread_checker_.CalledOnValidThread()); - // Finish initializing the HttpBridgeFactory. We do this here because - // building the user agent may block on some platforms. - options->http_bridge_factory->Init(options->sync_user_agent, - base::Bind(&BindFetcherToDataTracker)); - // Blow away the partial or corrupt sync data folder before doing any more // initialization, if necessary. - if (options->delete_sync_data_folder) { + if (params.delete_sync_data_folder) { DeleteSyncDataFolder(); } @@ -388,38 +335,42 @@ } // Load the previously persisted set of invalidation versions into memory. - last_invalidation_versions_ = options->invalidation_versions; + last_invalidation_versions_ = params.invalidation_versions; DCHECK(!registrar_); - registrar_ = options->registrar; + registrar_ = std::move(params.registrar); DCHECK(registrar_); - sync_manager_ = options->sync_manager_factory->CreateSyncManager(name_); + sync_manager_ = params.sync_manager_factory->CreateSyncManager(name_); sync_manager_->AddObserver(this); SyncManager::InitArgs args; args.database_location = sync_data_folder_path_; - args.event_handler = options->event_handler; - args.service_url = options->service_url; - args.enable_local_sync_backend = options->enable_local_sync_backend; - args.local_sync_backend_folder = options->local_sync_backend_folder; - args.post_factory = std::move(options->http_bridge_factory); - args.workers = options->workers; - args.extensions_activity = options->extensions_activity.get(); - args.change_delegate = options->registrar; // as SyncManager::ChangeDelegate - args.credentials = options->credentials; - args.invalidator_client_id = options->invalidator_client_id; - args.restored_key_for_bootstrapping = options->restored_key_for_bootstrapping; + args.event_handler = params.event_handler; + args.service_url = params.service_url; + args.enable_local_sync_backend = params.enable_local_sync_backend; + args.local_sync_backend_folder = params.local_sync_backend_folder; + args.post_factory = + params.http_factory_getter.Run(&release_request_context_signal_); + // Finish initializing the HttpBridgeFactory. We do this here because + // building the user agent may block on some platforms. + args.post_factory->Init(params.sync_user_agent, + base::Bind(&BindFetcherToDataTracker)); + registrar_->GetWorkers(&args.workers); + args.extensions_activity = params.extensions_activity.get(); + args.change_delegate = registrar_.get(); // as SyncManager::ChangeDelegate + args.credentials = params.credentials; + args.invalidator_client_id = params.invalidator_client_id; + args.restored_key_for_bootstrapping = params.restored_key_for_bootstrapping; args.restored_keystore_key_for_bootstrapping = - options->restored_keystore_key_for_bootstrapping; - args.engine_components_factory = - std::move(options->engine_components_factory); + params.restored_keystore_key_for_bootstrapping; + args.engine_components_factory = std::move(params.engine_components_factory); args.encryptor = &encryptor_; - args.unrecoverable_error_handler = options->unrecoverable_error_handler; + args.unrecoverable_error_handler = params.unrecoverable_error_handler; args.report_unrecoverable_error_function = - options->report_unrecoverable_error_function; + params.report_unrecoverable_error_function; args.cancelation_signal = &stop_syncing_signal_; - args.saved_nigori_state = std::move(options->saved_nigori_state); + args.saved_nigori_state = std::move(params.saved_nigori_state); sync_manager_->Init(&args); base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "SyncDirectory", base::ThreadTaskRunnerHandle::Get());
diff --git a/components/sync/driver/glue/sync_backend_host_core.h b/components/sync/driver/glue/sync_backend_host_core.h index 55e5372..71eb86c 100644 --- a/components/sync/driver/glue/sync_backend_host_core.h +++ b/components/sync/driver/glue/sync_backend_host_core.h
@@ -31,57 +31,6 @@ class SyncBackendHostImpl; -// Utility struct for holding initialization options. -struct DoInitializeOptions { - DoInitializeOptions( - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner, - SyncBackendRegistrar* registrar, - const std::vector<scoped_refptr<ModelSafeWorker>>& workers, - const scoped_refptr<ExtensionsActivity>& extensions_activity, - const WeakHandle<JsEventHandler>& event_handler, - const GURL& service_url, - const std::string& sync_user_agent, - std::unique_ptr<HttpPostProviderFactory> http_bridge_factory, - const SyncCredentials& credentials, - const std::string& invalidator_client_id, - std::unique_ptr<SyncManagerFactory> sync_manager_factory, - bool delete_sync_data_folder, - bool enable_local_sync_backend, - const base::FilePath& local_sync_backend_folder, - const std::string& restored_key_for_bootstrapping, - const std::string& restored_keystore_key_for_bootstrapping, - std::unique_ptr<EngineComponentsFactory> engine_components_factory, - const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler, - const base::Closure& report_unrecoverable_error_function, - std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state, - const std::map<ModelType, int64_t>& invalidation_versions); - ~DoInitializeOptions(); - - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner; - SyncBackendRegistrar* registrar; - std::vector<scoped_refptr<ModelSafeWorker>> workers; - scoped_refptr<ExtensionsActivity> extensions_activity; - WeakHandle<JsEventHandler> event_handler; - GURL service_url; - std::string sync_user_agent; - // Overridden by tests. - std::unique_ptr<HttpPostProviderFactory> http_bridge_factory; - SyncCredentials credentials; - const std::string invalidator_client_id; - std::unique_ptr<SyncManagerFactory> sync_manager_factory; - std::string lsid; - bool delete_sync_data_folder; - bool enable_local_sync_backend; - const base::FilePath local_sync_backend_folder; - std::string restored_key_for_bootstrapping; - std::string restored_keystore_key_for_bootstrapping; - std::unique_ptr<EngineComponentsFactory> engine_components_factory; - const WeakHandle<UnrecoverableErrorHandler> unrecoverable_error_handler; - base::Closure report_unrecoverable_error_function; - std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state; - const std::map<ModelType, int64_t> invalidation_versions; -}; - class SyncBackendHostCore : public base::RefCountedThreadSafe<SyncBackendHostCore>, public base::trace_event::MemoryDumpProvider, @@ -150,7 +99,7 @@ // // Called to perform initialization of the syncapi on behalf of // SyncEngine::Initialize. - void DoInitialize(std::unique_ptr<DoInitializeOptions> options); + void DoInitialize(SyncEngine::InitParams params); // Called to perform credential update on behalf of // SyncEngine::UpdateCredentials. @@ -229,12 +178,6 @@ // sync databases), as well as shutdown when you're no longer syncing. void DeleteSyncDataFolder(); - // We expose this member because it's required in the construction of the - // HttpBridgeFactory. - CancelationSignal* GetRequestContextCancelationSignal() { - return &release_request_context_signal_; - } - // Tell the sync manager to persist its state by writing to disk. // Called on the sync thread, both by a timer and, on Android, when the // application is backgrounded. @@ -268,9 +211,8 @@ // Our parent SyncBackendHostImpl. WeakHandle<SyncBackendHostImpl> host_; - // Our parent's registrar (not owned). Non-null only between - // calls to DoInitialize() and DoShutdown(). - SyncBackendRegistrar* registrar_ = nullptr; + // Non-null only between calls to DoInitialize() and DoShutdown(). + std::unique_ptr<SyncBackendRegistrar> registrar_; // The timer used to periodically call SaveChanges. std::unique_ptr<base::RepeatingTimer> save_changes_timer_;
diff --git a/components/sync/driver/glue/sync_backend_host_impl.cc b/components/sync/driver/glue/sync_backend_host_impl.cc index 1b135cb8..b125c44 100644 --- a/components/sync/driver/glue/sync_backend_host_impl.cc +++ b/components/sync/driver/glue/sync_backend_host_impl.cc
@@ -59,73 +59,21 @@ SyncBackendHostImpl::~SyncBackendHostImpl() { DCHECK(!core_.get() && !host_) << "Must call Shutdown before destructor."; - DCHECK(!registrar_.get()); + DCHECK(!registrar_); } -void SyncBackendHostImpl::Initialize( - SyncEngineHost* host, - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner, - const WeakHandle<JsEventHandler>& event_handler, - const GURL& sync_service_url, - const std::string& sync_user_agent, - const SyncCredentials& credentials, - bool delete_sync_data_folder, - bool enable_local_sync_backend, - const base::FilePath& local_sync_backend_folder, - std::unique_ptr<SyncManagerFactory> sync_manager_factory, - const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler, - const base::Closure& report_unrecoverable_error_function, - const HttpPostProviderFactoryGetter& http_post_provider_factory_getter, - std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state) { - CHECK(sync_task_runner); - sync_task_runner_ = sync_task_runner; +void SyncBackendHostImpl::Initialize(InitParams params) { + CHECK(params.sync_task_runner); + DCHECK(params.host); + DCHECK(params.registrar); - registrar_ = base::MakeUnique<SyncBackendRegistrar>( - name_, base::Bind(&SyncClient::CreateModelWorkerForGroup, - base::Unretained(sync_client_))); + sync_task_runner_ = params.sync_task_runner; + host_ = params.host; + registrar_ = params.registrar.get(); - DCHECK(host); - host_ = host; - - std::vector<scoped_refptr<ModelSafeWorker>> workers; - registrar_->GetWorkers(&workers); - - EngineComponentsFactory::Switches factory_switches = { - EngineComponentsFactory::ENCRYPTION_KEYSTORE, - EngineComponentsFactory::BACKOFF_NORMAL}; - - base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); - if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) { - factory_switches.backoff_override = - EngineComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE; - } - if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) { - factory_switches.pre_commit_updates_policy = - EngineComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE; - } - if (cl->HasSwitch(switches::kSyncShortNudgeDelayForTest)) { - factory_switches.nudge_delay = - EngineComponentsFactory::NudgeDelay::SHORT_NUDGE_DELAY; - } - - std::map<ModelType, int64_t> invalidation_versions; - sync_prefs_->GetInvalidationVersions(&invalidation_versions); - - std::unique_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions( - sync_task_runner_, registrar_.get(), workers, - sync_client_->GetExtensionsActivity(), event_handler, sync_service_url, - sync_user_agent, http_post_provider_factory_getter.Run( - core_->GetRequestContextCancelationSignal()), - credentials, invalidator_ ? invalidator_->GetInvalidatorClientId() : "", - std::move(sync_manager_factory), delete_sync_data_folder, - enable_local_sync_backend, local_sync_backend_folder, - sync_prefs_->GetEncryptionBootstrapToken(), - sync_prefs_->GetKeystoreEncryptionBootstrapToken(), - std::unique_ptr<EngineComponentsFactory>( - new EngineComponentsFactoryImpl(factory_switches)), - unrecoverable_error_handler, report_unrecoverable_error_function, - std::move(saved_nigori_state), invalidation_versions)); - InitCore(std::move(init_opts)); + sync_task_runner_->PostTask( + FROM_HERE, base::Bind(&SyncBackendHostCore::DoInitialize, core_, + base::Passed(¶ms))); } void SyncBackendHostImpl::TriggerRefresh(const ModelTypeSet& types) { @@ -252,9 +200,7 @@ sync_task_runner_->PostTask( FROM_HERE, base::Bind(&SyncBackendHostCore::DoShutdown, core_, reason)); core_ = nullptr; - - // Destroy |registrar_|. - sync_task_runner_->DeleteSoon(FROM_HERE, registrar_.release()); + registrar_ = nullptr; } void SyncBackendHostImpl::UnregisterInvalidationIds() { @@ -428,7 +374,7 @@ } bool SyncBackendHostImpl::IsNigoriEnabled() const { - return registrar_.get() && registrar_->IsNigoriEnabled(); + return registrar_ && registrar_->IsNigoriEnabled(); } PassphraseType SyncBackendHostImpl::GetPassphraseType() const { @@ -448,7 +394,7 @@ void SyncBackendHostImpl::GetModelSafeRoutingInfo( ModelSafeRoutingInfo* out) const { if (initialized()) { - CHECK(registrar_.get()); + CHECK(registrar_); registrar_->GetModelSafeRoutingInfo(out); } else { NOTREACHED(); @@ -491,13 +437,6 @@ core_)); } -void SyncBackendHostImpl::InitCore( - std::unique_ptr<DoInitializeOptions> options) { - sync_task_runner_->PostTask( - FROM_HERE, base::Bind(&SyncBackendHostCore::DoInitialize, core_, - base::Passed(&options))); -} - void SyncBackendHostImpl::RequestConfigureSyncer( ConfigureReason reason, ModelTypeSet to_download,
diff --git a/components/sync/driver/glue/sync_backend_host_impl.h b/components/sync/driver/glue/sync_backend_host_impl.h index c344dcc..55d6686 100644 --- a/components/sync/driver/glue/sync_backend_host_impl.h +++ b/components/sync/driver/glue/sync_backend_host_impl.h
@@ -31,8 +31,6 @@ #include "components/sync/protocol/encryption.pb.h" #include "components/sync/protocol/sync_protocol_error.h" -class GURL; - namespace invalidation { class InvalidationService; } // namespace invalidation @@ -43,10 +41,7 @@ class SyncBackendHostCore; class SyncBackendRegistrar; class SyncClient; -class SyncManagerFactory; class SyncPrefs; -class UnrecoverableErrorHandler; -struct DoInitializeOptions; // The only real implementation of the SyncEngine. See that interface's // definition for documentation of public methods. @@ -63,22 +58,7 @@ ~SyncBackendHostImpl() override; // SyncEngine implementation. - void Initialize( - SyncEngineHost* host, - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner, - const WeakHandle<JsEventHandler>& event_handler, - const GURL& service_url, - const std::string& sync_user_agent, - const SyncCredentials& credentials, - bool delete_sync_data_folder, - bool enable_local_sync_backend, - const base::FilePath& local_sync_backend_folder, - std::unique_ptr<SyncManagerFactory> sync_manager_factory, - const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler, - const base::Closure& report_unrecoverable_error_function, - const HttpPostProviderFactoryGetter& http_post_provider_factory_getter, - std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state) - override; + void Initialize(InitParams params) override; void TriggerRefresh(const ModelTypeSet& types) override; void UpdateCredentials(const SyncCredentials& credentials) override; void StartSyncingWithServer() override; @@ -131,9 +111,6 @@ // The types and functions below are protected so that test // subclasses can use them. - // Allows tests to perform alternate core initialization work. - virtual void InitCore(std::unique_ptr<DoInitializeOptions> options); - // Request the syncer to reconfigure with the specfied params. // Virtual for testing. virtual void RequestConfigureSyncer( @@ -300,12 +277,13 @@ const base::WeakPtr<SyncPrefs> sync_prefs_; - std::unique_ptr<SyncBackendRegistrar> registrar_; - // The host which we serve (and are owned by). Set in Initialize() and nulled // out in StopSyncingForShutdown(). SyncEngineHost* host_ = nullptr; + // A pointer to the registrar; owned by |core_|. + SyncBackendRegistrar* registrar_ = nullptr; + // We cache the cryptographer's pending keys whenever NotifyPassphraseRequired // is called. This way, before the UI calls SetDecryptionPassphrase on the // syncer, it can avoid the overhead of an asynchronous decryption call and
diff --git a/components/sync/driver/glue/sync_backend_host_impl_unittest.cc b/components/sync/driver/glue/sync_backend_host_impl_unittest.cc index 5276ddb3..f6c698a 100644 --- a/components/sync/driver/glue/sync_backend_host_impl_unittest.cc +++ b/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
@@ -213,13 +213,24 @@ base::Bind(&NetworkResources::GetHttpPostProviderFactory, base::Unretained(network_resources_.get()), nullptr, base::Bind(&EmptyNetworkTimeUpdate)); - backend_->Initialize( - &mock_host_, sync_thread_.task_runner(), WeakHandle<JsEventHandler>(), - GURL(std::string()), std::string(), credentials_, true, false, - base::FilePath(), std::move(fake_manager_factory_), + + SyncEngine::InitParams params; + params.sync_task_runner = sync_thread_.task_runner(); + params.host = &mock_host_; + params.registrar = base::MakeUnique<SyncBackendRegistrar>( + std::string(), base::Bind(&SyncClient::CreateModelWorkerForGroup, + base::Unretained(&sync_client_))); + params.http_factory_getter = http_post_provider_factory_getter; + params.credentials = credentials_; + params.sync_manager_factory = std::move(fake_manager_factory_); + params.delete_sync_data_folder = true; + params.unrecoverable_error_handler = MakeWeakHandle(test_unrecoverable_error_handler_.GetWeakPtr()), - base::Closure(), http_post_provider_factory_getter, - std::move(saved_nigori_state_)); + params.saved_nigori_state = std::move(saved_nigori_state_); + sync_prefs_->GetInvalidationVersions(¶ms.invalidation_versions); + + backend_->Initialize(std::move(params)); + base::RunLoop run_loop; base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, run_loop.QuitClosure(), TestTimeouts::action_timeout());
diff --git a/components/sync/driver/sync_service_base.cc b/components/sync/driver/sync_service_base.cc new file mode 100644 index 0000000..e9b9753 --- /dev/null +++ b/components/sync/driver/sync_service_base.cc
@@ -0,0 +1,147 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/sync/driver/sync_service_base.h" + +#include <utility> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/memory/ptr_util.h" +#include "base/path_service.h" +#include "components/invalidation/public/invalidation_service.h" +#include "components/sync/base/report_unrecoverable_error.h" +#include "components/sync/device_info/local_device_info_provider.h" +#include "components/sync/driver/sync_driver_switches.h" +#include "components/sync/engine/engine_components_factory_impl.h" + +namespace syncer { + +namespace { + +const base::FilePath::CharType kSyncDataFolderName[] = + FILE_PATH_LITERAL("Sync Data"); + +#if defined(OS_WIN) +const base::FilePath::CharType kLoopbackServerBackendFilename[] = + FILE_PATH_LITERAL("profile.pb"); +#endif + +EngineComponentsFactory::Switches EngineSwitchesFromCommandLine() { + EngineComponentsFactory::Switches factory_switches = { + EngineComponentsFactory::ENCRYPTION_KEYSTORE, + EngineComponentsFactory::BACKOFF_NORMAL}; + + base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); + if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) { + factory_switches.backoff_override = + EngineComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE; + } + if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) { + factory_switches.pre_commit_updates_policy = + EngineComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE; + } + if (cl->HasSwitch(switches::kSyncShortNudgeDelayForTest)) { + factory_switches.nudge_delay = + EngineComponentsFactory::NudgeDelay::SHORT_NUDGE_DELAY; + } + return factory_switches; +} + +} // namespace + +SyncServiceBase::SyncServiceBase(std::unique_ptr<SyncClient> sync_client, + std::unique_ptr<SigninManagerWrapper> signin, + const version_info::Channel& channel, + const base::FilePath& base_directory, + const std::string& debug_identifier) + : sync_client_(std::move(sync_client)), + signin_(std::move(signin)), + channel_(channel), + base_directory_(base_directory), + directory_path_( + base_directory_.Append(base::FilePath(kSyncDataFolderName))), + debug_identifier_(debug_identifier), + sync_prefs_(sync_client_->GetPrefService()) {} + +SyncServiceBase::~SyncServiceBase() = default; + +void SyncServiceBase::InitializeEngine() { + DCHECK(engine_); + + if (!sync_thread_) { + sync_thread_ = base::MakeUnique<base::Thread>("Chrome_SyncThread"); + base::Thread::Options options; + options.timer_slack = base::TIMER_SLACK_MAXIMUM; + CHECK(sync_thread_->StartWithOptions(options)); + } + + SyncEngine::InitParams params; + params.sync_task_runner = sync_thread_->task_runner(); + params.host = this; + params.registrar = base::MakeUnique<SyncBackendRegistrar>( + debug_identifier_, base::Bind(&SyncClient::CreateModelWorkerForGroup, + base::Unretained(sync_client_.get()))); + params.extensions_activity = sync_client_->GetExtensionsActivity(); + params.event_handler = GetJsEventHandler(); + params.service_url = sync_service_url(); + params.sync_user_agent = GetLocalDeviceInfoProvider()->GetSyncUserAgent(); + params.http_factory_getter = MakeHttpPostProviderFactoryGetter(); + params.credentials = GetCredentials(); + invalidation::InvalidationService* invalidator = + sync_client_->GetInvalidationService(); + params.invalidator_client_id = + invalidator ? invalidator->GetInvalidatorClientId() : "", + params.sync_manager_factory = base::MakeUnique<SyncManagerFactory>(); + // The first time we start up the engine we want to ensure we have a clean + // directory, so delete any old one that might be there. + params.delete_sync_data_folder = !IsFirstSetupComplete(); + params.enable_local_sync_backend = + GetLocalSyncConfig(¶ms.local_sync_backend_folder); + params.restored_key_for_bootstrapping = + sync_prefs_.GetEncryptionBootstrapToken(); + params.restored_keystore_key_for_bootstrapping = + sync_prefs_.GetKeystoreEncryptionBootstrapToken(); + params.engine_components_factory = + base::MakeUnique<EngineComponentsFactoryImpl>( + EngineSwitchesFromCommandLine()); + params.unrecoverable_error_handler = GetUnrecoverableErrorHandler(); + params.report_unrecoverable_error_function = + base::Bind(ReportUnrecoverableError, channel_); + params.saved_nigori_state = MoveSavedNigoriState(); + sync_prefs_.GetInvalidationVersions(¶ms.invalidation_versions); + + engine_->Initialize(std::move(params)); +} + +bool SyncServiceBase::GetLocalSyncConfig( + base::FilePath* local_sync_backend_folder) const { + bool enable_local_sync_backend = false; + *local_sync_backend_folder = sync_prefs_.GetLocalSyncBackendDir(); +#if defined(OS_WIN) + enable_local_sync_backend = sync_prefs_.IsLocalSyncEnabled(); + if (local_sync_backend_folder->empty()) { + // TODO(pastarmovj): Add DIR_ROAMING_USER_DATA to PathService to simplify + // this code and move the logic in its right place. See crbug/657810. + CHECK( + base::PathService::Get(base::DIR_APP_DATA, local_sync_backend_folder)); + *local_sync_backend_folder = local_sync_backend_folder->Append( + FILE_PATH_LITERAL("Chrome/User Data")); + } + // This code as it is now will assume the same profile order is present on all + // machines, which is not a given. It is to be defined if only the Default + // profile should get this treatment or all profile as is the case now. The + // solution for now will be to assume profiles are created in the same order + // on all machines and in the future decide if only the Default one should be + // considered roamed. + *local_sync_backend_folder = + local_sync_backend_folder->Append(base_directory_.BaseName()); + *local_sync_backend_folder = + local_sync_backend_folder->Append(kLoopbackServerBackendFilename); +#endif // defined(OS_WIN) + return enable_local_sync_backend; +} + +} // namespace syncer
diff --git a/components/sync/driver/sync_service_base.h b/components/sync/driver/sync_service_base.h new file mode 100644 index 0000000..1f068b1 --- /dev/null +++ b/components/sync/driver/sync_service_base.h
@@ -0,0 +1,107 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SYNC_DRIVER_SYNC_SERVICE_BASE_H_ +#define COMPONENTS_SYNC_DRIVER_SYNC_SERVICE_BASE_H_ + +#include <memory> +#include <string> + +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "base/threading/thread.h" +#include "components/sync/base/sync_prefs.h" +#include "components/sync/base/unrecoverable_error_handler.h" +#include "components/sync/base/weak_handle.h" +#include "components/sync/driver/signin_manager_wrapper.h" +#include "components/sync/driver/sync_client.h" +#include "components/sync/driver/sync_service.h" +#include "components/sync/engine/sync_engine.h" +#include "components/sync/engine/sync_engine_host.h" +#include "components/sync/engine/sync_manager.h" +#include "components/sync/js/sync_js_controller.h" +#include "components/version_info/version_info.h" + +namespace syncer { + +// This is a base class for implementations of SyncService that contains some +// common functionality and member variables. Anything that can live inside the +// sync component should eventually live here instead of a concrete +// implementation. This is set up as a base class so things can be transferred +// piece by piece as easily as possible. +class SyncServiceBase : public SyncService, public SyncEngineHost { + public: + SyncServiceBase(std::unique_ptr<SyncClient> sync_client, + std::unique_ptr<SigninManagerWrapper> signin, + const version_info::Channel& channel, + const base::FilePath& base_directory, + const std::string& debug_identifier); + ~SyncServiceBase() override; + + protected: + // Kicks off asynchronous initialization of the SyncEngine. + void InitializeEngine(); + + // Returns SyncCredentials from the OAuth2TokenService. + virtual SyncCredentials GetCredentials() = 0; + + // Returns a weak handle to the JsEventHandler. + virtual WeakHandle<JsEventHandler> GetJsEventHandler() = 0; + + // Returns a callback that makes an HttpPostProviderFactory. + virtual SyncEngine::HttpPostProviderFactoryGetter + MakeHttpPostProviderFactoryGetter() = 0; + + // Takes the previously saved nigori state; null if there isn't any. + virtual std::unique_ptr<SyncEncryptionHandler::NigoriState> + MoveSavedNigoriState() = 0; + + // Returns a weak handle to an UnrecoverableErrorHandler (may be |this|). + virtual WeakHandle<UnrecoverableErrorHandler> + GetUnrecoverableErrorHandler() = 0; + + // This profile's SyncClient, which abstracts away non-Sync dependencies and + // the Sync API component factory. + const std::unique_ptr<SyncClient> sync_client_; + + // Encapsulates user signin - used to set/get the user's authenticated + // email address. + const std::unique_ptr<SigninManagerWrapper> signin_; + + // The product channel of the embedder. + const version_info::Channel channel_; + + // The path to the base directory under which sync should store its + // information. + const base::FilePath base_directory_; + + // The full path to the sync data directory. + const base::FilePath directory_path_; + + // An identifier representing this instance for debugging purposes. + const std::string debug_identifier_; + + // The class that handles getting, setting, and persisting sync + // preferences. + SyncPrefs sync_prefs_; + + // The thread where all the sync operations happen. This thread is kept alive + // until browser shutdown and reused if sync is turned off and on again. It is + // joined during the shutdown process, but there is an abort mechanism in + // place to prevent slow HTTP requests from blocking browser shutdown. + std::unique_ptr<base::Thread> sync_thread_; + + // Our asynchronous engine to communicate with sync components living on + // other threads. + std::unique_ptr<SyncEngine> engine_; + + private: + bool GetLocalSyncConfig(base::FilePath* local_sync_backend_folder) const; + + DISALLOW_COPY_AND_ASSIGN(SyncServiceBase); +}; + +} // namespace syncer + +#endif // COMPONENTS_SYNC_DRIVER_SYNC_SERVICE_BASE_H_
diff --git a/components/sync/engine/fake_sync_engine.cc b/components/sync/engine/fake_sync_engine.cc index 141bed1..c22ce88 100644 --- a/components/sync/engine/fake_sync_engine.cc +++ b/components/sync/engine/fake_sync_engine.cc
@@ -14,24 +14,10 @@ FakeSyncEngine::FakeSyncEngine() : fail_initial_download_(false) {} FakeSyncEngine::~FakeSyncEngine() {} -void FakeSyncEngine::Initialize( - SyncEngineHost* host, - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner, - const WeakHandle<JsEventHandler>& event_handler, - const GURL& service_url, - const std::string& sync_user_agent, - const SyncCredentials& credentials, - bool delete_sync_data_folder, - bool enable_local_sync_backend, - const base::FilePath& local_sync_backend_folder, - std::unique_ptr<SyncManagerFactory> sync_manager_factory, - const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler, - const base::Closure& report_unrecoverable_error_function, - const HttpPostProviderFactoryGetter& http_post_provider_factory_getter, - std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state) { - host->OnEngineInitialized(ModelTypeSet(), WeakHandle<JsBackend>(), - WeakHandle<DataTypeDebugInfoListener>(), - kTestCacheGuid, !fail_initial_download_); +void FakeSyncEngine::Initialize(InitParams params) { + params.host->OnEngineInitialized(ModelTypeSet(), WeakHandle<JsBackend>(), + WeakHandle<DataTypeDebugInfoListener>(), + kTestCacheGuid, !fail_initial_download_); } void FakeSyncEngine::TriggerRefresh(const ModelTypeSet& types) {}
diff --git a/components/sync/engine/fake_sync_engine.h b/components/sync/engine/fake_sync_engine.h index 68e9347..ac8ff25a 100644 --- a/components/sync/engine/fake_sync_engine.h +++ b/components/sync/engine/fake_sync_engine.h
@@ -26,22 +26,7 @@ FakeSyncEngine(); ~FakeSyncEngine() override; - void Initialize( - SyncEngineHost* host, - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner, - const WeakHandle<JsEventHandler>& event_handler, - const GURL& service_url, - const std::string& sync_user_agent, - const SyncCredentials& credentials, - bool delete_sync_data_folder, - bool enable_local_sync_backend, - const base::FilePath& local_sync_backend_folder, - std::unique_ptr<SyncManagerFactory> sync_manager_factory, - const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler, - const base::Closure& report_unrecoverable_error_function, - const HttpPostProviderFactoryGetter& http_post_provider_factory_getter, - std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state) - override; + void Initialize(InitParams params) override; void TriggerRefresh(const ModelTypeSet& types) override;
diff --git a/components/sync/engine/sync_engine.cc b/components/sync/engine/sync_engine.cc index 5348259..33beacf 100644 --- a/components/sync/engine/sync_engine.cc +++ b/components/sync/engine/sync_engine.cc
@@ -6,7 +6,11 @@ namespace syncer { -SyncEngine::SyncEngine() {} -SyncEngine::~SyncEngine() {} +SyncEngine::InitParams::InitParams() = default; +SyncEngine::InitParams::InitParams(InitParams&& other) = default; +SyncEngine::InitParams::~InitParams() = default; + +SyncEngine::SyncEngine() = default; +SyncEngine::~SyncEngine() = default; } // namespace syncer
diff --git a/components/sync/engine/sync_engine.h b/components/sync/engine/sync_engine.h index 790651f..faf18d6 100644 --- a/components/sync/engine/sync_engine.h +++ b/components/sync/engine/sync_engine.h
@@ -5,19 +5,24 @@ #ifndef COMPONENTS_SYNC_ENGINE_SYNC_ENGINE_H_ #define COMPONENTS_SYNC_ENGINE_SYNC_ENGINE_H_ +#include <map> #include <memory> #include <string> #include "base/callback.h" #include "base/compiler_specific.h" +#include "base/files/file_path.h" #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" +#include "components/sync/base/extensions_activity.h" #include "components/sync/base/model_type.h" #include "components/sync/base/weak_handle.h" #include "components/sync/engine/configure_reason.h" #include "components/sync/engine/cycle/sync_cycle_snapshot.h" #include "components/sync/engine/model_type_configurer.h" #include "components/sync/engine/shutdown_reason.h" +#include "components/sync/engine/sync_backend_registrar.h" #include "components/sync/engine/sync_manager.h" #include "components/sync/engine/sync_manager_factory.h" @@ -42,7 +47,38 @@ CancelationSignal*)> HttpPostProviderFactoryGetter; - // Stubs used by implementing classes. + // Utility struct for holding initialization options. + struct InitParams { + InitParams(); + InitParams(InitParams&& other); + ~InitParams(); + + scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner; + SyncEngineHost* host = nullptr; + std::unique_ptr<SyncBackendRegistrar> registrar; + scoped_refptr<ExtensionsActivity> extensions_activity; + WeakHandle<JsEventHandler> event_handler; + GURL service_url; + std::string sync_user_agent; + SyncEngine::HttpPostProviderFactoryGetter http_factory_getter; + SyncCredentials credentials; + std::string invalidator_client_id; + std::unique_ptr<SyncManagerFactory> sync_manager_factory; + bool delete_sync_data_folder = false; + bool enable_local_sync_backend = false; + base::FilePath local_sync_backend_folder; + std::string restored_key_for_bootstrapping; + std::string restored_keystore_key_for_bootstrapping; + std::unique_ptr<EngineComponentsFactory> engine_components_factory; + WeakHandle<UnrecoverableErrorHandler> unrecoverable_error_handler; + base::Closure report_unrecoverable_error_function; + std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state; + std::map<ModelType, int64_t> invalidation_versions; + + private: + DISALLOW_COPY_AND_ASSIGN(InitParams); + }; + SyncEngine(); ~SyncEngine() override; @@ -51,22 +87,7 @@ // // |saved_nigori_state| is optional nigori state to restore from a previous // engine instance. May be null. - virtual void Initialize( - SyncEngineHost* host, - scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner, - const WeakHandle<JsEventHandler>& event_handler, - const GURL& service_url, - const std::string& sync_user_agent, - const SyncCredentials& credentials, - bool delete_sync_data_folder, - bool enable_local_sync_backend, - const base::FilePath& local_sync_backend_folder, - std::unique_ptr<SyncManagerFactory> sync_manager_factory, - const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler, - const base::Closure& report_unrecoverable_error_function, - const HttpPostProviderFactoryGetter& http_post_provider_factory_getter, - std::unique_ptr<SyncEncryptionHandler::NigoriState> - saved_nigori_state) = 0; + virtual void Initialize(InitParams params) = 0; // Inform the engine to trigger a sync cycle for |types|. virtual void TriggerRefresh(const ModelTypeSet& types) = 0;
diff --git a/components/sync/test/fake_server/fake_server_network_resources.cc b/components/sync/test/fake_server/fake_server_network_resources.cc index f94ea34d..4459b5d 100644 --- a/components/sync/test/fake_server/fake_server_network_resources.cc +++ b/components/sync/test/fake_server/fake_server_network_resources.cc
@@ -19,7 +19,8 @@ FakeServerNetworkResources::FakeServerNetworkResources( const base::WeakPtr<FakeServer>& fake_server) - : fake_server_(fake_server) {} + : fake_server_(fake_server), + fake_server_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} FakeServerNetworkResources::~FakeServerNetworkResources() {} @@ -28,9 +29,8 @@ const scoped_refptr<net::URLRequestContextGetter>& baseline_context_getter, const NetworkTimeUpdateCallback& network_time_update_callback, CancelationSignal* cancelation_signal) { - return base::WrapUnique<syncer::HttpPostProviderFactory>( - new FakeServerHttpPostProviderFactory( - fake_server_, base::ThreadTaskRunnerHandle::Get())); + return base::MakeUnique<FakeServerHttpPostProviderFactory>( + fake_server_, fake_server_task_runner_); } } // namespace fake_server
diff --git a/components/sync/test/fake_server/fake_server_network_resources.h b/components/sync/test/fake_server/fake_server_network_resources.h index 4b36314..389da64 100644 --- a/components/sync/test/fake_server/fake_server_network_resources.h +++ b/components/sync/test/fake_server/fake_server_network_resources.h
@@ -7,7 +7,9 @@ #include <memory> +#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" #include "components/sync/engine/net/network_resources.h" #include "components/sync/engine/net/network_time_update_callback.h" @@ -35,6 +37,7 @@ private: base::WeakPtr<FakeServer> fake_server_; + scoped_refptr<base::SingleThreadTaskRunner> fake_server_task_runner_; }; } // namespace fake_server
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc index ac51474..04e01b7 100644 --- a/components/sync_sessions/sessions_sync_manager.cc +++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -7,12 +7,9 @@ #include <algorithm> #include <utility> -#include "base/format_macros.h" -#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram_macros.h" -#include "base/strings/stringprintf.h" #include "build/build_config.h" #include "components/sync/base/hash_util.h" #include "components/sync/device_info/local_device_info_provider.h" @@ -24,7 +21,6 @@ #include "components/sync_sessions/synced_tab_delegate.h" #include "components/sync_sessions/synced_window_delegate.h" #include "components/sync_sessions/synced_window_delegates_getter.h" -#include "components/sync_sessions/tab_node_pool.h" #include "components/variations/variations_associated_data.h" using sessions::SerializedNavigationEntry; @@ -66,31 +62,17 @@ return s1->modified_time > s2->modified_time; } -std::string TabNodeIdToTag(const std::string& machine_tag, int tab_node_id) { - return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id); -} - std::string TagFromSpecifics(const sync_pb::SessionSpecifics& specifics) { if (specifics.has_header()) { return specifics.session_tag(); } else if (specifics.has_tab()) { - return TabNodeIdToTag(specifics.session_tag(), specifics.tab_node_id()); + return TabNodePool::TabIdToTag(specifics.session_tag(), + specifics.tab_node_id()); } else { return std::string(); } } -sync_pb::SessionSpecifics SessionTabToSpecifics( - const sessions::SessionTab& session_tab, - const std::string& local_tag, - int tab_node_id) { - sync_pb::SessionSpecifics specifics; - specifics.mutable_tab()->CopyFrom(session_tab.ToSyncData()); - specifics.set_session_tag(local_tag); - specifics.set_tab_node_id(tab_node_id); - return specifics; -} - } // namespace // |local_device| is owned by ProfileSyncService, its lifetime exceeds @@ -135,6 +117,7 @@ std::unique_ptr<syncer::SyncErrorFactory> error_handler) { syncer::SyncMergeResult merge_result(type); DCHECK(session_tracker_.Empty()); + DCHECK_EQ(0U, local_tab_pool_.Capacity()); error_handler_ = std::move(error_handler); sync_processor_ = std::move(sync_processor); @@ -170,12 +153,13 @@ InitializeCurrentMachineTag(local_device_->GetLocalSyncCacheGUID()); } - session_tracker_.SetLocalSessionTag(current_machine_tag()); + session_tracker_.SetLocalSessionTag(current_machine_tag_); syncer::SyncChangeList new_changes; // First, we iterate over sync data to update our session_tracker_. - if (!InitFromSyncModel(initial_sync_data, &new_changes)) { + syncer::SyncDataList restored_tabs; + if (!InitFromSyncModel(initial_sync_data, &restored_tabs, &new_changes)) { // The sync db didn't have a header node for us. Create one. sync_pb::EntitySpecifics specifics; sync_pb::SessionSpecifics* base_specifics = specifics.mutable_session(); @@ -192,12 +176,12 @@ #if defined(OS_ANDROID) std::string sync_machine_tag( BuildMachineTag(local_device_->GetLocalSyncCacheGUID())); - if (current_machine_tag().compare(sync_machine_tag) != 0) + if (current_machine_tag_.compare(sync_machine_tag) != 0) DeleteForeignSessionInternal(sync_machine_tag, &new_changes); #endif // Check if anything has changed on the local client side. - AssociateWindows(RELOAD_TABS, &new_changes); + AssociateWindows(RELOAD_TABS, restored_tabs, &new_changes); local_tab_pool_out_of_sync_ = false; merge_result.set_error( @@ -209,6 +193,7 @@ void SessionsSyncManager::AssociateWindows( ReloadTabsOption option, + const syncer::SyncDataList& restored_tabs, syncer::SyncChangeList* change_output) { const std::string local_tag = current_machine_tag(); sync_pb::SessionSpecifics specifics; @@ -277,12 +262,6 @@ if (!synced_tab) continue; - // Placeholder tabs are those without WebContents, either because they - // were never loaded into memory or they were evicted from memory - // (typically only on Android devices). They only have a tab id, window - // id, and a saved synced id (corresponding to the tab node id). Note - // that only placeholders have this sync id, as it's necessary to - // properly reassociate the tab with the entity that was backing it. if (synced_tab->IsPlaceholderTab()) { // For tabs without WebContents update the |tab_id| and |window_id|, // as it could have changed after a session restore. @@ -292,7 +271,7 @@ if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID && tab_id > TabNodePool::kInvalidTabID) { AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id, - change_output); + restored_tabs, change_output); found_tabs = true; window_s.add_tab(tab_id); } @@ -325,15 +304,8 @@ } } } - std::set<int> deleted_tab_node_ids; - session_tracker_.CleanupLocalTabs(&deleted_tab_node_ids); - for (int tab_node_id : deleted_tab_node_ids) { - std::string tab_node_tag = - TabNodeIdToTag(current_machine_tag(), tab_node_id); - change_output->push_back(syncer::SyncChange( - FROM_HERE, syncer::SyncChange::ACTION_DELETE, - syncer::SyncData::CreateLocalDelete(tab_node_tag, syncer::SESSIONS))); - } + local_tab_pool_.DeleteUnassociatedTabNodes(change_output); + session_tracker_.CleanupSession(local_tag); // Always update the header. Sync takes care of dropping this update // if the entity specifics are identical (i.e windows, client name did @@ -346,63 +318,73 @@ syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); } -void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate, +void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab, syncer::SyncChangeList* change_output) { - DCHECK(!tab_delegate->IsPlaceholderTab()); + DCHECK(!tab->IsPlaceholderTab()); + SessionID::id_type tab_id = tab->GetSessionId(); - if (tab_delegate->IsBeingDestroyed()) { - // Do nothing. By not proactively adding the tab to the session, it will be - // removed if necessary during subsequent cleanup. + if (tab->IsBeingDestroyed()) { + // This tab is closing. + TabLinksMap::iterator tab_iter = local_tab_map_.find(tab_id); + if (tab_iter == local_tab_map_.end()) { + // We aren't tracking this tab (for example, sync setting page). + return; + } + local_tab_pool_.FreeTabNode(tab_iter->second->tab_node_id(), change_output); + local_tab_map_.erase(tab_iter); return; } - if (!tab_delegate->ShouldSync(sessions_client_)) + if (!tab->ShouldSync(sessions_client_)) return; - SessionID::id_type tab_id = tab_delegate->GetSessionId(); - DVLOG(1) << "Syncing tab " << tab_id << " from window " - << tab_delegate->GetWindowId(); + TabLinksMap::iterator local_tab_map_iter = local_tab_map_.find(tab_id); + TabLink* tab_link = nullptr; - int tab_node_id = TabNodePool::kInvalidTabNodeID; - bool existing_tab_node = - session_tracker_.GetTabNodeForLocalTab(tab_id, &tab_node_id); - DCHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id); - tab_delegate->SetSyncId(tab_node_id); - sessions::SessionTab* session_tab = - session_tracker_.GetTab(current_machine_tag(), tab_id); + if (local_tab_map_iter == local_tab_map_.end()) { + int tab_node_id = tab->GetSyncId(); + // If there is an old sync node for the tab, reuse it. If this is a new + // tab, get a sync node for it. + if (!local_tab_pool_.IsUnassociatedTabNode(tab_node_id)) { + tab_node_id = local_tab_pool_.GetFreeTabNode(change_output); + tab->SetSyncId(tab_node_id); + } + local_tab_pool_.AssociateTabNode(tab_node_id, tab_id); + tab_link = new TabLink(tab_node_id, tab); + local_tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link); + } else { + // This tab is already associated with a sync node, reuse it. + // Note: on some platforms the tab object may have changed, so we ensure + // the tab link is up to date. + tab_link = local_tab_map_iter->second.get(); + local_tab_map_iter->second->set_tab(tab); + } + DCHECK(tab_link); + DCHECK_NE(tab_link->tab_node_id(), TabNodePool::kInvalidTabNodeID); + DVLOG(1) << "Reloading tab " << tab_id << " from window " + << tab->GetWindowId(); - // Get the previously synced url. - int old_index = session_tab->normalized_navigation_index(); - GURL old_url; - if (session_tab->navigations.size() > static_cast<size_t>(old_index)) - old_url = session_tab->navigations[old_index].virtual_url(); + // Write to sync model. + sync_pb::EntitySpecifics specifics; + LocalTabDelegateToSpecifics(*tab, specifics.mutable_session()); + syncer::SyncData data = syncer::SyncData::CreateLocalData( + TabNodePool::TabIdToTag(current_machine_tag_, tab_link->tab_node_id()), + current_session_name_, specifics); + change_output->push_back( + syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); - // Update the tracker's session representation. - SetSessionTabFromDelegate(*tab_delegate, base::Time::Now(), session_tab); - SetVariationIds(session_tab); + int current_index = tab->GetCurrentEntryIndex(); + const GURL new_url = tab->GetVirtualURLAtIndex(current_index); + if (new_url != tab_link->url()) { + tab_link->set_url(new_url); + favicon_cache_.OnFaviconVisited(new_url, + tab->GetFaviconURLAtIndex(current_index)); + page_revisit_broadcaster_.OnPageVisit( + new_url, tab->GetTransitionAtIndex(current_index)); + } + session_tracker_.GetSession(current_machine_tag())->modified_time = base::Time::Now(); - - // Write to the sync model itself. - sync_pb::EntitySpecifics specifics; - specifics.mutable_session()->CopyFrom( - SessionTabToSpecifics(*session_tab, current_machine_tag(), tab_node_id)); - syncer::SyncData data = syncer::SyncData::CreateLocalData( - TabNodeIdToTag(current_machine_tag(), tab_node_id), current_session_name_, - specifics); - change_output->push_back(syncer::SyncChange( - FROM_HERE, existing_tab_node ? syncer::SyncChange::ACTION_UPDATE - : syncer::SyncChange::ACTION_ADD, - data)); - - int current_index = tab_delegate->GetCurrentEntryIndex(); - const GURL new_url = tab_delegate->GetVirtualURLAtIndex(current_index); - if (new_url != old_url) { - favicon_cache_.OnFaviconVisited( - new_url, tab_delegate->GetFaviconURLAtIndex(current_index)); - page_revisit_broadcaster_.OnPageVisit( - new_url, tab_delegate->GetTransitionAtIndex(current_index)); - } } bool SessionsSyncManager::RebuildAssociations() { @@ -462,14 +444,21 @@ // "interesting" by going to a valid URL, in which case it needs to be added // to the window's tab information. Similarly, if a tab became // "uninteresting", we remove it from the window's tab information. - AssociateWindows(DONT_RELOAD_TABS, &changes); + AssociateWindows(DONT_RELOAD_TABS, syncer::SyncDataList(), &changes); sync_processor_->ProcessSyncChanges(FROM_HERE, changes); } void SessionsSyncManager::OnFaviconsChanged(const std::set<GURL>& page_urls, const GURL& /* icon_url */) { - for (const GURL& page_url : page_urls) - favicon_cache_.OnPageFaviconUpdated(page_url); + // TODO(zea): consider a separate container for tabs with outstanding favicon + // loads so we don't have to iterate through all tabs comparing urls. + for (const GURL& page_url : page_urls) { + for (TabLinksMap::iterator tab_iter = local_tab_map_.begin(); + tab_iter != local_tab_map_.end(); ++tab_iter) { + if (tab_iter->second->url() == page_url) + favicon_cache_.OnPageFaviconUpdated(page_url); + } + } } void SessionsSyncManager::StopSyncing(syncer::ModelType type) { @@ -482,6 +471,8 @@ sync_processor_.reset(nullptr); error_handler_.reset(); session_tracker_.Clear(); + local_tab_map_.clear(); + local_tab_pool_.Clear(); current_machine_tag_.clear(); current_session_name_.clear(); local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID; @@ -504,17 +495,22 @@ current_machine_tag(), current_session_name_, header_entity); list.push_back(data); - for (auto& win_iter : session->windows) { - for (auto& tab : win_iter.second->tabs) { - // TODO(zea): replace with with the correct tab node id once there's a - // sync specific wrapper for SessionTab. This method is only used in - // tests though, so it's fine for now. crbug.com/662597 - int tab_node_id = 0; + for (auto win_iter = session->windows.begin(); + win_iter != session->windows.end(); ++win_iter) { + for (auto tabs_iter = win_iter->second->tabs.begin(); + tabs_iter != win_iter->second->tabs.end(); ++tabs_iter) { sync_pb::EntitySpecifics entity; - entity.mutable_session()->CopyFrom( - SessionTabToSpecifics(*tab, current_machine_tag(), tab_node_id)); + sync_pb::SessionSpecifics* specifics = entity.mutable_session(); + specifics->mutable_tab()->MergeFrom((*tabs_iter)->ToSyncData()); + specifics->set_session_tag(current_machine_tag_); + + TabLinksMap::const_iterator tab_map_iter = + local_tab_map_.find((*tabs_iter)->tab_id.id()); + DCHECK(tab_map_iter != local_tab_map_.end()); + specifics->set_tab_node_id(tab_map_iter->second->tab_node_id()); syncer::SyncData data = syncer::SyncData::CreateLocalData( - TabNodeIdToTag(current_machine_tag(), tab_node_id), + TabNodePool::TabIdToTag(current_machine_tag_, + specifics->tab_node_id()), current_session_name_, entity); list.push_back(data); } @@ -523,7 +519,7 @@ } bool SessionsSyncManager::GetLocalSession(const SyncedSession** local_session) { - if (current_machine_tag().empty()) + if (current_machine_tag_.empty()) return false; *local_session = session_tracker_.GetSession(current_machine_tag()); return true; @@ -583,7 +579,7 @@ LOG(WARNING) << "Dropping modification to local session."; return syncer::SyncError(); } - UpdateTrackerWithSpecifics( + UpdateTrackerWithForeignSession( session, syncer::SyncDataRemote(it->sync_data()).GetModifiedTime()); break; default: @@ -605,7 +601,7 @@ return syncer::SyncChange( FROM_HERE, SyncChange::ACTION_DELETE, SyncData::CreateLocalDelete( - TabNodeIdToTag(current_machine_tag(), tab.tab_node_id()), + TabNodePool::TabIdToTag(current_machine_tag(), tab.tab_node_id()), syncer::SESSIONS)); } } @@ -621,6 +617,7 @@ bool SessionsSyncManager::InitFromSyncModel( const syncer::SyncDataList& sync_data, + syncer::SyncDataList* restored_tabs, syncer::SyncChangeList* new_changes) { bool found_current_header = false; int bad_foreign_hash_count = 0; @@ -638,7 +635,7 @@ new_changes->push_back(tombstone); } else if (specifics.session_tag() != current_machine_tag()) { if (TagHashFromSpecifics(specifics) == remote.GetClientTagHash()) { - UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime()); + UpdateTrackerWithForeignSession(specifics, remote.GetModifiedTime()); } else { // In the past, like years ago, we believe that some session data was // created with bad tag hashes. This causes any change this client makes @@ -657,10 +654,6 @@ found_current_header = true; if (specifics.header().has_client_name()) current_session_name_ = specifics.header().client_name(); - - // TODO(zea): crbug.com/639009 update the tracker with the specifics - // from the header node as well. This will be necessary to preserve - // the set of open tabs when a custom tab is opened. } else { if (specifics.has_header() || !specifics.has_tab()) { LOG(WARNING) << "Found more than one session header node with local " @@ -669,13 +662,10 @@ if (tombstone.IsValid()) new_changes->push_back(tombstone); } else { - // This is a valid old tab node, add it to the tracker and associate - // it. - DVLOG(1) << "Associating local tab " << specifics.tab().tab_id() - << " with node " << specifics.tab_node_id(); - session_tracker_.ReassociateLocalTab(specifics.tab_node_id(), - specifics.tab().tab_id()); - UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime()); + // This is a valid old tab node, add it to the pool so it can be + // reused for reassociation. + local_tab_pool_.AddTabNode(specifics.tab_node_id()); + restored_tabs->push_back(*it); } } } @@ -687,7 +677,7 @@ session_tracker_.LookupAllForeignSessions(&sessions, SyncedSessionTracker::RAW); for (const auto* session : sessions) { - session_tracker_.CleanupForeignSession(session->session_tag); + session_tracker_.CleanupSession(session->session_tag); } UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount", @@ -696,84 +686,70 @@ return found_current_header; } -void SessionsSyncManager::UpdateTrackerWithSpecifics( +void SessionsSyncManager::UpdateTrackerWithForeignSession( const sync_pb::SessionSpecifics& specifics, const base::Time& modification_time) { - std::string session_tag = specifics.session_tag(); - SyncedSession* session = session_tracker_.GetSession(session_tag); + std::string foreign_session_tag = specifics.session_tag(); + DCHECK_NE(foreign_session_tag, current_machine_tag()); + + SyncedSession* foreign_session = + session_tracker_.GetSession(foreign_session_tag); if (specifics.has_header()) { - // Read in the header data for this session. Header data is + // Read in the header data for this foreign session. Header data is // essentially a collection of windows, each of which has an ordered id list // for their tabs. if (!IsValidSessionHeader(specifics.header())) { - LOG(WARNING) << "Ignoring session node with invalid header " - << "and tag " << session_tag << "."; + LOG(WARNING) << "Ignoring foreign session node with invalid header " + << "and tag " << foreign_session_tag << "."; return; } // Load (or create) the SyncedSession object for this client. const sync_pb::SessionHeader& header = specifics.header(); - PopulateSessionHeaderFromSpecifics(header, modification_time, session); + PopulateSessionHeaderFromSpecifics(header, modification_time, + foreign_session); // Reset the tab/window tracking for this session (must do this before // we start calling PutWindowInSession and PutTabInWindow so that all // unused tabs/windows get cleared by the CleanupSession(...) call). - session_tracker_.ResetSessionTracking(session_tag); + session_tracker_.ResetSessionTracking(foreign_session_tag); // Process all the windows and their tab information. int num_windows = header.window_size(); - DVLOG(1) << "Populating " << session_tag << " with " << num_windows + DVLOG(1) << "Associating " << foreign_session_tag << " with " << num_windows << " windows."; for (int i = 0; i < num_windows; ++i) { const sync_pb::SessionWindow& window_s = header.window(i); SessionID::id_type window_id = window_s.window_id(); - session_tracker_.PutWindowInSession(session_tag, window_id); - BuildSyncedSessionFromSpecifics(session_tag, window_s, modification_time, - session->windows[window_id].get()); + session_tracker_.PutWindowInSession(foreign_session_tag, window_id); + BuildSyncedSessionFromSpecifics( + foreign_session_tag, window_s, modification_time, + foreign_session->windows[window_id].get()); } // Delete any closed windows and unused tabs as necessary. - session_tracker_.CleanupForeignSession(session_tag); + session_tracker_.CleanupSession(foreign_session_tag); } else if (specifics.has_tab()) { const sync_pb::SessionTab& tab_s = specifics.tab(); SessionID::id_type tab_id = tab_s.tab_id(); - DVLOG(1) << "Populating " << session_tag << "'s tab id " << tab_id - << " from node " << specifics.tab_node_id(); - // Ensure the tracker is aware of the tab node id. Deleting foreign sessions - // requires deleting all relevant tab nodes, and it's easier to track the - // tab node ids themselves separately from the tab ids. - // - // Note that TabIDs are not stable across restarts of a client. Consider - // this example with two tabs: - // - // http://a.com TabID1 --> NodeIDA - // http://b.com TabID2 --> NodeIDB - // - // After restart, tab ids are reallocated. e.g, one possibility: - // http://a.com TabID2 --> NodeIDA - // http://b.com TabID1 --> NodeIDB - // - // If that happened on a remote client, here we will see an update to - // TabID1 with tab_node_id changing from NodeIDA to NodeIDB, and TabID2 - // with tab_node_id changing from NodeIDB to NodeIDA. - // - // We can also wind up here if we created this tab as an out-of-order - // update to the header node for this session before actually associating - // the tab itself, so the tab node id wasn't available at the time and - // is currently kInvalidTabNodeID. - // - // In both cases, we can safely throw it into the set of node ids. - session_tracker_.OnTabNodeSeen(session_tag, specifics.tab_node_id()); - sessions::SessionTab* tab = session_tracker_.GetTab(session_tag, tab_id); - if (!tab->timestamp.is_null() && tab->timestamp > modification_time) { - DVLOG(1) << "Ignoring " << session_tag << "'s session tab " << tab_id - << " with earlier modification time: " << tab->timestamp - << " vs " << modification_time; + const sessions::SessionTab* existing_tab; + if (session_tracker_.LookupSessionTab(foreign_session_tag, tab_id, + &existing_tab) && + existing_tab->timestamp > modification_time) { + // Force the tracker to remember this tab node id, even if it isn't + // currently being used. + session_tracker_.GetTab(foreign_session_tag, tab_id, + specifics.tab_node_id()); + DVLOG(1) << "Ignoring " << foreign_session_tag << "'s session tab " + << tab_id << " with earlier modification time"; return; } + sessions::SessionTab* tab = session_tracker_.GetTab( + foreign_session_tag, tab_id, specifics.tab_node_id()); + // Update SessionTab based on protobuf. tab->SetFromSyncData(tab_s, modification_time); @@ -782,11 +758,11 @@ RefreshFaviconVisitTimesFromForeignTab(tab_s, modification_time); // Update the last modified time. - if (session->modified_time < modification_time) - session->modified_time = modification_time; + if (foreign_session->modified_time < modification_time) + foreign_session->modified_time = modification_time; } else { - LOG(WARNING) << "Ignoring session node with missing header/tab " - << "fields and tag " << session_tag << "."; + LOG(WARNING) << "Ignoring foreign session node with missing header/tab " + << "fields and tag " << foreign_session_tag << "."; } } @@ -804,6 +780,8 @@ DVLOG(1) << "Creating session sync guid: " << current_machine_tag_; sync_prefs_->SetSyncSessionsGUID(current_machine_tag_); } + + local_tab_pool_.SetMachineTag(current_machine_tag_); } // static @@ -913,7 +891,7 @@ } std::set<int> tab_node_ids_to_delete; - session_tracker_.LookupForeignTabNodeIds(tag, &tab_node_ids_to_delete); + session_tracker_.LookupTabNodeIds(tag, &tab_node_ids_to_delete); if (DisassociateForeignSession(tag)) { // Only tell sync to delete the header if there was one. change_output->push_back( @@ -922,10 +900,10 @@ } for (std::set<int>::const_iterator it = tab_node_ids_to_delete.begin(); it != tab_node_ids_to_delete.end(); ++it) { - change_output->push_back( - syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, - SyncData::CreateLocalDelete(TabNodeIdToTag(tag, *it), - syncer::SESSIONS))); + change_output->push_back(syncer::SyncChange( + FROM_HERE, SyncChange::ACTION_DELETE, + SyncData::CreateLocalDelete(TabNodePool::TabIdToTag(tag, *it), + syncer::SESSIONS))); } if (!sessions_updated_callback_.is_null()) sessions_updated_callback_.Run(); @@ -935,7 +913,7 @@ const std::string& foreign_session_tag) { DCHECK_NE(foreign_session_tag, current_machine_tag()); DVLOG(1) << "Disassociating session " << foreign_session_tag; - return session_tracker_.DeleteForeignSession(foreign_session_tag); + return session_tracker_.DeleteSession(foreign_session_tag); } bool SessionsSyncManager::GetForeignSession( @@ -981,32 +959,66 @@ return success; } +void SessionsSyncManager::LocalTabDelegateToSpecifics( + const SyncedTabDelegate& tab_delegate, + sync_pb::SessionSpecifics* specifics) { + sessions::SessionTab* session_tab = nullptr; + session_tab = session_tracker_.GetTab(current_machine_tag(), + tab_delegate.GetSessionId(), + tab_delegate.GetSyncId()); + SetSessionTabFromDelegate(tab_delegate, base::Time::Now(), session_tab); + SetVariationIds(session_tab); + sync_pb::SessionTab tab_s = session_tab->ToSyncData(); + specifics->set_session_tag(current_machine_tag_); + specifics->set_tab_node_id(tab_delegate.GetSyncId()); + specifics->mutable_tab()->CopyFrom(tab_s); +} + void SessionsSyncManager::AssociateRestoredPlaceholderTab( const SyncedTabDelegate& tab_delegate, SessionID::id_type new_tab_id, SessionID::id_type new_window_id, + const syncer::SyncDataList& restored_tabs, syncer::SyncChangeList* change_output) { DCHECK_NE(tab_delegate.GetSyncId(), TabNodePool::kInvalidTabNodeID); + // Rewrite the tab using |restored_tabs| to retrieve the specifics. + if (restored_tabs.empty()) { + DLOG(WARNING) << "Can't Update tab ID."; + return; + } - // Update tracker with the new association (and inform it of the tab node - // in the process). - session_tracker_.ReassociateLocalTab(tab_delegate.GetSyncId(), new_tab_id); + for (syncer::SyncDataList::const_iterator it = restored_tabs.begin(); + it != restored_tabs.end(); ++it) { + if (it->GetSpecifics().session().tab_node_id() != + tab_delegate.GetSyncId()) { + continue; + } - // Update the window id on the SessionTab itself. - sessions::SessionTab* local_tab = - session_tracker_.GetTab(current_machine_tag(), new_tab_id); - local_tab->window_id.set_id(new_window_id); + sync_pb::EntitySpecifics entity; + sync_pb::SessionSpecifics* specifics = entity.mutable_session(); + specifics->CopyFrom(it->GetSpecifics().session()); + DCHECK(specifics->has_tab()); - // Rewrite the specifics based on the reassociated SessionTab to preserve - // the new tab and window ids. - sync_pb::EntitySpecifics entity; - entity.mutable_session()->CopyFrom(SessionTabToSpecifics( - *local_tab, current_machine_tag(), tab_delegate.GetSyncId())); - syncer::SyncData data = syncer::SyncData::CreateLocalData( - TabNodeIdToTag(current_machine_tag(), tab_delegate.GetSyncId()), - current_session_name_, entity); - change_output->push_back( - syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); + // Update tab node pool with the new association. + local_tab_pool_.ReassociateTabNode(tab_delegate.GetSyncId(), new_tab_id); + TabLink* tab_link = new TabLink(tab_delegate.GetSyncId(), &tab_delegate); + local_tab_map_[new_tab_id] = make_linked_ptr<TabLink>(tab_link); + + if (specifics->tab().tab_id() == new_tab_id && + specifics->tab().window_id() == new_window_id) + return; + + // Either the tab_id or window_id changed (e.g due to session restore), so + // update the sync node. + specifics->mutable_tab()->set_tab_id(new_tab_id); + specifics->mutable_tab()->set_window_id(new_window_id); + syncer::SyncData data = syncer::SyncData::CreateLocalData( + TabNodePool::TabIdToTag(current_machine_tag_, specifics->tab_node_id()), + current_session_name_, entity); + change_output->push_back( + syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data)); + return; + } } // static
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h index 1f6af39..5f2b5981 100644 --- a/components/sync_sessions/sessions_sync_manager.h +++ b/components/sync_sessions/sessions_sync_manager.h
@@ -30,6 +30,7 @@ #include "components/sync_sessions/revisit/page_revisit_broadcaster.h" #include "components/sync_sessions/synced_session.h" #include "components/sync_sessions/synced_session_tracker.h" +#include "components/sync_sessions/tab_node_pool.h" namespace syncer { class LocalDeviceInfoProvider; @@ -117,6 +118,37 @@ void DoGarbageCollection(); private: + // Keep all the links to local tab data in one place. A tab_node_id and tab + // must be passed at creation. The tab_node_id is not mutable, although + // all other fields are. + class TabLink { + public: + TabLink(int tab_node_id, const SyncedTabDelegate* tab) + : tab_node_id_(tab_node_id), tab_(tab) {} + + void set_tab(const SyncedTabDelegate* tab) { tab_ = tab; } + void set_url(const GURL& url) { url_ = url; } + + int tab_node_id() const { return tab_node_id_; } + const SyncedTabDelegate* tab() const { return tab_; } + const GURL& url() const { return url_; } + + private: + // The id for the sync node this tab is stored in. + const int tab_node_id_; + + // The tab object itself. + const SyncedTabDelegate* tab_; + + // The currently visible url of the tab (used for syncing favicons). + GURL url_; + + DISALLOW_COPY_AND_ASSIGN(TabLink); + }; + + // Container for accessing local tab data by tab id. + typedef std::map<SessionID::id_type, linked_ptr<TabLink>> TabLinksMap; + friend class extensions::ExtensionSessionsTest; friend class SessionsSyncManagerTest; FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, PopulateSessionHeader); @@ -150,16 +182,20 @@ void InitializeCurrentMachineTag(const std::string& cache_guid); - // Load and add window or tab data from synced specifics to our internal + // Load and add window or tab data for a foreign session to our internal // tracking. - void UpdateTrackerWithSpecifics(const sync_pb::SessionSpecifics& specifics, - const base::Time& modification_time); + void UpdateTrackerWithForeignSession( + const sync_pb::SessionSpecifics& specifics, + const base::Time& modification_time); // Returns true if |sync_data| contained a header node for the current - // machine, false otherwise. |new_changes| is a link to the SyncChange - // pipeline that exists in the caller's context. This function will append - // necessary changes for processing later. + // machine, false otherwise. |restored_tabs| is a filtered tab-only + // subset of |sync_data| returned by this function for convenience. + // |new_changes| is a link to the SyncChange pipeline that exists in the + // caller's context. This function will append necessary changes for + // processing later. bool InitFromSyncModel(const syncer::SyncDataList& sync_data, + syncer::SyncDataList* restored_tabs, syncer::SyncChangeList* new_changes); // Helper to construct a deletion SyncChange for a *tab node*. @@ -208,6 +244,11 @@ // RELOAD_TABS will additionally cause a resync of all tabs (same as calling // AssociateTabs with a vector of all tabs). // + // |restored_tabs| is a filtered tab-only subset of initial sync data, if + // available (during MergeDataAndStartSyncing). It can be used to obtain + // baseline SessionSpecifics for tabs we can't fully associate any other + // way because they don't yet have a WebContents. + // // Returns: false if the local session's sync nodes were deleted and // reassociation is necessary, true otherwise. // @@ -216,6 +257,7 @@ // changes for processing later. enum ReloadTabsOption { RELOAD_TABS, DONT_RELOAD_TABS }; void AssociateWindows(ReloadTabsOption option, + const syncer::SyncDataList& restored_tabs, syncer::SyncChangeList* change_output); // Loads and reassociates the local tabs referenced in |tabs|. @@ -244,10 +286,17 @@ // as they may have changed after a session was restored. This method // compares new_tab_id and new_window_id against the previously persisted tab // ID and window ID (from our TabNodePool) and updates them if either differs. + // |restored_tabs| is a filtered tab-only subset of initial sync data, if + // available (during MergeDataAndStartSyncing). It can be used to obtain + // baseline SessionSpecifics for tabs we can't fully associate any other + // way because they don't yet have a WebContents. + // TODO(tim): Bug 98892. We should be able to test this for this on android + // even though we didn't have tests for old API-based sessions sync. void AssociateRestoredPlaceholderTab( const SyncedTabDelegate& tab_delegate, SessionID::id_type new_tab_id, SessionID::id_type new_window_id, + const syncer::SyncDataList& restored_tabs, syncer::SyncChangeList* change_output); // Stops and re-starts syncing to rebuild association mappings. Returns true @@ -274,9 +323,15 @@ // The client of this sync sessions datatype. SyncSessionsClient* const sessions_client_; + // Mapping of current open (local) tabs to their sync identifiers. + TabLinksMap local_tab_map_; + SyncedSessionTracker session_tracker_; FaviconCache favicon_cache_; + // Pool of used/available sync nodes associated with local tabs. + TabNodePool local_tab_pool_; + // Tracks whether our local representation of which sync nodes map to what // tabs (belonging to the current local session) is inconsistent. This can // happen if a foreign client deems our session as "stale" and decides to
diff --git a/components/sync_sessions/synced_session_tracker.cc b/components/sync_sessions/synced_session_tracker.cc index 67c075c..a74b877c 100644 --- a/components/sync_sessions/synced_session_tracker.cc +++ b/components/sync_sessions/synced_session_tracker.cc
@@ -53,8 +53,6 @@ void SyncedSessionTracker::SetLocalSessionTag( const std::string& local_session_tag) { - DCHECK(local_session_tag_.empty()); - DCHECK(!local_session_tag.empty()); local_session_tag_ = local_session_tag; } @@ -109,9 +107,8 @@ return true; } -void SyncedSessionTracker::LookupForeignTabNodeIds( - const std::string& session_tag, - std::set<int>* tab_node_ids) const { +void SyncedSessionTracker::LookupTabNodeIds(const std::string& session_tag, + std::set<int>* tab_node_ids) { tab_node_ids->clear(); auto session_iter = synced_session_map_.find(session_tag); if (session_iter != synced_session_map_.end()) { @@ -147,9 +144,7 @@ return synced_session_map_[session_tag].get(); } -bool SyncedSessionTracker::DeleteForeignSession( - const std::string& session_tag) { - DCHECK_NE(local_session_tag_, session_tag); +bool SyncedSessionTracker::DeleteSession(const std::string& session_tag) { unmapped_windows_.erase(session_tag); unmapped_tabs_.erase(session_tag); @@ -193,14 +188,13 @@ void SyncedSessionTracker::DeleteForeignTab(const std::string& session_tag, int tab_node_id) { - DCHECK_NE(local_session_tag_, session_tag); auto session_iter = synced_session_map_.find(session_tag); if (session_iter != synced_session_map_.end()) { session_iter->second->tab_node_ids.erase(tab_node_id); } } -void SyncedSessionTracker::CleanupSessionImpl(const std::string& session_tag) { +void SyncedSessionTracker::CleanupSession(const std::string& session_tag) { for (const auto& window_pair : unmapped_windows_[session_tag]) synced_window_map_[session_tag].erase(window_pair.first); unmapped_windows_[session_tag].clear(); @@ -242,7 +236,7 @@ SessionID::id_type tab_id, size_t tab_index) { // We're called here for two reasons. 1) We've received an update to the - // SessionWindow information of a SessionHeader node for a session, + // SessionWindow information of a SessionHeader node for a foreign session, // and 2) The SessionHeader node for our local session changed. In both cases // we need to update our tracking state to reflect the change. // @@ -252,7 +246,7 @@ // We know that we will eventually process (via GetTab) every single tab node // in the system, so we permit ourselves to use kInvalidTabNodeID here and // rely on the later update to build the mapping (or a restart). - GetTab(session_tag, tab_id); + GetTabImpl(session_tag, tab_id, TabNodePool::kInvalidTabNodeID); // The tab should be unmapped. std::unique_ptr<sessions::SessionTab> tab; @@ -261,11 +255,7 @@ tab = std::move(it->second); unmapped_tabs_[session_tag].erase(it); } - if (!tab) { - LOG(ERROR) << "crbug.com/665196 Attempting to map tab " << tab_id - << " multiple times!"; - return; - } + DCHECK(tab); tab->window_id.set_id(window_id); DVLOG(1) << " - tab " << tab_id << " added to window " << window_id; @@ -279,18 +269,46 @@ window_tabs[tab_index] = std::move(tab); } -void SyncedSessionTracker::OnTabNodeSeen(const std::string& session_tag, - int tab_node_id) { - GetSession(session_tag)->tab_node_ids.insert(tab_node_id); -} - sessions::SessionTab* SyncedSessionTracker::GetTab( const std::string& session_tag, - SessionID::id_type tab_id) { + SessionID::id_type tab_id, + int tab_node_id) { + DCHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id); + return GetTabImpl(session_tag, tab_id, tab_node_id); +} + +sessions::SessionTab* SyncedSessionTracker::GetTabImpl( + const std::string& session_tag, + SessionID::id_type tab_id, + int tab_node_id) { sessions::SessionTab* tab_ptr = nullptr; auto iter = synced_tab_map_[session_tag].find(tab_id); if (iter != synced_tab_map_[session_tag].end()) { tab_ptr = iter->second; + if (tab_node_id != TabNodePool::kInvalidTabNodeID && + tab_id != TabNodePool::kInvalidTabID) { + // TabIDs are not stable across restarts of a client. Consider this + // example with two tabs: + // + // http://a.com TabID1 --> NodeIDA + // http://b.com TabID2 --> NodeIDB + // + // After restart, tab ids are reallocated. e.g, one possibility: + // http://a.com TabID2 --> NodeIDA + // http://b.com TabID1 --> NodeIDB + // + // If that happend on a remote client, here we will see an update to + // TabID1 with tab_node_id changing from NodeIDA to NodeIDB, and TabID2 + // with tab_node_id changing from NodeIDB to NodeIDA. + // + // We can also wind up here if we created this tab as an out-of-order + // update to the header node for this session before actually associating + // the tab itself, so the tab node id wasn't available at the time and + // is currently kInvalidTabNodeID. + // + // In both cases, we can safely throw it into the set of node ids. + GetSession(session_tag)->tab_node_ids.insert(tab_node_id); + } if (VLOG_IS_ON(1)) { std::string title; @@ -310,6 +328,7 @@ tab->tab_id.set_id(tab_id); synced_tab_map_[session_tag][tab_id] = tab_ptr; unmapped_tabs_[session_tag][tab_id] = std::move(tab); + GetSession(session_tag)->tab_node_ids.insert(tab_node_id); DVLOG(1) << "Getting " << (session_tag == local_session_tag_ ? "local session" : session_tag) @@ -320,90 +339,6 @@ return tab_ptr; } -void SyncedSessionTracker::CleanupForeignSession( - const std::string& session_tag) { - DCHECK_NE(local_session_tag_, session_tag); - CleanupSessionImpl(session_tag); -} - -void SyncedSessionTracker::CleanupLocalTabs(std::set<int>* deleted_node_ids) { - DCHECK(!local_session_tag_.empty()); - for (const auto& tab_pair : unmapped_tabs_[local_session_tag_]) - local_tab_pool_.FreeTab(tab_pair.first); - CleanupSessionImpl(local_session_tag_); - local_tab_pool_.CleanupTabNodes(deleted_node_ids); - for (int tab_node_id : *deleted_node_ids) { - GetSession(local_session_tag_)->tab_node_ids.erase(tab_node_id); - } -} - -bool SyncedSessionTracker::GetTabNodeForLocalTab(int tab_id, int* tab_node_id) { - DCHECK(!local_session_tag_.empty()); - // Ensure a placeholder SessionTab is in place, if not already. - // Although we don't need a SessionTab to fulfill this request, this forces - // the - // creation of one if it doesn't already exist. This helps to make sure we're - // tracking this |tab_id| if |local_tab_pool_| is, and everyone's data - // structures - // are kept in sync and as consistent as possible. - GetTab(local_session_tag_, tab_id); // Ignore result. - - bool reused_existing_tab = - local_tab_pool_.GetTabNodeForTab(tab_id, tab_node_id); - DCHECK_NE(TabNodePool::kInvalidTabNodeID, *tab_node_id); - GetSession(local_session_tag_)->tab_node_ids.insert(*tab_node_id); - return reused_existing_tab; -} - -void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id, - SessionID::id_type new_tab_id) { - DCHECK(!local_session_tag_.empty()); - DCHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id); - DCHECK_NE(TabNodePool::kInvalidTabID, new_tab_id); - - SessionID::id_type old_tab_id = - local_tab_pool_.GetTabIdFromTabNodeId(tab_node_id); - local_tab_pool_.ReassociateTabNode(tab_node_id, new_tab_id); - - sessions::SessionTab* tab_ptr = nullptr; - - auto old_tab_iter = synced_tab_map_[local_session_tag_].find(old_tab_id); - if (old_tab_iter != synced_tab_map_[local_session_tag_].end()) { - tab_ptr = old_tab_iter->second; - // Remove the tab from the synced tab map under the old id. - synced_tab_map_[local_session_tag_].erase(old_tab_iter); - } else { - // It's possible a placeholder is already in place for the new tab. If so, - // reuse it, otherwise create a new one (which will default to unmapped). - tab_ptr = GetTab(local_session_tag_, new_tab_id); - } - - // If the old tab is unmapped, update the tab id under which it is indexed. - auto unmapped_tabs_iter = unmapped_tabs_[local_session_tag_].find(old_tab_id); - if (old_tab_id != TabNodePool::kInvalidTabID && - unmapped_tabs_iter != unmapped_tabs_[local_session_tag_].end()) { - std::unique_ptr<sessions::SessionTab> tab = - std::move(unmapped_tabs_iter->second); - DCHECK_EQ(tab_ptr, tab.get()); - unmapped_tabs_[local_session_tag_].erase(unmapped_tabs_iter); - unmapped_tabs_[local_session_tag_][new_tab_id] = std::move(tab); - } - - // Update the tab id. - if (old_tab_id != TabNodePool::kInvalidTabID) { - DVLOG(1) << "Remapped tab " << old_tab_id << " with node " << tab_node_id - << " to tab " << new_tab_id; - } else { - DVLOG(1) << "Mapped new tab node " << tab_node_id << " to tab " - << new_tab_id; - } - tab_ptr->tab_id.set_id(new_tab_id); - - // Add the tab back into the tab map with the new id. - synced_tab_map_[local_session_tag_][new_tab_id] = tab_ptr; - GetSession(local_session_tag_)->tab_node_ids.insert(tab_node_id); -} - void SyncedSessionTracker::Clear() { // Cleanup unmapped tabs and windows. unmapped_windows_.clear(); @@ -417,7 +352,6 @@ synced_window_map_.clear(); synced_tab_map_.clear(); - local_tab_pool_.Clear(); local_session_tag_.clear(); }
diff --git a/components/sync_sessions/synced_session_tracker.h b/components/sync_sessions/synced_session_tracker.h index e27ba21..35123d7 100644 --- a/components/sync_sessions/synced_session_tracker.h +++ b/components/sync_sessions/synced_session_tracker.h
@@ -40,7 +40,8 @@ explicit SyncedSessionTracker(SyncSessionsClient* sessions_client); ~SyncedSessionTracker(); - // **** Synced session/tab query methods. **** + // We track and distinguish the local session from foreign sessions. + void SetLocalSessionTag(const std::string& local_session_tag); // Fill a preallocated vector with all foreign sessions we're tracking (skips // the local session object). SyncedSession ownership remains within the @@ -50,11 +51,6 @@ bool LookupAllForeignSessions(std::vector<const SyncedSession*>* sessions, SessionLookup lookup) const; - // Fills |tab_node_ids| with the tab node ids (see GetTab) for all the tabs* - // associated with the session having tag |session_tag|. - void LookupForeignTabNodeIds(const std::string& session_tag, - std::set<int>* tab_node_ids) const; - // Attempts to look up the session windows associatd with the session given // by |session_tag|. Ownership of SessionWindows stays within the // SyncedSessionTracker. @@ -80,13 +76,15 @@ // this won't create-if-not-present. bool LookupLocalSession(const SyncedSession** output) const; - // **** Methods for manipulating synced sessions and tabs. **** - // Returns a pointer to the SyncedSession object associated with // |session_tag|. If none exists, creates one. Ownership of the // SyncedSession remains within the SyncedSessionTracker. SyncedSession* GetSession(const std::string& session_tag); + // Deletes the session associated with |session_tag| if it exists. + // Returns true if the session existed and was deleted, false otherwise. + bool DeleteSession(const std::string& session_tag); + // Resets the tracking information for the session specified by |session_tag|. // This involves clearing all the windows and tabs from the session, while // keeping pointers saved in the synced_window_map_ and synced_tab_map_. Once @@ -96,6 +94,19 @@ // tabs not owned. void ResetSessionTracking(const std::string& session_tag); + // Tracks the deletion of a foreign tab by removing the given |tab_node_id| + // from the parent session. Doesn't actually remove any tab objects because + // the header may have or may not have already been updated to no longer + // parent this tab. Regardless, when the header is updated then cleanup will + // remove the actual tab data. However, this method always needs to be called + // upon foreign tab deletion, otherwise LookupTabNodeIds(...) may return + // already deleted tab node ids. + void DeleteForeignTab(const std::string& session_tag, int tab_node_id); + + // Deletes those windows and tabs associated with |session_tag| that are no + // longer owned. See ResetSessionTracking(...). + void CleanupSession(const std::string& session_tag); + // Adds the window with id |window_id| to the session specified by // |session_tag|. If none existed for that session, creates one. Similarly, if // the session did not exist yet, creates it. Ownership of the SessionWindow @@ -114,64 +125,18 @@ SessionID::id_type tab_id, size_t tab_index); - // Adds |tab_node_id| to the session specified by |session_tag|, creating that - // session if necessary. This is necessary to ensure that each session has an - // up to date list of tab nodes linked to it for session deletion purposes. - // Note that this won't update the local tab pool, even if the local session - // tag is passed. The tab pool is only updated with new tab nodes when they're - // associated with a tab id (see ReassociateLocalTabNode or GetTabNodeForTab). - void OnTabNodeSeen(const std::string& session_tag, int tab_node_id); - - // Returns a pointer to the SessionTab object associated with - // |tab_id| for the session specified with |session_tag|. - // Note: Ownership of the SessionTab remains within the SyncedSessionTracker. - // TODO(zea): Replace SessionTab with a Sync specific wrapper. - // crbug.com/662597 + // Returns a pointer to the SessionTab object associated with |tab_id| for + // the session specified with |session_tag|. If none exists, creates one. + // Ownership of the SessionTab remains within the SyncedSessionTracker. + // |tab_node_id| must be a valid node id for the node backing this tab. sessions::SessionTab* GetTab(const std::string& session_tag, - SessionID::id_type tab_id); + SessionID::id_type tab_id, + int tab_node_id); - // **** Methods specific to foreign sessions. **** - - // Tracks the deletion of a foreign tab by removing the given |tab_node_id| - // from the parent session. Doesn't actually remove any tab objects because - // the header may have or may not have already been updated to no longer - // parent this tab. Regardless, when the header is updated then cleanup will - // remove the actual tab data. However, this method always needs to be called - // upon foreign tab deletion, otherwise LookupTabNodeIds(...) may return - // already deleted tab node ids. - void DeleteForeignTab(const std::string& session_tag, int tab_node_id); - - // Deletes the session associated with |session_tag| if it exists. - // Returns true if the session existed and was deleted, false otherwise. - bool DeleteForeignSession(const std::string& session_tag); - - // Deletes those windows and tabs associated with |session_tag| that are no - // longer owned. See ResetSessionTracking(...).. - void CleanupForeignSession(const std::string& session_tag); - - // **** Methods specific to the local session. **** - - // Set the local session tag. Must be called before any other local session - // methods are invoked. - void SetLocalSessionTag(const std::string& local_session_tag); - - // Similar to CleanupForeignSession, but also marks any unmapped tabs as free - // in the tab node pool and fills |deleted_node_ids| with the set of locally - // free tab nodes to be deleted. - void CleanupLocalTabs(std::set<int>* deleted_node_ids); - - // Fills |tab_node_id| with a tab node for |tab_id|. Returns true if an - // existing tab node was found, false if there was none and one had to be - // created. - bool GetTabNodeForLocalTab(int tab_id, int* tab_node_id); - - // Reassociates the tab denoted by |tab_node_id| with a new tab id, preserving - // any previous SessionTab object the node was associated with. This is useful - // on restart when sync needs to reassociate tabs from a previous session with - // newly restored tabs (and can be used in conjunction with PutTabInWindow). - void ReassociateLocalTab(int tab_node_id, SessionID::id_type new_tab_id); - - // **** Methods for querying/manipulating overall state ****. + // Fills |tab_node_ids| with the tab node ids (see GetTab) for all the tabs* + // associated with the session having tag |session_tag|. + void LookupTabNodeIds(const std::string& session_tag, + std::set<int>* tab_node_ids); // Free the memory for all dynamically allocated objects and clear the // tracking structures. @@ -195,21 +160,20 @@ } private: - friend class SessionsSyncManagerTest; - friend class SyncedSessionTrackerTest; - - // Implementation of CleanupForeignSession/CleanupLocalTabs. - void CleanupSessionImpl(const std::string& session_tag); + // Implementation for GetTab(...) above, permits invalid tab_node_id. + sessions::SessionTab* GetTabImpl(const std::string& session_tag, + SessionID::id_type tab_id, + int tab_node_id); // The client of the sync sessions datatype. SyncSessionsClient* const sessions_client_; - // The mapping of tab/window to their SessionTab/SessionWindow objects. + // The mapping of tab/window ids to their SessionTab/SessionWindow objects. // The SessionTab/SessionWindow objects referred to may be owned either by the // session in the |synced_session_map_| or be temporarily unmapped and live in // the |unmapped_tabs_|/|unmapped_windows_| collections. // - // Map: session tag -> (tab/window -> SessionTab*/SessionWindow*) + // Map: session tag -> (tab/window id -> SessionTab*/SessionWindow*) std::map<std::string, std::map<SessionID::id_type, sessions::SessionTab*>> synced_tab_map_; std::map<std::string, std::map<SessionID::id_type, sessions::SessionWindow*>> @@ -239,9 +203,6 @@ // sessions. std::string local_session_tag_; - // Pool of used/available sync nodes associated with local tabs. - TabNodePool local_tab_pool_; - DISALLOW_COPY_AND_ASSIGN(SyncedSessionTracker); };
diff --git a/components/sync_sessions/synced_session_tracker_unittest.cc b/components/sync_sessions/synced_session_tracker_unittest.cc index 282baf7..68c1f471 100644 --- a/components/sync_sessions/synced_session_tracker_unittest.cc +++ b/components/sync_sessions/synced_session_tracker_unittest.cc
@@ -17,10 +17,6 @@ const char kValidUrl[] = "http://www.example.com"; const char kInvalidUrl[] = "invalid.url"; -const char kTag[] = "tag"; -const char kTag2[] = "tag2"; -const char kTag3[] = "tag3"; -const char kTitle[] = "title"; } // namespace @@ -30,7 +26,6 @@ ~SyncedSessionTrackerTest() override {} SyncedSessionTracker* GetTracker() { return &tracker_; } - TabNodePool* GetTabNodePool() { return &tracker_.local_tab_pool_; } private: FakeSyncSessionsClient sessions_client_; @@ -38,34 +33,34 @@ }; TEST_F(SyncedSessionTrackerTest, GetSession) { - SyncedSession* session1 = GetTracker()->GetSession(kTag); - SyncedSession* session2 = GetTracker()->GetSession(kTag2); - ASSERT_EQ(session1, GetTracker()->GetSession(kTag)); + SyncedSession* session1 = GetTracker()->GetSession("tag"); + SyncedSession* session2 = GetTracker()->GetSession("tag2"); + ASSERT_EQ(session1, GetTracker()->GetSession("tag")); ASSERT_NE(session1, session2); // Should clean up memory on its own. } TEST_F(SyncedSessionTrackerTest, GetTabUnmapped) { - sessions::SessionTab* tab = GetTracker()->GetTab(kTag, 0); - ASSERT_EQ(tab, GetTracker()->GetTab(kTag, 0)); + sessions::SessionTab* tab = GetTracker()->GetTab("tag", 0, 0); + ASSERT_EQ(tab, GetTracker()->GetTab("tag", 0, 0)); // Should clean up memory on its own. } TEST_F(SyncedSessionTrackerTest, PutWindowInSession) { - GetTracker()->PutWindowInSession(kTag, 0); - SyncedSession* session = GetTracker()->GetSession(kTag); + GetTracker()->PutWindowInSession("tag", 0); + SyncedSession* session = GetTracker()->GetSession("tag"); ASSERT_EQ(1U, session->windows.size()); // Should clean up memory on its own. } TEST_F(SyncedSessionTrackerTest, PutTabInWindow) { - GetTracker()->PutWindowInSession(kTag, 10); - GetTracker()->PutTabInWindow(kTag, 10, 15, + GetTracker()->PutWindowInSession("tag", 10); + GetTracker()->PutTabInWindow("tag", 10, 15, 0); // win id 10, tab id 15, tab ind 0. - SyncedSession* session = GetTracker()->GetSession(kTag); + SyncedSession* session = GetTracker()->GetSession("tag"); ASSERT_EQ(1U, session->windows.size()); ASSERT_EQ(1U, session->windows[10]->tabs.size()); - ASSERT_EQ(GetTracker()->GetTab(kTag, 15), + ASSERT_EQ(GetTracker()->GetTab("tag", 15, 1), session->windows[10]->tabs[0].get()); // Should clean up memory on its own. } @@ -74,28 +69,28 @@ std::vector<const SyncedSession*> sessions; ASSERT_FALSE(GetTracker()->LookupAllForeignSessions( &sessions, SyncedSessionTracker::PRESENTABLE)); - GetTracker()->GetSession(kTag); - GetTracker()->PutWindowInSession(kTag, 0); - GetTracker()->PutTabInWindow(kTag, 0, 15, 0); - sessions::SessionTab* tab = GetTracker()->GetTab(kTag, 15); + GetTracker()->GetSession("tag1"); + GetTracker()->PutWindowInSession("tag1", 0); + GetTracker()->PutTabInWindow("tag1", 0, 15, 0); + sessions::SessionTab* tab = GetTracker()->GetTab("tag1", 15, 1); ASSERT_TRUE(tab); tab->navigations.push_back( sessions::SerializedNavigationEntryTestHelper::CreateNavigation(kValidUrl, - kTitle)); - GetTracker()->GetSession(kTag2); - GetTracker()->GetSession(kTag3); - GetTracker()->PutWindowInSession(kTag3, 0); - GetTracker()->PutTabInWindow(kTag3, 0, 15, 0); - tab = GetTracker()->GetTab(kTag3, 15); + "title")); + GetTracker()->GetSession("tag2"); + GetTracker()->GetSession("tag3"); + GetTracker()->PutWindowInSession("tag3", 0); + GetTracker()->PutTabInWindow("tag3", 0, 15, 0); + tab = GetTracker()->GetTab("tag3", 15, 1); ASSERT_TRUE(tab); tab->navigations.push_back( sessions::SerializedNavigationEntryTestHelper::CreateNavigation( - kInvalidUrl, kTitle)); + kInvalidUrl, "title")); ASSERT_TRUE(GetTracker()->LookupAllForeignSessions( &sessions, SyncedSessionTracker::PRESENTABLE)); // Only the session with a valid window and tab gets returned. ASSERT_EQ(1U, sessions.size()); - ASSERT_EQ(kTag, sessions[0]->session_tag); + ASSERT_EQ("tag1", sessions[0]->session_tag); ASSERT_TRUE(GetTracker()->LookupAllForeignSessions( &sessions, SyncedSessionTracker::RAW)); @@ -104,15 +99,15 @@ TEST_F(SyncedSessionTrackerTest, LookupSessionWindows) { std::vector<const sessions::SessionWindow*> windows; - ASSERT_FALSE(GetTracker()->LookupSessionWindows(kTag, &windows)); - GetTracker()->GetSession(kTag); - GetTracker()->PutWindowInSession(kTag, 0); - GetTracker()->PutWindowInSession(kTag, 2); - GetTracker()->GetSession(kTag2); - GetTracker()->PutWindowInSession(kTag2, 0); - GetTracker()->PutWindowInSession(kTag2, 2); - ASSERT_TRUE(GetTracker()->LookupSessionWindows(kTag, &windows)); - ASSERT_EQ(2U, windows.size()); // Only windows from kTag session. + ASSERT_FALSE(GetTracker()->LookupSessionWindows("tag1", &windows)); + GetTracker()->GetSession("tag1"); + GetTracker()->PutWindowInSession("tag1", 0); + GetTracker()->PutWindowInSession("tag1", 2); + GetTracker()->GetSession("tag2"); + GetTracker()->PutWindowInSession("tag2", 0); + GetTracker()->PutWindowInSession("tag2", 2); + ASSERT_TRUE(GetTracker()->LookupSessionWindows("tag1", &windows)); + ASSERT_EQ(2U, windows.size()); // Only windows from tag1 session. ASSERT_NE((sessions::SessionWindow*)nullptr, windows[0]); ASSERT_NE((sessions::SessionWindow*)nullptr, windows[1]); ASSERT_NE(windows[1], windows[0]); @@ -120,37 +115,40 @@ TEST_F(SyncedSessionTrackerTest, LookupSessionTab) { const sessions::SessionTab* tab; - ASSERT_FALSE(GetTracker()->LookupSessionTab(kTag, 5, &tab)); - GetTracker()->GetSession(kTag); - GetTracker()->PutWindowInSession(kTag, 0); - GetTracker()->PutTabInWindow(kTag, 0, 5, 0); - ASSERT_TRUE(GetTracker()->LookupSessionTab(kTag, 5, &tab)); + ASSERT_FALSE(GetTracker()->LookupSessionTab("tag1", 5, &tab)); + GetTracker()->GetSession("tag1"); + GetTracker()->PutWindowInSession("tag1", 0); + GetTracker()->PutTabInWindow("tag1", 0, 5, 0); + ASSERT_TRUE(GetTracker()->LookupSessionTab("tag1", 5, &tab)); ASSERT_NE((sessions::SessionTab*)nullptr, tab); } TEST_F(SyncedSessionTrackerTest, Complex) { + const std::string tag1 = "tag"; + const std::string tag2 = "tag2"; + const std::string tag3 = "tag3"; std::vector<sessions::SessionTab *> tabs1, tabs2; sessions::SessionTab* temp_tab; ASSERT_TRUE(GetTracker()->Empty()); ASSERT_EQ(0U, GetTracker()->num_synced_sessions()); - ASSERT_EQ(0U, GetTracker()->num_synced_tabs(kTag)); - tabs1.push_back(GetTracker()->GetTab(kTag, 0)); - tabs1.push_back(GetTracker()->GetTab(kTag, 1)); - tabs1.push_back(GetTracker()->GetTab(kTag, 2)); - ASSERT_EQ(3U, GetTracker()->num_synced_tabs(kTag)); - ASSERT_EQ(0U, GetTracker()->num_synced_sessions()); - temp_tab = GetTracker()->GetTab(kTag, 0); // Already created. - ASSERT_EQ(3U, GetTracker()->num_synced_tabs(kTag)); - ASSERT_EQ(0U, GetTracker()->num_synced_sessions()); + ASSERT_EQ(0U, GetTracker()->num_synced_tabs(tag1)); + tabs1.push_back(GetTracker()->GetTab(tag1, 0, 0)); + tabs1.push_back(GetTracker()->GetTab(tag1, 1, 1)); + tabs1.push_back(GetTracker()->GetTab(tag1, 2, 2)); + ASSERT_EQ(3U, GetTracker()->num_synced_tabs(tag1)); + ASSERT_EQ(1U, GetTracker()->num_synced_sessions()); + temp_tab = GetTracker()->GetTab(tag1, 0, 0); // Already created. + ASSERT_EQ(3U, GetTracker()->num_synced_tabs(tag1)); + ASSERT_EQ(1U, GetTracker()->num_synced_sessions()); ASSERT_EQ(tabs1[0], temp_tab); - tabs2.push_back(GetTracker()->GetTab(kTag2, 0)); - ASSERT_EQ(1U, GetTracker()->num_synced_tabs(kTag2)); - ASSERT_EQ(0U, GetTracker()->num_synced_sessions()); - ASSERT_FALSE(GetTracker()->DeleteForeignSession(kTag3)); + tabs2.push_back(GetTracker()->GetTab(tag2, 0, 0)); + ASSERT_EQ(1U, GetTracker()->num_synced_tabs(tag2)); + ASSERT_EQ(2U, GetTracker()->num_synced_sessions()); + ASSERT_FALSE(GetTracker()->DeleteSession(tag3)); - SyncedSession* session = GetTracker()->GetSession(kTag); - SyncedSession* session2 = GetTracker()->GetSession(kTag2); - SyncedSession* session3 = GetTracker()->GetSession(kTag3); + SyncedSession* session = GetTracker()->GetSession(tag1); + SyncedSession* session2 = GetTracker()->GetSession(tag2); + SyncedSession* session3 = GetTracker()->GetSession(tag3); session3->device_type = SyncedSession::TYPE_OTHER; ASSERT_EQ(3U, GetTracker()->num_synced_sessions()); @@ -159,25 +157,25 @@ ASSERT_TRUE(session3); ASSERT_NE(session, session2); ASSERT_NE(session2, session3); - ASSERT_TRUE(GetTracker()->DeleteForeignSession(kTag3)); + ASSERT_TRUE(GetTracker()->DeleteSession(tag3)); ASSERT_EQ(2U, GetTracker()->num_synced_sessions()); - GetTracker()->PutWindowInSession(kTag, 0); // Create a window. - GetTracker()->PutTabInWindow(kTag, 0, 2, 0); // No longer unmapped. - ASSERT_EQ(3U, GetTracker()->num_synced_tabs(kTag)); // Has not changed. + GetTracker()->PutWindowInSession(tag1, 0); // Create a window. + GetTracker()->PutTabInWindow(tag1, 0, 2, 0); // No longer unmapped. + ASSERT_EQ(3U, GetTracker()->num_synced_tabs(tag1)); // Has not changed. const sessions::SessionTab* tab_ptr; - ASSERT_TRUE(GetTracker()->LookupSessionTab(kTag, 0, &tab_ptr)); + ASSERT_TRUE(GetTracker()->LookupSessionTab(tag1, 0, &tab_ptr)); ASSERT_EQ(tab_ptr, tabs1[0]); - ASSERT_TRUE(GetTracker()->LookupSessionTab(kTag, 2, &tab_ptr)); + ASSERT_TRUE(GetTracker()->LookupSessionTab(tag1, 2, &tab_ptr)); ASSERT_EQ(tab_ptr, tabs1[2]); - ASSERT_FALSE(GetTracker()->LookupSessionTab(kTag, 3, &tab_ptr)); + ASSERT_FALSE(GetTracker()->LookupSessionTab(tag1, 3, &tab_ptr)); ASSERT_FALSE(tab_ptr); std::vector<const sessions::SessionWindow*> windows; - ASSERT_TRUE(GetTracker()->LookupSessionWindows(kTag, &windows)); + ASSERT_TRUE(GetTracker()->LookupSessionWindows(tag1, &windows)); ASSERT_EQ(1U, windows.size()); - ASSERT_TRUE(GetTracker()->LookupSessionWindows(kTag2, &windows)); + ASSERT_TRUE(GetTracker()->LookupSessionWindows(tag2, &windows)); ASSERT_EQ(0U, windows.size()); // The sessions don't have valid tabs, lookup should not succeed. @@ -189,8 +187,8 @@ ASSERT_EQ(2U, sessions.size()); GetTracker()->Clear(); - ASSERT_EQ(0U, GetTracker()->num_synced_tabs(kTag)); - ASSERT_EQ(0U, GetTracker()->num_synced_tabs(kTag2)); + ASSERT_EQ(0U, GetTracker()->num_synced_tabs(tag1)); + ASSERT_EQ(0U, GetTracker()->num_synced_tabs(tag2)); ASSERT_EQ(0U, GetTracker()->num_synced_sessions()); } @@ -205,101 +203,107 @@ // More attempts than tabs means we'll sometimes get the same tabs, // sometimes have to allocate new tabs. int rand_tab_num = base::RandInt(0, kMaxTabs); - sessions::SessionTab* tab = GetTracker()->GetTab(tag, rand_tab_num + 1); + sessions::SessionTab* tab = + GetTracker()->GetTab(tag, rand_tab_num, rand_tab_num + 1); ASSERT_TRUE(tab); } } } -TEST_F(SyncedSessionTrackerTest, LookupForeignTabNodeIds) { +TEST_F(SyncedSessionTrackerTest, LookupTabNodeIds) { std::set<int> result; + std::string tag1 = "session1"; + std::string tag2 = "session2"; + std::string tag3 = "session3"; - GetTracker()->OnTabNodeSeen(kTag, 1); - GetTracker()->OnTabNodeSeen(kTag, 2); - GetTracker()->LookupForeignTabNodeIds(kTag, &result); + GetTracker()->GetTab(tag1, 1, 1); + GetTracker()->GetTab(tag1, 2, 2); + GetTracker()->LookupTabNodeIds(tag1, &result); EXPECT_EQ(2U, result.size()); EXPECT_FALSE(result.end() == result.find(1)); EXPECT_FALSE(result.end() == result.find(2)); - GetTracker()->LookupForeignTabNodeIds(kTag2, &result); + GetTracker()->LookupTabNodeIds(tag2, &result); EXPECT_TRUE(result.empty()); - GetTracker()->PutWindowInSession(kTag, 0); - GetTracker()->PutTabInWindow(kTag, 0, 3, 0); - GetTracker()->LookupForeignTabNodeIds(kTag, &result); + GetTracker()->PutWindowInSession(tag1, 0); + GetTracker()->PutTabInWindow(tag1, 0, 3, 0); + GetTracker()->LookupTabNodeIds(tag1, &result); EXPECT_EQ(2U, result.size()); - GetTracker()->OnTabNodeSeen(kTag, 3); - GetTracker()->LookupForeignTabNodeIds(kTag, &result); + GetTracker()->GetTab(tag1, 3, 3); + GetTracker()->LookupTabNodeIds(tag1, &result); EXPECT_EQ(3U, result.size()); EXPECT_FALSE(result.end() == result.find(3)); - GetTracker()->OnTabNodeSeen(kTag2, 21); - GetTracker()->OnTabNodeSeen(kTag2, 22); - GetTracker()->LookupForeignTabNodeIds(kTag2, &result); + GetTracker()->GetTab(tag2, 1, 21); + GetTracker()->GetTab(tag2, 2, 22); + GetTracker()->LookupTabNodeIds(tag2, &result); EXPECT_EQ(2U, result.size()); EXPECT_FALSE(result.end() == result.find(21)); EXPECT_FALSE(result.end() == result.find(22)); - GetTracker()->LookupForeignTabNodeIds(kTag, &result); + GetTracker()->LookupTabNodeIds(tag1, &result); EXPECT_EQ(3U, result.size()); EXPECT_FALSE(result.end() == result.find(1)); EXPECT_FALSE(result.end() == result.find(2)); - GetTracker()->LookupForeignTabNodeIds(kTag3, &result); + GetTracker()->LookupTabNodeIds(tag3, &result); EXPECT_TRUE(result.empty()); - GetTracker()->PutWindowInSession(kTag3, 1); - GetTracker()->PutTabInWindow(kTag3, 1, 5, 0); - GetTracker()->LookupForeignTabNodeIds(kTag3, &result); + GetTracker()->PutWindowInSession(tag3, 1); + GetTracker()->PutTabInWindow(tag3, 1, 5, 0); + GetTracker()->LookupTabNodeIds(tag3, &result); EXPECT_TRUE(result.empty()); - EXPECT_FALSE(GetTracker()->DeleteForeignSession(kTag3)); - GetTracker()->LookupForeignTabNodeIds(kTag3, &result); + EXPECT_FALSE(GetTracker()->DeleteSession(tag3)); + GetTracker()->LookupTabNodeIds(tag3, &result); EXPECT_TRUE(result.empty()); - EXPECT_FALSE(GetTracker()->DeleteForeignSession(kTag)); - GetTracker()->LookupForeignTabNodeIds(kTag, &result); + EXPECT_FALSE(GetTracker()->DeleteSession(tag1)); + GetTracker()->LookupTabNodeIds(tag1, &result); EXPECT_TRUE(result.empty()); - GetTracker()->LookupForeignTabNodeIds(kTag2, &result); + GetTracker()->LookupTabNodeIds(tag2, &result); EXPECT_EQ(2U, result.size()); EXPECT_FALSE(result.end() == result.find(21)); EXPECT_FALSE(result.end() == result.find(22)); - GetTracker()->OnTabNodeSeen(kTag2, 21); - GetTracker()->OnTabNodeSeen(kTag2, 23); - GetTracker()->LookupForeignTabNodeIds(kTag2, &result); + GetTracker()->GetTab(tag2, 1, 21); + GetTracker()->GetTab(tag2, 2, 23); + GetTracker()->LookupTabNodeIds(tag2, &result); EXPECT_EQ(3U, result.size()); EXPECT_FALSE(result.end() == result.find(21)); EXPECT_FALSE(result.end() == result.find(22)); EXPECT_FALSE(result.end() == result.find(23)); - EXPECT_FALSE(GetTracker()->DeleteForeignSession(kTag2)); - GetTracker()->LookupForeignTabNodeIds(kTag2, &result); + EXPECT_FALSE(GetTracker()->DeleteSession(tag2)); + GetTracker()->LookupTabNodeIds(tag2, &result); EXPECT_TRUE(result.empty()); } TEST_F(SyncedSessionTrackerTest, SessionTracking) { ASSERT_TRUE(GetTracker()->Empty()); + std::string tag1 = "tag1"; + std::string tag2 = "tag2"; // Create some session information that is stale. - SyncedSession* session1 = GetTracker()->GetSession(kTag); - GetTracker()->PutWindowInSession(kTag, 0); - GetTracker()->PutTabInWindow(kTag, 0, 0, 0); - GetTracker()->PutTabInWindow(kTag, 0, 1, 1); - GetTracker()->GetTab(kTag, 2)->window_id.set_id(0); // Will be unmapped. - GetTracker()->GetTab(kTag, 3)->window_id.set_id(0); // Will be unmapped. - GetTracker()->PutWindowInSession(kTag, 1); - GetTracker()->PutTabInWindow(kTag, 1, 4, 0); - GetTracker()->PutTabInWindow(kTag, 1, 5, 1); + SyncedSession* session1 = GetTracker()->GetSession(tag1); + GetTracker()->PutWindowInSession(tag1, 0); + GetTracker()->PutTabInWindow(tag1, 0, 0, 0); + GetTracker()->PutTabInWindow(tag1, 0, 1, 1); + GetTracker()->GetTab(tag1, 2, 3U)->window_id.set_id(0); // Will be unmapped. + GetTracker()->GetTab(tag1, 3, 4U)->window_id.set_id(0); // Will be unmapped. + GetTracker()->PutWindowInSession(tag1, 1); + GetTracker()->PutTabInWindow(tag1, 1, 4, 0); + GetTracker()->PutTabInWindow(tag1, 1, 5, 1); ASSERT_EQ(2U, session1->windows.size()); ASSERT_EQ(2U, session1->windows[0]->tabs.size()); ASSERT_EQ(2U, session1->windows[1]->tabs.size()); - ASSERT_EQ(6U, GetTracker()->num_synced_tabs(kTag)); + ASSERT_EQ(6U, GetTracker()->num_synced_tabs(tag1)); // Create a session that should not be affected. - SyncedSession* session2 = GetTracker()->GetSession(kTag2); - GetTracker()->PutWindowInSession(kTag2, 2); - GetTracker()->PutTabInWindow(kTag2, 2, 1, 0); + SyncedSession* session2 = GetTracker()->GetSession(tag2); + GetTracker()->PutWindowInSession(tag2, 2); + GetTracker()->PutTabInWindow(tag2, 2, 1, 0); ASSERT_EQ(1U, session2->windows.size()); ASSERT_EQ(1U, session2->windows[2]->tabs.size()); - ASSERT_EQ(1U, GetTracker()->num_synced_tabs(kTag2)); + ASSERT_EQ(1U, GetTracker()->num_synced_tabs(tag2)); // Reset tracking and get the current windows/tabs. // We simulate moving a tab from one window to another, then closing the @@ -307,18 +311,18 @@ // on the remaining window. // New tab, arrived before meta node so unmapped. - GetTracker()->GetTab(kTag, 6); - GetTracker()->ResetSessionTracking(kTag); - GetTracker()->PutWindowInSession(kTag, 0); - GetTracker()->PutTabInWindow(kTag, 0, 0, 0); + GetTracker()->GetTab(tag1, 6, 7U); + GetTracker()->ResetSessionTracking(tag1); + GetTracker()->PutWindowInSession(tag1, 0); + GetTracker()->PutTabInWindow(tag1, 0, 0, 0); // Tab 1 is closed. - GetTracker()->PutTabInWindow(kTag, 0, 2, 1); // No longer unmapped. + GetTracker()->PutTabInWindow(tag1, 0, 2, 1); // No longer unmapped. // Tab 3 was unmapped and does not get used. - GetTracker()->PutTabInWindow(kTag, 0, 4, 2); // Moved from window 1. + GetTracker()->PutTabInWindow(tag1, 0, 4, 2); // Moved from window 1. // Window 1 was closed, along with tab 5. - GetTracker()->PutTabInWindow(kTag, 0, 6, 3); // No longer unmapped. + GetTracker()->PutTabInWindow(tag1, 0, 6, 3); // No longer unmapped. // Session 2 should not be affected. - GetTracker()->CleanupForeignSession(kTag); + GetTracker()->CleanupSession(tag1); // Verify that only those parts of the session not owned have been removed. ASSERT_EQ(1U, session1->windows.size()); @@ -326,171 +330,39 @@ ASSERT_EQ(1U, session2->windows.size()); ASSERT_EQ(1U, session2->windows[2]->tabs.size()); ASSERT_EQ(2U, GetTracker()->num_synced_sessions()); - ASSERT_EQ(4U, GetTracker()->num_synced_tabs(kTag)); - ASSERT_EQ(1U, GetTracker()->num_synced_tabs(kTag2)); + ASSERT_EQ(4U, GetTracker()->num_synced_tabs(tag1)); + ASSERT_EQ(1U, GetTracker()->num_synced_tabs(tag2)); // All memory should be properly deallocated by destructor for the // SyncedSessionTracker. } TEST_F(SyncedSessionTrackerTest, DeleteForeignTab) { - int tab_node_id_1 = 1; - int tab_node_id_2 = 2; + std::string session_tag = "session_tag"; + int tab_id_1 = 1; + int tab_id_2 = 2; + int tab_node_id_3 = 3; + int tab_node_id_4 = 4; std::set<int> result; - GetTracker()->OnTabNodeSeen(kTag, tab_node_id_1); - GetTracker()->OnTabNodeSeen(kTag, tab_node_id_2); + GetTracker()->GetTab(session_tag, tab_id_1, tab_node_id_3); + GetTracker()->GetTab(session_tag, tab_id_1, tab_node_id_4); + GetTracker()->GetTab(session_tag, tab_id_2, tab_node_id_3); + GetTracker()->GetTab(session_tag, tab_id_2, tab_node_id_4); - GetTracker()->LookupForeignTabNodeIds(kTag, &result); + GetTracker()->LookupTabNodeIds(session_tag, &result); EXPECT_EQ(2U, result.size()); - EXPECT_TRUE(result.find(tab_node_id_1) != result.end()); - EXPECT_TRUE(result.find(tab_node_id_2) != result.end()); + EXPECT_TRUE(result.find(tab_node_id_3) != result.end()); + EXPECT_TRUE(result.find(tab_node_id_4) != result.end()); - GetTracker()->DeleteForeignTab(kTag, tab_node_id_1); - GetTracker()->LookupForeignTabNodeIds(kTag, &result); + GetTracker()->DeleteForeignTab(session_tag, tab_node_id_3); + GetTracker()->LookupTabNodeIds(session_tag, &result); EXPECT_EQ(1U, result.size()); - EXPECT_TRUE(result.find(tab_node_id_2) != result.end()); + EXPECT_TRUE(result.find(tab_node_id_4) != result.end()); - GetTracker()->DeleteForeignTab(kTag, tab_node_id_2); - GetTracker()->LookupForeignTabNodeIds(kTag, &result); + GetTracker()->DeleteForeignTab(session_tag, tab_node_id_4); + GetTracker()->LookupTabNodeIds(session_tag, &result); EXPECT_TRUE(result.empty()); } -TEST_F(SyncedSessionTrackerTest, CleanupLocalTabs) { - std::set<int> free_node_ids; - int tab_node_id = TabNodePool::kInvalidTabNodeID; - const int kWindow1 = 1; - const int kTabNode1 = 1; - const int kTabNode2 = 2; - const int kTabNode3 = 3; - const int kTab1 = 15; - const int kTab2 = 25; - const int kTab3 = 35; - const int kTabIndex = 0; - - GetTracker()->SetLocalSessionTag(kTag); - - // Start with two restored tab nodes. - GetTracker()->ReassociateLocalTab(kTabNode1, kTab1); - GetTracker()->ReassociateLocalTab(kTabNode2, kTab2); - EXPECT_TRUE(GetTabNodePool()->Empty()); - EXPECT_FALSE(GetTabNodePool()->Full()); - EXPECT_EQ(2U, GetTabNodePool()->Capacity()); - - // Associate with no tabs. The tab pool should now be full. - GetTracker()->ResetSessionTracking(kTag); - GetTracker()->CleanupLocalTabs(&free_node_ids); - EXPECT_TRUE(free_node_ids.empty()); - EXPECT_TRUE(GetTabNodePool()->Full()); - - // Associate with only 1 tab open. A tab node should be reused. - GetTracker()->ResetSessionTracking(kTag); - GetTracker()->PutWindowInSession(kTag, kWindow1); - GetTracker()->PutTabInWindow(kTag, kWindow1, kTab1, kTabIndex); - EXPECT_TRUE(GetTracker()->GetTabNodeForLocalTab(kTab1, &tab_node_id)); - GetTracker()->CleanupLocalTabs(&free_node_ids); - EXPECT_TRUE(free_node_ids.empty()); - - // TabNodePool should have one free tab node and one used. - EXPECT_EQ(2U, GetTabNodePool()->Capacity()); - EXPECT_FALSE(GetTabNodePool()->Empty()); - EXPECT_FALSE(GetTabNodePool()->Full()); - - // Simulate a tab opening, which should use the last free tab node. - EXPECT_TRUE(GetTracker()->GetTabNodeForLocalTab(kTab2, &tab_node_id)); - EXPECT_TRUE(GetTabNodePool()->Empty()); - - // Simulate another tab opening, which should create a new associated tab - // node. - EXPECT_FALSE(GetTracker()->GetTabNodeForLocalTab(kTab3, &tab_node_id)); - EXPECT_EQ(kTabNode3, tab_node_id); - EXPECT_EQ(3U, GetTabNodePool()->Capacity()); - EXPECT_TRUE(GetTabNodePool()->Empty()); - - // Fetching the same tab should return the same tab node id. - EXPECT_TRUE(GetTracker()->GetTabNodeForLocalTab(kTab3, &tab_node_id)); - EXPECT_EQ(kTabNode3, tab_node_id); - EXPECT_TRUE(GetTabNodePool()->Empty()); - - // Associate with no tabs. All tabs should be freed again, and the pool - // should now be full. - GetTracker()->ResetSessionTracking(kTag); - GetTracker()->CleanupLocalTabs(&free_node_ids); - EXPECT_TRUE(free_node_ids.empty()); - EXPECT_TRUE(GetTabNodePool()->Full()); - EXPECT_FALSE(GetTabNodePool()->Empty()); -} - -TEST_F(SyncedSessionTrackerTest, ReassociateTabMapped) { - std::set<int> free_node_ids; - const int kWindow1 = 1; - const int kTabNode = 0; - const int kTabIndex = 0; - const int kTab1 = 15; - const int kTab2 = 25; - - // First create the tab normally. - GetTracker()->SetLocalSessionTag(kTag); - GetTracker()->ReassociateLocalTab(kTabNode, kTab1); - - // Map it to a window with the same tab id as it was created with. - GetTracker()->ResetSessionTracking(kTag); - GetTracker()->PutWindowInSession(kTag, kWindow1); - GetTracker()->PutTabInWindow(kTag, kWindow1, kTab1, kTabIndex); - GetTracker()->CleanupLocalTabs(&free_node_ids); - SyncedSession* session = GetTracker()->GetSession(kTag); - ASSERT_EQ(1U, session->windows.size()); - ASSERT_EQ(1U, session->windows[kWindow1]->tabs.size()); - ASSERT_EQ(GetTracker()->GetTab(kTag, kTab1), - session->windows[kWindow1]->tabs[0].get()); - - // Then reassociate with a new tab id. - GetTracker()->ReassociateLocalTab(kTabNode, kTab2); - - // Reset tracking, and put the new tab id into the window. - GetTracker()->ResetSessionTracking(kTag); - GetTracker()->PutWindowInSession(kTag, kWindow1); - GetTracker()->PutTabInWindow(kTag, kWindow1, kTab2, kTabIndex); - GetTracker()->CleanupLocalTabs(&free_node_ids); - EXPECT_TRUE(free_node_ids.empty()); - - // Now that it's been mapped, it should be accessible both via the - // GetSession as well as the GetTab. - ASSERT_EQ(GetTracker()->GetTab(kTag, kTab2), - session->windows[kWindow1]->tabs[0].get()); - ASSERT_EQ(session->tab_node_ids.size(), - session->tab_node_ids.count(kTabNode)); - ASSERT_EQ(1U, GetTabNodePool()->Capacity()); -} - -TEST_F(SyncedSessionTrackerTest, ReassociateTabUnmapped) { - std::set<int> free_node_ids; - const int kWindow1 = 1; - const int kTabNode = 0; - const int kTabIndex = 0; - const int kTab1 = 15; - const int kTab2 = 25; - - // First create the old tab in an unmapped state. - GetTracker()->SetLocalSessionTag(kTag); - GetTracker()->ReassociateLocalTab(kTabNode, kTab1); - - // Map it to a window, but reassociated with a new tab id. - GetTracker()->ResetSessionTracking(kTag); - GetTracker()->ReassociateLocalTab(kTabNode, kTab2); - GetTracker()->PutWindowInSession(kTag, kWindow1); - GetTracker()->PutTabInWindow(kTag, kWindow1, kTab2, kTabIndex); - GetTracker()->CleanupLocalTabs(&free_node_ids); - EXPECT_TRUE(free_node_ids.empty()); - - // Now that it's been mapped, it should be accessible both via the - // GetSession as well as GetTab. - SyncedSession* session = GetTracker()->GetSession(kTag); - ASSERT_EQ(GetTracker()->GetTab(kTag, kTab2), - session->windows[kWindow1]->tabs[0].get()); - ASSERT_EQ(session->tab_node_ids.size(), - session->tab_node_ids.count(kTabNode)); - ASSERT_EQ(1U, GetTabNodePool()->Capacity()); -} - } // namespace sync_sessions
diff --git a/components/sync_sessions/tab_node_pool.cc b/components/sync_sessions/tab_node_pool.cc index f187d23d..4067b92 100644 --- a/components/sync_sessions/tab_node_pool.cc +++ b/components/sync_sessions/tab_node_pool.cc
@@ -4,10 +4,12 @@ #include "components/sync_sessions/tab_node_pool.h" -#include <algorithm> - +#include "base/format_macros.h" #include "base/logging.h" +#include "base/strings/stringprintf.h" #include "components/sync/base/model_type.h" +#include "components/sync/model/sync_change.h" +#include "components/sync/model/sync_data.h" #include "components/sync/protocol/session_specifics.pb.h" #include "components/sync/protocol/sync.pb.h" @@ -24,91 +26,114 @@ TabNodePool::~TabNodePool() {} +// Static +std::string TabNodePool::TabIdToTag(const std::string& machine_tag, + int tab_node_id) { + return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id); +} + void TabNodePool::AddTabNode(int tab_node_id) { DCHECK_GT(tab_node_id, kInvalidTabNodeID); DCHECK(nodeid_tabid_map_.find(tab_node_id) == nodeid_tabid_map_.end()); - DVLOG(1) << "Adding tab node " << tab_node_id << " to pool."; - max_used_tab_node_id_ = std::max(max_used_tab_node_id_, tab_node_id); - free_nodes_pool_.insert(tab_node_id); + unassociated_nodes_.insert(tab_node_id); + if (max_used_tab_node_id_ < tab_node_id) + max_used_tab_node_id_ = tab_node_id; } void TabNodePool::AssociateTabNode(int tab_node_id, SessionID::id_type tab_id) { DCHECK_GT(tab_node_id, kInvalidTabNodeID); - DCHECK_GT(tab_id, kInvalidTabID); - - // This is a new node association, the sync node should be free. - // Remove node from free node pool and then associate it with the tab. - std::set<int>::iterator it = free_nodes_pool_.find(tab_node_id); - DCHECK(it != free_nodes_pool_.end()); - free_nodes_pool_.erase(it); - + // Remove sync node if it is in unassociated nodes pool. + std::set<int>::iterator u_it = unassociated_nodes_.find(tab_node_id); + if (u_it != unassociated_nodes_.end()) { + unassociated_nodes_.erase(u_it); + } else { + // This is a new node association, the sync node should be free. + // Remove node from free node pool and then associate it with the tab. + std::set<int>::iterator it = free_nodes_pool_.find(tab_node_id); + DCHECK(it != free_nodes_pool_.end()); + free_nodes_pool_.erase(it); + } DCHECK(nodeid_tabid_map_.find(tab_node_id) == nodeid_tabid_map_.end()); - DVLOG(1) << "Associating tab node " << tab_node_id << " with tab " << tab_id; nodeid_tabid_map_[tab_node_id] = tab_id; - tabid_nodeid_map_[tab_id] = tab_node_id; } -bool TabNodePool::GetTabNodeForTab(SessionID::id_type tab_id, - int* tab_node_id) { - if (tabid_nodeid_map_.find(tab_id) != tabid_nodeid_map_.end()) { - *tab_node_id = tabid_nodeid_map_[tab_id]; - return true; - } - +int TabNodePool::GetFreeTabNode(syncer::SyncChangeList* append_changes) { + DCHECK_GT(machine_tag_.length(), 0U); + DCHECK(append_changes); if (free_nodes_pool_.empty()) { // Tab pool has no free nodes, allocate new one. - *tab_node_id = ++max_used_tab_node_id_; - AddTabNode(*tab_node_id); + int tab_node_id = ++max_used_tab_node_id_; + std::string tab_node_tag = TabIdToTag(machine_tag_, tab_node_id); - AssociateTabNode(*tab_node_id, tab_id); - return false; + // We fill the new node with just enough data so that in case of a crash/bug + // we can identify the node as our own on re-association and reuse it. + sync_pb::EntitySpecifics entity; + sync_pb::SessionSpecifics* specifics = entity.mutable_session(); + specifics->set_session_tag(machine_tag_); + specifics->set_tab_node_id(tab_node_id); + append_changes->push_back(syncer::SyncChange( + FROM_HERE, syncer::SyncChange::ACTION_ADD, + syncer::SyncData::CreateLocalData(tab_node_tag, tab_node_tag, entity))); + + // Grow the pool by 1 since we created a new node. + DVLOG(1) << "Adding sync node " << tab_node_id << " to tab node id pool"; + free_nodes_pool_.insert(tab_node_id); + return tab_node_id; } else { // Return the next free node. - *tab_node_id = *free_nodes_pool_.begin(); - AssociateTabNode(*tab_node_id, tab_id); - return true; + return *free_nodes_pool_.begin(); } } -void TabNodePool::FreeTab(int tab_id) { - DCHECK_GT(tab_id, kInvalidTabID); - TabIDToTabNodeIDMap::iterator it = tabid_nodeid_map_.find(tab_id); - if (it == tabid_nodeid_map_.end()) { - return; // Already freed. - } +void TabNodePool::FreeTabNode(int tab_node_id, + syncer::SyncChangeList* append_changes) { + DCHECK(append_changes); + TabNodeIDToTabIDMap::iterator it = nodeid_tabid_map_.find(tab_node_id); + DCHECK(it != nodeid_tabid_map_.end()); + nodeid_tabid_map_.erase(it); + FreeTabNodeInternal(tab_node_id, append_changes); +} - int tab_node_id = it->second; - DVLOG(1) << "Freeing tab " << tab_id << " at node " << tab_node_id; - nodeid_tabid_map_.erase(nodeid_tabid_map_.find(tab_node_id)); - tabid_nodeid_map_.erase(it); +void TabNodePool::FreeTabNodeInternal(int tab_node_id, + syncer::SyncChangeList* append_changes) { + DCHECK(free_nodes_pool_.find(tab_node_id) == free_nodes_pool_.end()); + DCHECK(append_changes); free_nodes_pool_.insert(tab_node_id); + + // If number of free nodes exceed kFreeNodesHighWatermark, + // delete sync nodes till number reaches kFreeNodesLowWatermark. + // Note: This logic is to mitigate temporary disassociation issues with old + // clients: http://crbug.com/259918. Newer versions do not need this. + if (free_nodes_pool_.size() > kFreeNodesHighWatermark) { + for (std::set<int>::iterator free_it = free_nodes_pool_.begin(); + free_it != free_nodes_pool_.end();) { + const std::string tab_node_tag = TabIdToTag(machine_tag_, *free_it); + append_changes->push_back(syncer::SyncChange( + FROM_HERE, syncer::SyncChange::ACTION_DELETE, + syncer::SyncData::CreateLocalDelete(tab_node_tag, syncer::SESSIONS))); + free_nodes_pool_.erase(free_it++); + if (free_nodes_pool_.size() <= kFreeNodesLowWatermark) { + return; + } + } + } +} + +bool TabNodePool::IsUnassociatedTabNode(int tab_node_id) { + return unassociated_nodes_.find(tab_node_id) != unassociated_nodes_.end(); } void TabNodePool::ReassociateTabNode(int tab_node_id, SessionID::id_type tab_id) { - DCHECK_GT(tab_node_id, kInvalidTabNodeID); - DCHECK_GT(tab_id, kInvalidTabID); - - auto tabid_it = tabid_nodeid_map_.find(tab_id); - if (tabid_it != tabid_nodeid_map_.end()) { - if (tabid_it->second == tab_node_id) { - return; // Already associated properly. - } else { - // Another node is already associated with this tab. Free it. - FreeTab(tab_id); - } - } - - auto nodeid_it = nodeid_tabid_map_.find(tab_node_id); - if (nodeid_it != nodeid_tabid_map_.end()) { - // This node was already associated with another tab. Free it. - FreeTab(nodeid_it->second); + // Remove from list of unassociated sync_nodes if present. + std::set<int>::iterator it = unassociated_nodes_.find(tab_node_id); + if (it != unassociated_nodes_.end()) { + unassociated_nodes_.erase(it); } else { - // This is a new tab node. Add it before association. - AddTabNode(tab_node_id); + // tab_node_id must be an already associated node. + DCHECK(nodeid_tabid_map_.find(tab_node_id) != nodeid_tabid_map_.end()); } - - AssociateTabNode(tab_node_id, tab_id); + nodeid_tabid_map_[tab_node_id] = tab_id; } SessionID::id_type TabNodePool::GetTabIdFromTabNodeId(int tab_node_id) const { @@ -119,33 +144,27 @@ return kInvalidTabID; } -void TabNodePool::CleanupTabNodes(std::set<int>* deleted_node_ids) { - // If number of free nodes exceed kFreeNodesHighWatermark, - // delete sync nodes till number reaches kFreeNodesLowWatermark. - // Note: This logic is to mitigate temporary disassociation issues with old - // clients: http://crbug.com/259918. Newer versions do not need this. - if (free_nodes_pool_.size() > kFreeNodesHighWatermark) { - for (std::set<int>::iterator free_it = free_nodes_pool_.begin(); - free_it != free_nodes_pool_.end();) { - deleted_node_ids->insert(*free_it); - free_nodes_pool_.erase(free_it++); - if (free_nodes_pool_.size() <= kFreeNodesLowWatermark) { - return; - } - } +void TabNodePool::DeleteUnassociatedTabNodes( + syncer::SyncChangeList* append_changes) { + for (std::set<int>::iterator it = unassociated_nodes_.begin(); + it != unassociated_nodes_.end();) { + FreeTabNodeInternal(*it, append_changes); + unassociated_nodes_.erase(it++); } + DCHECK(unassociated_nodes_.empty()); } // Clear tab pool. void TabNodePool::Clear() { + unassociated_nodes_.clear(); free_nodes_pool_.clear(); nodeid_tabid_map_.clear(); - tabid_nodeid_map_.clear(); max_used_tab_node_id_ = kInvalidTabNodeID; } size_t TabNodePool::Capacity() const { - return nodeid_tabid_map_.size() + free_nodes_pool_.size(); + return nodeid_tabid_map_.size() + unassociated_nodes_.size() + + free_nodes_pool_.size(); } bool TabNodePool::Empty() const { @@ -156,4 +175,8 @@ return nodeid_tabid_map_.empty(); } +void TabNodePool::SetMachineTag(const std::string& machine_tag) { + machine_tag_ = machine_tag; +} + } // namespace sync_sessions
diff --git a/components/sync_sessions/tab_node_pool.h b/components/sync_sessions/tab_node_pool.h index 833daf7..caadc4e 100644 --- a/components/sync_sessions/tab_node_pool.h +++ b/components/sync_sessions/tab_node_pool.h
@@ -13,6 +13,11 @@ #include "base/macros.h" #include "components/sessions/core/session_id.h" +#include "components/sync/model/sync_change_processor.h" + +namespace syncer { +class SyncChangeProcessor; +} // namespace syncer namespace sync_sessions { @@ -22,11 +27,17 @@ // - a tab_id: created by session service, unique to this client // - a tab_node_id: the id for a particular sync tab node. This is used // to generate the sync tab node tag through: -// tab_tag = StringPrintf("%s %d", local_session_tag, tab_node_id); +// tab_tag = StringPrintf("%s_%ui", local_session_tag, tab_node_id); // -// A sync node can be in one of the two states: +// A sync node can be in one of the three states: // 1. Associated : Sync node is used and associated with a tab. -// 2. Free : Sync node is unused. +// 2. Unassociated : Sync node is used but currently unassociated with any tab. +// This is true for old nodes that remain from a session +// restart. Nodes are only unassociated temporarily while the +// model associator figures out which tabs belong to which +// nodes. Eventually any remaining unassociated nodes are +// freed. +// 3. Free : Sync node is unused. class TabNodePool { public: @@ -43,37 +54,65 @@ static const int kInvalidTabNodeID; - // Fills |tab_node_id| with a tab node associated with |tab_id|. - // If tab_id is already associated with a tab_node_id, reuses the existing - // association. Otherwise attempts to get the next free tab node and - // associate it with |tab_id|. If none are available, will create a new tab - // node. - // Returns true if a pre-existing tab node could be reused, false if a new one - // had to be created. - bool GetTabNodeForTab(SessionID::id_type tab_id, int* tab_node_id); + // Build a sync tag from tab_node_id. + static std::string TabIdToTag(const std::string& machine_tag, + int tab_node_id); + + // Returns the tab_node_id for the next free tab node. If none are available, + // creates a new tab node and adds it to free nodes pool. The free node can + // then be used to associate with a tab by calling AssociateTabNode. + // Note: The node is considered free until it has been associated. Repeated + // calls to GetFreeTabNode will return the same id until node has been + // associated. + // |change_output| *must* be provided. It is the TabNodePool's link to + // the SyncChange pipeline that exists in the caller context. If the need + // to create nodes arises in the implementation, associated SyncChanges will + // be appended to this list for later application by the caller via the + // SyncChangeProcessor. + int GetFreeTabNode(syncer::SyncChangeList* change_output); + + // Removes association for |tab_node_id| and returns it to the free node pool. + // |change_output| *must* be provided. It is the TabNodePool's link to + // the SyncChange pipeline that exists in the caller's context. If the need + // to delete sync nodes arises in the implementation, associated SyncChanges + // will be appended to this list for later application by the caller via the + // SyncChangeProcessor. + void FreeTabNode(int tab_node_id, syncer::SyncChangeList* change_output); + + // Associates |tab_node_id| with |tab_id|. |tab_node_id| should either be + // unassociated or free. If |tab_node_id| is free, |tab_node_id| is removed + // from the free node pool In order to associate a non free sync node, + // use ReassociateTabNode. + void AssociateTabNode(int tab_node_id, SessionID::id_type tab_id); + + // Adds |tab_node_id| as an unassociated sync node. + // Note: this should only be called when we discover tab sync nodes from + // previous sessions, not for freeing tab nodes we created through + // GetFreeTabNode (use FreeTabNode below for that). + void AddTabNode(int tab_node_id); // Returns the tab_id for |tab_node_id| if it is associated else returns // kInvalidTabID. SessionID::id_type GetTabIdFromTabNodeId(int tab_node_id) const; - // Reassociates |tab_node_id| with |tab_id|. If |tab_node_id| is not already - // known, it is added to the tab node pool before being associated. + // Reassociates |tab_node_id| with |tab_id|. |tab_node_id| must be either + // associated with a tab or in the set of unassociated nodes. void ReassociateTabNode(int tab_node_id, SessionID::id_type tab_id); - // Removes association for |tab_id| and returns its tab node to the free node - // pool. - void FreeTab(int tab_id); + // Returns true if |tab_node_id| is an unassociated tab node. + bool IsUnassociatedTabNode(int tab_node_id); - // Fills |deleted_node_ids| with any free nodes to be deleted as proscribed - // by the free node low/high watermarks, in order to ensure the free node pool - // does not grow too large. - void CleanupTabNodes(std::set<int>* deleted_node_ids); + // Returns any unassociated nodes to the free node pool. + // |change_output| *must* be provided. It is the TabNodePool's link to + // the SyncChange pipeline that exists in the caller's context. + // See FreeTabNode for more detail. + void DeleteUnassociatedTabNodes(syncer::SyncChangeList* change_output); // Clear tab pool. void Clear(); // Return the number of tab nodes this client currently has allocated - // (including both free and associated nodes). + // (including both free, unassociated and associated nodes) size_t Capacity() const; // Return empty status (all tab nodes are in use). @@ -82,36 +121,41 @@ // Return full status (no tab nodes are in use). bool Full(); + void SetMachineTag(const std::string& machine_tag); + private: friend class SyncTabNodePoolTest; typedef std::map<int, SessionID::id_type> TabNodeIDToTabIDMap; - typedef std::map<SessionID::id_type, int> TabIDToTabNodeIDMap; - // Adds |tab_node_id| to the tab node pool. - // Note: this should only be called when we discover tab sync nodes from - // previous sessions, not for freeing tab nodes we created through - // GetTabNodeForTab (use FreeTab for that). - void AddTabNode(int tab_node_id); - - // Associates |tab_node_id| with |tab_id|. |tab_node_id| must be free. In - // order to associated a non-free tab node, ReassociateTabNode must be - // used. - void AssociateTabNode(int tab_node_id, SessionID::id_type tab_id); + // Adds |tab_node_id| to free node pool. + // |change_output| *must* be provided. It is the TabNodePool's link to + // the SyncChange pipeline that exists in the caller's context. + // See FreeTabNode for more detail. + void FreeTabNodeInternal(int tab_node_id, + syncer::SyncChangeList* change_output); // Stores mapping of node ids associated with tab_ids, these are the used // nodes of tab node pool. // The nodes in the map can be returned to free tab node pool by calling - // FreeTab(..). + // FreeTabNode(tab_node_id). TabNodeIDToTabIDMap nodeid_tabid_map_; - TabIDToTabNodeIDMap tabid_nodeid_map_; // The node ids for the set of free sync nodes. std::set<int> free_nodes_pool_; + // The node ids that are added to pool using AddTabNode and are currently + // not associated with any tab. They can be reassociated using + // ReassociateTabNode. + std::set<int> unassociated_nodes_; + // The maximum used tab_node id for a sync node. A new sync node will always // be created with max_used_tab_node_id_ + 1. int max_used_tab_node_id_; + // The machine tag associated with this tab pool. Used in the title of new + // sync nodes. + std::string machine_tag_; + DISALLOW_COPY_AND_ASSIGN(TabNodePool); };
diff --git a/components/sync_sessions/tab_node_pool_unittest.cc b/components/sync_sessions/tab_node_pool_unittest.cc index 591c8b54..cd125a2 100644 --- a/components/sync_sessions/tab_node_pool_unittest.cc +++ b/components/sync_sessions/tab_node_pool_unittest.cc
@@ -6,13 +6,16 @@ #include <vector> +#include "components/sync/model/sync_change.h" +#include "components/sync/protocol/session_specifics.pb.h" +#include "components/sync/protocol/sync.pb.h" #include "testing/gtest/include/gtest/gtest.h" namespace sync_sessions { class SyncTabNodePoolTest : public testing::Test { protected: - SyncTabNodePoolTest() {} + SyncTabNodePoolTest() { pool_.SetMachineTag("tag"); } int GetMaxUsedTabNodeId() const { return pool_.max_used_tab_node_id_; } @@ -29,127 +32,107 @@ namespace { -const int kTabNodeId1 = 10; -const int kTabNodeId2 = 5; -const int kTabNodeId3 = 1000; -const int kTabId1 = 1; -const int kTabId2 = 2; -const int kTabId3 = 3; - TEST_F(SyncTabNodePoolTest, TabNodeIdIncreases) { - std::set<int> deleted_node_ids; - + syncer::SyncChangeList changes; // max_used_tab_node_ always increases. - pool_.ReassociateTabNode(kTabNodeId1, kTabId1); - EXPECT_EQ(kTabNodeId1, GetMaxUsedTabNodeId()); - pool_.ReassociateTabNode(kTabNodeId2, kTabId2); - EXPECT_EQ(kTabNodeId1, GetMaxUsedTabNodeId()); - pool_.ReassociateTabNode(kTabNodeId3, kTabId3); - EXPECT_EQ(kTabNodeId3, GetMaxUsedTabNodeId()); + pool_.AddTabNode(10); + EXPECT_EQ(10, GetMaxUsedTabNodeId()); + pool_.AddTabNode(5); + EXPECT_EQ(10, GetMaxUsedTabNodeId()); + pool_.AddTabNode(1000); + EXPECT_EQ(1000, GetMaxUsedTabNodeId()); + pool_.ReassociateTabNode(1000, 1); + pool_.ReassociateTabNode(5, 2); + pool_.ReassociateTabNode(10, 3); // Freeing a tab node does not change max_used_tab_node_id_. - pool_.FreeTab(kTabId3); - pool_.CleanupTabNodes(&deleted_node_ids); - EXPECT_TRUE(deleted_node_ids.empty()); - pool_.FreeTab(kTabId2); - pool_.CleanupTabNodes(&deleted_node_ids); - EXPECT_TRUE(deleted_node_ids.empty()); - pool_.FreeTab(kTabId1); - pool_.CleanupTabNodes(&deleted_node_ids); - EXPECT_TRUE(deleted_node_ids.empty()); + pool_.FreeTabNode(1000, &changes); + EXPECT_TRUE(changes.empty()); + pool_.FreeTabNode(5, &changes); + EXPECT_TRUE(changes.empty()); + pool_.FreeTabNode(10, &changes); + EXPECT_TRUE(changes.empty()); for (int i = 0; i < 3; ++i) { - int tab_node_id = -1; - EXPECT_TRUE(pool_.GetTabNodeForTab(i + 1, &tab_node_id)); - EXPECT_EQ(kTabNodeId3, GetMaxUsedTabNodeId()); + pool_.AssociateTabNode(pool_.GetFreeTabNode(&changes), i + 1); + EXPECT_EQ(1000, GetMaxUsedTabNodeId()); } - pool_.CleanupTabNodes(&deleted_node_ids); - EXPECT_TRUE(deleted_node_ids.empty()); - EXPECT_EQ(kTabNodeId3, GetMaxUsedTabNodeId()); + EXPECT_TRUE(changes.empty()); + EXPECT_EQ(1000, GetMaxUsedTabNodeId()); EXPECT_TRUE(pool_.Empty()); } -TEST_F(SyncTabNodePoolTest, Reassociation) { - // Reassociate tab node 1 with tab id 1. - pool_.ReassociateTabNode(kTabNodeId1, kTabId1); - EXPECT_EQ(1U, pool_.Capacity()); +TEST_F(SyncTabNodePoolTest, OldTabNodesAddAndRemove) { + syncer::SyncChangeList changes; + // VerifyOldTabNodes are added. + pool_.AddTabNode(1); + pool_.AddTabNode(2); + EXPECT_EQ(2u, pool_.Capacity()); + EXPECT_TRUE(pool_.Empty()); + EXPECT_TRUE(pool_.IsUnassociatedTabNode(1)); + EXPECT_TRUE(pool_.IsUnassociatedTabNode(2)); + pool_.ReassociateTabNode(1, 2); + EXPECT_TRUE(pool_.Empty()); + pool_.AssociateTabNode(2, 3); + EXPECT_FALSE(pool_.IsUnassociatedTabNode(1)); + EXPECT_FALSE(pool_.IsUnassociatedTabNode(2)); + pool_.FreeTabNode(2, &changes); + EXPECT_TRUE(changes.empty()); + // 2 should be returned to free node pool_. + EXPECT_EQ(2u, pool_.Capacity()); + // Should be able to free 1. + pool_.FreeTabNode(1, &changes); + EXPECT_FALSE(pool_.Empty()); + EXPECT_TRUE(pool_.Full()); + EXPECT_EQ(1, pool_.GetFreeTabNode(&changes)); + EXPECT_TRUE(changes.empty()); + pool_.AssociateTabNode(1, 1); + EXPECT_EQ(2, pool_.GetFreeTabNode(&changes)); + EXPECT_TRUE(changes.empty()); + pool_.AssociateTabNode(2, 1); EXPECT_TRUE(pool_.Empty()); EXPECT_FALSE(pool_.Full()); - EXPECT_EQ(kTabId1, pool_.GetTabIdFromTabNodeId(kTabNodeId1)); - EXPECT_EQ(TabNodePool::kInvalidTabNodeID, - pool_.GetTabIdFromTabNodeId(kTabNodeId2)); - - // Introduce a new tab node associated with the same tab. The old tab node - // should get added to the free pool - pool_.ReassociateTabNode(kTabNodeId2, kTabId1); - EXPECT_EQ(2U, pool_.Capacity()); - EXPECT_FALSE(pool_.Empty()); EXPECT_FALSE(pool_.Full()); - EXPECT_EQ(TabNodePool::kInvalidTabNodeID, - pool_.GetTabIdFromTabNodeId(kTabNodeId1)); - EXPECT_EQ(kTabId1, pool_.GetTabIdFromTabNodeId(kTabNodeId2)); - - // Reassociating the same tab node/tab should have no effect. - pool_.ReassociateTabNode(kTabNodeId2, kTabId1); - EXPECT_EQ(2U, pool_.Capacity()); - EXPECT_FALSE(pool_.Empty()); - EXPECT_FALSE(pool_.Full()); - EXPECT_EQ(TabNodePool::kInvalidTabNodeID, - pool_.GetTabIdFromTabNodeId(kTabNodeId1)); - EXPECT_EQ(kTabId1, pool_.GetTabIdFromTabNodeId(kTabNodeId2)); - - // Reassociating the new tab node with a new tab should just update the - // association tables. - pool_.ReassociateTabNode(kTabNodeId2, kTabId2); - EXPECT_EQ(2U, pool_.Capacity()); - EXPECT_FALSE(pool_.Empty()); - EXPECT_FALSE(pool_.Full()); - EXPECT_EQ(TabNodePool::kInvalidTabNodeID, - pool_.GetTabIdFromTabNodeId(kTabNodeId1)); - EXPECT_EQ(kTabId2, pool_.GetTabIdFromTabNodeId(kTabNodeId2)); - - // Reassociating the first tab node should make the pool empty. - pool_.ReassociateTabNode(kTabNodeId1, kTabId1); - EXPECT_EQ(2U, pool_.Capacity()); - EXPECT_TRUE(pool_.Empty()); - EXPECT_FALSE(pool_.Full()); - EXPECT_EQ(kTabId1, pool_.GetTabIdFromTabNodeId(kTabNodeId1)); - EXPECT_EQ(kTabId2, pool_.GetTabIdFromTabNodeId(kTabNodeId2)); } -TEST_F(SyncTabNodePoolTest, ReassociateThenFree) { - std::set<int> deleted_node_ids; - - // Verify old tab nodes are reassociated correctly. - pool_.ReassociateTabNode(kTabNodeId1, kTabId1); - pool_.ReassociateTabNode(kTabNodeId2, kTabId2); - pool_.ReassociateTabNode(kTabNodeId3, kTabId3); +TEST_F(SyncTabNodePoolTest, OldTabNodesReassociation) { + // VerifyOldTabNodes are reassociated correctly. + pool_.AddTabNode(4); + pool_.AddTabNode(5); + pool_.AddTabNode(6); EXPECT_EQ(3u, pool_.Capacity()); EXPECT_TRUE(pool_.Empty()); - // Free tabs 2 and 3. - pool_.FreeTab(kTabId2); - pool_.FreeTab(kTabId3); - pool_.CleanupTabNodes(&deleted_node_ids); - EXPECT_TRUE(deleted_node_ids.empty()); - // Free node pool should have 2 and 3. + EXPECT_TRUE(pool_.IsUnassociatedTabNode(4)); + pool_.ReassociateTabNode(4, 5); + pool_.AssociateTabNode(5, 6); + pool_.AssociateTabNode(6, 7); + // Free 5 and 6. + syncer::SyncChangeList changes; + pool_.FreeTabNode(5, &changes); + pool_.FreeTabNode(6, &changes); + EXPECT_TRUE(changes.empty()); + // 5 and 6 nodes should not be unassociated. + EXPECT_FALSE(pool_.IsUnassociatedTabNode(5)); + EXPECT_FALSE(pool_.IsUnassociatedTabNode(6)); + // Free node pool should have 5 and 6. EXPECT_FALSE(pool_.Empty()); EXPECT_EQ(3u, pool_.Capacity()); // Free all nodes - pool_.FreeTab(kTabId1); - pool_.CleanupTabNodes(&deleted_node_ids); - EXPECT_TRUE(deleted_node_ids.empty()); + pool_.FreeTabNode(4, &changes); + EXPECT_TRUE(changes.empty()); EXPECT_TRUE(pool_.Full()); std::set<int> free_sync_ids; for (int i = 0; i < 3; ++i) { - int tab_node_id = -1; - EXPECT_TRUE(pool_.GetTabNodeForTab(i, &tab_node_id)); - free_sync_ids.insert(tab_node_id); + free_sync_ids.insert(pool_.GetFreeTabNode(&changes)); + // GetFreeTabNode will return the same value till the node is + // reassociated. + pool_.AssociateTabNode(pool_.GetFreeTabNode(&changes), i + 1); } EXPECT_TRUE(pool_.Empty()); EXPECT_EQ(3u, free_sync_ids.size()); - EXPECT_EQ(1u, free_sync_ids.count(kTabNodeId1)); - EXPECT_EQ(1u, free_sync_ids.count(kTabNodeId2)); - EXPECT_EQ(1u, free_sync_ids.count(kTabNodeId3)); + EXPECT_EQ(1u, free_sync_ids.count(4)); + EXPECT_EQ(1u, free_sync_ids.count(5)); + EXPECT_EQ(1u, free_sync_ids.count(6)); } TEST_F(SyncTabNodePoolTest, Init) { @@ -158,49 +141,106 @@ } TEST_F(SyncTabNodePoolTest, AddGet) { + syncer::SyncChangeList changes; int free_nodes[] = {5, 10}; AddFreeTabNodes(2, free_nodes); EXPECT_EQ(2U, pool_.Capacity()); - int tab_node_id = -1; - EXPECT_TRUE(pool_.GetTabNodeForTab(1, &tab_node_id)); - EXPECT_EQ(5, tab_node_id); + EXPECT_EQ(5, pool_.GetFreeTabNode(&changes)); + pool_.AssociateTabNode(5, 1); EXPECT_FALSE(pool_.Empty()); EXPECT_FALSE(pool_.Full()); EXPECT_EQ(2U, pool_.Capacity()); // 5 is now used, should return 10. - EXPECT_TRUE(pool_.GetTabNodeForTab(2, &tab_node_id)); - EXPECT_EQ(10, tab_node_id); + EXPECT_EQ(10, pool_.GetFreeTabNode(&changes)); } -TEST_F(SyncTabNodePoolTest, GetTabNodeForTabCreate) { - int tab_node_id = -1; - EXPECT_FALSE(pool_.GetTabNodeForTab(1, &tab_node_id)); - EXPECT_EQ(0, tab_node_id); +TEST_F(SyncTabNodePoolTest, All) { + syncer::SyncChangeList changes; + EXPECT_TRUE(pool_.Empty()); + EXPECT_TRUE(pool_.Full()); + EXPECT_EQ(0U, pool_.Capacity()); + + // GetFreeTabNode returns the lowest numbered free node. + EXPECT_EQ(0, pool_.GetFreeTabNode(&changes)); + EXPECT_EQ(1U, changes.size()); + EXPECT_FALSE(pool_.Empty()); + EXPECT_TRUE(pool_.Full()); + EXPECT_EQ(1U, pool_.Capacity()); + + // Associate 5, next free node should be 10. + pool_.AssociateTabNode(0, 1); + EXPECT_EQ(1, pool_.GetFreeTabNode(&changes)); + EXPECT_EQ(2U, changes.size()); + changes.clear(); + pool_.AssociateTabNode(1, 2); + EXPECT_TRUE(pool_.Empty()); + EXPECT_FALSE(pool_.Full()); + EXPECT_EQ(2U, pool_.Capacity()); + // Release them in reverse order. + pool_.FreeTabNode(1, &changes); + pool_.FreeTabNode(0, &changes); + EXPECT_EQ(2U, pool_.Capacity()); + EXPECT_FALSE(pool_.Empty()); + EXPECT_TRUE(pool_.Full()); + EXPECT_EQ(0, pool_.GetFreeTabNode(&changes)); + EXPECT_TRUE(changes.empty()); + EXPECT_FALSE(pool_.Empty()); + EXPECT_TRUE(pool_.Full()); + EXPECT_EQ(2U, pool_.Capacity()); + EXPECT_FALSE(pool_.Empty()); + EXPECT_TRUE(pool_.Full()); + pool_.AssociateTabNode(0, 1); + EXPECT_EQ(2U, pool_.Capacity()); + EXPECT_EQ(1, pool_.GetFreeTabNode(&changes)); + EXPECT_TRUE(changes.empty()); + pool_.AssociateTabNode(1, 2); + EXPECT_TRUE(pool_.Empty()); + EXPECT_FALSE(pool_.Full()); + EXPECT_EQ(2U, pool_.Capacity()); + // Release them again. + pool_.FreeTabNode(1, &changes); + pool_.FreeTabNode(0, &changes); + EXPECT_FALSE(pool_.Empty()); + EXPECT_TRUE(pool_.Full()); + EXPECT_EQ(2U, pool_.Capacity()); + pool_.Clear(); + EXPECT_TRUE(pool_.Empty()); + EXPECT_TRUE(pool_.Full()); + EXPECT_EQ(0U, pool_.Capacity()); +} + +TEST_F(SyncTabNodePoolTest, GetFreeTabNodeCreate) { + syncer::SyncChangeList changes; + EXPECT_EQ(0, pool_.GetFreeTabNode(&changes)); + EXPECT_TRUE(changes[0].IsValid()); + EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type()); + EXPECT_TRUE(changes[0].sync_data().IsValid()); + sync_pb::EntitySpecifics entity = changes[0].sync_data().GetSpecifics(); + sync_pb::SessionSpecifics specifics(entity.session()); + EXPECT_EQ(0, specifics.tab_node_id()); } TEST_F(SyncTabNodePoolTest, TabPoolFreeNodeLimits) { - std::set<int> deleted_node_ids; - // Allocate TabNodePool::kFreeNodesHighWatermark + 1 nodes and verify that // freeing the last node reduces the free node pool size to // kFreeNodesLowWatermark. + syncer::SyncChangeList changes; SessionID session_id; std::vector<int> used_sync_ids; for (size_t i = 1; i <= TabNodePool::kFreeNodesHighWatermark + 1; ++i) { session_id.set_id(i); - int sync_id = -1; - EXPECT_FALSE(pool_.GetTabNodeForTab(i, &sync_id)); + int sync_id = pool_.GetFreeTabNode(&changes); + pool_.AssociateTabNode(sync_id, i); used_sync_ids.push_back(sync_id); } // Free all except one node. + int last_sync_id = used_sync_ids.back(); used_sync_ids.pop_back(); - for (size_t i = 1; i <= used_sync_ids.size(); ++i) { - pool_.FreeTab(i); - pool_.CleanupTabNodes(&deleted_node_ids); - EXPECT_TRUE(deleted_node_ids.empty()); + for (size_t i = 0; i < used_sync_ids.size(); ++i) { + pool_.FreeTabNode(used_sync_ids[i], &changes); } // Except one node all nodes should be in FreeNode pool. @@ -211,11 +251,7 @@ // Freeing the last sync node should drop the free nodes to // kFreeNodesLowWatermark. - pool_.FreeTab(TabNodePool::kFreeNodesHighWatermark + 1); - pool_.CleanupTabNodes(&deleted_node_ids); - EXPECT_EQ(TabNodePool::kFreeNodesHighWatermark + 1 - - TabNodePool::kFreeNodesLowWatermark, - deleted_node_ids.size()); + pool_.FreeTabNode(last_sync_id, &changes); EXPECT_FALSE(pool_.Empty()); EXPECT_TRUE(pool_.Full()); EXPECT_EQ(TabNodePool::kFreeNodesLowWatermark, pool_.Capacity());
diff --git a/components/variations/net/variations_http_headers.cc b/components/variations/net/variations_http_headers.cc index 1729ede..c02faea 100644 --- a/components/variations/net/variations_http_headers.cc +++ b/components/variations/net/variations_http_headers.cc
@@ -48,11 +48,13 @@ NOT_HTTPS, NOT_GOOGLE_DOMAIN, SHOULD_APPEND, + NEITHER_HTTP_HTTPS, + IS_GOOGLE_NOT_HTTPS, URL_VALIDATION_RESULT_SIZE, }; // Checks whether headers should be appended to the |url|, based on the domain -// of |url|. |url| is assumed to be valid, and to have the https scheme. +// of |url|. |url| is assumed to be valid, and to have an http/https scheme. bool IsGoogleDomain(const GURL& url) { if (google_util::IsGoogleDomainUrl(url, google_util::ALLOW_SUBDOMAIN, google_util::ALLOW_NON_STANDARD_PORTS)) { @@ -131,15 +133,20 @@ LogUrlValidationHistogram(INVALID_URL); return false; } - if (!url.SchemeIs("https")) { - LogUrlValidationHistogram(NOT_HTTPS); + if (!url.SchemeIsHTTPOrHTTPS()) { + LogUrlValidationHistogram(NEITHER_HTTP_HTTPS); return false; } if (!IsGoogleDomain(url)) { LogUrlValidationHistogram(NOT_GOOGLE_DOMAIN); return false; } - + // We check https here, rather than before the IsGoogleDomain() check, to know + // how many Google domains are being rejected by the change to https only. + if (!url.SchemeIs("https")) { + LogUrlValidationHistogram(IS_GOOGLE_NOT_HTTPS); + return false; + } LogUrlValidationHistogram(SHOULD_APPEND); return true; }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 827e7ad..78f886f 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -184,6 +184,8 @@ "$target_gen_dir/devtools/protocol/schema.h", "$target_gen_dir/devtools/protocol/security.cc", "$target_gen_dir/devtools/protocol/security.h", + "$target_gen_dir/devtools/protocol/storage.cc", + "$target_gen_dir/devtools/protocol/storage.h", "$target_gen_dir/devtools/protocol/system_info.cc", "$target_gen_dir/devtools/protocol/system_info.h", "$target_gen_dir/devtools/protocol/tethering.cc", @@ -969,8 +971,8 @@ "notifications/platform_notification_context_impl.h", "notifications/type_converters.cc", "notifications/type_converters.h", - "payments/payment_app_context.cc", - "payments/payment_app_context.h", + "payments/payment_app_context_impl.cc", + "payments/payment_app_context_impl.h", "payments/payment_app_manager.cc", "payments/payment_app_manager.h", "permissions/permission_service_context.cc", @@ -1128,6 +1130,8 @@ "renderer_host/media/video_capture_host.h", "renderer_host/media/video_capture_manager.cc", "renderer_host/media/video_capture_manager.h", + "renderer_host/media/video_frame_receiver_on_io_thread.cc", + "renderer_host/media/video_frame_receiver_on_io_thread.h", "renderer_host/native_web_keyboard_event_aura.cc", "renderer_host/native_web_keyboard_event_mac.mm", "renderer_host/offscreen_canvas_compositor_frame_sink.cc",
diff --git a/content/browser/DEPS b/content/browser/DEPS index 6bebd9e4c..d85ab38 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS
@@ -124,7 +124,7 @@ # one separately. "+third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h", "+third_party/WebKit/public/platform/modules/notifications/notification_service.mojom.h", - "+third_party/WebKit/public/platform/modules/shapedetection/facedetection.mojom.h", + "+third_party/WebKit/public/platform/modules/shapedetection/facedetection_provider.mojom.h", # DO NOT ADD ANY CHROME OR COMPONENTS INCLUDES HERE!!! # See https://sites.google.com/a/chromium.org/dev/developers/content-module
diff --git a/content/browser/accessibility/accessibility_ui.cc b/content/browser/accessibility/accessibility_ui.cc index e9e7f851..a8b077a 100644 --- a/content/browser/accessibility/accessibility_ui.cc +++ b/content/browser/accessibility/accessibility_ui.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/command_line.h" #include "base/json/json_writer.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -31,6 +32,7 @@ #include "content/public/browser/render_widget_host_iterator.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui_data_source.h" +#include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" #include "net/base/escape.h" @@ -44,6 +46,19 @@ static const char kPidField[] = "pid"; static const char kAccessibilityModeField[] = "a11y_mode"; +// Global flags +static const char kInternal[] = "internal"; +static const char kNative[] = "native"; +static const char kWeb[] = "web"; +static const char kText[] = "text"; +static const char kScreenReader[] = "screenreader"; +static const char kHTML[] = "html"; + +// Possible global flag values +static const char kOff[]= "off"; +static const char kOn[] = "on"; +static const char kDisabled[] = "disabled"; + namespace content { namespace { @@ -66,8 +81,9 @@ target_data->SetString(kNameField, net::EscapeForHTML(name)); target_data->SetInteger(kPidField, base::GetProcId(handle)); target_data->SetString(kFaviconUrlField, favicon_url.spec()); - target_data->SetInteger(kAccessibilityModeField, - accessibility_mode); + target_data->SetBoolean( + kAccessibilityModeField, + 0 != (accessibility_mode & ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS)); return target_data; } @@ -129,12 +145,29 @@ base::DictionaryValue data; data.Set("list", rvh_list.release()); - data.SetInteger( - "global_a11y_mode", - BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()); - data.SetBoolean( - "global_internal_tree_mode", - g_show_internal_accessibility_tree); + AccessibilityMode mode = + BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode(); + bool disabled = base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableRendererAccessibility); + bool native = 0 != (mode & ACCESSIBILITY_MODE_FLAG_NATIVE_APIS); + bool web = 0 != (mode & ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS); + bool text = 0 != (mode & ACCESSIBILITY_MODE_FLAG_INLINE_TEXT_BOXES); + bool screenreader = 0 != (mode & ACCESSIBILITY_MODE_FLAG_SCREEN_READER); + bool html = 0 != (mode & ACCESSIBILITY_MODE_FLAG_HTML); + + // The "native" and "web" flags are disabled if + // --disable-renderer-accessibility is set. + data.SetString(kNative, disabled ? kDisabled : (native ? kOn : kOff)); + data.SetString(kWeb, disabled ? kDisabled : (web ? kOn : kOff)); + + // The "text", "screenreader", and "html" flags are only meaningful if + // "web" is enabled. + data.SetString(kText, web ? (text ? kOn : kOff) : kDisabled); + data.SetString(kScreenReader, web ? (screenreader ? kOn : kOff) : kDisabled); + data.SetString(kHTML, web ? (html ? kOn : kOff) : kDisabled); + + data.SetString(kInternal, + g_show_internal_accessibility_tree ? kOn : kOff); std::string json_string; base::JSONWriter::Write(data, &json_string); @@ -155,12 +188,8 @@ base::Bind(&AccessibilityUI::ToggleAccessibility, base::Unretained(this))); web_ui->RegisterMessageCallback( - "toggleGlobalAccessibility", - base::Bind(&AccessibilityUI::ToggleGlobalAccessibility, - base::Unretained(this))); - web_ui->RegisterMessageCallback( - "toggleInternalTree", - base::Bind(&AccessibilityUI::ToggleInternalTree, + "setGlobalFlag", + base::Bind(&AccessibilityUI::SetGlobalFlag, base::Unretained(this))); web_ui->RegisterMessageCallback( "requestAccessibilityTree", @@ -210,18 +239,58 @@ } } -void AccessibilityUI::ToggleGlobalAccessibility(const base::ListValue* args) { +void AccessibilityUI::SetGlobalFlag(const base::ListValue* args) { + std::string flag_name_str; + bool enabled; + CHECK_EQ(2U, args->GetSize()); + CHECK(args->GetString(0, &flag_name_str)); + CHECK(args->GetBoolean(1, &enabled)); + + if (flag_name_str == kInternal) { + g_show_internal_accessibility_tree = enabled; + LOG(ERROR) << "INTERNAL: " << g_show_internal_accessibility_tree; + return; + } + + AccessibilityMode new_mode; + if (flag_name_str == kNative) { + new_mode = ACCESSIBILITY_MODE_FLAG_NATIVE_APIS; + } else if (flag_name_str == kWeb) { + new_mode = ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS; + } else if (flag_name_str == kText) { + new_mode = ACCESSIBILITY_MODE_FLAG_INLINE_TEXT_BOXES; + } else if (flag_name_str == kScreenReader) { + new_mode = ACCESSIBILITY_MODE_FLAG_SCREEN_READER; + } else if (flag_name_str == kHTML) { + new_mode = ACCESSIBILITY_MODE_FLAG_HTML; + } else { + NOTREACHED(); + return; + } + + // It doesn't make sense to enable one of the flags that depends on + // web contents without enabling web contents accessibility too. + if (enabled && + (new_mode == ACCESSIBILITY_MODE_FLAG_INLINE_TEXT_BOXES || + new_mode == ACCESSIBILITY_MODE_FLAG_SCREEN_READER || + new_mode == ACCESSIBILITY_MODE_FLAG_HTML)) { + new_mode |= ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS; + } + + // Similarly if you disable web accessibility we should remove all + // flags that depend on it. + if (!enabled && new_mode == ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS) { + new_mode |= ACCESSIBILITY_MODE_FLAG_INLINE_TEXT_BOXES; + new_mode |= ACCESSIBILITY_MODE_FLAG_SCREEN_READER; + new_mode |= ACCESSIBILITY_MODE_FLAG_HTML; + } + BrowserAccessibilityStateImpl* state = BrowserAccessibilityStateImpl::GetInstance(); - AccessibilityMode mode = state->accessibility_mode(); - if ((mode & ACCESSIBILITY_MODE_COMPLETE) != ACCESSIBILITY_MODE_COMPLETE) - state->EnableAccessibility(); + if (enabled) + state->AddAccessibilityModeFlags(new_mode); else - state->DisableAccessibility(); -} - -void AccessibilityUI::ToggleInternalTree(const base::ListValue* args) { - g_show_internal_accessibility_tree = !g_show_internal_accessibility_tree; + state->RemoveAccessibilityModeFlags(new_mode); } void AccessibilityUI::RequestAccessibilityTree(const base::ListValue* args) {
diff --git a/content/browser/accessibility/accessibility_ui.h b/content/browser/accessibility/accessibility_ui.h index 67799cbe..2167b292 100644 --- a/content/browser/accessibility/accessibility_ui.h +++ b/content/browser/accessibility/accessibility_ui.h
@@ -22,8 +22,7 @@ private: void ToggleAccessibility(const base::ListValue* args); - void ToggleGlobalAccessibility(const base::ListValue* args); - void ToggleInternalTree(const base::ListValue* args); + void SetGlobalFlag(const base::ListValue* args); void RequestAccessibilityTree(const base::ListValue* args); DISALLOW_COPY_AND_ASSIGN(AccessibilityUI);
diff --git a/content/browser/devtools/BUILD.gn b/content/browser/devtools/BUILD.gn index 5c0d063..5ef4994 100644 --- a/content/browser/devtools/BUILD.gn +++ b/content/browser/devtools/BUILD.gn
@@ -76,6 +76,8 @@ "protocol/schema.h", "protocol/security.cc", "protocol/security.h", + "protocol/storage.cc", + "protocol/storage.h", "protocol/system_info.cc", "protocol/system_info.h", "protocol/tethering.cc",
diff --git a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py index 00f9c00b6..823d2185c 100755 --- a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py +++ b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -643,7 +643,7 @@ includes = [] fields_init = [] -browser_domains_list = ["Target", "ServiceWorker", "Input", "Storage"] +browser_domains_list = ["Target", "ServiceWorker", "Input"] browser_commands_list = [] async_commands_list = [ "Input.synthesizePinchGesture",
diff --git a/content/browser/devtools/protocol/storage_handler.cc b/content/browser/devtools/protocol/storage_handler.cc index 94415de7..9c3a06ce 100644 --- a/content/browser/devtools/protocol/storage_handler.cc +++ b/content/browser/devtools/protocol/storage_handler.cc
@@ -9,14 +9,12 @@ #include <vector> #include "base/strings/string_split.h" -#include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h" -#include "content/public/browser/render_frame_host.h" +#include "content/browser/frame_host/render_frame_host_impl.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/storage_partition.h" namespace content { -namespace devtools { -namespace storage { +namespace protocol { namespace { static const char kAppCache[] = "appcache"; @@ -31,23 +29,29 @@ static const char kAll[] = "all"; } -typedef DevToolsProtocolClient::Response Response; - StorageHandler::StorageHandler() : host_(nullptr) { } StorageHandler::~StorageHandler() = default; -void StorageHandler::SetRenderFrameHost(RenderFrameHost* host) { +void StorageHandler::Wire(UberDispatcher* dispatcher) { + Storage::Dispatcher::wire(dispatcher, this); +} + +void StorageHandler::SetRenderFrameHost(RenderFrameHostImpl* host) { host_ = host; } +Response StorageHandler::Disable() { + return Response::OK(); +} + Response StorageHandler::ClearDataForOrigin( const std::string& origin, const std::string& storage_types) { if (!host_) - return Response::InternalError("Not connected to host"); + return Response::InternalError(); StoragePartition* partition = host_->GetProcess()->GetStoragePartition(); std::vector<std::string> types = base::SplitString( @@ -87,6 +91,5 @@ return Response::OK(); } -} // namespace storage -} // namespace devtools +} // namespace protocol } // namespace content
diff --git a/content/browser/devtools/protocol/storage_handler.h b/content/browser/devtools/protocol/storage_handler.h index d6f7c65..f203a12 100644 --- a/content/browser/devtools/protocol/storage_handler.h +++ b/content/browser/devtools/protocol/storage_handler.h
@@ -6,37 +6,34 @@ #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_STORAGE_HANDLER_H_ #include "base/macros.h" -#include "content/browser/devtools/devtools_protocol_handler.h" -#include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h" +#include "content/browser/devtools/protocol/storage.h" namespace content { -class RenderFrameHost; +class RenderFrameHostImpl; -namespace devtools { -namespace storage { +namespace protocol { -class StorageHandler { +class StorageHandler : public Storage::Backend { public: - typedef DevToolsProtocolClient::Response Response; - StorageHandler(); - ~StorageHandler(); + ~StorageHandler() override; - void SetRenderFrameHost(RenderFrameHost* host); + void Wire(UberDispatcher*); + void SetRenderFrameHost(RenderFrameHostImpl* host); + Response Disable() override; Response ClearDataForOrigin( const std::string& origin, - const std::string& storage_types); + const std::string& storage_types) override; private: - RenderFrameHost* host_; + RenderFrameHostImpl* host_; DISALLOW_COPY_AND_ASSIGN(StorageHandler); }; -} // namespace storage -} // namespace devtools +} // namespace protocol } // namespace content #endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_STORAGE_HANDLER_H_
diff --git a/content/browser/devtools/protocol_config.json b/content/browser/devtools/protocol_config.json index cb1899f7..c64ec06c 100644 --- a/content/browser/devtools/protocol_config.json +++ b/content/browser/devtools/protocol_config.json
@@ -52,6 +52,9 @@ "domain": "Security" }, { + "domain": "Storage" + }, + { "domain": "SystemInfo", "async": ["getInfo"] },
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc index c7693a5..21f8d39b 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -397,7 +397,6 @@ input_handler_(new devtools::input::InputHandler()), service_worker_handler_( new devtools::service_worker::ServiceWorkerHandler()), - storage_handler_(new devtools::storage::StorageHandler()), target_handler_(new devtools::target::TargetHandler()), frame_trace_recorder_(nullptr), protocol_handler_(new DevToolsProtocolHandler(this)), @@ -408,7 +407,6 @@ DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher(); dispatcher->SetInputHandler(input_handler_.get()); dispatcher->SetServiceWorkerHandler(service_worker_handler_.get()); - dispatcher->SetStorageHandler(storage_handler_.get()); dispatcher->SetTargetHandler(target_handler_.get()); SetPending(host); @@ -511,6 +509,10 @@ security_handler_->SetRenderFrameHost(handlers_frame_host_); } + storage_handler_.reset(new protocol::StorageHandler()); + storage_handler_->Wire(session()->dispatcher()); + storage_handler_->SetRenderFrameHost(handlers_frame_host_); + tracing_handler_.reset(new protocol::TracingHandler( protocol::TracingHandler::Renderer, frame_tree_node_->frame_tree_node_id(), @@ -547,6 +549,8 @@ security_handler_->Disable(); security_handler_.reset(); } + storage_handler_->Disable(); + storage_handler_.reset(); tracing_handler_->Disable(); tracing_handler_.reset();
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h index b17972cd..2b464da 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.h +++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -42,7 +42,6 @@ namespace devtools { namespace input { class InputHandler; } namespace service_worker { class ServiceWorkerHandler; } -namespace storage { class StorageHandler; } namespace target { class TargetHandler; } } @@ -55,6 +54,7 @@ class PageHandler; class SchemaHandler; class SecurityHandler; +class StorageHandler; class TracingHandler; } // namespace protocol @@ -193,8 +193,7 @@ std::unique_ptr<protocol::SecurityHandler> security_handler_; std::unique_ptr<devtools::service_worker::ServiceWorkerHandler> service_worker_handler_; - std::unique_ptr<devtools::storage::StorageHandler> - storage_handler_; + std::unique_ptr<protocol::StorageHandler> storage_handler_; std::unique_ptr<devtools::target::TargetHandler> target_handler_; std::unique_ptr<protocol::TracingHandler> tracing_handler_; std::unique_ptr<protocol::EmulationHandler> emulation_handler_;
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index c845479..07fc760 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -104,7 +104,7 @@ #include "mojo/public/cpp/bindings/strong_binding.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/interface_provider.h" -#include "third_party/WebKit/public/platform/modules/shapedetection/facedetection.mojom.h" +#include "third_party/WebKit/public/platform/modules/shapedetection/facedetection_provider.mojom.h" #include "ui/accessibility/ax_tree.h" #include "ui/accessibility/ax_tree_update.h" #include "ui/gfx/geometry/quad_f.h" @@ -2221,7 +2221,7 @@ #if defined(OS_ANDROID) GetInterfaceRegistry()->AddInterface( GetGlobalJavaInterfaces() - ->CreateInterfaceFactory<blink::mojom::FaceDetection>()); + ->CreateInterfaceFactory<blink::mojom::FaceDetectionProvider>()); GetInterfaceRegistry()->AddInterface( GetGlobalJavaInterfaces()
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc index e114814..83ef7cac 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.cc +++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -337,6 +337,9 @@ return false; } + if (in_process_gpu_) + return true; + if (card_blacklisted_) { if (reason) { *reason = "GPU access is disabled "; @@ -600,8 +603,7 @@ gpu_driver_bug_list_string, gpu_info); - if (command_line->HasSwitch(switches::kSingleProcess) || - command_line->HasSwitch(switches::kInProcessGPU)) { + if (in_process_gpu_) { command_line->AppendSwitch(switches::kDisableGpuWatchdog); AppendGpuCommandLine(command_line, nullptr); } @@ -1105,16 +1107,21 @@ owner_(owner), gpu_process_accessible_(true), is_initialized_(false), - finalized_(false) { + finalized_(false), + in_process_gpu_(false) { DCHECK(owner_); const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - swiftshader_path_ = - base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( - switches::kSwiftShaderPath); + swiftshader_path_ = command_line->GetSwitchValuePath( + switches::kSwiftShaderPath); if (ShouldDisableHardwareAcceleration()) DisableHardwareAcceleration(); + if (command_line->HasSwitch(switches::kSingleProcess) || + command_line->HasSwitch(switches::kInProcessGPU)) { + in_process_gpu_ = true; + } + #if defined(OS_MACOSX) CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, owner_); #endif // OS_MACOSX
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h index 97cd3808..c00d02dc 100644 --- a/content/browser/gpu/gpu_data_manager_impl_private.h +++ b/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -269,6 +269,9 @@ // True if all future Initialize calls should be ignored. bool finalized_; + // True if --single-process or --in-process-gpu is passed in. + bool in_process_gpu_; + std::string disabled_extensions_; // If one tries to call a member before initialization then it is defered
diff --git a/content/browser/indexed_db/list_set.h b/content/browser/indexed_db/list_set.h index 86ef45bb..ab46af20 100644 --- a/content/browser/indexed_db/list_set.h +++ b/content/browser/indexed_db/list_set.h
@@ -70,34 +70,34 @@ public: typedef iterator self_type; typedef T value_type; - typedef T& reference; - typedef T* pointer; + typedef value_type& reference; + typedef value_type* pointer; typedef std::bidirectional_iterator_tag iterator_category; typedef std::ptrdiff_t difference_type; - explicit inline iterator(typename std::list<T>::iterator it) : it_(it) {} - inline self_type& operator++() { + explicit iterator(typename std::list<T>::iterator it) : it_(it) {} + self_type& operator++() { ++it_; return *this; } - inline self_type operator++(int /*ignored*/) { + self_type operator++(int /*ignored*/) { self_type result(*this); ++(*this); return result; } - inline self_type& operator--() { + self_type& operator--() { --it_; return *this; } - inline self_type operator--(int /*ignored*/) { + self_type operator--(int /*ignored*/) { self_type result(*this); --(*this); return result; } - inline value_type& operator*() { return *it_; } - inline value_type* operator->() { return &(*it_); } - inline bool operator==(const iterator& rhs) const { return it_ == rhs.it_; } - inline bool operator!=(const iterator& rhs) const { return it_ != rhs.it_; } + reference operator*() const { return *it_; } + pointer operator->() const { return &(*it_); } + bool operator==(const iterator& rhs) const { return it_ == rhs.it_; } + bool operator!=(const iterator& rhs) const { return it_ != rhs.it_; } inline operator const_iterator() const { return const_iterator(it_); } @@ -109,39 +109,35 @@ public: typedef const_iterator self_type; typedef T value_type; - typedef T& reference; - typedef T* pointer; + typedef const value_type& reference; + typedef const value_type* pointer; typedef std::bidirectional_iterator_tag iterator_category; typedef std::ptrdiff_t difference_type; explicit inline const_iterator(typename std::list<T>::const_iterator it) : it_(it) {} - inline self_type& operator++() { + self_type& operator++() { ++it_; return *this; } - inline self_type operator++(int ignored) { + self_type operator++(int ignored) { self_type result(*this); ++(*this); return result; } - inline self_type& operator--() { + self_type& operator--() { --it_; return *this; } - inline self_type operator--(int ignored) { + self_type operator--(int ignored) { self_type result(*this); --(*this); return result; } - inline const value_type& operator*() { return *it_; } - inline const value_type* operator->() { return &(*it_); } - inline bool operator==(const const_iterator& rhs) const { - return it_ == rhs.it_; - } - inline bool operator!=(const const_iterator& rhs) const { - return it_ != rhs.it_; - } + reference operator*() const { return *it_; } + pointer operator->() const { return &(*it_); } + bool operator==(const const_iterator& rhs) const { return it_ == rhs.it_; } + bool operator!=(const const_iterator& rhs) const { return it_ != rhs.it_; } private: typename std::list<T>::const_iterator it_;
diff --git a/content/browser/payments/payment_app_context.cc b/content/browser/payments/payment_app_context_impl.cc similarity index 63% rename from content/browser/payments/payment_app_context.cc rename to content/browser/payments/payment_app_context_impl.cc index 8fc961a52..2565567a 100644 --- a/content/browser/payments/payment_app_context.cc +++ b/content/browser/payments/payment_app_context_impl.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 "content/browser/payments/payment_app_context.h" +#include "content/browser/payments/payment_app_context_impl.h" #include <utility> @@ -15,52 +15,60 @@ namespace content { -PaymentAppContext::PaymentAppContext( +PaymentAppContextImpl::PaymentAppContextImpl( scoped_refptr<ServiceWorkerContextWrapper> service_worker_context) : service_worker_context_(std::move(service_worker_context)) { DCHECK_CURRENTLY_ON(BrowserThread::UI); } -PaymentAppContext::~PaymentAppContext() { - DCHECK(services_.empty()); -} - -void PaymentAppContext::Shutdown() { +void PaymentAppContextImpl::Shutdown() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&PaymentAppContext::ShutdownOnIO, this)); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&PaymentAppContextImpl::ShutdownOnIO, this)); } -void PaymentAppContext::CreateService( +void PaymentAppContextImpl::CreateService( mojo::InterfaceRequest<payments::mojom::PaymentAppManager> request) { DCHECK_CURRENTLY_ON(BrowserThread::UI); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&PaymentAppContext::CreateServiceOnIOThread, this, + base::Bind(&PaymentAppContextImpl::CreateServiceOnIOThread, this, base::Passed(&request))); } -void PaymentAppContext::ServiceHadConnectionError(PaymentAppManager* service) { +void PaymentAppContextImpl::ServiceHadConnectionError( + PaymentAppManager* service) { DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(base::ContainsKey(services_, service)); services_.erase(service); } -ServiceWorkerContextWrapper* PaymentAppContext::service_worker_context() const { +ServiceWorkerContextWrapper* PaymentAppContextImpl::service_worker_context() + const { return service_worker_context_.get(); } -void PaymentAppContext::CreateServiceOnIOThread( +void PaymentAppContextImpl::GetAllManifests( + const GetAllManifestsCallback& callback) { + NOTIMPLEMENTED(); +} + +PaymentAppContextImpl::~PaymentAppContextImpl() { + DCHECK(services_.empty()); +} + +void PaymentAppContextImpl::CreateServiceOnIOThread( mojo::InterfaceRequest<payments::mojom::PaymentAppManager> request) { DCHECK_CURRENTLY_ON(BrowserThread::IO); PaymentAppManager* service = new PaymentAppManager(this, std::move(request)); services_[service] = base::WrapUnique(service); } -void PaymentAppContext::ShutdownOnIO() { +void PaymentAppContextImpl::ShutdownOnIO() { DCHECK_CURRENTLY_ON(BrowserThread::IO); services_.clear();
diff --git a/content/browser/payments/payment_app_context.h b/content/browser/payments/payment_app_context_impl.h similarity index 68% rename from content/browser/payments/payment_app_context.h rename to content/browser/payments/payment_app_context_impl.h index 3572a8b..e3fd583 100644 --- a/content/browser/payments/payment_app_context.h +++ b/content/browser/payments/payment_app_context_impl.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 CONTENT_BROWSER_PAYMENTS_PAYMENT_APP_CONTEXT_H_ -#define CONTENT_BROWSER_PAYMENTS_PAYMENT_APP_CONTEXT_H_ +#ifndef CONTENT_BROWSER_PAYMENTS_PAYMENT_APP_CONTEXT_IMPL_H_ +#define CONTENT_BROWSER_PAYMENTS_PAYMENT_APP_CONTEXT_IMPL_H_ #include <map> #include <memory> @@ -12,16 +12,18 @@ #include "base/memory/ref_counted.h" #include "components/payments/payment_app.mojom.h" #include "content/common/content_export.h" +#include "content/public/browser/payment_app_context.h" namespace content { class PaymentAppManager; class ServiceWorkerContextWrapper; -class CONTENT_EXPORT PaymentAppContext - : public base::RefCountedThreadSafe<PaymentAppContext> { +class CONTENT_EXPORT PaymentAppContextImpl + : public base::RefCountedThreadSafe<PaymentAppContextImpl>, + NON_EXPORTED_BASE(public PaymentAppContext) { public: - explicit PaymentAppContext( + explicit PaymentAppContextImpl( scoped_refptr<ServiceWorkerContextWrapper> service_worker_context); // Shutdown must be called before deleting this. Call on the UI thread. @@ -38,12 +40,16 @@ ServiceWorkerContextWrapper* service_worker_context() const; + // PaymentAppContext implementation: + void GetAllManifests(const GetAllManifestsCallback& callback) override; + protected: - friend class base::RefCountedThreadSafe<PaymentAppContext>; friend class PaymentAppManagerTest; - virtual ~PaymentAppContext(); private: + friend class base::RefCountedThreadSafe<PaymentAppContextImpl>; + ~PaymentAppContextImpl() override; + void CreateServiceOnIOThread( mojo::InterfaceRequest<payments::mojom::PaymentAppManager> request); @@ -56,9 +62,9 @@ // ServiceHadConnectionError. Only accessed on the IO thread. std::map<PaymentAppManager*, std::unique_ptr<PaymentAppManager>> services_; - DISALLOW_COPY_AND_ASSIGN(PaymentAppContext); + DISALLOW_COPY_AND_ASSIGN(PaymentAppContextImpl); }; } // namespace content -#endif // CONTENT_BROWSER_PAYMENTS_PAYMENT_APP_CONTEXT_H_ +#endif // CONTENT_BROWSER_PAYMENTS_PAYMENT_APP_CONTEXT_IMPL_H_
diff --git a/content/browser/payments/payment_app_manager.cc b/content/browser/payments/payment_app_manager.cc index bb75263c..dc98a02 100644 --- a/content/browser/payments/payment_app_manager.cc +++ b/content/browser/payments/payment_app_manager.cc
@@ -9,7 +9,7 @@ #include "base/bind.h" #include "base/optional.h" #include "content/browser/payments/payment_app.pb.h" -#include "content/browser/payments/payment_app_context.h" +#include "content/browser/payments/payment_app_context_impl.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/public/browser/browser_thread.h" @@ -26,7 +26,7 @@ } PaymentAppManager::PaymentAppManager( - PaymentAppContext* payment_app_context, + PaymentAppContextImpl* payment_app_context, mojo::InterfaceRequest<payments::mojom::PaymentAppManager> request) : payment_app_context_(payment_app_context), binding_(this, std::move(request)),
diff --git a/content/browser/payments/payment_app_manager.h b/content/browser/payments/payment_app_manager.h index 28d2e85..8f68347 100644 --- a/content/browser/payments/payment_app_manager.h +++ b/content/browser/payments/payment_app_manager.h
@@ -16,14 +16,14 @@ namespace content { -class PaymentAppContext; +class PaymentAppContextImpl; class ServiceWorkerRegistration; class CONTENT_EXPORT PaymentAppManager : public NON_EXPORTED_BASE(payments::mojom::PaymentAppManager) { public: PaymentAppManager( - PaymentAppContext* payment_app_context, + PaymentAppContextImpl* payment_app_context, mojo::InterfaceRequest<payments::mojom::PaymentAppManager> request); ~PaymentAppManager() override; @@ -59,8 +59,8 @@ // Called when an error is detected on binding_. void OnConnectionError(); - // PaymentAppContext owns PaymentAppManager - PaymentAppContext* payment_app_context_; + // PaymentAppContextImpl owns PaymentAppManager + PaymentAppContextImpl* payment_app_context_; mojo::Binding<payments::mojom::PaymentAppManager> binding_;
diff --git a/content/browser/payments/payment_app_manager_unittest.cc b/content/browser/payments/payment_app_manager_unittest.cc index d29d395..e67b57c 100644 --- a/content/browser/payments/payment_app_manager_unittest.cc +++ b/content/browser/payments/payment_app_manager_unittest.cc
@@ -67,7 +67,7 @@ storage_partition_impl_.get()); payment_app_context_ = - new PaymentAppContext(embedded_worker_helper_->context_wrapper()); + new PaymentAppContextImpl(embedded_worker_helper_->context_wrapper()); bool called = false; embedded_worker_helper_->context()->RegisterServiceWorker( @@ -109,7 +109,7 @@ std::unique_ptr<EmbeddedWorkerTestHelper> embedded_worker_helper_; std::unique_ptr<StoragePartitionImpl> storage_partition_impl_; int64_t sw_registration_id_; - scoped_refptr<PaymentAppContext> payment_app_context_; + scoped_refptr<PaymentAppContextImpl> payment_app_context_; payments::mojom::PaymentAppManagerPtr service_; // Owned by payment_app_context_.
diff --git a/content/browser/renderer_host/media/OWNERS b/content/browser/renderer_host/media/OWNERS index 8ac77eba..a8e56056 100644 --- a/content/browser/renderer_host/media/OWNERS +++ b/content/browser/renderer_host/media/OWNERS
@@ -6,4 +6,5 @@ per-file gpu_memory*=mcasas@chromium.org per-file shared_memory*=mcasas@chromium.org -per-file video_capture*=mcasas@chromium.org +per-file video_*=mcasas@chromium.org +per-file video_*=chfremer@chromium.org
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc index 5f226b6..e39cc610 100644 --- a/content/browser/renderer_host/media/video_capture_controller.cc +++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -18,12 +18,11 @@ #include "build/build_config.h" #include "components/display_compositor/gl_helper.h" #include "content/browser/renderer_host/media/media_stream_manager.h" -#include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h" #include "content/browser/renderer_host/media/video_capture_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_switches.h" #include "media/base/video_frame.h" -#include "media/capture/video/video_capture_buffer_pool_impl.h" +#include "media/capture/video/video_capture_buffer_pool.h" #include "media/capture/video/video_capture_buffer_tracker_factory_impl.h" #include "media/capture/video/video_capture_device_client.h" @@ -46,50 +45,6 @@ name, \ (height) ? ((width) * 100) / (height) : kInfiniteRatio); -std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( - const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { - return base::MakeUnique<VideoCaptureGpuJpegDecoder>(decode_done_cb); -} - -// Decorator for media::VideoFrameReceiver that forwards all incoming calls -// to the Browser IO thread. -class VideoFrameReceiverOnIOThread : public media::VideoFrameReceiver { - public: - explicit VideoFrameReceiverOnIOThread( - const base::WeakPtr<VideoFrameReceiver>& receiver) - : receiver_(receiver) {} - - void OnIncomingCapturedVideoFrame( - std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer, - scoped_refptr<media::VideoFrame> frame) override { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&VideoFrameReceiver::OnIncomingCapturedVideoFrame, receiver_, - base::Passed(&buffer), std::move(frame))); - } - - void OnError() override { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&VideoFrameReceiver::OnError, receiver_)); - } - - void OnLog(const std::string& message) override { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&VideoFrameReceiver::OnLog, receiver_, message)); - } - - void OnBufferDestroyed(int buffer_id_to_drop) override { - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&VideoFrameReceiver::OnBufferDestroyed, - receiver_, buffer_id_to_drop)); - } - - private: - base::WeakPtr<VideoFrameReceiver> receiver_; -}; - } // anonymous namespace struct VideoCaptureController::ControllerClient { @@ -140,12 +95,12 @@ int buffer_id, int frame_feedback_id, media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer, - scoped_refptr<media::VideoCaptureBufferPool> buffer_pool, + media::FrameBufferPool* frame_buffer_pool, scoped_refptr<media::VideoFrame> frame) : buffer_id_(buffer_id), frame_feedback_id_(frame_feedback_id), consumer_feedback_observer_(consumer_feedback_observer), - buffer_pool_(std::move(buffer_pool)), + frame_buffer_pool_(frame_buffer_pool), frame_(std::move(frame)), max_consumer_utilization_( media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded), @@ -166,7 +121,8 @@ void VideoCaptureController::BufferState::IncreaseConsumerCount() { if (consumer_hold_count_ == 0) - buffer_pool_->HoldForConsumers(buffer_id_, 1); + if (frame_buffer_pool_ != nullptr) + frame_buffer_pool_->SetBufferHold(buffer_id_); consumer_hold_count_++; } @@ -179,7 +135,8 @@ consumer_feedback_observer_->OnUtilizationReport( frame_feedback_id_, max_consumer_utilization_); } - buffer_pool_->RelinquishConsumerHold(buffer_id_, 1); + if (frame_buffer_pool_ != nullptr) + frame_buffer_pool_->ReleaseBufferHold(buffer_id_); max_consumer_utilization_ = media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded; } @@ -194,10 +151,13 @@ consumer_feedback_observer_ = consumer_feedback_observer; } -VideoCaptureController::VideoCaptureController(int max_buffers) - : buffer_pool_(new media::VideoCaptureBufferPoolImpl( - base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), - max_buffers)), +void VideoCaptureController::BufferState::SetFrameBufferPool( + media::FrameBufferPool* frame_buffer_pool) { + frame_buffer_pool_ = frame_buffer_pool; +} + +VideoCaptureController::VideoCaptureController() + : frame_buffer_pool_(nullptr), consumer_feedback_observer_(nullptr), state_(VIDEO_CAPTURE_STATE_STARTED), has_received_frames_(false), @@ -205,11 +165,22 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); } +VideoCaptureController::~VideoCaptureController() = default; + base::WeakPtr<VideoCaptureController> VideoCaptureController::GetWeakPtrForIOThread() { return weak_ptr_factory_.GetWeakPtr(); } +void VideoCaptureController::SetFrameBufferPool( + std::unique_ptr<media::FrameBufferPool> frame_buffer_pool) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + frame_buffer_pool_ = std::move(frame_buffer_pool); + // Update existing BufferState entries. + for (auto& entry : buffer_id_to_state_map_) + entry.second.SetFrameBufferPool(frame_buffer_pool_.get()); +} + void VideoCaptureController::SetConsumerFeedbackObserver( std::unique_ptr<media::VideoFrameConsumerFeedbackObserver> consumer_feedback_observer) { @@ -220,18 +191,6 @@ entry.second.SetConsumerFeedbackObserver(consumer_feedback_observer_.get()); } -std::unique_ptr<media::VideoCaptureDevice::Client> -VideoCaptureController::NewDeviceClient() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - return base::MakeUnique<media::VideoCaptureDeviceClient>( - base::MakeUnique<VideoFrameReceiverOnIOThread>( - this->GetWeakPtrForIOThread()), - buffer_pool_, - base::Bind(&CreateGpuJpegDecoder, - base::Bind(&VideoFrameReceiver::OnIncomingCapturedVideoFrame, - this->GetWeakPtrForIOThread()))); -} - void VideoCaptureController::AddClient( VideoCaptureControllerID id, VideoCaptureControllerEventHandler* event_handler, @@ -410,13 +369,11 @@ return video_capture_format_; } -VideoCaptureController::~VideoCaptureController() { -} - void VideoCaptureController::OnIncomingCapturedVideoFrame( std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer, scoped_refptr<VideoFrame> frame) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(frame_buffer_pool_); const int buffer_id = buffer->id(); DCHECK_NE(buffer_id, media::VideoCaptureBufferPool::kInvalidId); @@ -426,7 +383,7 @@ .insert(std::make_pair( buffer_id, BufferState(buffer_id, buffer->frame_feedback_id(), consumer_feedback_observer_.get(), - buffer_pool_, frame))) + frame_buffer_pool_.get(), frame))) .first; BufferState& buffer_state = it->second; DCHECK(buffer_state.HasZeroConsumerHoldCount()); @@ -520,6 +477,7 @@ void VideoCaptureController::OnBufferDestroyed(int buffer_id_to_drop) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(frame_buffer_pool_); for (const auto& client : controller_clients_) { if (client->session_closed) @@ -547,7 +505,7 @@ const int buffer_id = buffer->id(); mojo::ScopedSharedBufferHandle handle = - buffer_pool_->GetHandleForTransit(buffer_id); + frame_buffer_pool_->GetHandleForTransit(buffer_id); client->event_handler->OnBufferCreated(client->controller_id, std::move(handle), buffer->mapped_size(), buffer_id);
diff --git a/content/browser/renderer_host/media/video_capture_controller.h b/content/browser/renderer_host/media/video_capture_controller.h index b1a455f..0e54c740 100644 --- a/content/browser/renderer_host/media/video_capture_controller.h +++ b/content/browser/renderer_host/media/video_capture_controller.h
@@ -55,23 +55,27 @@ #include "media/capture/video_capture_types.h" namespace media { -class VideoCaptureBufferPool; +class FrameBufferPool; } namespace content { class CONTENT_EXPORT VideoCaptureController : public media::VideoFrameReceiver { public: - // |max_buffers| is the maximum number of video frame buffers in-flight at any - // one time. This value should be based on the logical capacity of the - // capture pipeline, and not on hardware performance. For example, tab - // capture requires more buffers than webcam capture because the pipeline is - // longer (it includes read-backs pending in the GPU pipeline). - explicit VideoCaptureController(int max_buffers); + VideoCaptureController(); ~VideoCaptureController() override; base::WeakPtr<VideoCaptureController> GetWeakPtrForIOThread(); + // Factory code creating instances of VideoCaptureController must set a + // FrameBufferPool before any of the media::VideoFrameReceiver are used. + // Setting the observer is done in this method separate from the constructor + // in order to allow use the media::VideoFrameReceiver methods + // before the observer can be provided. (This is the case with + // VideoCaptureManager). + void SetFrameBufferPool( + std::unique_ptr<media::FrameBufferPool> frame_buffer_pool); + // Factory code creating instances of VideoCaptureController may optionally // set a VideoFrameConsumerFeedbackObserver. Setting the observer is done in // this method separate from the constructor to allow clients to create and @@ -80,10 +84,6 @@ void SetConsumerFeedbackObserver( std::unique_ptr<media::VideoFrameConsumerFeedbackObserver> observer); - // Return a new VideoCaptureDeviceClient to forward capture events to this - // instance. - std::unique_ptr<media::VideoCaptureDevice::Client> NewDeviceClient(); - // Start video capturing and try to use the resolution specified in |params|. // Buffers will be shared to the client as necessary. The client will continue // to receive frames from the device until RemoveClient() is called. @@ -153,7 +153,7 @@ int buffer_id, int frame_feedback_id, media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer, - scoped_refptr<media::VideoCaptureBufferPool> buffer_pool, + media::FrameBufferPool* frame_buffer_pool, scoped_refptr<media::VideoFrame> frame); ~BufferState(); BufferState(const BufferState& other); @@ -163,12 +163,13 @@ bool HasZeroConsumerHoldCount(); void SetConsumerFeedbackObserver( media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer); + void SetFrameBufferPool(media::FrameBufferPool* frame_buffer_pool); private: const int buffer_id_; const int frame_feedback_id_; media::VideoFrameConsumerFeedbackObserver* consumer_feedback_observer_; - const scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_; + media::FrameBufferPool* frame_buffer_pool_; const scoped_refptr<media::VideoFrame> frame_; double max_consumer_utilization_; int consumer_hold_count_; @@ -188,8 +189,7 @@ ControllerClient* FindClient(int session_id, const ControllerClients& clients); - // The pool of shared-memory buffers used for capturing. - const scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_; + std::unique_ptr<media::FrameBufferPool> frame_buffer_pool_; std::unique_ptr<media::VideoFrameConsumerFeedbackObserver> consumer_feedback_observer_;
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc index 2529e895..337e6d0 100644 --- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -23,11 +23,16 @@ #include "base/threading/thread_task_runner_handle.h" #include "content/browser/renderer_host/media/media_stream_provider.h" #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h" +#include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h" #include "content/browser/renderer_host/media/video_capture_manager.h" +#include "content/browser/renderer_host/media/video_frame_receiver_on_io_thread.h" #include "content/common/media/media_stream_options.h" #include "content/public/test/test_browser_thread_bundle.h" #include "media/base/video_frame_metadata.h" #include "media/base/video_util.h" +#include "media/capture/video/video_capture_buffer_pool_impl.h" +#include "media/capture/video/video_capture_buffer_tracker_factory_impl.h" +#include "media/capture/video/video_capture_device_client.h" #include "media/capture/video_capture_types.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -40,13 +45,17 @@ namespace content { +std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( + const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { + return base::MakeUnique<content::VideoCaptureGpuJpegDecoder>(decode_done_cb); +} + class MockVideoCaptureControllerEventHandler : public VideoCaptureControllerEventHandler { public: explicit MockVideoCaptureControllerEventHandler( VideoCaptureController* controller) - : controller_(controller), - resource_utilization_(-1.0) {} + : controller_(controller), resource_utilization_(-1.0) {} ~MockVideoCaptureControllerEventHandler() override {} // These mock methods are delegated to by our fake implementation of @@ -57,12 +66,11 @@ MOCK_METHOD1(DoEnded, void(VideoCaptureControllerID)); MOCK_METHOD1(DoError, void(VideoCaptureControllerID)); - void OnError(VideoCaptureControllerID id) override { - DoError(id); - } + void OnError(VideoCaptureControllerID id) override { DoError(id); } void OnBufferCreated(VideoCaptureControllerID id, mojo::ScopedSharedBufferHandle handle, - int length, int buffer_id) override { + int length, + int buffer_id) override { DoBufferCreated(id); } void OnBufferDestroyed(VideoCaptureControllerID id, int buffer_id) override { @@ -103,6 +111,14 @@ void(int frame_feedback_id, double utilization)); }; +class MockFrameBufferPool : public media::FrameBufferPool { + public: + MOCK_METHOD1(SetBufferHold, void(int buffer_id)); + MOCK_METHOD1(ReleaseBufferHold, void(int buffer_id)); + MOCK_METHOD1(GetHandleForTransit, + mojo::ScopedSharedBufferHandle(int buffer_id)); +}; + // Test class. class VideoCaptureControllerTest : public testing::Test, @@ -115,8 +131,22 @@ static const int kPoolSize = 3; void SetUp() override { - controller_.reset(new VideoCaptureController(kPoolSize)); - device_ = controller_->NewDeviceClient(); + scoped_refptr<media::VideoCaptureBufferPool> buffer_pool( + new media::VideoCaptureBufferPoolImpl( + base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), + kPoolSize)); + controller_.reset(new VideoCaptureController()); + device_client_.reset(new media::VideoCaptureDeviceClient( + base::MakeUnique<VideoFrameReceiverOnIOThread>( + controller_->GetWeakPtrForIOThread()), + buffer_pool, + base::Bind( + &CreateGpuJpegDecoder, + base::Bind(&media::VideoFrameReceiver::OnIncomingCapturedVideoFrame, + controller_->GetWeakPtrForIOThread())))); + auto frame_receiver_observer = base::MakeUnique<MockFrameBufferPool>(); + mock_frame_receiver_observer_ = frame_receiver_observer.get(); + controller_->SetFrameBufferPool(std::move(frame_receiver_observer)); auto consumer_feedback_observer = base::MakeUnique<MockConsumerFeedbackObserver>(); mock_consumer_feedback_observer_ = consumer_feedback_observer.get(); @@ -147,7 +177,8 @@ std::unique_ptr<MockVideoCaptureControllerEventHandler> client_a_; std::unique_ptr<MockVideoCaptureControllerEventHandler> client_b_; std::unique_ptr<VideoCaptureController> controller_; - std::unique_ptr<media::VideoCaptureDevice::Client> device_; + std::unique_ptr<media::VideoCaptureDevice::Client> device_client_; + MockFrameBufferPool* mock_frame_receiver_observer_; MockConsumerFeedbackObserver* mock_consumer_feedback_observer_; private: @@ -299,13 +330,13 @@ // side effect this will cause the first buffer to be shared with clients. uint8_t buffer_no = 1; const int arbitrary_frame_feedback_id = 101; - ASSERT_EQ(0.0, device_->GetBufferPoolUtilization()); + ASSERT_EQ(0.0, device_client_->GetBufferPoolUtilization()); std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer( - device_->ReserveOutputBuffer(capture_resolution, format, - media::PIXEL_STORAGE_CPU, - arbitrary_frame_feedback_id)); + device_client_->ReserveOutputBuffer(capture_resolution, format, + media::PIXEL_STORAGE_CPU, + arbitrary_frame_feedback_id)); ASSERT_TRUE(buffer.get()); - ASSERT_EQ(1.0 / kPoolSize, device_->GetBufferPoolUtilization()); + ASSERT_EQ(1.0 / kPoolSize, device_client_->GetBufferPoolUtilization()); memset(buffer->data(), buffer_no++, buffer->mapped_size()); { InSequence s; @@ -332,30 +363,37 @@ media::VideoFrameMetadata::RESOURCE_UTILIZATION)); client_a_->resource_utilization_ = 0.5; client_b_->resource_utilization_ = -1.0; - - // Expect VideoCaptureController to call the load observer with a - // resource utilization of 0.5 (the largest of all reported values). - EXPECT_CALL(*mock_consumer_feedback_observer_, - OnUtilizationReport(arbitrary_frame_feedback_id, 0.5)) - .Times(1); + { + InSequence s; + EXPECT_CALL(*mock_frame_receiver_observer_, SetBufferHold(buffer->id())) + .Times(1); + // Expect VideoCaptureController to call the load observer with a + // resource utilization of 0.5 (the largest of all reported values). + EXPECT_CALL(*mock_consumer_feedback_observer_, + OnUtilizationReport(arbitrary_frame_feedback_id, 0.5)) + .Times(1); + EXPECT_CALL(*mock_frame_receiver_observer_, ReleaseBufferHold(buffer->id())) + .Times(1); + } video_frame->metadata()->SetTimeTicks( media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks()); - device_->OnIncomingCapturedVideoFrame(std::move(buffer), video_frame); + device_client_->OnIncomingCapturedVideoFrame(std::move(buffer), video_frame); base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(client_a_.get()); Mock::VerifyAndClearExpectations(client_b_.get()); Mock::VerifyAndClearExpectations(mock_consumer_feedback_observer_); + Mock::VerifyAndClearExpectations(mock_frame_receiver_observer_); // Second buffer which ought to use the same shared memory buffer. In this // case pretend that the Buffer pointer is held by the device for a long // delay. This shouldn't affect anything. const int arbitrary_frame_feedback_id_2 = 102; std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer2 = - device_->ReserveOutputBuffer(capture_resolution, format, - media::PIXEL_STORAGE_CPU, - arbitrary_frame_feedback_id_2); + device_client_->ReserveOutputBuffer(capture_resolution, format, + media::PIXEL_STORAGE_CPU, + arbitrary_frame_feedback_id_2); ASSERT_TRUE(buffer2.get()); memset(buffer2->data(), buffer_no++, buffer2->mapped_size()); video_frame = WrapBuffer(capture_resolution, @@ -366,11 +404,21 @@ media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks()); // Expect VideoCaptureController to call the load observer with a // resource utilization of 3.14 (the largest of all reported values). - EXPECT_CALL(*mock_consumer_feedback_observer_, - OnUtilizationReport(arbitrary_frame_feedback_id_2, 3.14)) - .Times(1); + { + InSequence s; + EXPECT_CALL(*mock_frame_receiver_observer_, SetBufferHold(buffer2->id())) + .Times(1); + // Expect VideoCaptureController to call the load observer with a + // resource utilization of 3.14 (the largest of all reported values). + EXPECT_CALL(*mock_consumer_feedback_observer_, + OnUtilizationReport(arbitrary_frame_feedback_id_2, 3.14)) + .Times(1); + EXPECT_CALL(*mock_frame_receiver_observer_, + ReleaseBufferHold(buffer2->id())) + .Times(1); + } - device_->OnIncomingCapturedVideoFrame(std::move(buffer2), video_frame); + device_client_->OnIncomingCapturedVideoFrame(std::move(buffer2), video_frame); // The buffer should be delivered to the clients in any order. { @@ -395,6 +443,7 @@ Mock::VerifyAndClearExpectations(client_a_.get()); Mock::VerifyAndClearExpectations(client_b_.get()); Mock::VerifyAndClearExpectations(mock_consumer_feedback_observer_); + Mock::VerifyAndClearExpectations(mock_frame_receiver_observer_); // Add a fourth client now that some buffers have come through. controller_->AddClient(client_b_route_2, @@ -407,9 +456,9 @@ for (int i = 0; i < kPoolSize; i++) { const int arbitrary_frame_feedback_id = 200 + i; std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer = - device_->ReserveOutputBuffer(capture_resolution, format, - media::PIXEL_STORAGE_CPU, - arbitrary_frame_feedback_id); + device_client_->ReserveOutputBuffer(capture_resolution, format, + media::PIXEL_STORAGE_CPU, + arbitrary_frame_feedback_id); ASSERT_TRUE(buffer.get()); memset(buffer->data(), buffer_no++, buffer->mapped_size()); video_frame = WrapBuffer(capture_resolution, @@ -417,10 +466,11 @@ ASSERT_TRUE(video_frame); video_frame->metadata()->SetTimeTicks( media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks()); - device_->OnIncomingCapturedVideoFrame(std::move(buffer), video_frame); + device_client_->OnIncomingCapturedVideoFrame(std::move(buffer), + video_frame); } // ReserveOutputBuffer ought to fail now, because the pool is depleted. - ASSERT_FALSE(device_ + ASSERT_FALSE(device_client_ ->ReserveOutputBuffer(capture_resolution, format, media::PIXEL_STORAGE_CPU, arbitrary_frame_feedback_id) @@ -455,9 +505,9 @@ controller_->StopSession(300); // Queue up another buffer. std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer3 = - device_->ReserveOutputBuffer(capture_resolution, format, - media::PIXEL_STORAGE_CPU, - arbitrary_frame_feedback_id); + device_client_->ReserveOutputBuffer(capture_resolution, format, + media::PIXEL_STORAGE_CPU, + arbitrary_frame_feedback_id); ASSERT_TRUE(buffer3.get()); memset(buffer3->data(), buffer_no++, buffer3->mapped_size()); video_frame = WrapBuffer(capture_resolution, @@ -465,12 +515,12 @@ ASSERT_TRUE(video_frame); video_frame->metadata()->SetTimeTicks( media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks()); - device_->OnIncomingCapturedVideoFrame(std::move(buffer3), video_frame); + device_client_->OnIncomingCapturedVideoFrame(std::move(buffer3), video_frame); std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer4 = - device_->ReserveOutputBuffer(capture_resolution, format, - media::PIXEL_STORAGE_CPU, - arbitrary_frame_feedback_id); + device_client_->ReserveOutputBuffer(capture_resolution, format, + media::PIXEL_STORAGE_CPU, + arbitrary_frame_feedback_id); { // Kill A2 via session close (posts a task to disconnect, but A2 must not // be sent either of these two buffers). @@ -484,7 +534,7 @@ ASSERT_TRUE(video_frame); video_frame->metadata()->SetTimeTicks( media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks()); - device_->OnIncomingCapturedVideoFrame(std::move(buffer4), video_frame); + device_client_->OnIncomingCapturedVideoFrame(std::move(buffer4), video_frame); // B2 is the only client left, and is the only one that should // get the buffer. EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2, capture_resolution)) @@ -514,7 +564,7 @@ // Start with one client. controller_->AddClient(route_id, client_a_.get(), 100, session_100); - device_->OnError(FROM_HERE, "Test Error"); + device_client_->OnError(FROM_HERE, "Test Error"); EXPECT_CALL(*client_a_, DoError(route_id)).Times(1); base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(client_a_.get()); @@ -528,16 +578,16 @@ const int arbitrary_frame_feedback_id = 101; std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer( - device_->ReserveOutputBuffer(capture_resolution, media::PIXEL_FORMAT_I420, - media::PIXEL_STORAGE_CPU, - arbitrary_frame_feedback_id)); + device_client_->ReserveOutputBuffer( + capture_resolution, media::PIXEL_FORMAT_I420, + media::PIXEL_STORAGE_CPU, arbitrary_frame_feedback_id)); ASSERT_TRUE(buffer.get()); scoped_refptr<media::VideoFrame> video_frame = WrapBuffer(capture_resolution, static_cast<uint8_t*>(buffer->data())); ASSERT_TRUE(video_frame); video_frame->metadata()->SetTimeTicks( media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks()); - device_->OnIncomingCapturedVideoFrame(std::move(buffer), video_frame); + device_client_->OnIncomingCapturedVideoFrame(std::move(buffer), video_frame); base::RunLoop().RunUntilIdle(); } @@ -567,18 +617,18 @@ const gfx::Size dims(320, 240); const int arbitrary_frame_feedback_id = 101; std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer( - device_->ReserveOutputBuffer(dims, media::PIXEL_FORMAT_I420, - media::PIXEL_STORAGE_CPU, - arbitrary_frame_feedback_id)); + device_client_->ReserveOutputBuffer(dims, media::PIXEL_FORMAT_I420, + media::PIXEL_STORAGE_CPU, + arbitrary_frame_feedback_id)); ASSERT_TRUE(buffer.get()); scoped_refptr<media::VideoFrame> video_frame = WrapBuffer(dims, static_cast<uint8_t*>(buffer->data())); ASSERT_TRUE(video_frame); - device_->OnError(FROM_HERE, "Test Error"); + device_client_->OnError(FROM_HERE, "Test Error"); video_frame->metadata()->SetTimeTicks( media::VideoFrameMetadata::REFERENCE_TIME, base::TimeTicks()); - device_->OnIncomingCapturedVideoFrame(std::move(buffer), video_frame); + device_client_->OnIncomingCapturedVideoFrame(std::move(buffer), video_frame); EXPECT_CALL(*client_a_, DoError(route_id)).Times(1); base::RunLoop().RunUntilIdle();
diff --git a/content/browser/renderer_host/media/video_capture_device_client_unittest.cc b/content/browser/renderer_host/media/video_capture_device_client_unittest.cc index 020854b..e2a6a82 100644 --- a/content/browser/renderer_host/media/video_capture_device_client_unittest.cc +++ b/content/browser/renderer_host/media/video_capture_device_client_unittest.cc
@@ -16,9 +16,12 @@ #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "content/browser/renderer_host/media/video_capture_controller.h" +#include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h" +#include "content/browser/renderer_host/media/video_frame_receiver_on_io_thread.h" #include "content/public/test/test_browser_thread_bundle.h" #include "media/base/limits.h" -#include "media/capture/video/video_capture_buffer_pool.h" +#include "media/capture/video/video_capture_buffer_pool_impl.h" +#include "media/capture/video/video_capture_buffer_tracker_factory_impl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -33,8 +36,7 @@ class MockVideoCaptureController : public VideoCaptureController { public: - explicit MockVideoCaptureController(int max_buffers) - : VideoCaptureController(max_buffers) {} + explicit MockVideoCaptureController() : VideoCaptureController() {} ~MockVideoCaptureController() override {} MOCK_METHOD1(MockOnIncomingCapturedVideoFrame, void(const gfx::Size&)); @@ -49,6 +51,11 @@ } }; +std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( + const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { + return base::MakeUnique<content::VideoCaptureGpuJpegDecoder>(decode_done_cb); +} + // Note that this test does not exercise the class VideoCaptureDeviceClient // in isolation. The "unit under test" is an instance of // VideoCaptureDeviceClient with some context that is specific to @@ -57,17 +64,29 @@ class VideoCaptureDeviceClientTest : public ::testing::Test { public: VideoCaptureDeviceClientTest() - : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), - controller_(new MockVideoCaptureController(1)), - device_client_(controller_->NewDeviceClient()) {} + : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { + scoped_refptr<media::VideoCaptureBufferPoolImpl> buffer_pool( + new media::VideoCaptureBufferPoolImpl( + base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), + 1)); + controller_ = base::MakeUnique<MockVideoCaptureController>(); + device_client_ = base::MakeUnique<media::VideoCaptureDeviceClient>( + base::MakeUnique<VideoFrameReceiverOnIOThread>( + controller_->GetWeakPtrForIOThread()), + buffer_pool, + base::Bind( + &CreateGpuJpegDecoder, + base::Bind(&media::VideoFrameReceiver::OnIncomingCapturedVideoFrame, + controller_->GetWeakPtrForIOThread()))); + } ~VideoCaptureDeviceClientTest() override {} void TearDown() override { base::RunLoop().RunUntilIdle(); } protected: const content::TestBrowserThreadBundle thread_bundle_; - const std::unique_ptr<MockVideoCaptureController> controller_; - const std::unique_ptr<media::VideoCaptureDevice::Client> device_client_; + std::unique_ptr<MockVideoCaptureController> controller_; + std::unique_ptr<media::VideoCaptureDeviceClient> device_client_; private: DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceClientTest);
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc index e1830ee..bec642e 100644 --- a/content/browser/renderer_host/media/video_capture_manager.cc +++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -26,12 +26,17 @@ #include "content/browser/media/media_internals.h" #include "content/browser/renderer_host/media/video_capture_controller.h" #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h" +#include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h" +#include "content/browser/renderer_host/media/video_frame_receiver_on_io_thread.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/desktop_media_id.h" #include "content/public/common/media_stream_request.h" #include "media/base/bind_to_current_loop.h" #include "media/base/media_switches.h" +#include "media/capture/video/video_capture_buffer_pool_impl.h" +#include "media/capture/video/video_capture_buffer_tracker_factory_impl.h" #include "media/capture/video/video_capture_device.h" +#include "media/capture/video/video_capture_device_client.h" #include "media/capture/video/video_capture_device_factory.h" #if defined(ENABLE_SCREEN_CAPTURE) && !defined(OS_ANDROID) @@ -113,8 +118,11 @@ } } -// The maximum number of buffers in the capture pipeline. See -// VideoCaptureController ctor comments for more details. +// The maximum number of video frame buffers in-flight at any one time. This +// value should be based on the logical capacity of the capture pipeline, and +// not on hardware performance. For example, tab capture requires more buffers +// than webcam capture because the pipeline is longer (it includes read-backs +// pending in the GPU pipeline). const int kMaxNumberOfBuffers = 3; // TODO(miu): The value for tab capture should be determined programmatically. // http://crbug.com/460318 @@ -143,6 +151,11 @@ const media::VideoCaptureSessionId kFakeSessionId = -1; +std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( + const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { + return base::MakeUnique<content::VideoCaptureGpuJpegDecoder>(decode_done_cb); +} + } // namespace namespace content { @@ -153,36 +166,27 @@ // is no device present. // Phase 2: When a request to "start" the entry comes in (via // HandleQueuedStartRequest()), a VideoCaptureDevice::Client is created -// via video_capture_controller()->NewDeviceClient() and is used to schedule the +// via CreateDeviceClient() and is used to schedule the // creation and start of a VideoCaptureDevice on the Device Thread. // Phase 3: As soon as the creation of the VideoCaptureDevice is complete, this // newly created VideoCaptureDevice instance is connected to the // VideoCaptureController via SetConsumerFeedbackObserver(). -class VideoCaptureManager::DeviceEntry { +struct VideoCaptureManager::DeviceEntry { public: DeviceEntry(MediaStreamType stream_type, const std::string& id, - std::unique_ptr<VideoCaptureController> controller, const media::VideoCaptureParams& params); ~DeviceEntry(); + std::unique_ptr<media::VideoCaptureDevice::Client> CreateDeviceClient(); + std::unique_ptr<media::FrameBufferPool> CreateFrameBufferPool(); const int serial_id; const MediaStreamType stream_type; const std::string id; const media::VideoCaptureParams parameters; - - VideoCaptureController* video_capture_controller() const; - media::VideoCaptureDevice* video_capture_device() const; - - void SetVideoCaptureDevice(std::unique_ptr<VideoCaptureDevice> device); - std::unique_ptr<VideoCaptureDevice> ReleaseVideoCaptureDevice(); - - private: - const std::unique_ptr<VideoCaptureController> video_capture_controller_; - - std::unique_ptr<VideoCaptureDevice> video_capture_device_; - - base::ThreadChecker thread_checker_; + VideoCaptureController video_capture_controller; + scoped_refptr<media::VideoCaptureBufferPool> buffer_pool; + std::unique_ptr<media::VideoCaptureDevice> video_capture_device; }; // Bundles a media::VideoCaptureDeviceDescriptor with corresponding supported @@ -198,6 +202,28 @@ media::VideoCaptureFormats supported_formats; }; +class BufferPoolFrameBufferPool : public media::FrameBufferPool { + public: + explicit BufferPoolFrameBufferPool( + scoped_refptr<media::VideoCaptureBufferPool> buffer_pool) + : buffer_pool_(std::move(buffer_pool)) {} + + void SetBufferHold(int buffer_id) override { + buffer_pool_->HoldForConsumers(buffer_id, 1); + } + + void ReleaseBufferHold(int buffer_id) override { + buffer_pool_->RelinquishConsumerHold(buffer_id, 1); + } + + mojo::ScopedSharedBufferHandle GetHandleForTransit(int buffer_id) override { + return buffer_pool_->GetHandleForTransit(buffer_id); + } + + private: + scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_; +}; + // Class used for queuing request for starting a device. class VideoCaptureManager::CaptureDeviceStartRequest { public: @@ -225,44 +251,46 @@ VideoCaptureManager::DeviceEntry::DeviceEntry( MediaStreamType stream_type, const std::string& id, - std::unique_ptr<VideoCaptureController> controller, const media::VideoCaptureParams& params) : serial_id(g_device_start_id++), stream_type(stream_type), id(id), - parameters(params), - video_capture_controller_(std::move(controller)) {} + parameters(params) {} VideoCaptureManager::DeviceEntry::~DeviceEntry() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CURRENTLY_ON(BrowserThread::IO); // DCHECK that this DeviceEntry does not still own a // media::VideoCaptureDevice. media::VideoCaptureDevice must be deleted on // the device thread. - DCHECK(video_capture_device_ == nullptr); + DCHECK(video_capture_device == nullptr); } -void VideoCaptureManager::DeviceEntry::SetVideoCaptureDevice( - std::unique_ptr<VideoCaptureDevice> device) { - DCHECK(thread_checker_.CalledOnValidThread()); - video_capture_device_.swap(device); +std::unique_ptr<media::VideoCaptureDevice::Client> +VideoCaptureManager::DeviceEntry::CreateDeviceClient() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + const int max_buffers = stream_type == MEDIA_TAB_VIDEO_CAPTURE + ? kMaxNumberOfBuffersForTabCapture + : kMaxNumberOfBuffers; + buffer_pool = new media::VideoCaptureBufferPoolImpl( + base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), + max_buffers); + + return base::MakeUnique<media::VideoCaptureDeviceClient>( + base::MakeUnique<VideoFrameReceiverOnIOThread>( + video_capture_controller.GetWeakPtrForIOThread()), + buffer_pool, + base::Bind( + &CreateGpuJpegDecoder, + base::Bind(&media::VideoFrameReceiver::OnIncomingCapturedVideoFrame, + video_capture_controller.GetWeakPtrForIOThread()))); } -std::unique_ptr<media::VideoCaptureDevice> -VideoCaptureManager::DeviceEntry::ReleaseVideoCaptureDevice() { - DCHECK(thread_checker_.CalledOnValidThread()); - return std::move(video_capture_device_); -} - -VideoCaptureController* -VideoCaptureManager::DeviceEntry::video_capture_controller() const { - DCHECK(thread_checker_.CalledOnValidThread()); - return video_capture_controller_.get(); -} - -media::VideoCaptureDevice* -VideoCaptureManager::DeviceEntry::video_capture_device() const { - DCHECK(thread_checker_.CalledOnValidThread()); - return video_capture_device_.get(); +std::unique_ptr<media::FrameBufferPool> +VideoCaptureManager::DeviceEntry::CreateFrameBufferPool() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(buffer_pool); + return base::MakeUnique<BufferPoolFrameBufferPool>(buffer_pool); } VideoCaptureManager::DeviceInfo::DeviceInfo() = default; @@ -384,8 +412,7 @@ if (existing_device) { // Remove any client that is still using the session. This is safe to call // even if there are no clients using the session. - existing_device->video_capture_controller() - ->StopSession(capture_session_id); + existing_device->video_capture_controller.StopSession(capture_session_id); // StopSession() may have removed the last client, so we might need to // close the device. @@ -433,17 +460,18 @@ DVLOG(3) << "DoStopDevice. Send stop request for device = " << entry->id << " serial_id = " << entry->serial_id << "."; - entry->video_capture_controller()->OnLog( + entry->video_capture_controller.OnLog( base::StringPrintf("Stopping device: id: %s", entry->id.c_str())); - entry->video_capture_controller()->SetConsumerFeedbackObserver(nullptr); + entry->video_capture_controller.SetConsumerFeedbackObserver(nullptr); + entry->video_capture_controller.SetFrameBufferPool(nullptr); // |entry->video_capture_device| can be null if creating the device has // failed. - if (entry->video_capture_device()) { + if (entry->video_capture_device) { device_task_runner_->PostTask( FROM_HERE, base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this, - base::Passed(entry->ReleaseVideoCaptureDevice()))); + base::Passed(&entry->video_capture_device))); } } @@ -465,6 +493,11 @@ DVLOG(3) << "HandleQueuedStartRequest, Post start to device thread, device = " << entry->id << " start id = " << entry->serial_id; + std::unique_ptr<media::VideoCaptureDevice::Client> device_client = + entry->CreateDeviceClient(); + std::unique_ptr<media::FrameBufferPool> frame_buffer_pool = + entry->CreateFrameBufferPool(); + base::Callback<std::unique_ptr<VideoCaptureDevice>(void)> start_capture_function; @@ -475,16 +508,16 @@ // held in the browser-side VideoCaptureDevice::Name structure. const DeviceInfo* found = GetDeviceInfoById(entry->id); if (found) { - entry->video_capture_controller()->OnLog( + entry->video_capture_controller.OnLog( base::StringPrintf("Starting device: id: %s, name: %s, api: %s", found->descriptor.device_id.c_str(), found->descriptor.GetNameAndModel().c_str(), found->descriptor.GetCaptureApiTypeString())); - start_capture_function = base::Bind( - &VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread, this, - found->descriptor, request->params(), - base::Passed(entry->video_capture_controller()->NewDeviceClient())); + start_capture_function = + base::Bind(&VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread, + this, found->descriptor, request->params(), + base::Passed(std::move(device_client))); } else { // Errors from DoStartDeviceCaptureOnDeviceThread go via // VideoCaptureDeviceClient::OnError, which needs some thread @@ -495,8 +528,8 @@ "Error on %s:%d: device %s unknown. Maybe recently disconnected?", __FILE__, __LINE__, entry->id.c_str()); DLOG(ERROR) << log_message; - entry->video_capture_controller()->OnLog(log_message); - entry->video_capture_controller()->OnError(); + entry->video_capture_controller.OnLog(log_message); + entry->video_capture_controller.OnError(); // Drop the failed start request. device_start_queue_.pop_front(); @@ -507,15 +540,13 @@ case MEDIA_TAB_VIDEO_CAPTURE: start_capture_function = base::Bind( &VideoCaptureManager::DoStartTabCaptureOnDeviceThread, this, - entry->id, request->params(), - base::Passed(entry->video_capture_controller()->NewDeviceClient())); + entry->id, request->params(), base::Passed(std::move(device_client))); break; case MEDIA_DESKTOP_VIDEO_CAPTURE: start_capture_function = base::Bind( &VideoCaptureManager::DoStartDesktopCaptureOnDeviceThread, this, - entry->id, request->params(), - base::Passed(entry->video_capture_controller()->NewDeviceClient())); + entry->id, request->params(), base::Passed(std::move(device_client))); break; default: { @@ -526,11 +557,12 @@ base::PostTaskAndReplyWithResult( device_task_runner_.get(), FROM_HERE, start_capture_function, base::Bind(&VideoCaptureManager::OnDeviceStarted, this, - request->serial_id())); + request->serial_id(), base::Passed(&frame_buffer_pool))); } void VideoCaptureManager::OnDeviceStarted( int serial_id, + std::unique_ptr<media::FrameBufferPool> frame_buffer_pool, std::unique_ptr<VideoCaptureDevice> device) { DVLOG(3) << __func__; DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -551,15 +583,19 @@ } else { DeviceEntry* const entry = GetDeviceEntryBySerialId(serial_id); DCHECK(entry); - DCHECK(!entry->video_capture_device()); - // Passing raw pointer |device.get()| to the controller is safe, - // because we transfer ownership of it to |entry|. We are calling - // SetConsumerFeedbackObserver(nullptr) before releasing - // |entry->video_capture_device_| on the |device_task_runner_|. - entry->video_capture_controller()->SetConsumerFeedbackObserver( - base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( - device.get(), device_task_runner_)); - entry->SetVideoCaptureDevice(std::move(device)); + DCHECK(!entry->video_capture_device); + if (device) { + entry->video_capture_controller.SetFrameBufferPool( + std::move(frame_buffer_pool)); + // Passing raw pointer |device.get()| to the controller is safe, + // because we transfer ownership of it to |entry|. We are calling + // SetConsumerFeedbackObserver(nullptr) before releasing + // |entry->video_capture_device_| on the |device_task_runner_|. + entry->video_capture_controller.SetConsumerFeedbackObserver( + base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( + device.get(), device_task_runner_)); + } + entry->video_capture_device = std::move(device); if (entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE) { const media::VideoCaptureSessionId session_id = @@ -572,8 +608,8 @@ while (it != photo_request_queue_.end()) { auto request = it++; DeviceEntry* maybe_entry = GetDeviceEntryBySessionId(request->first); - if (maybe_entry && maybe_entry->video_capture_device()) { - request->second.Run(maybe_entry->video_capture_device()); + if (maybe_entry && maybe_entry->video_capture_device) { + request->second.Run(maybe_entry->video_capture_device.get()); photo_request_queue_.erase(request); } } @@ -686,21 +722,19 @@ return; } - DCHECK(entry->video_capture_controller()); - LogVideoCaptureEvent(VIDEO_CAPTURE_START_CAPTURE); // First client starts the device. - if (!entry->video_capture_controller()->HasActiveClient() && - !entry->video_capture_controller()->HasPausedClient()) { + if (!entry->video_capture_controller.HasActiveClient() && + !entry->video_capture_controller.HasPausedClient()) { DVLOG(1) << "VideoCaptureManager starting device (type = " << entry->stream_type << ", id = " << entry->id << ")"; QueueStartDevice(session_id, entry, params); } // Run the callback first, as AddClient() may trigger OnFrameInfo(). - done_cb.Run(entry->video_capture_controller()->GetWeakPtrForIOThread()); - entry->video_capture_controller()->AddClient( - client_id, client_handler, session_id, params); + done_cb.Run(entry->video_capture_controller.GetWeakPtrForIOThread()); + entry->video_capture_controller.AddClient(client_id, client_handler, + session_id, params); } void VideoCaptureManager::StopCaptureForClient( @@ -765,7 +799,7 @@ controller->PauseClient(client_id, client_handler); if (!had_active_client || controller->HasActiveClient()) return; - if (media::VideoCaptureDevice* device = entry->video_capture_device()) { + if (media::VideoCaptureDevice* device = entry->video_capture_device.get()) { device_task_runner_->PostTask( FROM_HERE, base::Bind(&VideoCaptureDevice::MaybeSuspend, @@ -795,7 +829,7 @@ controller->ResumeClient(client_id, client_handler); if (had_active_client || !controller->HasActiveClient()) return; - if (media::VideoCaptureDevice* device = entry->video_capture_device()) { + if (media::VideoCaptureDevice* device = entry->video_capture_device.get()) { device_task_runner_->PostTask( FROM_HERE, base::Bind(&VideoCaptureDevice::Resume, @@ -812,7 +846,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); if (DeviceEntry* entry = GetDeviceEntryByController(controller)) { - if (media::VideoCaptureDevice* device = entry->video_capture_device()) { + if (media::VideoCaptureDevice* device = entry->video_capture_device.get()) { device_task_runner_->PostTask( FROM_HERE, base::Bind(&VideoCaptureDevice::RequestRefreshFrame, @@ -860,7 +894,7 @@ if (device_in_use) { // Currently only one format-in-use is supported at the VCC level. formats_in_use->push_back( - device_in_use->video_capture_controller()->GetVideoCaptureFormat()); + device_in_use->video_capture_controller.GetVideoCaptureFormat()); } return true; } @@ -888,7 +922,7 @@ return; } - if (!existing_device->video_capture_device()) { + if (!existing_device->video_capture_device) { DVLOG(2) << "Screen capture device not yet started."; return; } @@ -910,8 +944,7 @@ device_task_runner_->PostTask( FROM_HERE, base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread, - this, - existing_device->video_capture_device(), + this, existing_device->video_capture_device.get(), window_id_it->second)); notification_window_ids_.erase(window_id_it); @@ -925,7 +958,7 @@ const DeviceEntry* entry = GetDeviceEntryBySessionId(session_id); if (!entry) return; - VideoCaptureDevice* device = entry->video_capture_device(); + VideoCaptureDevice* device = entry->video_capture_device.get(); if (device) { VideoCaptureManager::DoGetPhotoCapabilities(std::move(callback), device); return; @@ -945,7 +978,7 @@ const DeviceEntry* entry = GetDeviceEntryBySessionId(session_id); if (!entry) return; - VideoCaptureDevice* device = entry->video_capture_device(); + VideoCaptureDevice* device = entry->video_capture_device.get(); if (device) { VideoCaptureManager::DoSetPhotoOptions(std::move(callback), std::move(settings), device); @@ -965,7 +998,7 @@ const DeviceEntry* entry = GetDeviceEntryBySessionId(session_id); if (!entry) return; - VideoCaptureDevice* device = entry->video_capture_device(); + VideoCaptureDevice* device = entry->video_capture_device.get(); if (device) { VideoCaptureManager::DoTakePhoto(std::move(callback), device); return; @@ -1073,8 +1106,8 @@ void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) { DCHECK_CURRENTLY_ON(BrowserThread::IO); // Removal of the last client stops the device. - if (!entry->video_capture_controller()->HasActiveClient() && - !entry->video_capture_controller()->HasPausedClient()) { + if (!entry->video_capture_controller.HasActiveClient() && + !entry->video_capture_controller.HasPausedClient()) { DVLOG(1) << "VideoCaptureManager stopping device (type = " << entry->stream_type << ", id = " << entry->id << ")"; @@ -1124,7 +1157,7 @@ // Look up |controller| in |devices_|. for (const std::unique_ptr<DeviceEntry>& device : devices_) { - if (device->video_capture_controller() == controller) + if (&device->video_capture_controller == controller) return device.get(); } return nullptr; @@ -1169,15 +1202,9 @@ return existing_device; } - const int max_buffers = device_info.type == MEDIA_TAB_VIDEO_CAPTURE ? - kMaxNumberOfBuffersForTabCapture : kMaxNumberOfBuffers; - std::unique_ptr<VideoCaptureController> video_capture_controller( - new VideoCaptureController(max_buffers)); - DeviceEntry* new_device = - new DeviceEntry(device_info.type, device_info.id, - std::move(video_capture_controller), params); - devices_.emplace_back(new_device); - return new_device; + devices_.emplace_back( + new DeviceEntry(device_info.type, device_info.id, params)); + return devices_.back().get(); } void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread( @@ -1263,7 +1290,7 @@ // Do not resume Content Video Capture devices, e.g. Tab or Screen capture. // Do not try to restart already running devices. if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE || - entry->video_capture_device()) + entry->video_capture_device) continue; // Check if the device is already in the start queue.
diff --git a/content/browser/renderer_host/media/video_capture_manager.h b/content/browser/renderer_host/media/video_capture_manager.h index e6857c6..3bad7b1 100644 --- a/content/browser/renderer_host/media/video_capture_manager.h +++ b/content/browser/renderer_host/media/video_capture_manager.h
@@ -174,7 +174,7 @@ private: class CaptureDeviceStartRequest; - class DeviceEntry; + struct DeviceEntry; struct DeviceInfo; using SessionMap = std::map<media::VideoCaptureSessionId, MediaStreamDevice>; @@ -239,8 +239,10 @@ void QueueStartDevice(media::VideoCaptureSessionId session_id, DeviceEntry* entry, const media::VideoCaptureParams& params); - void OnDeviceStarted(int serial_id, - std::unique_ptr<VideoCaptureDevice> device); + void OnDeviceStarted( + int serial_id, + std::unique_ptr<media::FrameBufferPool> frame_buffer_pool, + std::unique_ptr<VideoCaptureDevice> device); void DoStopDevice(DeviceEntry* entry); void HandleQueuedStartRequest();
diff --git a/content/browser/renderer_host/media/video_frame_receiver_on_io_thread.cc b/content/browser/renderer_host/media/video_frame_receiver_on_io_thread.cc new file mode 100644 index 0000000..a4a46c2e --- /dev/null +++ b/content/browser/renderer_host/media/video_frame_receiver_on_io_thread.cc
@@ -0,0 +1,45 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/media/video_frame_receiver_on_io_thread.h" + +#include "content/public/browser/browser_thread.h" + +namespace content { + +VideoFrameReceiverOnIOThread::VideoFrameReceiverOnIOThread( + const base::WeakPtr<VideoFrameReceiver>& receiver) + : receiver_(receiver) {} + +VideoFrameReceiverOnIOThread::~VideoFrameReceiverOnIOThread() = default; + +void VideoFrameReceiverOnIOThread::OnIncomingCapturedVideoFrame( + std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer, + scoped_refptr<media::VideoFrame> frame) { + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&VideoFrameReceiver::OnIncomingCapturedVideoFrame, receiver_, + base::Passed(&buffer), frame)); +} + +void VideoFrameReceiverOnIOThread::OnError() { + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&VideoFrameReceiver::OnError, receiver_)); +} + +void VideoFrameReceiverOnIOThread::OnLog(const std::string& message) { + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&VideoFrameReceiver::OnLog, receiver_, message)); +} + +void VideoFrameReceiverOnIOThread::OnBufferDestroyed(int buffer_id_to_drop) { + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&VideoFrameReceiver::OnBufferDestroyed, receiver_, + buffer_id_to_drop)); +} + +} // namespace content
diff --git a/content/browser/renderer_host/media/video_frame_receiver_on_io_thread.h b/content/browser/renderer_host/media/video_frame_receiver_on_io_thread.h new file mode 100644 index 0000000..9925dd1 --- /dev/null +++ b/content/browser/renderer_host/media/video_frame_receiver_on_io_thread.h
@@ -0,0 +1,37 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_FRAME_RECEIVER_ON_IO_THREAD_H_ +#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_FRAME_RECEIVER_ON_IO_THREAD_H_ + +#include "content/common/content_export.h" +#include "media/capture/video/video_frame_receiver.h" + +namespace content { + +// Decorator for media::VideoFrameReceiver that forwards all incoming calls +// to the Browser IO thread. +// TODO(chfremer): Change this to VideoFrameReceiverOnTaskRunner and have the +// target task runner be passed into the constructor. See crbug.com/674190. +class CONTENT_EXPORT VideoFrameReceiverOnIOThread + : public media::VideoFrameReceiver { + public: + explicit VideoFrameReceiverOnIOThread( + const base::WeakPtr<VideoFrameReceiver>& receiver); + ~VideoFrameReceiverOnIOThread() override; + + void OnIncomingCapturedVideoFrame( + std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer, + scoped_refptr<media::VideoFrame> frame) override; + void OnError() override; + void OnLog(const std::string& message) override; + void OnBufferDestroyed(int buffer_id_to_drop) override; + + private: + base::WeakPtr<VideoFrameReceiver> receiver_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_FRAME_RECEIVER_ON_IO_THREAD_H_
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc index e90ba3f..fa0d239 100644 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc +++ b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc
@@ -6,118 +6,91 @@ #include "cc/surfaces/surface.h" #include "cc/surfaces/surface_manager.h" -#include "content/browser/compositor/surface_utils.h" #include "mojo/public/cpp/bindings/strong_binding.h" namespace content { -OffscreenCanvasCompositorFrameSink::OffscreenCanvasCompositorFrameSink( - const cc::SurfaceId& surface_id, - cc::mojom::MojoCompositorFrameSinkClientPtr client) - : surface_id_(surface_id), client_(std::move(client)) { - cc::SurfaceManager* manager = GetSurfaceManager(); - surface_factory_ = base::MakeUnique<cc::SurfaceFactory>( - surface_id_.frame_sink_id(), manager, this); - manager->RegisterFrameSinkId(surface_id_.frame_sink_id()); -} - -OffscreenCanvasCompositorFrameSink::~OffscreenCanvasCompositorFrameSink() { - cc::SurfaceManager* manager = GetSurfaceManager(); - if (!manager) { - // Inform SurfaceFactory that SurfaceManager's no longer alive to - // avoid its destruction error. - surface_factory_->DidDestroySurfaceManager(); - } else { - manager->InvalidateFrameSinkId(surface_id_.frame_sink_id()); - } - surface_factory_->EvictSurface(); -} - // static void OffscreenCanvasCompositorFrameSink::Create( - const cc::SurfaceId& surface_id, + const cc::FrameSinkId& frame_sink_id, + cc::SurfaceManager* surface_manager, cc::mojom::MojoCompositorFrameSinkClientPtr client, cc::mojom::MojoCompositorFrameSinkRequest request) { - mojo::MakeStrongBinding(base::MakeUnique<OffscreenCanvasCompositorFrameSink>( - surface_id, std::move(client)), - std::move(request)); + std::unique_ptr<OffscreenCanvasCompositorFrameSink> impl = + base::MakeUnique<OffscreenCanvasCompositorFrameSink>( + frame_sink_id, surface_manager, std::move(client)); + OffscreenCanvasCompositorFrameSink* compositor_frame_sink = impl.get(); + compositor_frame_sink->binding_ = + mojo::MakeStrongBinding(std::move(impl), std::move(request)); +} + +OffscreenCanvasCompositorFrameSink::OffscreenCanvasCompositorFrameSink( + const cc::FrameSinkId& frame_sink_id, + cc::SurfaceManager* surface_manager, + cc::mojom::MojoCompositorFrameSinkClientPtr client) + : support_(this, surface_manager, frame_sink_id, nullptr, nullptr), + client_(std::move(client)) {} + +OffscreenCanvasCompositorFrameSink::~OffscreenCanvasCompositorFrameSink() {} + +void OffscreenCanvasCompositorFrameSink::SetNeedsBeginFrame( + bool needs_begin_frame) { + support_.SetNeedsBeginFrame(needs_begin_frame); } void OffscreenCanvasCompositorFrameSink::SubmitCompositorFrame( const cc::LocalFrameId& local_frame_id, cc::CompositorFrame frame) { - ++ack_pending_count_; - surface_factory_->SubmitCompositorFrame( - surface_id_.local_frame_id(), std::move(frame), - base::Bind( - &OffscreenCanvasCompositorFrameSink::DidReceiveCompositorFrameAck, - base::Unretained(this))); -} - -void OffscreenCanvasCompositorFrameSink::SetNeedsBeginFrame( - bool needs_begin_frame) { - NOTIMPLEMENTED(); + support_.SubmitCompositorFrame(local_frame_id, std::move(frame)); } void OffscreenCanvasCompositorFrameSink::AddSurfaceReferences( const std::vector<cc::SurfaceReference>& references) { + // TODO(fsamuel, staraz): Implement this. NOTIMPLEMENTED(); } void OffscreenCanvasCompositorFrameSink::RemoveSurfaceReferences( const std::vector<cc::SurfaceReference>& references) { + // TODO(fsamuel, staraz): Implement this. NOTIMPLEMENTED(); } void OffscreenCanvasCompositorFrameSink::EvictFrame() { - // TODO(fsamuel, staraz): Implement this - NOTIMPLEMENTED(); + support_.EvictFrame(); } void OffscreenCanvasCompositorFrameSink::Require( const cc::LocalFrameId& local_frame_id, const cc::SurfaceSequence& sequence) { - // TODO(staraz): Implement this. - NOTIMPLEMENTED(); + support_.Require(local_frame_id, sequence); } void OffscreenCanvasCompositorFrameSink::Satisfy( const cc::SurfaceSequence& sequence) { - // TODO(staraz): Implement this. - NOTIMPLEMENTED(); + support_.Satisfy(sequence); } -void OffscreenCanvasCompositorFrameSink::ReturnResources( - const cc::ReturnedResourceArray& resources) { - if (resources.empty()) - return; - - if (!ack_pending_count_ && client_) { - client_->ReclaimResources(resources); - return; - } - - std::copy(resources.begin(), resources.end(), - std::back_inserter(surface_returned_resources_)); -} - -void OffscreenCanvasCompositorFrameSink::WillDrawSurface( - const cc::LocalFrameId& id, - const gfx::Rect& damage_rect) {} - -void OffscreenCanvasCompositorFrameSink::SetBeginFrameSource( - cc::BeginFrameSource* begin_frame_source) {} - void OffscreenCanvasCompositorFrameSink::DidReceiveCompositorFrameAck() { - if (!client_) - return; - client_->DidReceiveCompositorFrameAck(); - DCHECK_GT(ack_pending_count_, 0); - if (!surface_returned_resources_.empty()) { - client_->ReclaimResources(surface_returned_resources_); - surface_returned_resources_.clear(); - } - ack_pending_count_--; + if (client_) + client_->DidReceiveCompositorFrameAck(); +} + +void OffscreenCanvasCompositorFrameSink::OnBeginFrame( + const cc::BeginFrameArgs& args) { + if (client_) + client_->OnBeginFrame(args); +} + +void OffscreenCanvasCompositorFrameSink::ReclaimResources( + const cc::ReturnedResourceArray& resources) { + if (client_) + client_->ReclaimResources(resources); +} + +void OffscreenCanvasCompositorFrameSink::WillDrawSurface() { + if (client_) + client_->WillDrawSurface(); } } // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h index abd8187..c526e0b63 100644 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h +++ b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h
@@ -5,32 +5,35 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_H_ #define CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_H_ -#include <memory> -#include <vector> - -#include "cc/surfaces/surface_factory.h" -#include "cc/surfaces/surface_factory_client.h" -#include "third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom.h" +#include "cc/ipc/compositor_frame.mojom.h" +#include "cc/ipc/mojo_compositor_frame_sink.mojom.h" +#include "cc/resources/transferable_resource.h" +#include "cc/surfaces/compositor_frame_sink_support.h" +#include "cc/surfaces/compositor_frame_sink_support_client.h" +#include "mojo/public/cpp/bindings/strong_binding.h" namespace content { class OffscreenCanvasCompositorFrameSink - : public cc::mojom::MojoCompositorFrameSink, - public cc::SurfaceFactoryClient { + : public cc::CompositorFrameSinkSupportClient, + public cc::mojom::MojoCompositorFrameSink { public: - OffscreenCanvasCompositorFrameSink( - const cc::SurfaceId& surface_id, - cc::mojom::MojoCompositorFrameSinkClientPtr client); - ~OffscreenCanvasCompositorFrameSink() override; - - static void Create(const cc::SurfaceId& surface_id, + static void Create(const cc::FrameSinkId& frame_sink_id, + cc::SurfaceManager* surface_manager, cc::mojom::MojoCompositorFrameSinkClientPtr client, cc::mojom::MojoCompositorFrameSinkRequest request); - // cc::mojom::MojoCompositorFrameSink implementation. + OffscreenCanvasCompositorFrameSink( + const cc::FrameSinkId& frame_sink_id, + cc::SurfaceManager* surface_manager, + cc::mojom::MojoCompositorFrameSinkClientPtr client); + + ~OffscreenCanvasCompositorFrameSink() override; + + // Overridden from cc::mojom::MojoCompositorFrameSink: + void SetNeedsBeginFrame(bool needs_begin_frame) override; void SubmitCompositorFrame(const cc::LocalFrameId& local_frame_id, cc::CompositorFrame frame) override; - void SetNeedsBeginFrame(bool needs_begin_frame) override; void AddSurfaceReferences( const std::vector<cc::SurfaceReference>& references) override; void RemoveSurfaceReferences( @@ -40,20 +43,17 @@ const cc::SurfaceSequence& sequence) override; void Satisfy(const cc::SurfaceSequence& sequence) override; - // cc::SurfaceFactoryClient implementation. - void ReturnResources(const cc::ReturnedResourceArray& resources) override; - void WillDrawSurface(const cc::LocalFrameId& id, - const gfx::Rect& damage_rect) override; - void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override; + // Overridden from cc::CompositorFrameSinkSupportClient: + void DidReceiveCompositorFrameAck() override; + void OnBeginFrame(const cc::BeginFrameArgs& args) override; + void ReclaimResources(const cc::ReturnedResourceArray& resources) override; + void WillDrawSurface() override; private: - void DidReceiveCompositorFrameAck(); - - cc::SurfaceId surface_id_; - std::unique_ptr<cc::SurfaceFactory> surface_factory_; + cc::CompositorFrameSinkSupport support_; cc::mojom::MojoCompositorFrameSinkClientPtr client_; - int ack_pending_count_ = 0; cc::ReturnedResourceArray surface_returned_resources_; + mojo::StrongBindingPtr<cc::mojom::MojoCompositorFrameSink> binding_; DISALLOW_COPY_AND_ASSIGN(OffscreenCanvasCompositorFrameSink); };
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.cc b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.cc index 65a17494..d5877e31 100644 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.cc +++ b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.cc
@@ -4,6 +4,7 @@ #include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_provider_impl.h" +#include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h" #include "mojo/public/cpp/bindings/strong_binding.h" @@ -27,8 +28,9 @@ const cc::SurfaceId& surface_id, cc::mojom::MojoCompositorFrameSinkClientPtr client, cc::mojom::MojoCompositorFrameSinkRequest request) { - OffscreenCanvasCompositorFrameSink::Create(surface_id, std::move(client), - std::move(request)); + OffscreenCanvasCompositorFrameSink::Create( + surface_id.frame_sink_id(), GetSurfaceManager(), std::move(client), + std::move(request)); } } // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 0ae4796..9ae4ccf 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1209,7 +1209,7 @@ AddUIThreadInterface( registry.get(), - base::Bind(&PaymentAppContext::CreateService, + base::Bind(&PaymentAppContextImpl::CreateService, base::Unretained( storage_partition_impl_->GetPaymentAppContext())));
diff --git a/content/browser/resources/accessibility/accessibility.css b/content/browser/resources/accessibility/accessibility.css index e00a9223..4ef49c9 100644 --- a/content/browser/resources/accessibility/accessibility.css +++ b/content/browser/resources/accessibility/accessibility.css
@@ -7,7 +7,7 @@ body { font-family: Arial, sans-serif; font-size: 12px; - margin: 10px; + margin: 10px 20px; min-width: 47em; padding-bottom: 65px; } @@ -28,3 +28,45 @@ color: #A0A0A0; } +p { + line-height: 1.2em; +} + +.columns { + display: flex; +} + +.column { + flex-basis: 50%; +} + +.checkbox_row { + display: flex; + align-items: center; +} + +.checkbox_wrapper { + width: 32px; + margin: 0 0 2px 0; + padding: 0; + flex-grow: 0; +} + +.secondary { + margin: 0 0 12px 32px; + color: #696969; +} + +label { + margin: 0 0 2px 0; + padding: 0; + flex-grow: 1; +} + +label.disabled { + color: #696969; +} + +label input[type="checkbox"] { + margin-right: 6px; +}
diff --git a/content/browser/resources/accessibility/accessibility.html b/content/browser/resources/accessibility/accessibility.html index 1d8efd3..62749dca 100644 --- a/content/browser/resources/accessibility/accessibility.html +++ b/content/browser/resources/accessibility/accessibility.html
@@ -7,7 +7,7 @@ --> <head> <meta charset="utf-8"> - <title>Accessibility</title> + <title>Accessibility Internals</title> <link rel="stylesheet" href="chrome://resources/css/chrome_shared.css"> <link rel="stylesheet" href="accessibility.css"> <script src="chrome://resources/js/cr.js"></script> @@ -18,13 +18,123 @@ <script src="accessibility.js"></script> </head> <body> - <h1>Accessibility</h1> + <h1>Accessibility Internals</h1> + + <div class="columns"> + <div class="column"> + <h2>Global accessibility mode:</h2> + + <div class="checkbox_row"> + <span class="checkbox_wrapper"> + <input type="checkbox" id="native" + aria-describedby="native_secondary"> + </span> + <label for="native"> + Native accessibility API support + </label> + </div> + <div id="native_secondary" class="secondary"> + Allows Chrome to be controlled via native accessibility APIs + specific to this platform. + </div> + + <div class="checkbox_row"> + <span class="checkbox_wrapper"> + <input type="checkbox" id="web" + aria-describedby="web_secondary"> + </span> + <label for="web"> + Web accessibility + </label> + </div> + <div id="web_secondary" class="secondary"> + Accessibility support is enabled for web content. + </div> + + <div class="checkbox_row"> + <span class="checkbox_wrapper"> + <input type="checkbox" id="text" + aria-describedby="text_secondary"> + </span> + <label for="text"> + Text metrics + </label> + </div> + <div id="text_secondary" class="secondary"> + Enables support for querying line breaks and the bounding + box of arbitrary character ranges. + </div> + + <div class="checkbox_row"> + <span class="checkbox_wrapper"> + <input type="checkbox" id="screenreader" + aria-describedby="screenreader_secondary"> + </span> + <label for="screenreader"> + Screen reader support + </label> + </div> + <div id="screenreader_secondary" class="secondary"> + Exposes accessibility APIs typically needed only by + screen readers. + </div> + + <div class="checkbox_row"> + <span class="checkbox_wrapper"> + <input type="checkbox" id="html" + aria-describedby="html_secondary"> + </span> + <label for="html"> + HTML + </label> + </div> + <div id="html_secondary" class="secondary"> + Exposes HTML tag names and attributes via accessibility APIs. + </div> + + <h2>Options:</h2> + + <div class="checkbox_row"> + <span class="checkbox_wrapper"> + <input type="checkbox" id="internal" + aria-describedby="internal_secondary"> + </span> + <label for="internal"> + Internal + </label> + </div> + <div id="internal_secondary" class="secondary"> + Show internal accessibility tree instead of native + </div> + + </div> + <div class="column"> + <p> + Accessibility features in Chrome are off by default and enabled + automatically on-demand. Changes to this page only take effect + until the next time Chrome is restarted. + </p> + <p> + To force accessibility to be enabled at launch, run Chrome with this + command-line flag: + <pre>--force-renderer-accessibility</pre> + </p> + <p> + To disable accessibility, run Chrome with this flag: + <pre>--disable-renderer-accessibility</pre> + </p> + </div> + </div> + + <!-- <div id="global" class="row">Global accessibility mode: <a is="action-link" role="button" id="toggle_global" aria-labelledby="global"></a> </div> + <div id="internal" class="row">Show internal accessibility tree instead of native: <a is="action-link" role="button" id="toggle_internal" aria-labelledby="internal"></a> </div> +--> <div id="pages" class="list"></div> <script src="chrome://resources/js/i18n_template.js"></script> </body>
diff --git a/content/browser/resources/accessibility/accessibility.js b/content/browser/resources/accessibility/accessibility.js index 64a6873..a4ce498 100644 --- a/content/browser/resources/accessibility/accessibility.js +++ b/content/browser/resources/accessibility/accessibility.js
@@ -5,24 +5,6 @@ cr.define('accessibility', function() { 'use strict'; - // Keep in sync with view_message_enums.h - var AccessibilityModeFlag = { - Platform: 1 << 0, - FullTree: 1 << 1 - } - - var AccessibilityMode = { - Off: 0, - Complete: - AccessibilityModeFlag.Platform | AccessibilityModeFlag.FullTree, - EditableTextOnly: AccessibilityModeFlag.Platform, - TreeOnly: AccessibilityModeFlag.FullTree - } - - function isAccessibilityComplete(mode) { - return ((mode & AccessibilityMode.Complete) == AccessibilityMode.Complete); - } - function requestData() { var xhr = new XMLHttpRequest(); xhr.open('GET', 'targets-data.json', false); @@ -58,23 +40,16 @@ [String(data.processId), String(data.routeId)]); } - function toggleGlobalAccessibility() { - chrome.send('toggleGlobalAccessibility'); - document.location.reload(); // FIXME see TODO above - } - - function toggleInternalTree() { - chrome.send('toggleInternalTree'); - document.location.reload(); // FIXME see TODO above - } - function initialize() { console.log('initialize'); var data = requestData(); - addGlobalAccessibilityModeToggle(data['global_a11y_mode']); - - addInternalTreeToggle(data['global_internal_tree_mode']); + bindCheckbox('native', data['native']); + bindCheckbox('web', data['web']); + bindCheckbox('text', data['text']); + bindCheckbox('screenreader', data['screenreader']); + bindCheckbox('html', data['html']); + bindCheckbox('internal', data['internal']); $('pages').textContent = ''; @@ -84,22 +59,17 @@ } } - function addGlobalAccessibilityModeToggle(global_a11y_mode) { - var full_a11y_on = isAccessibilityComplete(global_a11y_mode); - $('toggle_global').textContent = (full_a11y_on ? 'on' : 'off'); - $('toggle_global').setAttribute('aria-pressed', - (full_a11y_on ? 'true' : 'false')); - $('toggle_global').addEventListener('click', - toggleGlobalAccessibility); - } - - function addInternalTreeToggle(global_internal_tree_mode) { - var on = global_internal_tree_mode; - $('toggle_internal').textContent = (on ? 'on' : 'off'); - $('toggle_internal').setAttribute('aria-pressed', - (on ? 'true' : 'false')); - $('toggle_internal').addEventListener('click', - toggleInternalTree); + function bindCheckbox(name, value) { + if (value == 'on') + $(name).checked = true; + if (value == 'disabled') { + $(name).disabled = true; + $(name).labels[0].classList.add('disabled'); + } + $(name).addEventListener('change', function() { + chrome.send('setGlobalFlag', [name, $(name).checked]); + document.location.reload(); // FIXME see TODO above + }); } function addToPagesList(data) { @@ -129,7 +99,7 @@ row.appendChild(formatValue(data, properties[j])); row.appendChild(createToggleAccessibilityElement(data)); - if (isAccessibilityComplete(data['a11y_mode'])) { + if (data['a11y_mode']) { row.appendChild(document.createTextNode(' | ')); if ('tree' in data) { row.appendChild(createShowAccessibilityTreeElement(data, row, true)); @@ -169,7 +139,7 @@ function createToggleAccessibilityElement(data) { var link = document.createElement('a', 'action-link'); link.setAttribute('role', 'button'); - var full_a11y_on = isAccessibilityComplete(data['a11y_mode']); + var full_a11y_on = data['a11y_mode']; link.textContent = 'accessibility ' + (full_a11y_on ? 'on' : 'off'); link.setAttribute('aria-pressed', (full_a11y_on ? 'true' : 'false')); link.addEventListener('click',
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index a2d6035..9d9b2a6 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -375,7 +375,7 @@ HostZoomLevelContext* host_zoom_level_context, PlatformNotificationContextImpl* platform_notification_context, BackgroundSyncContext* background_sync_context, - PaymentAppContext* payment_app_context, + PaymentAppContextImpl* payment_app_context, scoped_refptr<BroadcastChannelProvider> broadcast_channel_provider) : partition_path_(partition_path), quota_manager_(quota_manager), @@ -515,8 +515,8 @@ new BackgroundSyncContext(); background_sync_context->Init(service_worker_context); - scoped_refptr<PaymentAppContext> payment_app_context = - new PaymentAppContext(service_worker_context); + scoped_refptr<PaymentAppContextImpl> payment_app_context = + new PaymentAppContextImpl(service_worker_context); scoped_refptr<BroadcastChannelProvider> broadcast_channel_provider = new BroadcastChannelProvider(); @@ -605,7 +605,7 @@ return background_sync_context_.get(); } -PaymentAppContext* StoragePartitionImpl::GetPaymentAppContext() { +PaymentAppContextImpl* StoragePartitionImpl::GetPaymentAppContext() { return payment_app_context_.get(); }
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index b10f3ab..f00d02f 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h
@@ -22,7 +22,7 @@ #include "content/browser/host_zoom_level_context.h" #include "content/browser/indexed_db/indexed_db_context_impl.h" #include "content/browser/notifications/platform_notification_context_impl.h" -#include "content/browser/payments/payment_app_context.h" +#include "content/browser/payments/payment_app_context_impl.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/common/content_export.h" #include "content/common/storage_partition_service.mojom.h" @@ -75,7 +75,7 @@ PlatformNotificationContextImpl* GetPlatformNotificationContext() override; BackgroundSyncContext* GetBackgroundSyncContext(); - PaymentAppContext* GetPaymentAppContext(); + PaymentAppContextImpl* GetPaymentAppContext(); BroadcastChannelProvider* GetBroadcastChannelProvider(); // mojom::StoragePartitionService interface. @@ -180,7 +180,7 @@ HostZoomLevelContext* host_zoom_level_context, PlatformNotificationContextImpl* platform_notification_context, BackgroundSyncContext* background_sync_context, - PaymentAppContext* payment_app_context, + PaymentAppContextImpl* payment_app_context, scoped_refptr<BroadcastChannelProvider>broadcast_channel_provider); // We will never have both remove_origin be populated and a cookie_matcher. @@ -226,7 +226,7 @@ scoped_refptr<HostZoomLevelContext> host_zoom_level_context_; scoped_refptr<PlatformNotificationContextImpl> platform_notification_context_; scoped_refptr<BackgroundSyncContext> background_sync_context_; - scoped_refptr<PaymentAppContext> payment_app_context_; + scoped_refptr<PaymentAppContextImpl> payment_app_context_; scoped_refptr<BroadcastChannelProvider> broadcast_channel_provider_; mojo::BindingSet<mojom::StoragePartitionService> bindings_;
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc index ebcaf95..de94f2d1 100644 --- a/content/browser/web_contents/web_contents_view_aura.cc +++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -41,6 +41,7 @@ #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_view_delegate.h" #include "content/public/browser/web_drag_dest_delegate.h" +#include "content/public/common/child_process_host.h" #include "content/public/common/content_client.h" #include "content/public/common/content_switches.h" #include "content/public/common/drop_data.h" @@ -76,6 +77,7 @@ #include "ui/touch_selection/touch_selection_controller.h" namespace content { + WebContentsView* CreateWebContentsView( WebContentsImpl* web_contents, WebContentsViewDelegate* delegate, @@ -405,6 +407,10 @@ return web_input_event_modifiers; } +GlobalRoutingID GetRenderViewHostID(RenderViewHost* rvh) { + return GlobalRoutingID(rvh->GetProcess()->GetID(), rvh->GetRoutingID()); +} + } // namespace class WebContentsViewAura::WindowObserver @@ -520,7 +526,10 @@ delegate_(delegate), current_drag_op_(blink::WebDragOperationNone), drag_dest_delegate_(nullptr), - current_rvh_for_drag_(nullptr), + current_rvh_for_drag_(ChildProcessHost::kInvalidUniqueID, + MSG_ROUTING_NONE), + drag_start_process_id_(ChildProcessHost::kInvalidUniqueID), + drag_start_view_id_(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE), current_overscroll_gesture_(OVERSCROLL_NONE), completed_overscroll_gesture_(OVERSCROLL_NONE), navigation_overlay_(nullptr), @@ -557,6 +566,10 @@ void WebContentsViewAura::EndDrag(RenderWidgetHost* source_rwh, blink::WebDragOperationsMask ops) { + drag_start_process_id_ = ChildProcessHost::kInvalidUniqueID; + drag_start_view_id_ = GlobalRoutingID(ChildProcessHost::kInvalidUniqueID, + MSG_ROUTING_NONE); + if (!web_contents_) return; @@ -568,8 +581,8 @@ if (screen_position_client) screen_position_client->ConvertPointFromScreen(window, &client_loc); - // TODO(paulmeyer): In the OOPIF case, should |client_loc| be converted to - // the coordinates local to |drag_start_rwh_|? See crbug.com/647249. + // TODO(paulmeyer): In the OOPIF case, should |client_loc| be converted to the + // coordinates local to |source_rwh|? See crbug.com/647249. web_contents_->DragSourceEndedAt(client_loc.x(), client_loc.y(), screen_loc.x(), screen_loc.y(), ops, source_rwh); @@ -634,6 +647,13 @@ return window_.get(); } +bool WebContentsViewAura::IsValidDragTarget( + RenderWidgetHostImpl* target_rwh) const { + return target_rwh->GetProcess()->GetID() == drag_start_process_id_ || + GetRenderViewHostID(web_contents_->GetRenderViewHost()) != + drag_start_view_id_; +} + //////////////////////////////////////////////////////////////////////////////// // WebContentsViewAura, WebContentsView implementation: @@ -912,6 +932,9 @@ base::WeakPtr<RenderWidgetHostImpl> source_rwh_weak_ptr = source_rwh->GetWeakPtr(); + drag_start_process_id_ = source_rwh->GetProcess()->GetID(); + drag_start_view_id_ = GetRenderViewHostID(web_contents_->GetRenderViewHost()); + ui::TouchSelectionController* selection_controller = GetSelectionController(); if (selection_controller) selection_controller->HideAndDisallowShowingAutomatically(); @@ -1135,12 +1158,17 @@ void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) { gfx::Point transformed_pt; - current_rwh_for_drag_ = + RenderWidgetHostImpl* target_rwh = web_contents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint( web_contents_->GetRenderViewHost()->GetWidget()->GetView(), - event.location(), &transformed_pt)->GetWeakPtr(); - current_rvh_for_drag_ = web_contents_->GetRenderViewHost(); + event.location(), &transformed_pt); + if (!IsValidDragTarget(target_rwh)) + return; + + current_rwh_for_drag_ = target_rwh->GetWeakPtr(); + current_rvh_for_drag_ = + GetRenderViewHostID(web_contents_->GetRenderViewHost()); current_drop_data_.reset(new DropData()); PrepareDropData(current_drop_data_.get(), event.data()); current_rwh_for_drag_->FilterDropData(current_drop_data_.get()); @@ -1176,6 +1204,9 @@ web_contents_->GetRenderViewHost()->GetWidget()->GetView(), event.location(), &transformed_pt); + if (!IsValidDragTarget(target_rwh)) + return ui::DragDropTypes::DRAG_NONE; + if (target_rwh != current_rwh_for_drag_.get()) { if (current_rwh_for_drag_) current_rwh_for_drag_->DragTargetDragLeave(); @@ -1198,7 +1229,8 @@ } void WebContentsViewAura::OnDragExited() { - if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost() || + if (current_rvh_for_drag_ != + GetRenderViewHostID(web_contents_->GetRenderViewHost()) || !current_drop_data_) { return; } @@ -1221,6 +1253,9 @@ web_contents_->GetRenderViewHost()->GetWidget()->GetView(), event.location(), &transformed_pt); + if (!IsValidDragTarget(target_rwh)) + return ui::DragDropTypes::DRAG_NONE; + if (target_rwh != current_rwh_for_drag_.get()) { if (current_rwh_for_drag_) current_rwh_for_drag_->DragTargetDragLeave();
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h index 6869095..2e7beabc 100644 --- a/content/browser/web_contents/web_contents_view_aura.h +++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "content/browser/loader/global_routing_id.h" #include "content/browser/renderer_host/overscroll_controller_delegate.h" #include "content/browser/renderer_host/render_view_host_delegate_view.h" #include "content/browser/web_contents/web_contents_view.h" @@ -87,6 +88,11 @@ // Returns GetNativeView unless overridden for testing. gfx::NativeView GetRenderWidgetHostViewParent() const; + // Returns whether |target_rwh| is a valid RenderWidgetHost to be dragging + // over. This enforces that same-page, cross-site drags are not allowed. See + // crbug.com/666858. + bool IsValidDragTarget(RenderWidgetHostImpl* target_rwh) const; + // Overridden from WebContentsView: gfx::NativeView GetNativeView() const override; gfx::NativeView GetContentNativeView() const override; @@ -198,10 +204,24 @@ // during a drag, we need to re-send the DragEnter message. base::WeakPtr<RenderWidgetHostImpl> current_rwh_for_drag_; - // We also keep track of the RenderViewHost we're dragging over to avoid - // sending the drag exited message after leaving the current - // view. |current_rvh_for_drag_| should not be dereferenced. - void* current_rvh_for_drag_; + // We also keep track of the ID of the RenderViewHost we're dragging over to + // avoid sending the drag exited message after leaving the current view. + GlobalRoutingID current_rvh_for_drag_; + + // We track the IDs of the source RenderProcessHost and RenderViewHost from + // which the current drag originated. These are used to ensure that drag + // events do not fire over a cross-site frame (with respect to the source + // frame) in the same page (see crbug.com/666858). Specifically, the + // RenderViewHost is used to check the "same page" property, while the + // RenderProcessHost is used to check the "cross-site" property. Note that the + // reason the RenderProcessHost is tracked instead of the RenderWidgetHost is + // so that we still allow drags between non-contiguous same-site frames (such + // frames will have the same process, but different widgets). Note also that + // the RenderViewHost may not be in the same process as the RenderProcessHost, + // since the view corresponds to the page, while the process is specific to + // the frame from which the drag started. + int drag_start_process_id_; + GlobalRoutingID drag_start_view_id_; // The overscroll gesture currently in progress. OverscrollMode current_overscroll_gesture_;
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index 955d471..064a397 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -195,8 +195,9 @@ "java/src/org/chromium/content/browser/picker/TwoFieldDatePickerDialog.java", "java/src/org/chromium/content/browser/picker/WeekPicker.java", "java/src/org/chromium/content/browser/picker/WeekPickerDialog.java", - "java/src/org/chromium/content/browser/shapedetection/FaceDetectionFactory.java", "java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java", + "java/src/org/chromium/content/browser/shapedetection/FaceDetectionProviderFactory.java", + "java/src/org/chromium/content/browser/shapedetection/FaceDetectionProviderImpl.java", "java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java", "java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java", "java/src/org/chromium/content/common/ContentSwitches.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java b/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java index 2af818c2..bbe1db2 100644 --- a/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java
@@ -8,8 +8,8 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; -import org.chromium.blink.mojom.FaceDetection; -import org.chromium.content.browser.shapedetection.FaceDetectionFactory; +import org.chromium.blink.mojom.FaceDetectionProvider; +import org.chromium.content.browser.shapedetection.FaceDetectionProviderFactory; import org.chromium.content_public.browser.InterfaceRegistrar; import org.chromium.content_public.browser.WebContents; import org.chromium.device.BatteryMonitor; @@ -58,8 +58,8 @@ VibrationManager.MANAGER, new VibrationManagerImpl.Factory(applicationContext)); registry.addInterface( BatteryMonitor.MANAGER, new BatteryMonitorFactory(applicationContext)); - registry.addInterface( - FaceDetection.MANAGER, new FaceDetectionFactory(applicationContext)); + registry.addInterface(FaceDetectionProvider.MANAGER, + new FaceDetectionProviderFactory(applicationContext)); // TODO(avayvod): Register the PresentationService implementation here. } }
diff --git a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionFactory.java b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionFactory.java deleted file mode 100644 index 683df5b..0000000 --- a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionFactory.java +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.content.browser.shapedetection; - -import android.content.Context; - -import org.chromium.blink.mojom.FaceDetection; -import org.chromium.services.service_manager.InterfaceFactory; - -/** - * A factory method for registry in InterfaceRegistrarImpl.java. - */ -public class FaceDetectionFactory implements InterfaceFactory<FaceDetection> { - public FaceDetectionFactory(Context context) {} - - @Override - public FaceDetection createImpl() { - return new FaceDetectionImpl(); - } -}
diff --git a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java index be41b16..cfe1a69 100644 --- a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java
@@ -26,13 +26,18 @@ */ public class FaceDetectionImpl implements FaceDetection { private static final String TAG = "FaceDetectionImpl"; - // By default, there is no limit in the number of faces detected. - private static final int MAX_FACES = 10; + private static final int MAX_FACES = 32; + private final boolean mFastMode; + private final int mMaxFaces; + + FaceDetectionImpl(FaceDetectorOptions options) { + mFastMode = options.fastMode; + mMaxFaces = Math.min(options.maxDetectedFaces, MAX_FACES); + } @Override - public void detect(SharedBufferHandle frameData, int width, int height, - FaceDetectorOptions options, DetectResponse callback) { - + public void detect( + SharedBufferHandle frameData, int width, int height, DetectResponse callback) { final long numPixels = (long) width * height; // TODO(xianglu): https://crbug.com/670028 homogeneize overflow checking. if (!frameData.isValid() || width <= 0 || height <= 0 || numPixels > (Long.MAX_VALUE / 4)) { @@ -72,9 +77,9 @@ Bitmap unPremultipliedBitmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.RGB_565); - FaceDetector detector = new FaceDetector(width, height, MAX_FACES); - Face[] detectedFaces = new Face[MAX_FACES]; - // findFaces() will stop at MAX_FACES. + FaceDetector detector = new FaceDetector(width, height, mMaxFaces); + Face[] detectedFaces = new Face[mMaxFaces]; + // findFaces() will stop at |mMaxFaces|. final int numberOfFaces = detector.findFaces(unPremultipliedBitmap, detectedFaces); FaceDetectionResult faceDetectionResult = new FaceDetectionResult();
diff --git a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionProviderFactory.java b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionProviderFactory.java new file mode 100644 index 0000000..8ca1206c --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionProviderFactory.java
@@ -0,0 +1,22 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.browser.shapedetection; + +import android.content.Context; + +import org.chromium.blink.mojom.FaceDetectionProvider; +import org.chromium.services.service_manager.InterfaceFactory; + +/** + * A factory method for registry in InterfaceRegistrarImpl.java. + */ +public class FaceDetectionProviderFactory implements InterfaceFactory<FaceDetectionProvider> { + public FaceDetectionProviderFactory(Context context) {} + + @Override + public FaceDetectionProvider createImpl() { + return new FaceDetectionProviderImpl(); + } +}
diff --git a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionProviderImpl.java b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionProviderImpl.java new file mode 100644 index 0000000..22e3399 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionProviderImpl.java
@@ -0,0 +1,28 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.browser.shapedetection; + +import org.chromium.blink.mojom.FaceDetection; +import org.chromium.blink.mojom.FaceDetectionProvider; +import org.chromium.blink.mojom.FaceDetectorOptions; +import org.chromium.mojo.bindings.InterfaceRequest; +import org.chromium.mojo.system.MojoException; + +/** + * Service provider to create FaceDetection and BarcodeDetection services + */ +public class FaceDetectionProviderImpl implements FaceDetectionProvider { + @Override + public void createFaceDetection( + InterfaceRequest<FaceDetection> request, FaceDetectorOptions options) { + FaceDetection.MANAGER.bind(new FaceDetectionImpl(options), request); + } + + @Override + public void close() {} + + @Override + public void onConnectionError(MojoException e) {} +}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java index e47b980..89f6bfe 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/VSyncMonitorTest.java
@@ -10,6 +10,7 @@ import android.view.WindowManager; import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.DisabledTest; import org.chromium.ui.VSyncMonitor; import java.util.Arrays; @@ -92,6 +93,7 @@ // Check that the vsync period roughly matches the timestamps that the monitor generates. @MediumTest + @DisabledTest(message = "crbug.com/674129") public void testVSyncPeriod() throws InterruptedException { // Collect roughly one second of data on a 60 fps display. VSyncDataCollector collector = new VSyncDataCollector(FRAME_COUNT);
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json index c466532..1c6af2d 100644 --- a/content/public/app/mojo/content_browser_manifest.json +++ b/content/public/app/mojo/content_browser_manifest.json
@@ -13,10 +13,8 @@ ], "renderer": [ "blink::mojom::BackgroundSyncService", - "blink::mojom::BarcodeDetection", "blink::mojom::BroadcastChannelProvider", "blink::mojom::BudgetService", - "blink::mojom::FaceDetection", "blink::mojom::Hyphenation", "blink::mojom::MimeRegistry", "blink::mojom::NotificationService", @@ -72,7 +70,7 @@ "autofill::mojom::AutofillDriver", "autofill::mojom::PasswordManagerDriver", "blink::mojom::BarcodeDetection", - "blink::mojom::FaceDetection", + "blink::mojom::FaceDetectionProvider", "blink::mojom::MediaSessionService", "blink::mojom::PermissionService", "blink::mojom::PresentationService",
diff --git a/content/public/browser/payment_app_context.h b/content/public/browser/payment_app_context.h new file mode 100644 index 0000000..34401318 --- /dev/null +++ b/content/public/browser/payment_app_context.h
@@ -0,0 +1,31 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_BROWSER_PAYMENT_APP_CONTEXT_H_ +#define CONTENT_PUBLIC_BROWSER_PAYMENT_APP_CONTEXT_H_ + +#include <utility> +#include <vector> + +#include "base/callback_forward.h" + +namespace content { + +class PaymentAppContext { + public: + virtual ~PaymentAppContext() {} + + // The ManifestWithID is a pair of the service worker registration id and + // the payment app manifest data associated with it. + using ManifestWithID = + std::pair<int64_t, payments::mojom::PaymentAppManifestPtr>; + using Manifests = std::vector<ManifestWithID>; + using GetAllManifestsCallback = base::Callback<void(Manifests)>; + + virtual void GetAllManifests(const GetAllManifestsCallback& callback) = 0; +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_BROWSER_PAYMENT_APP_CONTEXT_H_
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py index e91fd7d..96f122ca 100755 --- a/content/test/gpu/generate_buildbot_json.py +++ b/content/test/gpu/generate_buildbot_json.py
@@ -1442,9 +1442,6 @@ return True def should_run_on_tester(tester_name, tester_config, test_config, is_fyi): - # TODO(jmadill): Re-enable when n5x fixed. See http://crbug.com/672502. - if 'Nexus 5X' in tester_name: - return False # Check if this config is disabled on this tester if 'disabled_tester_configs' in test_config: for dtc in test_config['disabled_tester_configs']: @@ -1504,7 +1501,7 @@ { 'cipd_package': 'infra/tools/luci/logdog/butler/${platform}', 'location': 'bin', - 'revision': 'git_revision:3ff24775a900b675866fbcacf2a8f98a18b2a16a' + 'revision': 'git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58' } ], 'output_links': [
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index f075ca9..d31eac5c 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -225,9 +225,6 @@ ['win', 'passthrough', 'd3d11'], bug=1523) # angle bug ID self.Fail('conformance/extensions/angle-instanced-arrays.html', ['win', 'passthrough', 'd3d11'], bug=1523) # angle bug ID - self.Fail('conformance/extensions/' + - 'angle-instanced-arrays-out-of-bounds.html', - ['win', 'passthrough', 'd3d11'], bug=1523) # angle bug ID self.Fail('conformance/extensions/ext-disjoint-timer-query.html', ['win', 'passthrough', 'd3d11'], bug=1523) # angle bug ID self.Fail('conformance/extensions/ext-frag-depth.html', @@ -274,30 +271,14 @@ ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/glsl/variables/glsl-built-ins.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID - self.Fail('conformance/limits/gl-line-width.html', - ['win', 'passthrough', 'd3d11'], bug=1523) # angle bug ID self.Fail('conformance/misc/invalid-passed-params.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/misc/object-deletion-behaviour.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID - self.Fail('conformance/misc/type-conversion-test.html', - ['win', 'passthrough', 'd3d11'], bug=602688) self.Fail('conformance/misc/uninitialized-test.html', ['win', 'passthrough', 'd3d11'], bug=1635) # angle bug ID - self.Fail('conformance/misc/webgl-specific.html', - ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID - self.Fail('conformance/more/functions/copyTexImage2D.html', - ['win', 'passthrough', 'd3d11'], bug=665518) self.Fail('conformance/more/functions/copyTexImage2DBadArgs.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID - self.Fail('conformance/more/functions/copyTexSubImage2D.html', - ['win', 'passthrough', 'd3d11'], bug=665518) - self.Fail('conformance/more/functions/drawArrays.html', - ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID - self.Fail('conformance/more/functions/drawArraysOutOfBounds.html', - ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID - self.Fail('conformance/more/functions/drawElementsBadArgs.html', - ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/more/functions/texSubImage2DBadArgs.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/more/functions/texSubImage2DHTMLBadArgs.html', @@ -310,22 +291,14 @@ ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/renderbuffers/framebuffer-object-attachment.html', ['win', 'passthrough', 'd3d11'], bug=602688) - self.Fail('conformance/renderbuffers/framebuffer-state-restoration.html', - ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/renderbuffers/framebuffer-test.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID - self.Fail('conformance/renderbuffers/renderbuffer-initialization.html', - ['win', 'passthrough', 'd3d11'], bug=1635) # angle bug ID - self.Fail('conformance/rendering/draw-arrays-out-of-bounds.html', - ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/rendering/draw-elements-out-of-bounds.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/textures/misc/copy-tex-image-2d-formats.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/textures/misc/copy-tex-image-and-sub-image-2d.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID - self.Fail('conformance/textures/misc/mipmap-fbo.html', - ['win', 'passthrough', 'd3d11'], bug=665518) self.Fail('conformance/textures/misc/tex-input-validation.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID self.Fail('conformance/textures/misc/texture-attachment-formats.html',
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn index ee47cfb..cec404b 100644 --- a/extensions/common/BUILD.gn +++ b/extensions/common/BUILD.gn
@@ -319,6 +319,7 @@ "image_util_unittest.cc", "manifest_handler_unittest.cc", "manifest_handlers/content_capabilities_manifest_unittest.cc", + "manifest_handlers/csp_info_unittest.cc", "manifest_handlers/default_locale_manifest_unittest.cc", "manifest_handlers/externally_connectable_unittest.cc", "manifest_handlers/file_handler_manifest_unittest.cc",
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index 5380a15..e06016c96 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json
@@ -300,9 +300,20 @@ "dependencies": ["permission:networking.config"], "contexts": ["blessed_extension"] }, + "networking.onc": { + "dependencies": ["permission:networking.onc"], + "contexts": ["blessed_extension"], + "source": "networkingPrivate" + }, "networkingPrivate": [{ "dependencies": ["permission:networkingPrivate"], - "contexts": ["blessed_extension"] + "contexts": ["blessed_extension"], + // TODO(tbarzic): networkingPrivate is being renamed to networking.onc. + // The goal is to eventually remove networkingPrivate API in favour of + // networking.onc, but until current usages are migrated to the new + // name, use API aliasing to expose the API under both names. + // (http://crbug.com/672186). + "alias": "networking.onc" }, { "channel": "stable", "contexts": ["webui"],
diff --git a/extensions/common/api/_behavior_features.json b/extensions/common/api/_behavior_features.json index b05f1fc9e..a2da0de 100644 --- a/extensions/common/api/_behavior_features.json +++ b/extensions/common/api/_behavior_features.json
@@ -90,5 +90,39 @@ "2FCBCE08B34CCA1728A85F1EFBD9A34DD2558B2E" // ChromeVox ] } - ] + ], + "whitelisted_for_networking_onc_api": { + "channel": "stable", + "extension_types": ["extension", "legacy_packaged_app", "platform_app"], + "platforms": ["chromeos", "mac", "win", "linux"], + "whitelist": [ + "0DE0F05680A4A056BCEC864ED8DDA84296F82B40", // http://crbug.com/434651 + "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80", // http://crbug.com/293683 + "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE", // http://crbug.com/293683 + "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578", // http://crbug.com/234235 + "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB", // http://crbug.com/234235 + "307E96539209F95A1A8740C713E6998A73657D96", // http://crbug.com/329690 + "11B478CEC461C766A2DC1E5BEEB7970AE06DC9C2", // http://crbug.com/380890 + "0EFB879311E9EFBB7C45251F89EC655711B1F6ED", // http://crbug.com/380890 + "9193D3A51E2FE33B496CDA53EA330423166E7F02", // http://crbug.com/380890 + "F9119B8B18C7C82B51E7BC6FF816B694F2EC3E89", // http://crbug.com/380890 + "63ED55E43214C211F82122ED56407FF1A807F2A3", // Dev + "FA01E0B81978950F2BC5A50512FD769725F57510", // Beta + "B11A93E7E5B541F8010245EBDE2C74647D6C14B9", // Canary + "F155646B5D1CA545F7E1E4E20D573DFDD44C2540", // Google Cast Beta + "16CA7A47AAE4BE49B1E75A6B960C3875E945B264", // Google Cast Stable + "226CF815E39A363090A1E547D53063472B8279FA", // http://crbug.com/588179 + "7AE714FFD394E073F0294CFA134C9F91DB5FBAA4", // CCD Development + "C7DA3A55C2355F994D3FDDAD120B426A0DF63843", // CCD Testing + "75E3CFFFC530582C583E4690EF97C70B9C8423B7", // CCD Release + "4F25792AF1AA7483936DE29C07806F203C7170A0", // http://crbug.com/407693 + "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9", // http://crbug.com/407693 + "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB", // http://crbug.com/407693 + "81986D4F846CEDDDB962643FA501D1780DD441BB", // http://crbug.com/407693 + "2F6F6FDB84E0290ABAB7A9D7571EB344821E5F12", // http://crbug.com/610452 + "5B9E39EA374B136CBE7AED2D872003107642EAD5", // http://crbug.com/610452 + "E0E94FB0C01FFB9CDC7A5F098C99B5A8D2F95902", // http://crbug.com/610452 + "52E0557059A7A28F74ED1D92DDD997E0CCD37806" // http://crbug.com/610452 + ] + } }
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json index edfaff6..9365997 100644 --- a/extensions/common/api/_permission_features.json +++ b/extensions/common/api/_permission_features.json
@@ -308,39 +308,14 @@ "platforms": ["chromeos"], "extension_types": ["extension", "platform_app"] }, + "networking.onc": { + "channel": "dev", + "dependencies": ["behavior:whitelisted_for_networking_onc_api"], + "extension_types": ["extension", "legacy_packaged_app", "platform_app"] + }, "networkingPrivate": { - "channel": "stable", - "extension_types": ["extension", "legacy_packaged_app", "platform_app"], - "platforms": ["chromeos", "mac", "win", "linux"], - "whitelist": [ - "0DE0F05680A4A056BCEC864ED8DDA84296F82B40", // http://crbug.com/434651 - "1C93BD3CF875F4A73C0B2A163BB8FBDA8B8B3D80", // http://crbug.com/293683 - "A3BC37E2148AC4E99BE4B16AF9D42DD1E592BBBE", // http://crbug.com/293683 - "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578", // http://crbug.com/234235 - "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB", // http://crbug.com/234235 - "307E96539209F95A1A8740C713E6998A73657D96", // http://crbug.com/329690 - "11B478CEC461C766A2DC1E5BEEB7970AE06DC9C2", // http://crbug.com/380890 - "0EFB879311E9EFBB7C45251F89EC655711B1F6ED", // http://crbug.com/380890 - "9193D3A51E2FE33B496CDA53EA330423166E7F02", // http://crbug.com/380890 - "F9119B8B18C7C82B51E7BC6FF816B694F2EC3E89", // http://crbug.com/380890 - "63ED55E43214C211F82122ED56407FF1A807F2A3", // Dev - "FA01E0B81978950F2BC5A50512FD769725F57510", // Beta - "B11A93E7E5B541F8010245EBDE2C74647D6C14B9", // Canary - "F155646B5D1CA545F7E1E4E20D573DFDD44C2540", // Google Cast Beta - "16CA7A47AAE4BE49B1E75A6B960C3875E945B264", // Google Cast Stable - "226CF815E39A363090A1E547D53063472B8279FA", // http://crbug.com/588179 - "7AE714FFD394E073F0294CFA134C9F91DB5FBAA4", // CCD Development - "C7DA3A55C2355F994D3FDDAD120B426A0DF63843", // CCD Testing - "75E3CFFFC530582C583E4690EF97C70B9C8423B7", // CCD Release - "4F25792AF1AA7483936DE29C07806F203C7170A0", // http://crbug.com/407693 - "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9", // http://crbug.com/407693 - "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB", // http://crbug.com/407693 - "81986D4F846CEDDDB962643FA501D1780DD441BB", // http://crbug.com/407693 - "2F6F6FDB84E0290ABAB7A9D7571EB344821E5F12", // http://crbug.com/610452 - "5B9E39EA374B136CBE7AED2D872003107642EAD5", // http://crbug.com/610452 - "E0E94FB0C01FFB9CDC7A5F098C99B5A8D2F95902", // http://crbug.com/610452 - "52E0557059A7A28F74ED1D92DDD997E0CCD37806" // http://crbug.com/610452 - ] + "dependencies": ["behavior:whitelisted_for_networking_onc_api"], + "extension_types": ["extension", "legacy_packaged_app", "platform_app"] }, "power": { "channel": "stable",
diff --git a/extensions/common/extension_api.cc b/extensions/common/extension_api.cc index a32b095..26ca193 100644 --- a/extensions/common/extension_api.cc +++ b/extensions/common/extension_api.cc
@@ -157,7 +157,7 @@ } void ExtensionAPI::InitDefaultConfiguration() { - const char* names[] = {"api", "manifest", "permission"}; + const char* names[] = {"api", "behavior", "manifest", "permission"}; for (size_t i = 0; i < arraysize(names); ++i) RegisterDependencyProvider(names[i], FeatureProvider::GetByName(names[i]));
diff --git a/extensions/common/features/behavior_feature.cc b/extensions/common/features/behavior_feature.cc index 519b829..1248276 100644 --- a/extensions/common/features/behavior_feature.cc +++ b/extensions/common/features/behavior_feature.cc
@@ -19,6 +19,9 @@ const char kSigninScreen[] = "signin_screen"; +const char kWhitelistedForNetworkingOncApi[] = + "whitelisted_for_networking_onc_api"; + } // namespace behavior_feature } // namespace extensions
diff --git a/extensions/common/features/behavior_feature.h b/extensions/common/features/behavior_feature.h index 190cf7d..bf799a5e 100644 --- a/extensions/common/features/behavior_feature.h +++ b/extensions/common/features/behavior_feature.h
@@ -16,6 +16,7 @@ extern const char kZoomWithoutBubble[]; extern const char kAllowUsbDevicesPermissionInterfaceClass[]; extern const char kSigninScreen[]; +extern const char kWhitelistedForNetworkingOncApi[]; } // namespace behavior_feature
diff --git a/extensions/common/manifest_handlers/csp_info_unittest.cc b/extensions/common/manifest_handlers/csp_info_unittest.cc new file mode 100644 index 0000000..e6698fa --- /dev/null +++ b/extensions/common/manifest_handlers/csp_info_unittest.cc
@@ -0,0 +1,74 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/common/manifest_constants.h" +#include "extensions/common/manifest_handlers/csp_info.h" +#include "extensions/common/manifest_test.h" + +namespace extensions { + +namespace errors = manifest_errors; + +using CSPInfoUnitTest = ManifestTest; + +TEST_F(CSPInfoUnitTest, SandboxedPages) { + // Sandboxed pages specified, no custom CSP value. + scoped_refptr<Extension> extension1( + LoadAndExpectSuccess("sandboxed_pages_valid_1.json")); + + // No sandboxed pages. + scoped_refptr<Extension> extension2( + LoadAndExpectSuccess("sandboxed_pages_valid_2.json")); + + // Sandboxed pages specified with a custom CSP value. + scoped_refptr<Extension> extension3( + LoadAndExpectSuccess("sandboxed_pages_valid_3.json")); + + // Sandboxed pages specified with wildcard, no custom CSP value. + scoped_refptr<Extension> extension4( + LoadAndExpectSuccess("sandboxed_pages_valid_4.json")); + + // Sandboxed pages specified with filename wildcard, no custom CSP value. + scoped_refptr<Extension> extension5( + LoadAndExpectSuccess("sandboxed_pages_valid_5.json")); + + const char kSandboxedCSP[] = + "sandbox allow-scripts allow-forms allow-popups allow-modals"; + const char kDefaultCSP[] = + "script-src 'self' blob: filesystem: chrome-extension-resource:; " + "object-src 'self' blob: filesystem:;"; + const char kCustomSandboxedCSP[] = + "sandbox; script-src: https://www.google.com"; + + EXPECT_EQ(kSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension1.get(), "/test")); + EXPECT_EQ(kDefaultCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension1.get(), "/none")); + EXPECT_EQ(kDefaultCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension2.get(), "/test")); + EXPECT_EQ(kCustomSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension3.get(), "/test")); + EXPECT_EQ(kDefaultCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension3.get(), "/none")); + EXPECT_EQ(kSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension4.get(), "/test")); + EXPECT_EQ(kSandboxedCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension5.get(), "/path/test.ext")); + EXPECT_EQ(kDefaultCSP, CSPInfo::GetResourceContentSecurityPolicy( + extension5.get(), "/test")); + + Testcase testcases[] = { + Testcase("sandboxed_pages_invalid_1.json", + errors::kInvalidSandboxedPagesList), + Testcase("sandboxed_pages_invalid_2.json", errors::kInvalidSandboxedPage), + Testcase("sandboxed_pages_invalid_3.json", + errors::kInvalidSandboxedPagesCSP), + Testcase("sandboxed_pages_invalid_4.json", + errors::kInvalidSandboxedPagesCSP), + Testcase("sandboxed_pages_invalid_5.json", + errors::kInvalidSandboxedPagesCSP)}; + RunTestcases(testcases, arraysize(testcases), EXPECT_TYPE_ERROR); +} + +} // namespace extensions
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h index d46bfb8..264c19e 100644 --- a/extensions/common/permissions/api_permission.h +++ b/extensions/common/permissions/api_permission.h
@@ -241,6 +241,7 @@ kResourcesPrivate, kDisplaySource, kClipboard, + kNetworkingOnc, // Last entry: Add new entries above and ensure to update the // "ExtensionPermission3" enum in tools/metrics/histograms/histograms.xml // (by running update_extension_permission.py).
diff --git a/extensions/common/permissions/extensions_api_permissions.cc b/extensions/common/permissions/extensions_api_permissions.cc index 3ff3a4991..225d6ca 100644 --- a/extensions/common/permissions/extensions_api_permissions.cc +++ b/extensions/common/permissions/extensions_api_permissions.cc
@@ -64,6 +64,7 @@ {APIPermission::kMetricsPrivate, "metricsPrivate", APIPermissionInfo::kFlagCannotBeOptional}, {APIPermission::kNetworkingConfig, "networking.config"}, + {APIPermission::kNetworkingOnc, "networking.onc"}, {APIPermission::kNetworkingPrivate, "networkingPrivate", APIPermissionInfo::kFlagCannotBeOptional}, {APIPermission::kPower, "power"},
diff --git a/extensions/common/switches.cc b/extensions/common/switches.cc index 1879b879..7d18633 100644 --- a/extensions/common/switches.cc +++ b/extensions/common/switches.cc
@@ -49,10 +49,6 @@ // Enables tab for desktop sharing. const char kDisableTabForDesktopShare[] = "disable-tab-for-desktop-share"; -// Disable new UI for desktop capture picker window. -const char kDisableDesktopCapturePickerNewUI[] = - "disable-desktop-capture-picker-new-ui"; - // Allows the ErrorConsole to collect runtime and manifest errors, and display // them in the chrome:extensions page. const char kErrorConsole[] = "error-console";
diff --git a/extensions/common/switches.h b/extensions/common/switches.h index 8f01e70f..deb6eb7 100644 --- a/extensions/common/switches.h +++ b/extensions/common/switches.h
@@ -14,7 +14,6 @@ extern const char kAllowHTTPBackgroundPage[]; extern const char kAllowLegacyExtensionManifests[]; extern const char kDisableDesktopCaptureAudio[]; -extern const char kDisableDesktopCapturePickerNewUI[]; extern const char kDisableTabForDesktopShare[]; extern const char kEmbeddedExtensionOptions[]; extern const char kEnableAppWindowControls[];
diff --git a/extensions/renderer/api_binding.cc b/extensions/renderer/api_binding.cc index 2f585a0..9b6b609 100644 --- a/extensions/renderer/api_binding.cc +++ b/extensions/renderer/api_binding.cc
@@ -290,6 +290,9 @@ DCHECK(success.FromJust()); } + if (binding_hooks_) + binding_hooks_->InitializeInContext(context, api_name_); + return object; } @@ -300,14 +303,15 @@ v8::Isolate* isolate = arguments->isolate(); v8::HandleScope handle_scope(isolate); - if (binding_hooks_) { - // Check for a custom hook to handle the method. - APIBindingHooks::HandleRequestHook handler = - binding_hooks_->GetHandleRequest(name); - if (!handler.is_null()) { - handler.Run(signature, arguments); - return; - } + // Since this is called synchronously from the JS entry point, + // GetCurrentContext() should always be correct. + v8::Local<v8::Context> context = isolate->GetCurrentContext(); + + // Check for a custom hook to handle the method. + if (binding_hooks_ && + binding_hooks_->HandleRequest(api_name_, name, context, + signature, arguments)) { + return; // Handled by a custom hook. } std::unique_ptr<base::ListValue> parsed_arguments; @@ -327,10 +331,8 @@ return; } - // Since this is called synchronously from the JS entry point, - // GetCurrentContext() should always be correct. method_callback_.Run(name, std::move(parsed_arguments), isolate, - isolate->GetCurrentContext(), callback); + context, callback); } } // namespace extensions
diff --git a/extensions/renderer/api_binding_hooks.cc b/extensions/renderer/api_binding_hooks.cc index 98d0c72b..5cd77ac8 100644 --- a/extensions/renderer/api_binding_hooks.cc +++ b/extensions/renderer/api_binding_hooks.cc
@@ -4,9 +4,117 @@ #include "extensions/renderer/api_binding_hooks.h" +#include "base/memory/ptr_util.h" +#include "base/strings/stringprintf.h" +#include "base/supports_user_data.h" +#include "gin/arguments.h" +#include "gin/handle.h" +#include "gin/object_template_builder.h" +#include "gin/per_context_data.h" +#include "gin/wrappable.h" + namespace extensions { -APIBindingHooks::APIBindingHooks() {} +namespace { + +// An interface to allow for registration of custom hooks from JavaScript. +// Contains registered hooks for a single API. +class JSHookInterface final : public gin::Wrappable<JSHookInterface> { + public: + using JSHooks = std::map<std::string, v8::Global<v8::Function>>; + + explicit JSHookInterface(const std::string& api_name) + : api_name_(api_name) {} + + static gin::WrapperInfo kWrapperInfo; + + // gin::Wrappable: + gin::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) override { + return Wrappable<JSHookInterface>::GetObjectTemplateBuilder(isolate) + .SetMethod("setHandleRequest", &JSHookInterface::SetHandleRequest); + } + + JSHooks* js_hooks() { return &js_hooks_; } + + private: + // Adds a custom hook. + void SetHandleRequest(v8::Isolate* isolate, + const std::string& method_name, + v8::Local<v8::Function> handler) { + std::string qualified_method_name = + base::StringPrintf("%s.%s", api_name_.c_str(), method_name.c_str()); + v8::Global<v8::Function>& entry = js_hooks_[qualified_method_name]; + if (!entry.IsEmpty()) { + NOTREACHED() << "Hooks can only be set once."; + return; + } + entry.Reset(isolate, handler); + } + + std::string api_name_; + + JSHooks js_hooks_; + + DISALLOW_COPY_AND_ASSIGN(JSHookInterface); +}; + +const char kExtensionAPIHooksPerContextKey[] = "extension_api_hooks"; + +struct APIHooksPerContextData : public base::SupportsUserData::Data { + APIHooksPerContextData(v8::Isolate* isolate) : isolate(isolate) {} + ~APIHooksPerContextData() override { + v8::HandleScope scope(isolate); + for (const auto& pair : hook_interfaces) { + // We explicitly clear the hook data map here to remove all references to + // v8 objects in order to avoid cycles. + JSHookInterface* hooks = nullptr; + gin::Converter<JSHookInterface*>::FromV8( + isolate, pair.second.Get(isolate), &hooks); + CHECK(hooks); + hooks->js_hooks()->clear(); + } + } + + v8::Isolate* isolate; + + std::map<std::string, v8::Global<v8::Object>> hook_interfaces; +}; + +gin::WrapperInfo JSHookInterface::kWrapperInfo = + {gin::kEmbedderNativeGin}; + +// Creates and returns JS object for the hook interface to allow for +// registering custom hooks from JS. +v8::Local<v8::Object> CreateJSHookInterface(const std::string& api_name, + v8::Local<v8::Context> context) { + gin::PerContextData* per_context_data = gin::PerContextData::From(context); + DCHECK(per_context_data); + APIHooksPerContextData* data = static_cast<APIHooksPerContextData*>( + per_context_data->GetUserData(kExtensionAPIHooksPerContextKey)); + if (!data) { + auto api_data = + base::MakeUnique<APIHooksPerContextData>(context->GetIsolate()); + data = api_data.get(); + per_context_data->SetUserData(kExtensionAPIHooksPerContextKey, + api_data.release()); + } + + DCHECK(data->hook_interfaces.find(api_name) == data->hook_interfaces.end()); + + gin::Handle<JSHookInterface> hooks = + gin::CreateHandle(context->GetIsolate(), new JSHookInterface(api_name)); + CHECK(!hooks.IsEmpty()); + v8::Local<v8::Object> hooks_object = hooks.ToV8().As<v8::Object>(); + data->hook_interfaces[api_name].Reset(context->GetIsolate(), hooks_object); + + return hooks_object; +} + +} // namespace + +APIBindingHooks::APIBindingHooks(const binding::RunJSFunction& run_js) + : run_js_(run_js) {} APIBindingHooks::~APIBindingHooks() {} void APIBindingHooks::RegisterHandleRequest(const std::string& method_name, @@ -15,14 +123,81 @@ request_hooks_[method_name] = hook; } -APIBindingHooks::HandleRequestHook APIBindingHooks::GetHandleRequest( - const std::string& method_name) { - hooks_used_ = true; - auto iter = request_hooks_.find(method_name); - if (iter != request_hooks_.end()) - return iter->second; +void APIBindingHooks::RegisterJsSource(v8::Global<v8::String> source, + v8::Global<v8::String> resource_name) { + js_hooks_source_ = std::move(source); + js_resource_name_ = std::move(resource_name); +} - return HandleRequestHook(); +bool APIBindingHooks::HandleRequest( + const std::string& api_name, + const std::string& method_name, + v8::Local<v8::Context> context, + const binding::APISignature* signature, + gin::Arguments* arguments) { + // Easy case: a native custom hook. + auto request_hooks_iter = request_hooks_.find(method_name); + if (request_hooks_iter != request_hooks_.end()) { + request_hooks_iter->second.Run(signature, arguments); + return true; + } + + // Harder case: looking up a custom hook registered on the context (since + // these are JS, each context has a separate instance). + gin::PerContextData* per_context_data = gin::PerContextData::From(context); + DCHECK(per_context_data); + APIHooksPerContextData* data = static_cast<APIHooksPerContextData*>( + per_context_data->GetUserData(kExtensionAPIHooksPerContextKey)); + if (!data) + return false; + + auto hook_interface_iter = data->hook_interfaces.find(api_name); + if (hook_interface_iter == data->hook_interfaces.end()) + return false; + + JSHookInterface* hook_interface = nullptr; + gin::Converter<JSHookInterface*>::FromV8( + context->GetIsolate(), + hook_interface_iter->second.Get(context->GetIsolate()), &hook_interface); + CHECK(hook_interface); + + auto js_hook_iter = hook_interface->js_hooks()->find(method_name); + if (js_hook_iter == hook_interface->js_hooks()->end()) + return false; + + // Found a JS handler. + std::vector<v8::Local<v8::Value>> v8_args; + // TODO(devlin): Right now, this doesn't support exceptions or return values, + // which we will need to at some point. + if (arguments->GetRemaining(&v8_args)) { + v8::Local<v8::Function> handler = + js_hook_iter->second.Get(context->GetIsolate()); + run_js_.Run(handler, context, v8_args.size(), v8_args.data()); + } + + return true; +} + +void APIBindingHooks::InitializeInContext( + v8::Local<v8::Context> context, + const std::string& api_name) { + if (js_hooks_source_.IsEmpty()) + return; + + v8::Local<v8::String> source = js_hooks_source_.Get(context->GetIsolate()); + v8::Local<v8::String> resource_name = + js_resource_name_.Get(context->GetIsolate()); + v8::Local<v8::Script> script; + v8::ScriptOrigin origin(resource_name); + if (!v8::Script::Compile(context, source, &origin).ToLocal(&script)) + return; + v8::Local<v8::Value> func_as_value = script->Run(); + v8::Local<v8::Function> function; + if (!gin::ConvertFromV8(context->GetIsolate(), func_as_value, &function)) + return; + v8::Local<v8::Object> api_hooks = CreateJSHookInterface(api_name, context); + v8::Local<v8::Value> args[] = {api_hooks}; + run_js_.Run(function, context, arraysize(args), args); } } // namespace extensions
diff --git a/extensions/renderer/api_binding_hooks.h b/extensions/renderer/api_binding_hooks.h index c075c1d..249a3390 100644 --- a/extensions/renderer/api_binding_hooks.h +++ b/extensions/renderer/api_binding_hooks.h
@@ -38,16 +38,29 @@ using HandleRequestHook = base::Callback<void(const binding::APISignature*, gin::Arguments*)>; - APIBindingHooks(); + explicit APIBindingHooks(const binding::RunJSFunction& run_js); ~APIBindingHooks(); // Register a custom binding to handle requests. void RegisterHandleRequest(const std::string& method_name, const HandleRequestHook& hook); - // Returns the custom hook for the given method, or a null callback if none - // exists. - HandleRequestHook GetHandleRequest(const std::string& method_name); + // Registers a JS script to be compiled and run in order to initialize any JS + // hooks within a v8 context. + void RegisterJsSource(v8::Global<v8::String> source, + v8::Global<v8::String> resource_name); + + // Initializes JS hooks within a context. + void InitializeInContext(v8::Local<v8::Context> context, + const std::string& api_name); + + // Looks for a custom hook to handle the given request and, if one exists, + // runs it. Returns true if a hook was found and run. + bool HandleRequest(const std::string& api_name, + const std::string& method_name, + v8::Local<v8::Context> context, + const binding::APISignature* signature, + gin::Arguments* arguments); private: // Whether we've tried to use any hooks associated with this object. @@ -56,6 +69,15 @@ // All registered request handlers. std::map<std::string, HandleRequestHook> request_hooks_; + // The script to run to initialize JS hooks, if any. + v8::Global<v8::String> js_hooks_source_; + + // The name of the JS resource for the hooks. Used to create a ScriptOrigin + // to make exception stack traces more readable. + v8::Global<v8::String> js_resource_name_; + + binding::RunJSFunction run_js_; + DISALLOW_COPY_AND_ASSIGN(APIBindingHooks); };
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/api_binding_unittest.cc index aed169bc..5f96ba0 100644 --- a/extensions/renderer/api_binding_unittest.cc +++ b/extensions/renderer/api_binding_unittest.cc
@@ -450,7 +450,8 @@ ArgumentSpec::RefMap refs; // Register a hook for the test.oneString method. - auto hooks = base::MakeUnique<APIBindingHooks>(); + auto hooks = base::MakeUnique<APIBindingHooks>( + base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); bool did_call = false; auto hook = [](bool* did_call, const binding::APISignature* signature, gin::Arguments* arguments) { @@ -488,4 +489,57 @@ ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]"); } +TEST_F(APIBindingUnittest, TestJSCustomHook) { + // Register a hook for the test.oneString method. + auto hooks = base::MakeUnique<APIBindingHooks>( + base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); + + v8::HandleScope handle_scope(isolate()); + v8::Local<v8::Context> context = ContextLocal(); + const char kRegisterHook[] = + "(function(hooks) {\n" + " hooks.setHandleRequest('oneString', function() {\n" + " this.requestArguments = Array.from(arguments);\n" + " });\n" + "})"; + v8::Local<v8::String> source_string = + gin::StringToV8(isolate(), kRegisterHook); + v8::Local<v8::String> source_name = + gin::StringToV8(isolate(), "custom_hook"); + hooks->RegisterJsSource( + v8::Global<v8::String>(isolate(), source_string), + v8::Global<v8::String>(isolate(), source_name)); + + std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); + ASSERT_TRUE(functions); + ArgumentSpec::RefMap refs; + + APIBinding binding( + "test", *functions, nullptr, nullptr, + base::Bind(&APIBindingUnittest::OnFunctionCall, base::Unretained(this)), + std::move(hooks), &refs); + EXPECT_TRUE(refs.empty()); + + APIEventHandler event_handler( + base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); + v8::Local<v8::Object> binding_object = binding.CreateInstance( + context, isolate(), &event_handler, base::Bind(&AllowAllAPIs)); + + // First try calling the oneString() method, which has a custom hook + // installed. + v8::Local<v8::Function> func = + FunctionFromString(context, "(function(obj) { obj.oneString('foo'); })"); + v8::Local<v8::Value> args[] = {binding_object}; + RunFunction(func, context, 1, args); + + std::unique_ptr<base::Value> response_args = + GetBaseValuePropertyFromObject(context->Global(), context, + "requestArguments"); + ASSERT_TRUE(response_args); + EXPECT_EQ("[\"foo\"]", ValueToString(*response_args)); + + // Other methods, like stringAndInt(), should behave normally. + ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]"); +} + } // namespace extensions
diff --git a/extensions/renderer/api_bindings_system.cc b/extensions/renderer/api_bindings_system.cc index b9879fb..8ab880bb 100644 --- a/extensions/renderer/api_bindings_system.cc +++ b/extensions/renderer/api_bindings_system.cc
@@ -19,6 +19,7 @@ const SendRequestMethod& send_request) : request_handler_(call_js), event_handler_(call_js), + call_js_(call_js), get_api_schema_(get_api_schema), send_request_(send_request) {} @@ -79,7 +80,7 @@ << "Hook registration must happen before creating any binding instances."; std::unique_ptr<APIBindingHooks>& hooks = binding_hooks_[api_name]; if (!hooks) - hooks = base::MakeUnique<APIBindingHooks>(); + hooks = base::MakeUnique<APIBindingHooks>(call_js_); return hooks.get(); }
diff --git a/extensions/renderer/api_bindings_system.h b/extensions/renderer/api_bindings_system.h index 57ce4e7..e7173c4 100644 --- a/extensions/renderer/api_bindings_system.h +++ b/extensions/renderer/api_bindings_system.h
@@ -109,6 +109,8 @@ // performance concern? std::map<std::string, std::unique_ptr<APIBindingHooks>> binding_hooks_; + binding::RunJSFunction call_js_; + // The method to retrieve the DictionaryValue describing a given extension // API. Curried in for testing purposes so we can use fake APIs. GetAPISchemaMethod get_api_schema_;
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_1.json b/extensions/test/data/manifest_tests/sandboxed_pages_invalid_1.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_1.json rename to extensions/test/data/manifest_tests/sandboxed_pages_invalid_1.json
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_2.json b/extensions/test/data/manifest_tests/sandboxed_pages_invalid_2.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_2.json rename to extensions/test/data/manifest_tests/sandboxed_pages_invalid_2.json
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_3.json b/extensions/test/data/manifest_tests/sandboxed_pages_invalid_3.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_3.json rename to extensions/test/data/manifest_tests/sandboxed_pages_invalid_3.json
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_4.json b/extensions/test/data/manifest_tests/sandboxed_pages_invalid_4.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_4.json rename to extensions/test/data/manifest_tests/sandboxed_pages_invalid_4.json
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_5.json b/extensions/test/data/manifest_tests/sandboxed_pages_invalid_5.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_invalid_5.json rename to extensions/test/data/manifest_tests/sandboxed_pages_invalid_5.json
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_1.json b/extensions/test/data/manifest_tests/sandboxed_pages_valid_1.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_1.json rename to extensions/test/data/manifest_tests/sandboxed_pages_valid_1.json
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_2.json b/extensions/test/data/manifest_tests/sandboxed_pages_valid_2.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_2.json rename to extensions/test/data/manifest_tests/sandboxed_pages_valid_2.json
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_3.json b/extensions/test/data/manifest_tests/sandboxed_pages_valid_3.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_3.json rename to extensions/test/data/manifest_tests/sandboxed_pages_valid_3.json
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_4.json b/extensions/test/data/manifest_tests/sandboxed_pages_valid_4.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_4.json rename to extensions/test/data/manifest_tests/sandboxed_pages_valid_4.json
diff --git a/chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_5.json b/extensions/test/data/manifest_tests/sandboxed_pages_valid_5.json similarity index 100% rename from chrome/test/data/extensions/manifest_tests/sandboxed_pages_valid_5.json rename to extensions/test/data/manifest_tests/sandboxed_pages_valid_5.json
diff --git a/ios/chrome/BUILD.gn b/ios/chrome/BUILD.gn index 21d249f..89c1953 100644 --- a/ios/chrome/BUILD.gn +++ b/ios/chrome/BUILD.gn
@@ -24,6 +24,7 @@ "//ios/chrome/browser/metrics:unit_tests", "//ios/chrome/browser/native_app_launcher:unit_tests", "//ios/chrome/browser/net:unit_tests", + "//ios/chrome/browser/omaha:unit_tests", "//ios/chrome/browser/passwords:unit_tests", "//ios/chrome/browser/reading_list:unit_tests", "//ios/chrome/browser/signin:unit_tests", @@ -42,6 +43,7 @@ "//ios/chrome/browser/ui/keyboard:unit_tests", "//ios/chrome/browser/ui/voice:unit_tests", "//ios/chrome/browser/update_client:unit_tests", + "//ios/chrome/browser/upgrade:unit_tests", "//ios/chrome/browser/voice:unit_tests", "//ios/chrome/browser/web:unit_tests", "//ios/chrome/browser/web_resource:unit_tests",
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS index 88e9cae..6c8847f3 100644 --- a/ios/chrome/browser/DEPS +++ b/ios/chrome/browser/DEPS
@@ -92,6 +92,7 @@ "+ios/public/provider/components", "+ios/public/provider/web", "+ios/web/public", + "+libxml/xmlwriter.h", "+net", "+rlz/features", "+third_party/brotli",
diff --git a/ios/chrome/browser/omaha/BUILD.gn b/ios/chrome/browser/omaha/BUILD.gn new file mode 100644 index 0000000..ec365d7 --- /dev/null +++ b/ios/chrome/browser/omaha/BUILD.gn
@@ -0,0 +1,53 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("omaha") { + sources = [ + "omaha_service.h", + "omaha_service.mm", + ] + deps = [ + "//base", + "//base:i18n", + "//components/metrics", + "//components/prefs", + "//components/profile_metrics", + "//components/version_info", + "//ios/chrome/browser", + "//ios/chrome/browser/browser_state:browser_state_impl", + "//ios/chrome/browser/browser_state_metrics", + "//ios/chrome/browser/ui", + "//ios/chrome/browser/upgrade", + "//ios/chrome/common", + "//ios/public/provider/chrome/browser", + "//ios/public/provider/chrome/browser/omaha", + "//ios/web", + "//net", + "//third_party/libxml", + "//url", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "omaha_service_unittest.mm", + ] + deps = [ + ":omaha", + "//base", + "//components/metrics", + "//components/prefs", + "//components/version_info", + "//ios/chrome/browser", + "//ios/chrome/browser/browser_state:test_support", + "//ios/chrome/common", + "//ios/chrome/test:test_support", + "//ios/public/provider/chrome/browser", + "//ios/public/provider/chrome/browser/omaha", + "//ios/web:test_support", + "//net:test_support", + "//testing/gtest", + ] +}
diff --git a/ios/chrome/browser/omaha/omaha_service.h b/ios/chrome/browser/omaha/omaha_service.h new file mode 100644 index 0000000..0808d9e9 --- /dev/null +++ b/ios/chrome/browser/omaha/omaha_service.h
@@ -0,0 +1,193 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_OMAHA_OMAHA_SERVICE_H_ +#define IOS_CHROME_BROWSER_OMAHA_OMAHA_SERVICE_H_ + +#include <memory> + +#include "base/callback.h" +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "base/memory/singleton.h" +#include "base/scoped_observer.h" +#include "base/timer/timer.h" +#include "base/version.h" +#include "net/url_request/url_fetcher_delegate.h" + +namespace base { +class DictionaryValue; +} + +namespace net { +class URLFetcher; +class URLRequestContextGetter; +} + +struct UpgradeRecommendedDetails; + +// This service handles the communication with the Omaha server. It also +// handles all the scheduling necessary to contact the server regularly. +// All methods, but the constructor, |GetInstance| and |Start| methods, must be +// called from the IO thread. +class OmahaService : public net::URLFetcherDelegate { + public: + // Called when an upgrade is recommended. + using UpgradeRecommendedCallback = + base::Callback<void(const UpgradeRecommendedDetails&)>; + + // Starts the service. Also set the |URLRequestContextGetter| necessary to + // access the Omaha server. This method should only be called once. + static void Start(net::URLRequestContextGetter* request_context_getter, + const UpgradeRecommendedCallback& callback); + + // Returns debug information about the omaha service. + static void GetDebugInformation( + const base::Callback<void(base::DictionaryValue*)> callback); + + private: + // For tests: + friend class OmahaServiceTest; + friend class OmahaServiceInternalTest; + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, PingMessageTest); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, + PingMessageTestWithUnknownInstallDate); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, InstallEventMessageTest); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, SendPingFailure); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, SendPingSuccess); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, SendInstallEventSuccess); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, SendPingReceiveUpdate); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, PersistStatesTest); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, BackoffTest); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, NonSpammingTest); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, ActivePingAfterInstallEventTest); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceTest, InstallRetryTest); + FRIEND_TEST_ALL_PREFIXES(OmahaServiceInternalTest, + PingMessageTestWithProfileData); + // For the singleton: + friend struct base::DefaultSingletonTraits<OmahaService>; + friend class base::Singleton<OmahaService>; + + // Enum for the |GetPingContent| and |GetNextPingRequestId| method. + enum PingContent { + INSTALL_EVENT, + USAGE_PING, + }; + + // Initialize the timer. Used on startup. + void Initialize(); + + // net::URLFetcherDelegate + void OnURLFetchComplete(const net::URLFetcher* fetcher) override; + + // Raw GetInstance method. Necessary for using singletons. + static OmahaService* GetInstance(); + + // Private constructor, only used by the singleton. + OmahaService(); + // Private constructor, only used for tests. + explicit OmahaService(bool schedule); + ~OmahaService() override; + + // Returns the time to wait before next attempt. + static base::TimeDelta GetBackOff(uint8_t number_of_tries); + + void set_upgrade_recommended_callback( + const UpgradeRecommendedCallback& callback) { + upgrade_recommended_callback_ = callback; + } + + // Sends a ping to the Omaha server. + void SendPing(); + + // Method that will either start sending a ping to the server, or schedule + // itself to be called again when the next ping must be send. + void SendOrScheduleNextPing(); + + // Persists the state of the service. + void PersistStates(); + + // Returns the XML representation of the ping message to send to the Omaha + // server. If |sendInstallEvent| is true, the message will contain an + // installation complete event. + std::string GetPingContent(const std::string& requestId, + const std::string& sessionId, + const std::string& versionName, + const std::string& channelName, + const base::Time& installationTime, + PingContent pingContent); + + // Returns the xml representation of the ping message to send to the Omaha + // server. Use the current state of the service to compute the right message. + std::string GetCurrentPingContent(); + + // Computes debugging information and fill |result|. + void GetDebugInformationOnIOThread( + const base::Callback<void(base::DictionaryValue*)> callback); + + // Returns whether the next ping to send must a an install/update ping. If + // |true|, the next ping must use |GetInstallRetryRequestId| as identifier + // for the request and must include a X-RequestAge header. + bool IsNextPingInstallRetry(); + + // Returns the request identifier to use for the next ping. If it is an + // install/update retry, it will return the identifier used on the initial + // request. If this is not the case, returns a random id. + // |send_install_event| must be true if the next ping is a install/update + // event, in that case, the identifier will be stored so that it can be + // reused until the ping is successful. + std::string GetNextPingRequestId(PingContent ping_content); + + // Stores the given request id to be reused on install/update retry. + void SetInstallRetryRequestId(const std::string& request_id); + + // Clears the stored request id for a installation/update ping retry. Must be + // called after a successfull installation/update ping. + void ClearInstallRetryRequestId(); + + // Clears the all persistent state. Should only be used for testing. + static void ClearPersistentStateForTests(); + + // To communicate with the Omaha server. + std::unique_ptr<net::URLFetcher> fetcher_; + net::URLRequestContextGetter* request_context_getter_; + + // The timer that call this object back when needed. + base::OneShotTimer timer_; + + // Whether to schedule pings. This is only false for tests. + const bool schedule_; + + // The install date of the application. This is fetched in |Initialize| on + // the main thread and cached for use on the IO thread. + int64_t application_install_date_; + + // The time at which the last ping was sent. + base::Time last_sent_time_; + + // The time at which to send the next ping. + base::Time next_tries_time_; + + // The timestamp of the ping to send. + base::Time current_ping_time_; + + // Last version for which an installation ping has been sent. + base::Version last_sent_version_; + + // The language in use at start up. + std::string locale_lang_; + + // Number of tries of the last ping. + uint8_t number_of_tries_; + + // Whether the ping currently being sent is an install (new or update) ping. + bool sending_install_event_; + + // Called to notify that upgrade is recommended. + UpgradeRecommendedCallback upgrade_recommended_callback_; + + DISALLOW_COPY_AND_ASSIGN(OmahaService); +}; + +#endif // IOS_CHROME_BROWSER_OMAHA_OMAHA_SERVICE_H_
diff --git a/ios/chrome/browser/omaha/omaha_service.mm b/ios/chrome/browser/omaha/omaha_service.mm new file mode 100644 index 0000000..ea46a956 --- /dev/null +++ b/ios/chrome/browser/omaha/omaha_service.mm
@@ -0,0 +1,710 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/omaha/omaha_service.h" + +#include <Foundation/Foundation.h> + +#include <memory> +#include <utility> + +#include "base/bind.h" +#include "base/i18n/time_formatting.h" +#include "base/ios/device_util.h" +#include "base/logging.h" +#include "base/mac/scoped_nsobject.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/field_trial.h" +#include "base/rand_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/sys_string_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "base/sys_info.h" +#include "base/time/time.h" +#include "base/values.h" +#include "components/metrics/metrics_pref_names.h" +#include "components/prefs/pref_service.h" +#include "components/version_info/version_info.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/arch_util.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h" +#include "ios/chrome/browser/browser_state_metrics/browser_state_metrics.h" +#include "ios/chrome/browser/install_time_util.h" +#include "ios/chrome/browser/ui/ui_util.h" +#include "ios/chrome/browser/upgrade/upgrade_recommended_details.h" +#include "ios/chrome/common/channel_info.h" +#include "ios/public/provider/chrome/browser/chrome_browser_provider.h" +#include "ios/public/provider/chrome/browser/omaha/omaha_service_provider.h" +#include "ios/public/provider/chrome/browser/omaha/omaha_xml_writer.h" +#include "ios/web/public/web_thread.h" +#include "libxml/xmlwriter.h" +#include "net/base/backoff_entry.h" +#include "net/base/load_flags.h" +#include "net/url_request/url_fetcher.h" +#include "url/gurl.h" + +namespace { +// Number of hours to wait between successful requests. +const int kHoursBetweenRequests = 5; +// Minimal time to wait between retry requests. +const CFTimeInterval kPostRetryBaseSeconds = 3600; +// Maximal time to wait between retry requests. +const CFTimeInterval kPostRetryMaxSeconds = 6 * kPostRetryBaseSeconds; + +// Default last sent application version when none has been sent yet. +const char kDefaultLastSentVersion[] = "0.0.0.0"; + +// Key for saving states in the UserDefaults. +NSString* const kNextTriesTimesKey = @"ChromeOmahaServiceNextTries"; +NSString* const kCurrentPingKey = @"ChromeOmahaServiceCurrentPing"; +NSString* const kNumberTriesKey = @"ChromeOmahaServiceNumberTries"; +NSString* const kLastSentVersionKey = @"ChromeOmahaServiceLastSentVersion"; +NSString* const kLastSentTimeKey = @"ChromeOmahaServiceLastSentTime"; +NSString* const kRetryRequestIdKey = @"ChromeOmahaServiceRetryRequestId"; + +class XmlWrapper : public OmahaXmlWriter { + public: + XmlWrapper() + : buffer_(xmlBufferCreate()), + writer_(xmlNewTextWriterMemory(buffer_, /* compression */ 0)) { + DCHECK(buffer_); + DCHECK(writer_); + } + + ~XmlWrapper() override { + xmlFreeTextWriter(writer_); + xmlBufferFree(buffer_); + } + + void StartElement(const char* name) override { + DCHECK(name); + int result = xmlTextWriterStartElement( + writer_, reinterpret_cast<const xmlChar*>(name)); + DCHECK_GE(result, 0); + } + + void EndElement() override { + int result = xmlTextWriterEndElement(writer_); + DCHECK_GE(result, 0); + } + + void WriteAttribute(const char* name, const char* value) override { + DCHECK(name); + int result = xmlTextWriterWriteAttribute( + writer_, reinterpret_cast<const xmlChar*>(name), + reinterpret_cast<const xmlChar*>(value)); + DCHECK_GE(result, 0); + } + + void Finalize() override { + int result = xmlTextWriterEndDocument(writer_); + DCHECK_GE(result, 0); + } + + std::string GetContentAsString() override { + return std::string(reinterpret_cast<char*>(buffer_->content)); + } + + private: + xmlBufferPtr buffer_; + xmlTextWriterPtr writer_; + + DISALLOW_COPY_AND_ASSIGN(XmlWrapper); +}; + +} // namespace + +#pragma mark - + +// XML parser for the server response. +@interface ResponseParser : NSObject<NSXMLParserDelegate> { + BOOL hasError_; + BOOL responseIsParsed_; + BOOL appIsParsed_; + BOOL updateCheckIsParsed_; + BOOL urlIsParsed_; + BOOL manifestIsParsed_; + BOOL pingIsParsed_; + BOOL eventIsParsed_; + base::scoped_nsobject<NSString> appId_; + std::unique_ptr<UpgradeRecommendedDetails> updateInformation_; +} + +// Initialization method. |appId| is the application id one expects to find in +// the response message. +- (instancetype)initWithAppId:(NSString*)appId; + +// Returns YES if the message has been correctly parsed. +- (BOOL)isCorrect; + +// If an upgrade is possible, returns the details of the notification to send. +// Otherwise, return NULL. +- (UpgradeRecommendedDetails*)upgradeRecommendedDetails; + +@end + +@implementation ResponseParser + +- (instancetype)initWithAppId:(NSString*)appId { + if (self = [super init]) { + appId_.reset([appId retain]); + } + return self; +} + +- (BOOL)isCorrect { + // A response should have either a ping ACK or an event ACK, depending on the + // contents of the request. + return !hasError_ && (pingIsParsed_ || eventIsParsed_); +} + +- (UpgradeRecommendedDetails*)upgradeRecommendedDetails { + return updateInformation_.get(); +} + +// This method is parsing a message with the following type: +// <response...> +// <daystart.../> +// <app...> +// <updatecheck status="ok"> +// <urls> +// <url codebase="???"/> +// </urls> +// <manifest version="???"> +// <packages> +// <package hash="0" name="Chrome" required="true" size="0"/> +// </packages> +// <actions> +// <action event="update" run="Chrome"/> +// <action event="postinstall"/> +// </actions> +// </manifest> +// </updatecheck> +// <ping.../> +// </app> +// </response> +// --- OR --- +// <response...> +// <daystart.../> +// <app...> +// <event.../> +// </app> +// </response> +// See http://code.google.com/p/omaha/wiki/ServerProtocol for details. +- (void)parser:(NSXMLParser*)parser + didStartElement:(NSString*)elementName + namespaceURI:(NSString*)namespaceURI + qualifiedName:(NSString*)qualifiedName + attributes:(NSDictionary*)attributeDict { + if (hasError_) + return; + + // Array of uninteresting tags in the Omaha xml response. + NSArray* ignoredTagNames = + @[ @"action", @"actions", @"daystart", @"package", @"packages", @"urls" ]; + if ([ignoredTagNames containsObject:elementName]) + return; + + if (!responseIsParsed_) { + if ([elementName isEqualToString:@"response"] && + [[attributeDict valueForKey:@"protocol"] isEqualToString:@"3.0"] && + [[attributeDict valueForKey:@"server"] isEqualToString:@"prod"]) { + responseIsParsed_ = YES; + } else { + hasError_ = YES; + } + } else if (!appIsParsed_) { + if ([elementName isEqualToString:@"app"] && + [[attributeDict valueForKey:@"status"] isEqualToString:@"ok"] && + [[attributeDict valueForKey:@"appid"] isEqualToString:appId_]) { + appIsParsed_ = YES; + } else { + hasError_ = YES; + } + } else if (!eventIsParsed_ && !updateCheckIsParsed_) { + if ([elementName isEqualToString:@"updatecheck"]) { + updateCheckIsParsed_ = YES; + NSString* status = [attributeDict valueForKey:@"status"]; + if ([status isEqualToString:@"noupdate"]) { + // No update is available on the Market, so we won't get a <url> or + // <manifest> tag. + urlIsParsed_ = YES; + manifestIsParsed_ = YES; + } else if ([status isEqualToString:@"ok"]) { + updateInformation_ = base::MakeUnique<UpgradeRecommendedDetails>(); + } else { + hasError_ = YES; + } + } else if ([elementName isEqualToString:@"event"]) { + if ([[attributeDict valueForKey:@"status"] isEqualToString:@"ok"]) { + eventIsParsed_ = YES; + } else { + hasError_ = YES; + } + } else { + hasError_ = YES; + } + } else if (!urlIsParsed_) { + if ([elementName isEqualToString:@"url"] && + [[attributeDict valueForKey:@"codebase"] length] > 0) { + urlIsParsed_ = YES; + DCHECK(updateInformation_); + NSString* url = [attributeDict valueForKey:@"codebase"]; + if ([[url substringFromIndex:([url length] - 1)] isEqualToString:@"/"]) + url = [url substringToIndex:([url length] - 1)]; + updateInformation_.get()->upgrade_url = + GURL(base::SysNSStringToUTF8(url)); + if (!updateInformation_.get()->upgrade_url.is_valid()) + hasError_ = YES; + } else { + hasError_ = YES; + } + } else if (!manifestIsParsed_) { + if ([elementName isEqualToString:@"manifest"] && + [attributeDict valueForKey:@"version"]) { + manifestIsParsed_ = YES; + DCHECK(updateInformation_); + updateInformation_.get()->next_version = + base::SysNSStringToUTF8([attributeDict valueForKey:@"version"]); + } else { + hasError_ = YES; + } + } else if (!pingIsParsed_) { + if ([elementName isEqualToString:@"ping"] && + [[attributeDict valueForKey:@"status"] isEqualToString:@"ok"]) { + pingIsParsed_ = YES; + } else { + hasError_ = YES; + } + } else { + hasError_ = YES; + } +} + +@end + +// static +OmahaService* OmahaService::GetInstance() { + return base::Singleton<OmahaService>::get(); +} + +// static +void OmahaService::Start(net::URLRequestContextGetter* request_context_getter, + const UpgradeRecommendedCallback& callback) { + DCHECK(request_context_getter); + DCHECK(!callback.is_null()); + OmahaService* result = GetInstance(); + result->set_upgrade_recommended_callback(callback); + // This should only be called once. + DCHECK(!result->request_context_getter_); + result->request_context_getter_ = request_context_getter; + result->locale_lang_ = GetApplicationContext()->GetApplicationLocale(); + web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, + base::Bind(&OmahaService::SendOrScheduleNextPing, + base::Unretained(result))); +} + +OmahaService::OmahaService() + : request_context_getter_(NULL), + schedule_(true), + application_install_date_(0), + sending_install_event_(false) { + Initialize(); +} + +OmahaService::OmahaService(bool schedule) + : request_context_getter_(NULL), + schedule_(schedule), + application_install_date_(0), + sending_install_event_(false) { + Initialize(); +} + +OmahaService::~OmahaService() {} + +void OmahaService::Initialize() { + // Initialize the provider at the same time as the rest of the service. + ios::GetChromeBrowserProvider()->GetOmahaServiceProvider()->Initialize(); + + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + next_tries_time_ = base::Time::FromCFAbsoluteTime( + [defaults doubleForKey:kNextTriesTimesKey]); + current_ping_time_ = + base::Time::FromCFAbsoluteTime([defaults doubleForKey:kCurrentPingKey]); + number_of_tries_ = [defaults integerForKey:kNumberTriesKey]; + last_sent_time_ = + base::Time::FromCFAbsoluteTime([defaults doubleForKey:kLastSentTimeKey]); + NSString* lastSentVersion = [defaults stringForKey:kLastSentVersionKey]; + if (lastSentVersion) { + last_sent_version_ = + base::Version(base::SysNSStringToUTF8(lastSentVersion)); + } else { + last_sent_version_ = base::Version(kDefaultLastSentVersion); + } + + application_install_date_ = + GetApplicationContext()->GetLocalState()->GetInt64( + metrics::prefs::kInstallDate); + DCHECK(application_install_date_); + + // Whether data should be persisted again to the user preferences. + bool persist_again = false; + + base::Time now = base::Time::Now(); + // If |last_sent_time_| is in the future, the clock has been tampered with. + // Reset |last_sent_time_| to now. + if (last_sent_time_ > now) { + last_sent_time_ = now; + persist_again = true; + } + + // If the |next_tries_time_| is more than kHoursBetweenRequests hours away, + // there is a possibility that the clock has been tampered with. Reschedule + // the ping to be the usual interval after the last successful one. + if (next_tries_time_ - now > + base::TimeDelta::FromHours(kHoursBetweenRequests)) { + next_tries_time_ = + last_sent_time_ + base::TimeDelta::FromHours(kHoursBetweenRequests); + persist_again = true; + } + + // Fire a ping as early as possible if the version changed. + base::Version current_version(version_info::GetVersionNumber()); + if (last_sent_version_ < current_version) { + next_tries_time_ = base::Time::Now() - base::TimeDelta::FromSeconds(1); + number_of_tries_ = 0; + persist_again = true; + } + + if (persist_again) + PersistStates(); +} + +// static +void OmahaService::GetDebugInformation( + const base::Callback<void(base::DictionaryValue*)> callback) { + web::WebThread::PostTask( + web::WebThread::IO, FROM_HERE, + base::Bind(&OmahaService::GetDebugInformationOnIOThread, + base::Unretained(GetInstance()), callback)); +} + +// static +base::TimeDelta OmahaService::GetBackOff(uint8_t number_of_tries) { + // Configuration for the service exponential backoff + static net::BackoffEntry::Policy kBackoffPolicy = { + 0, // num_errors_to_ignore + kPostRetryBaseSeconds * 1000, // initial_delay_ms + 2.0, // multiply_factor + 0.1, // jitter_factor + kPostRetryMaxSeconds * 1000, // maximum_backoff_ms + -1, // entry_lifetime_ms + false // always_use_initial_delay + }; + + net::BackoffEntry backoff_entry(&kBackoffPolicy); + for (int i = 0; i < number_of_tries; ++i) { + backoff_entry.InformOfRequest(false); + } + + return backoff_entry.GetTimeUntilRelease(); +} + +std::string OmahaService::GetPingContent(const std::string& requestId, + const std::string& sessionId, + const std::string& versionName, + const std::string& channelName, + const base::Time& installationTime, + PingContent pingContent) { + OmahaServiceProvider* provider = + ios::GetChromeBrowserProvider()->GetOmahaServiceProvider(); + + XmlWrapper xml_wrapper; + xml_wrapper.StartElement("request"); + xml_wrapper.WriteAttribute("protocol", "3.0"); + xml_wrapper.WriteAttribute("version", "iOS-1.0.0.0"); + xml_wrapper.WriteAttribute("ismachine", "1"); + xml_wrapper.WriteAttribute("requestid", requestId.c_str()); + xml_wrapper.WriteAttribute("sessionid", sessionId.c_str()); + provider->AppendExtraAttributes("request", &xml_wrapper); + xml_wrapper.WriteAttribute("hardware_class", + ios::device_util::GetPlatform().c_str()); + // Set up <os platform="ios"... /> + xml_wrapper.StartElement("os"); + xml_wrapper.WriteAttribute("platform", "ios"); + xml_wrapper.WriteAttribute("version", + base::SysInfo::OperatingSystemVersion().c_str()); + xml_wrapper.WriteAttribute("arch", arch_util::kCurrentArch); + xml_wrapper.EndElement(); + + bool is_first_install = + pingContent == INSTALL_EVENT && + last_sent_version_ == base::Version(kDefaultLastSentVersion); + + // Set up <app version="" ...> + xml_wrapper.StartElement("app"); + if (pingContent == INSTALL_EVENT) { + std::string previous_version = + is_first_install ? "" : last_sent_version_.GetString(); + xml_wrapper.WriteAttribute("version", previous_version.c_str()); + xml_wrapper.WriteAttribute("nextversion", versionName.c_str()); + } else { + xml_wrapper.WriteAttribute("version", versionName.c_str()); + xml_wrapper.WriteAttribute("nextversion", ""); + } + xml_wrapper.WriteAttribute("lang", locale_lang_.c_str()); + xml_wrapper.WriteAttribute("brand", provider->GetBrandCode().c_str()); + xml_wrapper.WriteAttribute("client", ""); + std::string application_id = provider->GetApplicationID(); + xml_wrapper.WriteAttribute("appid", application_id.c_str()); + std::string install_age; + if (is_first_install) { + install_age = "-1"; + } else if (!installationTime.is_null() && + installationTime.ToTimeT() != + install_time_util::kUnknownInstallDate) { + install_age = base::StringPrintf( + "%d", (base::Time::Now() - installationTime).InDays()); + } + provider->AppendExtraAttributes("app", &xml_wrapper); + // If the install date is unknown, send nothing. + if (!install_age.empty()) + xml_wrapper.WriteAttribute("installage", install_age.c_str()); + + if (pingContent == INSTALL_EVENT) { + // Add an install complete event. + xml_wrapper.StartElement("event"); + if (is_first_install) { + xml_wrapper.WriteAttribute("eventtype", "2"); // install + } else { + xml_wrapper.WriteAttribute("eventtype", "3"); // update + } + xml_wrapper.WriteAttribute("eventresult", "1"); // succeeded + xml_wrapper.EndElement(); + } else { + // Set up <updatecheck/> + xml_wrapper.StartElement("updatecheck"); + xml_wrapper.WriteAttribute("tag", channelName.c_str()); + xml_wrapper.EndElement(); + + // Set up <ping active=1/> + xml_wrapper.StartElement("ping"); + xml_wrapper.WriteAttribute("active", "1"); + xml_wrapper.EndElement(); + } + + // End app. + xml_wrapper.EndElement(); + // End request. + xml_wrapper.EndElement(); + + xml_wrapper.Finalize(); + return xml_wrapper.GetContentAsString(); +} + +std::string OmahaService::GetCurrentPingContent() { + base::Version current_version(version_info::GetVersionNumber()); + sending_install_event_ = last_sent_version_ < current_version; + PingContent ping_content = + sending_install_event_ ? INSTALL_EVENT : USAGE_PING; + + // An install retry ping only makes sense if an install event must be send. + DCHECK(sending_install_event_ || !IsNextPingInstallRetry()); + std::string request_id = GetNextPingRequestId(ping_content); + return GetPingContent(request_id, ios::device_util::GetRandomId(), + version_info::GetVersionNumber(), GetChannelString(), + base::Time::FromTimeT(application_install_date_), + ping_content); +} + +void OmahaService::SendPing() { + // Check that no request is in progress. + DCHECK(!fetcher_); + + GURL url(ios::GetChromeBrowserProvider() + ->GetOmahaServiceProvider() + ->GetUpdateServerURL()); + if (!url.is_valid()) { + return; + } + + fetcher_ = net::URLFetcher::Create(0, url, net::URLFetcher::POST, this); + fetcher_->SetRequestContext(request_context_getter_); + fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | + net::LOAD_DO_NOT_SAVE_COOKIES); + fetcher_->SetUploadData("text/xml", GetCurrentPingContent()); + + // If this is not the first try, notify the omaha server. + if (number_of_tries_ && IsNextPingInstallRetry()) { + fetcher_->SetExtraRequestHeaders(base::StringPrintf( + "X-RequestAge: %lld", + (base::Time::Now() - current_ping_time_).InSeconds())); + } + + // Update last fail time and number of tries, so that if anything fails + // catastrophically, the fail is taken into account. + if (number_of_tries_ < 30) + ++number_of_tries_; + next_tries_time_ = base::Time::Now() + GetBackOff(number_of_tries_); + PersistStates(); + + fetcher_->Start(); +} + +void OmahaService::SendOrScheduleNextPing() { + base::Time now = base::Time::Now(); + if (next_tries_time_ <= now) { + SendPing(); + return; + } + if (schedule_) { + timer_.Start(FROM_HERE, next_tries_time_ - now, this, + &OmahaService::SendPing); + } +} + +void OmahaService::PersistStates() { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + + [defaults setDouble:next_tries_time_.ToCFAbsoluteTime() + forKey:kNextTriesTimesKey]; + [defaults setDouble:current_ping_time_.ToCFAbsoluteTime() + forKey:kCurrentPingKey]; + [defaults setDouble:last_sent_time_.ToCFAbsoluteTime() + forKey:kLastSentTimeKey]; + [defaults setInteger:number_of_tries_ forKey:kNumberTriesKey]; + [defaults setObject:base::SysUTF8ToNSString(last_sent_version_.GetString()) + forKey:kLastSentVersionKey]; + + // Save critical state information for usage reporting. + [defaults synchronize]; +} + +void OmahaService::OnURLFetchComplete(const net::URLFetcher* fetcher) { + DCHECK(fetcher_.get() == fetcher); + // Transfer the ownership of fetcher_ to this method. + std::unique_ptr<net::URLFetcher> local_fetcher = std::move(fetcher_); + + if (fetcher->GetResponseCode() != 200) { + DLOG(WARNING) << "Error contacting the Omaha server"; + SendOrScheduleNextPing(); + return; + } + + std::string response; + bool result = fetcher->GetResponseAsString(&response); + DCHECK(result); + NSData* xml = [NSData dataWithBytes:response.data() length:response.length()]; + base::scoped_nsobject<NSXMLParser> parser( + [[NSXMLParser alloc] initWithData:xml]); + const std::string application_id = ios::GetChromeBrowserProvider() + ->GetOmahaServiceProvider() + ->GetApplicationID(); + base::scoped_nsobject<ResponseParser> delegate([[ResponseParser alloc] + initWithAppId:base::SysUTF8ToNSString(application_id)]); + parser.get().delegate = delegate.get(); + + if (![parser parse] || ![delegate isCorrect]) { + DLOG(ERROR) << "Unable to parse XML response from Omaha server."; + SendOrScheduleNextPing(); + return; + } + // Handle success. + number_of_tries_ = 0; + // Schedule the next request. If requset that just finished was an install + // notification, send an active ping immediately. + next_tries_time_ = sending_install_event_ + ? base::Time::Now() + : base::Time::Now() + base::TimeDelta::FromHours( + kHoursBetweenRequests); + current_ping_time_ = next_tries_time_; + last_sent_time_ = base::Time::Now(); + last_sent_version_ = base::Version(version_info::GetVersionNumber()); + sending_install_event_ = false; + ClearInstallRetryRequestId(); + PersistStates(); + SendOrScheduleNextPing(); + + // Send notification for updates if needed. + UpgradeRecommendedDetails* details = + [delegate.get() upgradeRecommendedDetails]; + if (details) { + web::WebThread::PostTask( + web::WebThread::UI, FROM_HERE, + base::Bind(upgrade_recommended_callback_, *details)); + } +} + +void OmahaService::GetDebugInformationOnIOThread( + const base::Callback<void(base::DictionaryValue*)> callback) { + auto result = base::MakeUnique<base::DictionaryValue>(); + + result->SetString("message", GetCurrentPingContent()); + result->SetString("last_sent_time", + base::TimeFormatShortDateAndTime(last_sent_time_)); + result->SetString("next_tries_time", + base::TimeFormatShortDateAndTime(next_tries_time_)); + result->SetString("current_ping_time", + base::TimeFormatShortDateAndTime(current_ping_time_)); + result->SetString("last_sent_version", last_sent_version_.GetString()); + result->SetString("number_of_tries", + base::StringPrintf("%d", number_of_tries_)); + result->SetString("timer_running", + base::StringPrintf("%d", timer_.IsRunning())); + result->SetString( + "timer_current_delay", + base::StringPrintf("%llds", timer_.GetCurrentDelay().InSeconds())); + result->SetString("timer_desired_run_time", + base::TimeFormatShortDateAndTime( + base::Time::Now() + + (timer_.desired_run_time() - base::TimeTicks::Now()))); + + // Sending the value to the callback. + web::WebThread::PostTask(web::WebThread::UI, FROM_HERE, + base::Bind(callback, base::Owned(result.release()))); +} + +bool OmahaService::IsNextPingInstallRetry() { + return [[NSUserDefaults standardUserDefaults] + stringForKey:kRetryRequestIdKey] != nil; +} + +std::string OmahaService::GetNextPingRequestId(PingContent ping_content) { + NSString* stored_id = + [[NSUserDefaults standardUserDefaults] stringForKey:kRetryRequestIdKey]; + if (stored_id) { + DCHECK(ping_content == INSTALL_EVENT); + return base::SysNSStringToUTF8(stored_id); + } else { + std::string identifier = ios::device_util::GetRandomId(); + if (ping_content == INSTALL_EVENT) + OmahaService::SetInstallRetryRequestId(identifier); + return identifier; + } +} + +void OmahaService::SetInstallRetryRequestId(const std::string& request_id) { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + [defaults setObject:base::SysUTF8ToNSString(request_id) + forKey:kRetryRequestIdKey]; + // Save critical state information for usage reporting. + [defaults synchronize]; +} + +void OmahaService::ClearInstallRetryRequestId() { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:kRetryRequestIdKey]; + // Clear critical state information for usage reporting. + [defaults synchronize]; +} + +void OmahaService::ClearPersistentStateForTests() { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:kNextTriesTimesKey]; + [defaults removeObjectForKey:kCurrentPingKey]; + [defaults removeObjectForKey:kNumberTriesKey]; + [defaults removeObjectForKey:kLastSentVersionKey]; + [defaults removeObjectForKey:kLastSentTimeKey]; + [defaults removeObjectForKey:kRetryRequestIdKey]; +}
diff --git a/ios/chrome/browser/omaha/omaha_service_unittest.mm b/ios/chrome/browser/omaha/omaha_service_unittest.mm new file mode 100644 index 0000000..c1f59048 --- /dev/null +++ b/ios/chrome/browser/omaha/omaha_service_unittest.mm
@@ -0,0 +1,506 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/omaha/omaha_service.h" + +#include <regex.h> +#include <sys/types.h> + +#include "base/bind.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "components/metrics/metrics_pref_names.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/version_info/version_info.h" +#include "ios/chrome/browser/application_context.h" +#include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h" +#include "ios/chrome/browser/install_time_util.h" +#include "ios/chrome/common/channel_info.h" +#include "ios/chrome/test/testing_application_context.h" +#include "ios/public/provider/chrome/browser/chrome_browser_provider.h" +#include "ios/public/provider/chrome/browser/omaha/omaha_service_provider.h" +#include "ios/web/public/test/test_web_thread.h" +#include "net/url_request/test_url_fetcher_factory.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest_mac.h" +#include "testing/platform_test.h" + +namespace { + +const char kUserDataDir[] = "."; + +} // namespace + +class OmahaServiceTest : public PlatformTest { + public: + OmahaServiceTest() + : need_update_(false), + loop_(base::MessageLoop::TYPE_IO), + browser_state_manager_(base::FilePath(kUserDataDir)), + ui_thread_(web::WebThread::UI, &loop_), + io_thread_(web::WebThread::IO, &loop_) { + GetApplicationContext()->GetLocalState()->SetInt64( + metrics::prefs::kInstallDate, install_time_util::kUnknownInstallDate); + OmahaService::ClearPersistentStateForTests(); + test_application_id_ = ios::GetChromeBrowserProvider() + ->GetOmahaServiceProvider() + ->GetApplicationID(); + } + + ~OmahaServiceTest() override {} + + void OnNeedUpdate(const UpgradeRecommendedDetails& details) { + need_update_ = true; + } + + bool NeedUpdate() { + DCHECK_CURRENTLY_ON(web::WebThread::UI); + if (!need_update_) { + base::RunLoop().RunUntilIdle(); + } + return need_update_; + } + + void CleanService(OmahaService* service, + const std::string& last_sent_version) { + service->ClearInstallRetryRequestId(); + service->number_of_tries_ = 0; + if (last_sent_version.length() == 0) + service->last_sent_version_ = base::Version("0.0.0.0"); + else + service->last_sent_version_ = base::Version(last_sent_version); + service->current_ping_time_ = base::Time(); + service->last_sent_time_ = base::Time(); + service->locale_lang_ = std::string(); + } + + protected: + std::string test_application_id_; + bool need_update_; + base::MessageLoop loop_; + TestChromeBrowserStateManager browser_state_manager_; + + private: + web::TestWebThread ui_thread_; + web::TestWebThread io_thread_; +}; + +TEST_F(OmahaServiceTest, PingMessageTest) { + const char* expectedResult = + "<request protocol=\"3.0\" version=\"iOS-1.0.0.0\" ismachine=\"1\" " + "requestid=\"requestId\" sessionid=\"sessionId\"" + " hardware_class=\"[^\"]*\">" + "<os platform=\"ios\" version=\"[0-9][0-9]*\\(\\.[0-9][0-9]*\\)*\"" + " arch=\"[^\"]*\"/>" + "<app version=\"[^\"]*\" nextversion=\"\" lang=\"[^\"]*\"" + " brand=\"[A-Z][A-Z][A-Z][A-Z]\" client=\"\" appid=\"{[^}]*}\"" + " installage=\"0\">" + "<updatecheck tag=\"[^\"]*\"/>" + "<ping active=\"1\"/></app></request>"; + + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + std::string content = service.GetPingContent( + "requestId", "sessionId", version_info::GetVersionNumber(), + GetChannelString(), base::Time::Now(), OmahaService::USAGE_PING); + regex_t regex; + regcomp(®ex, expectedResult, REG_NOSUB); + int result = regexec(®ex, content.c_str(), 0, NULL, 0); + regfree(®ex); + EXPECT_EQ(0, result); + EXPECT_FALSE(NeedUpdate()); +} + +TEST_F(OmahaServiceTest, PingMessageTestWithUnknownInstallDate) { + const char* expectedResult = + "<request protocol=\"3.0\" version=\"iOS-1.0.0.0\" ismachine=\"1\" " + "requestid=\"requestId\" sessionid=\"sessionId\"" + " hardware_class=\"[^\"]*\">" + "<os platform=\"ios\" version=\"[0-9][0-9]*\\(\\.[0-9][0-9]*\\)*\"" + " arch=\"[^\"]*\"/>" + "<app version=\"[^\"]*\" nextversion=\"\" lang=\"[^\"]*\"" + " brand=\"[A-Z][A-Z][A-Z][A-Z]\" client=\"\" appid=\"{[^}]*}\">" + "<updatecheck tag=\"[^\"]*\"/>" + "<ping active=\"1\"/></app></request>"; + + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + std::string content = service.GetPingContent( + "requestId", "sessionId", version_info::GetVersionNumber(), + GetChannelString(), + base::Time::FromTimeT(install_time_util::kUnknownInstallDate), + OmahaService::USAGE_PING); + regex_t regex; + regcomp(®ex, expectedResult, REG_NOSUB); + int result = regexec(®ex, content.c_str(), 0, NULL, 0); + regfree(®ex); + EXPECT_EQ(0, result); + EXPECT_FALSE(NeedUpdate()); +} + +TEST_F(OmahaServiceTest, InstallEventMessageTest) { + const char* kExpectedResultFormat = + "<request protocol=\"3.0\" version=\"iOS-1.0.0.0\" ismachine=\"1\" " + "requestid=\"requestId\" sessionid=\"sessionId\"" + " hardware_class=\"[^\"]*\">" + "<os platform=\"ios\" version=\"[0-9][0-9]*(\\.[0-9][0-9]*)*\"" + " arch=\"[^\"]*\"/>" + "<app version=\"%s\" nextversion=\"[^\"]*\" lang=\"[^\"]*\"" + " brand=\"[A-Z][A-Z][A-Z][A-Z]\" client=\"\" appid=\"{[^}]*}\"" + " installage=\"%d\">" + "<event eventtype=\"%d\" eventresult=\"1\"/>" + "</app></request>"; + + // First install. + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + CleanService(&service, ""); + std::string content = service.GetPingContent( + "requestId", "sessionId", version_info::GetVersionNumber(), + GetChannelString(), base::Time::Now(), OmahaService::INSTALL_EVENT); + regmatch_t matches[2]; + regex_t regex; + std::string expected_result = + base::StringPrintf(kExpectedResultFormat, "" /* previous version */, + -1 /* install age */, 2 /* event type */); + regcomp(®ex, expected_result.c_str(), REG_EXTENDED); + int result = regexec(®ex, content.c_str(), arraysize(matches), matches, 0); + regfree(®ex); + EXPECT_EQ(0, result) << "Actual contents: " << content; + EXPECT_FALSE(NeedUpdate()); + + // Update install. + const char* kPreviousVersion = "0.5"; + CleanService(&service, kPreviousVersion); + content = service.GetPingContent( + "requestId", "sessionId", version_info::GetVersionNumber(), + GetChannelString(), base::Time::Now(), OmahaService::INSTALL_EVENT); + expected_result = base::StringPrintf(kExpectedResultFormat, kPreviousVersion, + 0 /* install age */, 3 /* event type */); + regcomp(®ex, expected_result.c_str(), REG_EXTENDED); + result = regexec(®ex, content.c_str(), arraysize(matches), matches, 0); + regfree(®ex); + EXPECT_EQ(0, result) << "Actual contents: " << content; + EXPECT_FALSE(NeedUpdate()); +} + +TEST_F(OmahaServiceTest, SendPingSuccess) { + base::Time now = base::Time::Now(); + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + CleanService(&service, version_info::GetVersionNumber()); + net::TestURLFetcherFactory factory_; + + service.SendPing(); + EXPECT_EQ(1, service.number_of_tries_); + EXPECT_TRUE(service.current_ping_time_.is_null()); + EXPECT_GE(service.next_tries_time_, now + base::TimeDelta::FromMinutes(54)); + EXPECT_LE(service.next_tries_time_, now + base::TimeDelta::FromHours(7)); + + net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + fetcher->set_status(net::URLRequestStatus()); + fetcher->set_response_code(200); + std::string response = + std::string( + "<?xml version=\"1.0\"?><response protocol=\"3.0\" server=\"prod\">" + "<daystart elapsed_seconds=\"56754\"/><app appid=\"") + + test_application_id_ + + "\" status=\"ok\">" + "<updatecheck status=\"noupdate\"/><ping status=\"ok\"/>" + "</app></response>"; + fetcher->SetResponseString(response); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + EXPECT_EQ(0, service.number_of_tries_); + EXPECT_FALSE(service.current_ping_time_.is_null()); + EXPECT_EQ(service.current_ping_time_, service.next_tries_time_); + EXPECT_GT(service.last_sent_time_, now); + EXPECT_FALSE(NeedUpdate()); +} + +TEST_F(OmahaServiceTest, SendInstallEventSuccess) { + base::Time now = base::Time::Now(); + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + CleanService(&service, ""); + net::TestURLFetcherFactory factory_; + + service.SendPing(); + EXPECT_EQ(1, service.number_of_tries_); + EXPECT_TRUE(service.current_ping_time_.is_null()); + EXPECT_GE(service.next_tries_time_, now + base::TimeDelta::FromMinutes(54)); + EXPECT_LE(service.next_tries_time_, now + base::TimeDelta::FromHours(7)); + + net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + fetcher->set_status(net::URLRequestStatus()); + fetcher->set_response_code(200); + std::string response = + std::string( + "<?xml version=\"1.0\"?><response protocol=\"3.0\" server=\"prod\">" + "<daystart elapsed_seconds=\"56754\"/><app appid=\"") + + test_application_id_ + + "\" status=\"ok\">" + "<event status=\"ok\"/>" + "</app></response>"; + fetcher->SetResponseString(response); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + EXPECT_FALSE(service.current_ping_time_.is_null()); + EXPECT_GT(service.last_sent_time_, now); + EXPECT_FALSE(NeedUpdate()); +} + +TEST_F(OmahaServiceTest, SendPingReceiveUpdate) { + base::Time now = base::Time::Now(); + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + CleanService(&service, version_info::GetVersionNumber()); + net::TestURLFetcherFactory factory_; + + service.SendPing(); + EXPECT_EQ(1, service.number_of_tries_); + EXPECT_TRUE(service.current_ping_time_.is_null()); + EXPECT_GE(service.next_tries_time_, now + base::TimeDelta::FromMinutes(54)); + EXPECT_LE(service.next_tries_time_, now + base::TimeDelta::FromHours(7)); + + net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + fetcher->set_status(net::URLRequestStatus()); + fetcher->set_response_code(200); + std::string response = + std::string( + "<?xml version=\"1.0\"?><response protocol=\"3.0\" server=\"prod\">" + "<daystart elapsed_seconds=\"56754\"/><app appid=\"") + + test_application_id_ + + "\" status=\"ok\">" + "<updatecheck status=\"ok\"><urls>" + "<url codebase=\"http://www.goo.fr/foo/\"/></urls>" + "<manifest version=\"0.0.1075.1441\">" + "<packages>" + "<package hash=\"0\" name=\"Chrome\" required=\"true\" size=\"0\"/>" + "</packages>" + "<actions>" + "<action event=\"update\" run=\"Chrome\"/>" + "<action event=\"postinstall\" osminversion=\"6.0\"/>" + "</actions>" + "</manifest>" + "</updatecheck><ping status=\"ok\"/>" + "</app></response>"; + fetcher->SetResponseString(response); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + EXPECT_EQ(0, service.number_of_tries_); + EXPECT_FALSE(service.current_ping_time_.is_null()); + EXPECT_EQ(service.current_ping_time_, service.next_tries_time_); + EXPECT_GT(service.last_sent_time_, now); + EXPECT_TRUE(NeedUpdate()); +} + +TEST_F(OmahaServiceTest, SendPingFailure) { + base::Time now = base::Time::Now(); + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + CleanService(&service, version_info::GetVersionNumber()); + net::TestURLFetcherFactory factory_; + + // Tries with a non 200 result. + service.SendPing(); + EXPECT_EQ(1, service.number_of_tries_); + EXPECT_TRUE(service.current_ping_time_.is_null()); + EXPECT_GE(service.next_tries_time_, now + base::TimeDelta::FromMinutes(54)); + EXPECT_LE(service.next_tries_time_, now + base::TimeDelta::FromHours(7)); + base::Time next_tries_time = service.next_tries_time_; + + net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + fetcher->set_status(net::URLRequestStatus()); + fetcher->set_response_code(400); + fetcher->SetResponseString(""); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + EXPECT_EQ(1, service.number_of_tries_); + EXPECT_TRUE(service.current_ping_time_.is_null()); + EXPECT_EQ(next_tries_time, service.next_tries_time_); + EXPECT_LT(service.last_sent_time_, now); + EXPECT_FALSE(NeedUpdate()); + + // Tries with an incorrect xml message. + service.SendPing(); + EXPECT_EQ(2, service.number_of_tries_); + EXPECT_TRUE(service.current_ping_time_.is_null()); + EXPECT_GE(service.next_tries_time_, now + base::TimeDelta::FromMinutes(54)); + EXPECT_LE(service.next_tries_time_, now + base::TimeDelta::FromHours(7)); + next_tries_time = service.next_tries_time_; + + fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + fetcher->set_status(net::URLRequestStatus()); + fetcher->set_response_code(200); + fetcher->SetResponseString("Incorrect Message"); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + EXPECT_EQ(2, service.number_of_tries_); + EXPECT_TRUE(service.current_ping_time_.is_null()); + EXPECT_EQ(next_tries_time, service.next_tries_time_); + EXPECT_LT(service.last_sent_time_, now); + EXPECT_FALSE(NeedUpdate()); +} + +TEST_F(OmahaServiceTest, PersistStatesTest) { + std::string version_string = version_info::GetVersionNumber(); + base::Time now = base::Time::Now(); + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + service.number_of_tries_ = 5; + service.last_sent_time_ = now - base::TimeDelta::FromSeconds(1); + service.next_tries_time_ = now + base::TimeDelta::FromSeconds(2); + service.current_ping_time_ = now + base::TimeDelta::FromSeconds(3); + service.last_sent_version_ = base::Version(version_string); + service.PersistStates(); + + OmahaService service2(false); + EXPECT_EQ(service.number_of_tries_, 5); + EXPECT_EQ(service2.last_sent_time_, now - base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(service2.next_tries_time_, now + base::TimeDelta::FromSeconds(2)); + EXPECT_EQ(service2.current_ping_time_, now + base::TimeDelta::FromSeconds(3)); + EXPECT_EQ(service.last_sent_version_.GetString(), version_string); +} + +TEST_F(OmahaServiceTest, BackoffTest) { + for (int i = 1; i < 100; ++i) { + // Testing multiple times for a given number of retries, as the method has + // a random part. + for (int j = 0; j < 2; ++j) { + EXPECT_GE(OmahaService::GetBackOff(i).InSeconds(), 3600 - 360); + EXPECT_LE(OmahaService::GetBackOff(i).InSeconds(), 6 * 3600); + } + } +} + +// Tests that an active ping is scheduled immediately after a successful install +// event send. +TEST_F(OmahaServiceTest, ActivePingAfterInstallEventTest) { + base::Time now = base::Time::Now(); + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + CleanService(&service, ""); + net::TestURLFetcherFactory factory_; + + service.SendPing(); + EXPECT_EQ(1, service.number_of_tries_); + EXPECT_TRUE(service.current_ping_time_.is_null()); + EXPECT_GE(service.next_tries_time_, now + base::TimeDelta::FromMinutes(54)); + EXPECT_LE(service.next_tries_time_, now + base::TimeDelta::FromHours(7)); + + net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + fetcher->set_status(net::URLRequestStatus()); + fetcher->set_response_code(200); + std::string response = + std::string( + "<?xml version=\"1.0\"?><response protocol=\"3.0\" server=\"prod\">" + "<daystart elapsed_seconds=\"0\"/><app appid=\"") + + test_application_id_ + + "\" status=\"ok\">" + "<event status=\"ok\"/>" + "</app></response>"; + fetcher->SetResponseString(response); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + EXPECT_EQ(1, service.number_of_tries_); + EXPECT_LT(service.current_ping_time_ - now, base::TimeDelta::FromMinutes(1)); + EXPECT_GT(service.next_tries_time_, service.current_ping_time_); + EXPECT_FALSE(NeedUpdate()); +} + +// Tests that active pings are not sent in rapid succession. +TEST_F(OmahaServiceTest, NonSpammingTest) { + base::Time now = base::Time::Now(); + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + CleanService(&service, version_info::GetVersionNumber()); + net::TestURLFetcherFactory factory_; + + service.SendPing(); + EXPECT_EQ(1, service.number_of_tries_); + EXPECT_TRUE(service.current_ping_time_.is_null()); + EXPECT_GE(service.next_tries_time_, now + base::TimeDelta::FromMinutes(54)); + EXPECT_LE(service.next_tries_time_, now + base::TimeDelta::FromHours(7)); + + net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + fetcher->set_status(net::URLRequestStatus()); + fetcher->set_response_code(200); + std::string response = + std::string( + "<?xml version=\"1.0\"?><response protocol=\"3.0\" server=\"prod\">" + "<daystart elapsed_seconds=\"0\"/><app appid=\"") + + test_application_id_ + + "\" status=\"ok\">" + "<updatecheck status=\"noupdate\"/><ping status=\"ok\"/>" + "</app></response>"; + fetcher->SetResponseString(response); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + EXPECT_EQ(0, service.number_of_tries_); + EXPECT_FALSE(service.current_ping_time_.is_null()); + EXPECT_GE(service.next_tries_time_ - now, base::TimeDelta::FromHours(2)); + EXPECT_GT(service.last_sent_time_, now); + EXPECT_FALSE(NeedUpdate()); +} + +TEST_F(OmahaServiceTest, InstallRetryTest) { + OmahaService service(false); + service.set_upgrade_recommended_callback( + base::Bind(&OmahaServiceTest::OnNeedUpdate, base::Unretained(this))); + CleanService(&service, ""); + net::TestURLFetcherFactory factory_; + + EXPECT_FALSE(service.IsNextPingInstallRetry()); + std::string id1 = service.GetNextPingRequestId(OmahaService::INSTALL_EVENT); + EXPECT_TRUE(service.IsNextPingInstallRetry()); + ASSERT_EQ(id1, service.GetNextPingRequestId(OmahaService::INSTALL_EVENT)); + + service.SendPing(); + net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); + DCHECK(fetcher); + DCHECK(fetcher->delegate()); + fetcher->set_status(net::URLRequestStatus()); + fetcher->set_response_code(200); + std::string response = + std::string( + "<?xml version=\"1.0\"?><response protocol=\"3.0\" server=\"prod\">" + "<daystart elapsed_seconds=\"56754\"/><app appid=\"") + + test_application_id_ + + "\" status=\"ok\">" + "<updatecheck status=\"noupdate\"/><ping status=\"ok\"/>" + "</app></response>"; + fetcher->SetResponseString(response); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + EXPECT_FALSE(service.IsNextPingInstallRetry()); + id1 = service.GetNextPingRequestId(OmahaService::USAGE_PING); + ASSERT_NE(id1, service.GetNextPingRequestId(OmahaService::USAGE_PING)); +}
diff --git a/ios/chrome/browser/upgrade/BUILD.gn b/ios/chrome/browser/upgrade/BUILD.gn new file mode 100644 index 0000000..71132988 --- /dev/null +++ b/ios/chrome/browser/upgrade/BUILD.gn
@@ -0,0 +1,38 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("upgrade") { + sources = [ + "upgrade_center.h", + "upgrade_center.mm", + "upgrade_recommended_details.h", + ] + deps = [ + "//base", + "//components/infobars/core", + "//components/version_info", + "//ios/chrome/app/strings", + "//ios/chrome/browser", + "//ios/chrome/browser/ui/commands", + "//ios/chrome/browser/ui/infobars:resources", + "//ios/web", + "//net", + "//ui/base", + "//ui/gfx", + "//url", + ] + libs = [ "UIKit.framework" ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "upgrade_center_unittest.mm", + ] + deps = [ + ":upgrade", + "//base", + "//testing/gtest", + ] +}
diff --git a/ios/chrome/browser/upgrade/upgrade_center.h b/ios/chrome/browser/upgrade/upgrade_center.h new file mode 100644 index 0000000..a9ee57f --- /dev/null +++ b/ios/chrome/browser/upgrade/upgrade_center.h
@@ -0,0 +1,62 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UPGRADE_UPGRADE_CENTER_H_ +#define IOS_CHROME_BROWSER_UPGRADE_UPGRADE_CENTER_H_ + +#import <UIKit/UIKit.h> + +#include "ios/chrome/browser/upgrade/upgrade_recommended_details.h" + +@class UpgradeCenter; + +namespace infobars { +class InfoBarManager; +} + +@protocol UpgradeCenterClientProtocol + +// This is expected to call -addInfoBarToHelper:forTabId: for each tab to place +// the infobars in the UI. The client must not unregister itself while in this +// method. +- (void)showUpgrade:(UpgradeCenter*)center; + +@end + +@interface UpgradeCenter : NSObject + +// Returns the singleton instance of the class. ++ (UpgradeCenter*)sharedInstance; + +// Registers a client for the UpgradeCenter. The clients are not retained, +// unregisterClient: must be called before the object goes away. +- (void)registerClient:(id<UpgradeCenterClientProtocol>)client; + +// Unregisters a client. +- (void)unregisterClient:(id<UpgradeCenterClientProtocol>)client; + +// Clients should call this method when -showUpgrade: is called or when a new +// tab is created. The infobar will not be created if it already exists or if +// there is no need to do so. +- (void)addInfoBarToManager:(infobars::InfoBarManager*)infoBarManager + forTabId:(NSString*)tabId; + +// For the UpgradeCenter to make the distinction between an infobar closed by +// the user directly and an infobar dismissed because the Tab it is on is +// removed. +- (void)tabWillClose:(NSString*)tabId; + +// Called when a notification is received from one of the upgrade mechanism. +- (void)upgradeNotificationDidOccur:(const UpgradeRecommendedDetails&)details; + +@end + +@interface UpgradeCenter (UsedForTests) +// Reset everything (forget clients, remove the infobar everywhere...) +- (void)resetForTests; +// Simulate the minimum display interval having elapsed. +- (void)setLastDisplayToPast; +@end + +#endif // IOS_CHROME_BROWSER_UPGRADE_UPGRADE_CENTER_H_
diff --git a/ios/chrome/browser/upgrade/upgrade_center.mm b/ios/chrome/browser/upgrade/upgrade_center.mm new file mode 100644 index 0000000..3566c53 --- /dev/null +++ b/ios/chrome/browser/upgrade/upgrade_center.mm
@@ -0,0 +1,459 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/upgrade/upgrade_center.h" + +#include <memory> +#include <set> +#include <utility> + +#include "base/mac/bundle_locations.h" +#include "base/mac/scoped_nsobject.h" +#include "base/memory/ptr_util.h" +#include "base/scoped_observer.h" +#include "base/strings/sys_string_conversions.h" +#include "base/version.h" +#include "components/infobars/core/confirm_infobar_delegate.h" +#include "components/infobars/core/infobar.h" +#include "components/infobars/core/infobar_manager.h" +#include "components/version_info/version_info.h" +#import "ios/chrome/browser/open_url_util.h" +#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" +#import "ios/chrome/browser/ui/commands/open_url_command.h" +#include "ios/chrome/grit/ios_chromium_strings.h" +#include "ios/chrome/grit/ios_strings.h" +#import "ios/web/public/url_scheme_util.h" +#import "net/base/mac/url_conversions.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/image/image.h" +#include "url/gurl.h" + +@interface UpgradeCenter () +// Creates infobars on all tabs. +- (void)showUpgradeInfoBars; +// Removes all the infobars. +- (void)hideUpgradeInfoBars; +// Callback when an infobar is closed, for any reason. Perform upgrade is set to +// YES if the user choose to upgrade. +- (void)dismissedInfoBar:(NSString*)tabId performUpgrade:(BOOL)shouldUpgrade; +// Returns YES if the infobar should be shown. +- (BOOL)shouldShowInfoBar; +// Returns YES if the last version signaled by a server side service is more +// recent than the current version. +- (BOOL)isCurrentVersionObsolete; +// Returns YES if the infobar has already been shown within the allowed display +// interval. +- (BOOL)infoBarShownRecently; +// Called when the application become active again. +- (void)applicationWillEnterForeground:(NSNotification*)note; +@end + +namespace { + +// The user defaults key for the upgrade version. +NSString* const kNextVersionKey = @"UpdateInfobarNextVersion"; +// The user defaults key for the upgrade URL. +NSString* const kUpgradeURLKey = @"UpdateInfobarUpgradeURL"; +// The user defaults key for the last time the update infobar was shown. +NSString* const kLastInfobarDisplayTimeKey = @"UpdateInfobarLastDisplayTime"; +// The amount of time that must elapse before showing the infobar again. +const NSTimeInterval kInfobarDisplayInterval = 24 * 60 * 60; // One day. + +// The class controlling the look of the infobar displayed when an upgrade is +// available. +class UpgradeInfoBarDelegate : public ConfirmInfoBarDelegate { + public: + UpgradeInfoBarDelegate() : trigger_upgrade_(false) {} + + ~UpgradeInfoBarDelegate() override {} + + // Returns true is the infobar was closed by pressing the accept button. + bool AcceptPressed() { return trigger_upgrade_; } + + void RemoveSelf() { + infobars::InfoBar* infobar = this->infobar(); + if (infobar) + infobar->RemoveSelf(); + } + + private: + InfoBarIdentifier GetIdentifier() const override { + return UPGRADE_INFOBAR_DELEGATE_IOS; + } + + bool ShouldExpire(const NavigationDetails& details) const override { + return false; + } + + gfx::Image GetIcon() const override { + if (icon_.IsEmpty()) { + icon_ = gfx::Image([UIImage imageNamed:@"infobar_update"], + base::scoped_policy::RETAIN); + } + return icon_; + } + + InfoBarDelegate::Type GetInfoBarType() const override { + return PAGE_ACTION_TYPE; + } + + base::string16 GetMessageText() const override { + return l10n_util::GetStringUTF16(IDS_IOS_UPGRADE_AVAILABLE); + } + + bool Accept() override { + trigger_upgrade_ = true; + return true; + } + + int GetButtons() const override { return BUTTON_OK; } + + base::string16 GetButtonLabel(InfoBarButton button) const override { + DCHECK(button == BUTTON_OK); + return l10n_util::GetStringUTF16(IDS_IOS_UPGRADE_AVAILABLE_BUTTON); + } + + mutable gfx::Image icon_; + bool trigger_upgrade_; + + DISALLOW_COPY_AND_ASSIGN(UpgradeInfoBarDelegate); +}; + +// The InfoBarDelegate unfortunately is not called at all when an infoBar is +// simply dismissed. In order to catch that case this object listens to the +// infobars::InfoBarManager::Observer::OnInfoBarRemoved() which is invoked when +// an infobar is closed, for any reason. +class UpgradeInfoBarDismissObserver + : public infobars::InfoBarManager::Observer { + public: + UpgradeInfoBarDismissObserver() + : infobar_delegate_(nullptr), + dismiss_delegate_(nil), + scoped_observer_(this) {} + + ~UpgradeInfoBarDismissObserver() override {} + + void RegisterObserver(infobars::InfoBarManager* infobar_manager, + UpgradeInfoBarDelegate* infobar_delegate, + NSString* tab_id, + UpgradeCenter* dismiss_delegate) { + scoped_observer_.Add(infobar_manager); + infobar_delegate_ = infobar_delegate; + dismiss_delegate_ = dismiss_delegate; + tab_id_.reset([tab_id copy]); + } + + UpgradeInfoBarDelegate* infobar_delegate() { return infobar_delegate_; } + + private: + // infobars::InfoBarManager::Observer implementation. + void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override { + if (infobar->delegate() == infobar_delegate_) { + [dismiss_delegate_ dismissedInfoBar:tab_id_.get() + performUpgrade:infobar_delegate_->AcceptPressed()]; + } + } + + void OnManagerShuttingDown( + infobars::InfoBarManager* infobar_manager) override { + scoped_observer_.Remove(infobar_manager); + } + + UpgradeInfoBarDelegate* infobar_delegate_; + UpgradeCenter* dismiss_delegate_; + base::scoped_nsobject<NSString> tab_id_; + ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer> + scoped_observer_; + + DISALLOW_COPY_AND_ASSIGN(UpgradeInfoBarDismissObserver); +}; + +} // namespace + +// The delegateHolder is a simple wrapper to be able to store all the +// infoBarDelegate related information in an object that can be put in +// an ObjectiveC container. +@interface DelegateHolder : NSObject { + UpgradeInfoBarDismissObserver observer_; +} + +- (instancetype)initWithInfoBarManager:(infobars::InfoBarManager*)infoBarManager + infoBarDelegate:(UpgradeInfoBarDelegate*)infoBarDelegate + upgradeCenter:(UpgradeCenter*)upgradeCenter + tabId:(NSString*)tabId; + +@property(nonatomic, readonly) UpgradeInfoBarDelegate* infoBarDelegate; +@end + +@implementation DelegateHolder + +- (instancetype)initWithInfoBarManager:(infobars::InfoBarManager*)infoBarManager + infoBarDelegate:(UpgradeInfoBarDelegate*)infoBarDelegate + upgradeCenter:(UpgradeCenter*)upgradeCenter + tabId:(NSString*)tabId { + self = [super init]; + if (self) { + observer_.RegisterObserver(infoBarManager, infoBarDelegate, tabId, + upgradeCenter); + } + return self; +} + +- (UpgradeInfoBarDelegate*)infoBarDelegate { + return observer_.infobar_delegate(); +} + +@end + +@implementation UpgradeCenter { + // YES if the infobars are currently visible. + BOOL upgradeInfoBarIsVisible_; + // Used to store the visible upgrade infobars, indexed by tabId. + base::scoped_nsobject<NSMutableDictionary> upgradeInfoBarDelegates_; + // Stores the clients of the upgrade center. These objectiveC objects are not + // retained. + std::set<id<UpgradeCenterClientProtocol>> clients_; +#ifndef NDEBUG + bool inCallback_; +#endif +} + ++ (UpgradeCenter*)sharedInstance { + static UpgradeCenter* obj; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + obj = [[self alloc] init]; + }); + return obj; +} + +- (instancetype)init { + self = [super init]; + if (self) { + upgradeInfoBarDelegates_.reset([[NSMutableDictionary alloc] init]); + + // There is no dealloc and no unregister as this class is a never + // deallocated singleton. + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(applicationWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + + upgradeInfoBarIsVisible_ = [self shouldShowInfoBar]; + } + return self; +} + +- (BOOL)shouldShowInfoBar { + return [self isCurrentVersionObsolete] && ![self infoBarShownRecently]; +} + +- (BOOL)isCurrentVersionObsolete { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + NSString* nextVersion = [defaults stringForKey:kNextVersionKey]; + if (nextVersion) { + base::Version current_version(version_info::GetVersionNumber()); + const std::string upgrade = base::SysNSStringToUTF8(nextVersion); + return current_version < base::Version(upgrade); + } + return NO; +} + +- (BOOL)infoBarShownRecently { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + NSDate* lastDisplay = [defaults objectForKey:kLastInfobarDisplayTimeKey]; + // Absolute value is to ensure the infobar won't be supressed forever if the + // clock temporarily jumps to the distant future. + if (lastDisplay && + fabs([lastDisplay timeIntervalSinceNow]) < kInfobarDisplayInterval) { + return YES; + } + return NO; +} + +- (void)applicationWillEnterForeground:(NSNotification*)note { + if (upgradeInfoBarIsVisible_) + return; + + // When returning to active if the upgrade notification has been dismissed, + // bring it back. + if ([self shouldShowInfoBar]) + [self showUpgradeInfoBars]; +} + +- (void)registerClient:(id<UpgradeCenterClientProtocol>)client { + clients_.insert(client); + if (upgradeInfoBarIsVisible_) + [client showUpgrade:self]; +} + +- (void)unregisterClient:(id<UpgradeCenterClientProtocol>)client { +#ifndef NDEBUG + DCHECK(!inCallback_); +#endif + clients_.erase(client); +} + +- (void)addInfoBarToManager:(infobars::InfoBarManager*)infoBarManager + forTabId:(NSString*)tabId { + DCHECK(tabId); + DCHECK(infoBarManager); + + // Nothing to do if the infobar are not visible at this point in time. + if (!upgradeInfoBarIsVisible_) + return; + + // Nothing to do if the infobar is already there. + if ([upgradeInfoBarDelegates_ objectForKey:tabId]) + return; + + auto infobarDelegate = base::MakeUnique<UpgradeInfoBarDelegate>(); + base::scoped_nsobject<DelegateHolder> delegateHolder([[DelegateHolder alloc] + initWithInfoBarManager:infoBarManager + infoBarDelegate:infobarDelegate.get() + upgradeCenter:self + tabId:tabId]); + + [upgradeInfoBarDelegates_ setObject:delegateHolder forKey:tabId]; + infoBarManager->AddInfoBar( + infoBarManager->CreateConfirmInfoBar(std::move(infobarDelegate))); +} + +- (void)tabWillClose:(NSString*)tabId { + [upgradeInfoBarDelegates_ removeObjectForKey:tabId]; +} + +- (void)dismissedInfoBar:(NSString*)tabId performUpgrade:(BOOL)shouldUpgrade { + // If the tabId is not in the upgradeInfoBarDelegates_ just ignore the + // notification. In all likelyhood it was trigerred by calling + // -hideUpgradeInfoBars. Or because a tab was closed without dismissing the + // infobar. + base::scoped_nsobject<DelegateHolder> delegateHolder( + [[upgradeInfoBarDelegates_ objectForKey:tabId] retain]); + if (!delegateHolder.get()) + return; + + // Forget about this dismissed infobar. + [upgradeInfoBarDelegates_ removeObjectForKey:tabId]; + + // Get rid of all the infobars on the other tabs. + [self hideUpgradeInfoBars]; + + if (shouldUpgrade) { + NSString* urlString = + [[NSUserDefaults standardUserDefaults] valueForKey:kUpgradeURLKey]; + if (!urlString) + return; // Missing URL, no upgrade possible. + + GURL url = GURL(base::SysNSStringToUTF8(urlString)); + if (!url.is_valid()) + return; + + if (web::UrlHasWebScheme(url)) { + // This URL can be opened in the application, just open in a new tab. + base::scoped_nsobject<OpenUrlCommand> command( + [[OpenUrlCommand alloc] initWithURLFromChrome:url]); + UIWindow* main_window = [[UIApplication sharedApplication] keyWindow]; + DCHECK(main_window); + [main_window chromeExecuteCommand:command]; + } else { + // This URL scheme is not understood, ask the system to open it. + NSURL* nsurl = [NSURL URLWithString:urlString]; + if (nsurl) { + OpenUrlWithCompletionHandler(nsurl, nil); + } + } + } +} + +- (void)showUpgradeInfoBars { +// Add an infobar on all the open tabs. +#ifndef NDEBUG + inCallback_ = YES; +#endif + upgradeInfoBarIsVisible_ = YES; + std::set<id<UpgradeCenterClientProtocol>>::iterator it; + for (it = clients_.begin(); it != clients_.end(); ++it) + [*it showUpgrade:self]; +#ifndef NDEBUG + inCallback_ = NO; +#endif + + [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] + forKey:kLastInfobarDisplayTimeKey]; +} + +- (void)hideUpgradeInfoBars { + upgradeInfoBarIsVisible_ = NO; + // It is important to call -allKeys here and not using a fast iteration on the + // dictionary directly: the dictionary is modified as we go... + for (NSString* tabId in [upgradeInfoBarDelegates_ allKeys]) { + // It is important to retain the delegateHolder as otherwise it is + // deallocated as soon as it is removed from the dictionary. + base::scoped_nsobject<DelegateHolder> delegateHolder( + [[upgradeInfoBarDelegates_ objectForKey:tabId] retain]); + if (delegateHolder.get()) { + [upgradeInfoBarDelegates_ removeObjectForKey:tabId]; + UpgradeInfoBarDelegate* delegate = [delegateHolder infoBarDelegate]; + DCHECK(delegate); + delegate->RemoveSelf(); + } + } +} + +- (void)upgradeNotificationDidOccur:(const UpgradeRecommendedDetails&)details { + const GURL& upgradeUrl = details.upgrade_url; + + if (!upgradeUrl.is_valid()) { + // The application may crash if the URL is invalid. As the URL is defined + // externally to the application it needs to bail right away and ignore the + // upgrade notification. + NOTREACHED(); + return; + } + + if (!details.next_version.size() || + !base::Version(details.next_version).IsValid()) { + // If the upgrade version is not known or is invalid just ignore the + // upgrade notification. + NOTREACHED(); + return; + } + + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + + // Reset the display clock when the version changes. + NSString* newVersionString = base::SysUTF8ToNSString(details.next_version); + NSString* previousVersionString = [defaults stringForKey:kNextVersionKey]; + if (!previousVersionString || + ![previousVersionString isEqualToString:newVersionString]) { + [defaults removeObjectForKey:kLastInfobarDisplayTimeKey]; + } + + [defaults setValue:base::SysUTF8ToNSString(upgradeUrl.spec()) + forKey:kUpgradeURLKey]; + [defaults setValue:newVersionString forKey:kNextVersionKey]; + + if ([self shouldShowInfoBar]) + [self showUpgradeInfoBars]; +} + +- (void)resetForTests { + [[UpgradeCenter sharedInstance] hideUpgradeInfoBars]; + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:kNextVersionKey]; + [defaults removeObjectForKey:kUpgradeURLKey]; + [defaults removeObjectForKey:kLastInfobarDisplayTimeKey]; + clients_.clear(); +} + +- (void)setLastDisplayToPast { + NSDate* pastDate = + [NSDate dateWithTimeIntervalSinceNow:-(kInfobarDisplayInterval + 1)]; + [[NSUserDefaults standardUserDefaults] setObject:pastDate + forKey:kLastInfobarDisplayTimeKey]; +} + +@end
diff --git a/ios/chrome/browser/upgrade/upgrade_center_unittest.mm b/ios/chrome/browser/upgrade/upgrade_center_unittest.mm new file mode 100644 index 0000000..b8b1b1e --- /dev/null +++ b/ios/chrome/browser/upgrade/upgrade_center_unittest.mm
@@ -0,0 +1,139 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/upgrade/upgrade_center.h" + +#include "base/mac/scoped_nsobject.h" +#include "ios/chrome/browser/upgrade/upgrade_recommended_details.h" +#include "testing/platform_test.h" + +namespace { + +class UpgradeCenterTest : public PlatformTest { + public: + unsigned int count_; + + protected: + void SetUp() override { + [[UpgradeCenter sharedInstance] resetForTests]; + count_ = 0; + }; + + void TearDown() override { [[UpgradeCenter sharedInstance] resetForTests]; } +}; + +} // namespace + +@interface FakeUpgradeCenterClient : NSObject<UpgradeCenterClientProtocol> +- (instancetype)initWithTest:(UpgradeCenterTest*)test; +@end + +@implementation FakeUpgradeCenterClient { + UpgradeCenterTest* test_; // weak +} + +- (instancetype)initWithTest:(UpgradeCenterTest*)test { + self = [super init]; + if (self) { + test_ = test; + } + return self; +} + +- (void)showUpgrade:(UpgradeCenter*)center { + test_->count_ += 1; +} + +@end + +namespace { + +TEST_F(UpgradeCenterTest, NoUpgrade) { + EXPECT_EQ(count_, 0u); + base::scoped_nsobject<FakeUpgradeCenterClient> fake( + [[FakeUpgradeCenterClient alloc] initWithTest:this]); + [[UpgradeCenter sharedInstance] registerClient:fake]; + EXPECT_EQ(count_, 0u); + [[UpgradeCenter sharedInstance] unregisterClient:fake]; +}; + +TEST_F(UpgradeCenterTest, GoodUpgradeAfterRegistration) { + EXPECT_EQ(count_, 0u); + base::scoped_nsobject<FakeUpgradeCenterClient> fake( + [[FakeUpgradeCenterClient alloc] initWithTest:this]); + [[UpgradeCenter sharedInstance] registerClient:fake]; + EXPECT_EQ(count_, 0u); + + UpgradeRecommendedDetails details; + details.next_version = "9999.9999.9999.9999"; + details.upgrade_url = GURL("http://foobar.org"); + [[UpgradeCenter sharedInstance] upgradeNotificationDidOccur:details]; + EXPECT_EQ(count_, 1u); + [[UpgradeCenter sharedInstance] unregisterClient:fake]; +}; + +TEST_F(UpgradeCenterTest, GoodUpgradeBeforeRegistration) { + UpgradeRecommendedDetails details; + details.next_version = "9999.9999.9999.9999"; + details.upgrade_url = GURL("http://foobar.org"); + [[UpgradeCenter sharedInstance] upgradeNotificationDidOccur:details]; + EXPECT_EQ(count_, 0u); + base::scoped_nsobject<FakeUpgradeCenterClient> fake( + [[FakeUpgradeCenterClient alloc] initWithTest:this]); + [[UpgradeCenter sharedInstance] registerClient:fake]; + EXPECT_EQ(count_, 1u); + [[UpgradeCenter sharedInstance] unregisterClient:fake]; +}; + +TEST_F(UpgradeCenterTest, NoRepeatedDisplay) { + base::scoped_nsobject<FakeUpgradeCenterClient> fake( + [[FakeUpgradeCenterClient alloc] initWithTest:this]); + [[UpgradeCenter sharedInstance] registerClient:fake]; + EXPECT_EQ(count_, 0u); + + // First notification should display + UpgradeRecommendedDetails details; + details.next_version = "9999.9999.9999.9999"; + details.upgrade_url = GURL("http://foobar.org"); + [[UpgradeCenter sharedInstance] upgradeNotificationDidOccur:details]; + EXPECT_EQ(count_, 1u); + + // Second shouldn't, since it was just displayed. + [[UpgradeCenter sharedInstance] upgradeNotificationDidOccur:details]; + EXPECT_EQ(count_, 1u); + + // After enough time has elapsed, it should again. + [[UpgradeCenter sharedInstance] setLastDisplayToPast]; + [[UpgradeCenter sharedInstance] upgradeNotificationDidOccur:details]; + EXPECT_EQ(count_, 2u); + + [[UpgradeCenter sharedInstance] unregisterClient:fake]; +}; + +TEST_F(UpgradeCenterTest, NewVersionResetsInterval) { + base::scoped_nsobject<FakeUpgradeCenterClient> fake( + [[FakeUpgradeCenterClient alloc] initWithTest:this]); + [[UpgradeCenter sharedInstance] registerClient:fake]; + EXPECT_EQ(count_, 0u); + + // First notification should display + UpgradeRecommendedDetails details; + details.next_version = "9999.9999.9999.9998"; + details.upgrade_url = GURL("http://foobar.org"); + [[UpgradeCenter sharedInstance] upgradeNotificationDidOccur:details]; + EXPECT_EQ(count_, 1u); + + // Second shouldn't, since it was just displayed. + [[UpgradeCenter sharedInstance] upgradeNotificationDidOccur:details]; + EXPECT_EQ(count_, 1u); + + // A new version should show right away though. + details.next_version = "9999.9999.9999.9999"; + [[UpgradeCenter sharedInstance] upgradeNotificationDidOccur:details]; + EXPECT_EQ(count_, 2u); + + [[UpgradeCenter sharedInstance] unregisterClient:fake]; +}; + +} // namespace
diff --git a/ios/chrome/browser/upgrade/upgrade_recommended_details.h b/ios/chrome/browser/upgrade/upgrade_recommended_details.h new file mode 100644 index 0000000..ce297a3 --- /dev/null +++ b/ios/chrome/browser/upgrade/upgrade_recommended_details.h
@@ -0,0 +1,17 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UPGRADE_UPGRADE_RECOMMENDED_DETAILS_H_ +#define IOS_CHROME_BROWSER_UPGRADE_UPGRADE_RECOMMENDED_DETAILS_H_ + +#include <string> + +#include "url/gurl.h" + +struct UpgradeRecommendedDetails { + GURL upgrade_url; + std::string next_version; +}; + +#endif // IOS_CHROME_BROWSER_UPGRADE_UPGRADE_RECOMMENDED_DETAILS_H_
diff --git a/ios/third_party/material_font_disk_loader_ios/LICENSE b/ios/third_party/material_font_disk_loader_ios/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/ios/third_party/material_font_disk_loader_ios/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/ios/third_party/material_font_disk_loader_ios/README.chromium b/ios/third_party/material_font_disk_loader_ios/README.chromium index 59edaa8..e29a1dc 100644 --- a/ios/third_party/material_font_disk_loader_ios/README.chromium +++ b/ios/third_party/material_font_disk_loader_ios/README.chromium
@@ -3,7 +3,7 @@ Version: 0 Revision: 20c8fe37329cb18826f90159ce4ee445079e2e46 License: Apache 2.0 -License File: src/LICENSE +License File: LICENSE Security Critical: yes Description:
diff --git a/ios/third_party/material_roboto_font_loader_ios/LICENSE b/ios/third_party/material_roboto_font_loader_ios/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/ios/third_party/material_roboto_font_loader_ios/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/ios/third_party/material_roboto_font_loader_ios/README.chromium b/ios/third_party/material_roboto_font_loader_ios/README.chromium index 445fdb48..6058f4b 100644 --- a/ios/third_party/material_roboto_font_loader_ios/README.chromium +++ b/ios/third_party/material_roboto_font_loader_ios/README.chromium
@@ -3,7 +3,7 @@ Version: 0 Revision: 2e83b0fdbbd9b12782aa886695dd29b077bad430 License: Apache 2.0 -License File: src/LICENSE +License File: LICENSE Security Critical: yes Description:
diff --git a/ios/third_party/material_sprited_animation_view_ios/LICENSE b/ios/third_party/material_sprited_animation_view_ios/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/ios/third_party/material_sprited_animation_view_ios/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file
diff --git a/ios/third_party/material_sprited_animation_view_ios/README.chromium b/ios/third_party/material_sprited_animation_view_ios/README.chromium index 8fc051fb..268f933 100644 --- a/ios/third_party/material_sprited_animation_view_ios/README.chromium +++ b/ios/third_party/material_sprited_animation_view_ios/README.chromium
@@ -3,7 +3,7 @@ Version: 0 Revision: e240cdcd4538f0763ca5bd8c5afc2991eb482f1a License: Apache 2.0 -License File: src/LICENSE +License File: LICENSE Security Critical: yes Description:
diff --git a/ios/third_party/material_text_accessibility_ios/LICENSE b/ios/third_party/material_text_accessibility_ios/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/ios/third_party/material_text_accessibility_ios/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/ios/third_party/material_text_accessibility_ios/README.chromium b/ios/third_party/material_text_accessibility_ios/README.chromium index 99a4680..256c030 100644 --- a/ios/third_party/material_text_accessibility_ios/README.chromium +++ b/ios/third_party/material_text_accessibility_ios/README.chromium
@@ -3,7 +3,7 @@ Version: 0 Revision: 96d2b0f13976a897bc7a41daf67f36d9548cff94 License: Apache 2.0 -License File: src/LICENSE +License File: LICENSE Security Critical: yes Description:
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn index 43665e43..85ad7ce 100644 --- a/ios/web/BUILD.gn +++ b/ios/web/BUILD.gn
@@ -342,6 +342,7 @@ "//ios/testing:ios_test_support", "//ios/testing/earl_grey:earl_grey_support", "//ios/third_party/earl_grey", + "//net:net", ] sources = [
diff --git a/ios/web/public/test/earl_grey/web_view_matchers.h b/ios/web/public/test/earl_grey/web_view_matchers.h index e446d6c..71379f68 100644 --- a/ios/web/public/test/earl_grey/web_view_matchers.h +++ b/ios/web/public/test/earl_grey/web_view_matchers.h
@@ -26,7 +26,14 @@ id<GREYMatcher> webViewNotContainingText(std::string text, WebState* web_state); // Matcher for WKWebView containing a blocked |image_id|. When blocked, the +// image element will be smaller actual image size. +id<GREYMatcher> webViewContainingBlockedImage(std::string image_id, + WebState* web_state); + +// Matcher for WKWebView containing a blocked |image_id|. When blocked, the // image will be smaller than |expected_size|. +// Note: deprecated. Use webViewContainingBlockedImage(std::string, WebState*) +// instead. TODO(crbug.com/673520): Remove this method. id<GREYMatcher> webViewContainingBlockedImage(std::string image_id, CGSize expected_size, WebState* web_state);
diff --git a/ios/web/public/test/earl_grey/web_view_matchers.mm b/ios/web/public/test/earl_grey/web_view_matchers.mm index c09b876..3981962 100644 --- a/ios/web/public/test/earl_grey/web_view_matchers.mm +++ b/ios/web/public/test/earl_grey/web_view_matchers.mm
@@ -4,9 +4,11 @@ #import "ios/web/public/test/earl_grey/web_view_matchers.h" +#import <UIKit/UIKit.h> #import <WebKit/WebKit.h> #include "base/mac/bind_objc_block.h" +#import "base/mac/scoped_nsobject.h" #include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" @@ -16,9 +18,29 @@ #import "ios/web/interstitials/web_interstitial_impl.h" #import "ios/web/public/test/earl_grey/js_test_util.h" #import "ios/web/public/test/web_view_interaction_test_util.h" +#import "net/base/mac/url_conversions.h" +using testing::kWaitForDownloadTimeout; using testing::WaitUntilConditionOrTimeout; +// A helper delegate class that allows downloading responses with invalid +// SSL certs. +@interface TestURLSessionDelegate : NSObject<NSURLSessionDelegate> +@end + +@implementation TestURLSessionDelegate + +- (void)URLSession:(NSURLSession*)session + didReceiveChallenge:(NSURLAuthenticationChallenge*)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, + NSURLCredential*))completionHandler { + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + completionHandler(NSURLSessionAuthChallengeUseCredential, + [NSURLCredential credentialForTrust:serverTrust]); +} + +@end + namespace { // Script that returns document.body as a string. @@ -58,6 +80,40 @@ nil); } +// Fetches the image from |image_url|. +UIImage* LoadImage(const GURL& image_url) { + __block base::scoped_nsobject<UIImage> image; + __block base::scoped_nsobject<NSError> error; + TestURLSessionDelegate* session_delegate = + [[TestURLSessionDelegate alloc] init]; + NSURLSessionConfiguration* session_config = + [NSURLSessionConfiguration defaultSessionConfiguration]; + NSURLSession* session = + [NSURLSession sessionWithConfiguration:session_config + delegate:session_delegate + delegateQueue:nil]; + id completion_handler = ^(NSData* data, NSURLResponse*, NSError* task_error) { + if (task_error) { + error.reset([task_error retain]); + } else { + image.reset([[UIImage alloc] initWithData:data]); + } + [session_delegate autorelease]; + }; + + NSURLSessionDataTask* task = + [session dataTaskWithURL:net::NSURLWithGURL(image_url) + completionHandler:completion_handler]; + [task resume]; + + bool image_loaded = WaitUntilConditionOrTimeout(kWaitForDownloadTimeout, ^{ + return image || error; + }); + GREYAssert(image_loaded, @"Failed to download image"); + + return [[image retain] autorelease]; +} + } // namespace namespace web { @@ -87,6 +143,23 @@ } id<GREYMatcher> webViewContainingBlockedImage(std::string image_id, + WebState* web_state) { + std::string get_url_script = + base::StringPrintf("document.getElementById('%s').src", image_id.c_str()); + std::unique_ptr<base::Value> url_as_value = + test::ExecuteJavaScript(web_state, get_url_script); + std::string url_as_string; + if (!url_as_value->GetAsString(&url_as_string)) + return grey_nil(); + + UIImage* image = LoadImage(GURL(url_as_string)); + if (!image) + return grey_nil(); + + return webViewContainingBlockedImage(image_id, image.size, web_state); +} + +id<GREYMatcher> webViewContainingBlockedImage(std::string image_id, CGSize expected_size, WebState* web_state) { MatchesBlock matches = ^BOOL(WKWebView*) {
diff --git a/media/base/content_decryption_module.h b/media/base/content_decryption_module.h index e8af761d..3fe3eb6f 100644 --- a/media/base/content_decryption_module.h +++ b/media/base/content_decryption_module.h
@@ -125,6 +125,8 @@ // reject the |promise| when the call has been processed. This may be before // the session is closed. Once the session is closed, a SessionClosedCB must // also be called. + // Note that the EME spec executes the close() action asynchronously, so + // CloseSession() may be called multiple times on the same session. virtual void CloseSession(const std::string& session_id, std::unique_ptr<SimpleCdmPromise> promise) = 0;
diff --git a/media/blink/webcontentdecryptionmodulesession_impl.cc b/media/blink/webcontentdecryptionmodulesession_impl.cc index 2ee66b0..707fe5a0 100644 --- a/media/blink/webcontentdecryptionmodulesession_impl.cc +++ b/media/blink/webcontentdecryptionmodulesession_impl.cc
@@ -435,15 +435,19 @@ void WebContentDecryptionModuleSessionImpl::close( blink::WebContentDecryptionModuleResult result) { - // close() shouldn't be called if the session is already closed. blink - // prevents a second call to close(), but since the operation is - // asynchronous, there is a window where close() was called just before - // the closed event arrives. The CDM should handle the case where - // close() is called after it has already closed the session. DCHECK(!session_id_.empty()); - DCHECK(!has_close_been_called_); DCHECK(thread_checker_.CalledOnValidThread()); + // close() shouldn't be called if the session is already closed. Since the + // operation is asynchronous, there is a window where close() was called + // just before the closed event arrives. The CDM should handle the case where + // close() is called after it has already closed the session. However, if + // we can tell the session is now closed, simply resolve the promise. + if (is_closed_) { + result.complete(); + return; + } + has_close_been_called_ = true; adapter_->CloseSession( session_id_,
diff --git a/media/capture/video/video_capture_device.h b/media/capture/video/video_capture_device.h index dc0b77f..e561267 100644 --- a/media/capture/video/video_capture_device.h +++ b/media/capture/video/video_capture_device.h
@@ -41,6 +41,15 @@ namespace media { +class CAPTURE_EXPORT FrameBufferPool { + public: + virtual ~FrameBufferPool() {} + + virtual void SetBufferHold(int buffer_id) = 0; + virtual void ReleaseBufferHold(int buffer_id) = 0; + virtual mojo::ScopedSharedBufferHandle GetHandleForTransit(int buffer_id) = 0; +}; + class CAPTURE_EXPORT VideoFrameConsumerFeedbackObserver { public: virtual ~VideoFrameConsumerFeedbackObserver() {} @@ -148,11 +157,10 @@ // |timestamp|. // TODO(chfremer): Consider removing one of the two in order to simplify the // interface. - virtual void OnIncomingCapturedBuffer( - std::unique_ptr<Buffer> buffer, - const VideoCaptureFormat& frame_format, - base::TimeTicks reference_time, - base::TimeDelta timestamp) = 0; + virtual void OnIncomingCapturedBuffer(std::unique_ptr<Buffer> buffer, + const VideoCaptureFormat& format, + base::TimeTicks reference_time, + base::TimeDelta timestamp) = 0; virtual void OnIncomingCapturedVideoFrame( std::unique_ptr<Buffer> buffer, scoped_refptr<VideoFrame> frame) = 0;
diff --git a/media/capture/video/video_capture_device_client.cc b/media/capture/video/video_capture_device_client.cc index ab0b916..3321633 100644 --- a/media/capture/video/video_capture_device_client.cc +++ b/media/capture/video/video_capture_device_client.cc
@@ -95,20 +95,20 @@ void VideoCaptureDeviceClient::OnIncomingCapturedData( const uint8_t* data, int length, - const VideoCaptureFormat& frame_format, + const VideoCaptureFormat& format, int rotation, base::TimeTicks reference_time, base::TimeDelta timestamp, int frame_feedback_id) { TRACE_EVENT0("video", "VideoCaptureDeviceClient::OnIncomingCapturedData"); - DCHECK_EQ(media::PIXEL_STORAGE_CPU, frame_format.pixel_storage); + DCHECK_EQ(media::PIXEL_STORAGE_CPU, format.pixel_storage); - if (last_captured_pixel_format_ != frame_format.pixel_format) { + if (last_captured_pixel_format_ != format.pixel_format) { OnLog("Pixel format: " + - media::VideoPixelFormatToString(frame_format.pixel_format)); - last_captured_pixel_format_ = frame_format.pixel_format; + media::VideoPixelFormatToString(format.pixel_format)); + last_captured_pixel_format_ = format.pixel_format; - if (frame_format.pixel_format == media::PIXEL_FORMAT_MJPEG && + if (format.pixel_format == media::PIXEL_FORMAT_MJPEG && !external_jpeg_decoder_initialized_) { external_jpeg_decoder_initialized_ = true; external_jpeg_decoder_ = jpeg_decoder_factory_callback_.Run(); @@ -116,20 +116,20 @@ } } - if (!frame_format.IsValid()) + if (!format.IsValid()) return; - if (frame_format.pixel_format == media::PIXEL_FORMAT_Y16) { - return OnIncomingCapturedY16Data(data, length, frame_format, reference_time, + if (format.pixel_format == media::PIXEL_FORMAT_Y16) { + return OnIncomingCapturedY16Data(data, length, format, reference_time, timestamp, frame_feedback_id); } // |chopped_{width,height} and |new_unrotated_{width,height}| are the lowest // bit decomposition of {width, height}, grabbing the odd and even parts. - const int chopped_width = frame_format.frame_size.width() & 1; - const int chopped_height = frame_format.frame_size.height() & 1; - const int new_unrotated_width = frame_format.frame_size.width() & ~1; - const int new_unrotated_height = frame_format.frame_size.height() & ~1; + const int chopped_width = format.frame_size.width() & 1; + const int chopped_height = format.frame_size.height() & 1; + const int new_unrotated_width = format.frame_size.width() & ~1; + const int new_unrotated_height = format.frame_size.height() & ~1; int destination_width = new_unrotated_width; int destination_height = new_unrotated_height; @@ -167,7 +167,7 @@ libyuv::FourCC origin_colorspace = libyuv::FOURCC_ANY; bool flip = false; - switch (frame_format.pixel_format) { + switch (format.pixel_format) { case media::PIXEL_FORMAT_UNKNOWN: // Color format not set. break; case media::PIXEL_FORMAT_I420: @@ -232,7 +232,7 @@ // The input |length| can be greater than the required buffer size because of // paddings and/or alignments, but it cannot be smaller. - DCHECK_GE(static_cast<size_t>(length), frame_format.ImageAllocationSize()); + DCHECK_GE(static_cast<size_t>(length), format.ImageAllocationSize()); if (external_jpeg_decoder_) { const VideoCaptureJpegDecoder::STATUS status = @@ -240,29 +240,27 @@ if (status == VideoCaptureJpegDecoder::FAILED) { external_jpeg_decoder_.reset(); } else if (status == VideoCaptureJpegDecoder::INIT_PASSED && - frame_format.pixel_format == media::PIXEL_FORMAT_MJPEG && + format.pixel_format == media::PIXEL_FORMAT_MJPEG && rotation == 0 && !flip) { - external_jpeg_decoder_->DecodeCapturedData(data, length, frame_format, - reference_time, timestamp, - std::move(buffer)); + external_jpeg_decoder_->DecodeCapturedData( + data, length, format, reference_time, timestamp, std::move(buffer)); return; } } - if (libyuv::ConvertToI420(data, length, y_plane_data, yplane_stride, - u_plane_data, uv_plane_stride, v_plane_data, - uv_plane_stride, crop_x, crop_y, - frame_format.frame_size.width(), - (flip ? -1 : 1) * frame_format.frame_size.height(), - new_unrotated_width, new_unrotated_height, - rotation_mode, origin_colorspace) != 0) { + if (libyuv::ConvertToI420( + data, length, y_plane_data, yplane_stride, u_plane_data, + uv_plane_stride, v_plane_data, uv_plane_stride, crop_x, crop_y, + format.frame_size.width(), + (flip ? -1 : 1) * format.frame_size.height(), new_unrotated_width, + new_unrotated_height, rotation_mode, origin_colorspace) != 0) { DLOG(WARNING) << "Failed to convert buffer's pixel format to I420 from " - << media::VideoPixelFormatToString(frame_format.pixel_format); + << media::VideoPixelFormatToString(format.pixel_format); return; } const VideoCaptureFormat output_format = - VideoCaptureFormat(dimensions, frame_format.frame_rate, + VideoCaptureFormat(dimensions, format.frame_rate, media::PIXEL_FORMAT_I420, media::PIXEL_STORAGE_CPU); OnIncomingCapturedBuffer(std::move(buffer), output_format, reference_time, timestamp); @@ -294,11 +292,11 @@ void VideoCaptureDeviceClient::OnIncomingCapturedBuffer( std::unique_ptr<Buffer> buffer, - const VideoCaptureFormat& frame_format, + const VideoCaptureFormat& format, base::TimeTicks reference_time, base::TimeDelta timestamp) { - DCHECK(IsFormatSupported(frame_format.pixel_format)); - DCHECK_EQ(media::PIXEL_STORAGE_CPU, frame_format.pixel_storage); + DCHECK(IsFormatSupported(format.pixel_format)); + DCHECK_EQ(media::PIXEL_STORAGE_CPU, format.pixel_storage); scoped_refptr<VideoFrame> frame; if (buffer->IsBackedByVideoFrame()) { @@ -306,17 +304,15 @@ frame->set_timestamp(timestamp); } else { frame = VideoFrame::WrapExternalSharedMemory( - frame_format.pixel_format, frame_format.frame_size, - gfx::Rect(frame_format.frame_size), frame_format.frame_size, - reinterpret_cast<uint8_t*>(buffer->data()), - VideoFrame::AllocationSize(frame_format.pixel_format, - frame_format.frame_size), + format.pixel_format, format.frame_size, gfx::Rect(format.frame_size), + format.frame_size, reinterpret_cast<uint8_t*>(buffer->data()), + VideoFrame::AllocationSize(format.pixel_format, format.frame_size), base::SharedMemory::NULLHandle(), 0u, timestamp); } if (!frame) return; frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, - frame_format.frame_rate); + format.frame_rate); frame->metadata()->SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME, reference_time); OnIncomingCapturedVideoFrame(std::move(buffer), std::move(frame)); @@ -395,16 +391,16 @@ void VideoCaptureDeviceClient::OnIncomingCapturedY16Data( const uint8_t* data, int length, - const VideoCaptureFormat& frame_format, + const VideoCaptureFormat& format, base::TimeTicks reference_time, base::TimeDelta timestamp, int frame_feedback_id) { std::unique_ptr<Buffer> buffer( - ReserveOutputBuffer(frame_format.frame_size, media::PIXEL_FORMAT_Y16, + ReserveOutputBuffer(format.frame_size, media::PIXEL_FORMAT_Y16, media::PIXEL_STORAGE_CPU, frame_feedback_id)); // The input |length| can be greater than the required buffer size because of // paddings and/or alignments, but it cannot be smaller. - DCHECK_GE(static_cast<size_t>(length), frame_format.ImageAllocationSize()); + DCHECK_GE(static_cast<size_t>(length), format.ImageAllocationSize()); #if DCHECK_IS_ON() dropped_frame_counter_ = buffer.get() ? 0 : dropped_frame_counter_ + 1; if (dropped_frame_counter_ >= kMaxDroppedFrames) @@ -415,7 +411,7 @@ return; memcpy(buffer->data(), data, length); const VideoCaptureFormat output_format = - VideoCaptureFormat(frame_format.frame_size, frame_format.frame_rate, + VideoCaptureFormat(format.frame_size, format.frame_rate, media::PIXEL_FORMAT_Y16, media::PIXEL_STORAGE_CPU); OnIncomingCapturedBuffer(std::move(buffer), output_format, reference_time, timestamp);
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc index 8621584..3f41e29 100644 --- a/media/cdm/aes_decryptor.cc +++ b/media/cdm/aes_decryptor.cc
@@ -261,7 +261,7 @@ const std::vector<uint8_t>& init_data, std::unique_ptr<NewSessionCdmPromise> promise) { std::string session_id(base::UintToString(next_session_id_++)); - valid_sessions_.insert(session_id); + open_sessions_.insert(session_id); // For now, the AesDecryptor does not care about |session_type|. // TODO(jrummell): Validate |session_type|. @@ -329,8 +329,11 @@ std::unique_ptr<SimpleCdmPromise> promise) { CHECK(!response.empty()); - // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed. - if (valid_sessions_.find(session_id) == valid_sessions_.end()) { + // Currently the EME spec has blink check for session closed synchronously, + // but then this is called asynchronously. So it is possible that update() + // could get called on a closed session. + // https://github.com/w3c/encrypted-media/issues/365 + if (open_sessions_.find(session_id) == open_sessions_.end()) { promise->reject(CdmPromise::INVALID_ACCESS_ERROR, 0, "Session does not exist."); return; @@ -405,14 +408,25 @@ // Runs the parallel steps from https://w3c.github.io/encrypted-media/#close. void AesDecryptor::CloseSession(const std::string& session_id, std::unique_ptr<SimpleCdmPromise> promise) { - // Validate that this is a reference to an active session and then forget it. - std::set<std::string>::iterator it = valid_sessions_.find(session_id); - DCHECK(it != valid_sessions_.end()); + // Validate that this is a reference to an open session. close() shouldn't + // be called if the session is already closed. However, the operation is + // asynchronous, so there is a window where close() was called a second time + // just before the closed event arrives. As a result it is possible that the + // session is already closed, so assume that the session is closed if it + // doesn't exist. https://github.com/w3c/encrypted-media/issues/365. + // + // close() is called from a MediaKeySession object, so it is unlikely that + // this method will be called with a previously unseen |session_id|. + std::set<std::string>::iterator it = open_sessions_.find(session_id); + if (it == open_sessions_.end()) { + promise->resolve(); + return; + } // 5.1. Let cdm be the CDM instance represented by session's cdm instance // value. // 5.2. Use cdm to close the session associated with session. - valid_sessions_.erase(it); + open_sessions_.erase(it); DeleteKeysForSession(session_id); // 5.3. Queue a task to run the following steps:
diff --git a/media/cdm/aes_decryptor.h b/media/cdm/aes_decryptor.h index ecf380d..973ec2c 100644 --- a/media/cdm/aes_decryptor.h +++ b/media/cdm/aes_decryptor.h
@@ -146,8 +146,8 @@ KeyIdToSessionKeysMap key_map_; // Protected by |key_map_lock_|. mutable base::Lock key_map_lock_; // Protects the |key_map_|. - // Keeps track of current valid sessions. - std::set<std::string> valid_sessions_; + // Keeps track of current open sessions. + std::set<std::string> open_sessions_; // Make session ID unique per renderer by making it static. Session // IDs seen by the app will be "1", "2", etc.
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc index 2c13377b..7c7815c57 100644 --- a/media/renderers/video_renderer_impl.cc +++ b/media/renderers/video_renderer_impl.cc
@@ -638,14 +638,8 @@ } void VideoRendererImpl::RemoveFramesForUnderflowOrBackgroundRendering() { - // Nothing to do if we're not underflowing, background rendering, or frame - // dropping is disabled (test only). - const bool have_nothing = buffering_state_ == BUFFERING_HAVE_NOTHING; - if (!was_background_rendering_ && !have_nothing && !drop_frames_) - return; - - // If there are no frames to remove, nothing can be done. - if (!algorithm_->frames_queued()) + // Nothing to do if frame dropping is disabled for testing or we have nothing. + if (!drop_frames_ || !algorithm_->frames_queued()) return; // If we're paused for prerolling (current time is 0), don't expire any @@ -664,13 +658,6 @@ return; } - // Use the current media wall clock time plus the frame duration since - // RemoveExpiredFrames() is expecting the end point of an interval (it will - // subtract from the given value). It's important to always call this so - // that frame statistics are updated correctly. - frames_dropped_ += algorithm_->RemoveExpiredFrames( - current_time + algorithm_->average_frame_duration()); - // If we've paused for underflow, and still have no effective frames, clear // the entire queue. Note: this may cause slight inaccuracies in the number // of dropped frames since the frame may have been rendered before. @@ -685,7 +672,21 @@ // calling this function will check if we need to transition or not. if (buffering_state_ == BUFFERING_HAVE_ENOUGH) TransitionToHaveNothing_Locked(); + return; } + + // Use the current media wall clock time plus the frame duration since + // RemoveExpiredFrames() is expecting the end point of an interval (it will + // subtract from the given value). It's important to always call this so + // that frame statistics are updated correctly. + if (buffering_state_ == BUFFERING_HAVE_NOTHING) { + frames_dropped_ += algorithm_->RemoveExpiredFrames( + current_time + algorithm_->average_frame_duration()); + return; + } + + // If we reach this point, the normal rendering process will take care of + // removing any expired frames. } void VideoRendererImpl::CheckForMetadataChanges(VideoPixelFormat pixel_format,
diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h index 3ca8cc5..4268f19 100644 --- a/media/renderers/video_renderer_impl.h +++ b/media/renderers/video_renderer_impl.h
@@ -79,6 +79,9 @@ size_t frames_queued_for_testing() const { return algorithm_->frames_queued(); } + size_t effective_frames_queued_for_testing() const { + return algorithm_->effective_frames_queued(); + } // VideoRendererSink::RenderCallback implementation. scoped_refptr<VideoFrame> Render(base::TimeTicks deadline_min,
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc index 43f9071..53a4f5d 100644 --- a/media/renderers/video_renderer_impl_unittest.cc +++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -892,14 +892,14 @@ .WillOnce(RunClosure(event.GetClosure())); renderer_->OnTimeProgressing(); time_source_.StartTicking(); + // Jump time far enough forward that no frames are valid. + AdvanceTimeInMs(1000); event.RunAndWait(); } WaitForPendingDecode(); - // Jump time far enough forward that no frames are valid. renderer_->OnTimeStopped(); - AdvanceTimeInMs(1000); time_source_.StopTicking(); // Providing the end of stream packet should remove all frames and exit. @@ -927,32 +927,30 @@ event.RunAndWait(); } - null_video_sink_->set_background_render(true); - time_source_.StartTicking(); - renderer_->OnTimeProgressing(); - WaitForPendingDecode(); - renderer_->OnTimeStopped(); + // Now wait until we have no effective frames. + { + SCOPED_TRACE("Waiting for zero effective frames."); + WaitableMessageLoopEvent event; + null_video_sink_->set_background_render(true); + time_source_.StartTicking(); + AdvanceTimeInMs(1000); + renderer_->OnTimeProgressing(); + EXPECT_CALL(mock_cb_, FrameReceived(_)) + .WillOnce(RunClosure(event.GetClosure())); + event.RunAndWait(); + ASSERT_EQ(renderer_->effective_frames_queued_for_testing(), 0u); + } - // Jump time far enough forward that no frames are valid. - AdvanceTimeInMs(1000); - + // When OnTimeStopped() is called it should transition to HAVE_NOTHING. { SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING"); WaitableMessageLoopEvent event; EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)) .WillOnce(RunClosure(event.GetClosure())); - QueueFrames("120"); - SatisfyPendingDecode(); + renderer_->OnTimeStopped(); event.RunAndWait(); } - // This should do nothing. - renderer_->OnTimeProgressing(); - - // Providing the end of stream packet should remove all frames and exit. - SatisfyPendingDecodeWithEndOfStream(); - EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH)); - WaitForEnded(); Destroy(); }
diff --git a/net/BUILD.gn b/net/BUILD.gn index 02b77e2..f87cacb 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -1344,6 +1344,7 @@ "cert/internal/trust_store_nss_unittest.cc", "cert/nss_cert_database_unittest.cc", "ssl/client_cert_store_nss_unittest.cc", + "ssl/ssl_platform_key_nss_unittest.cc", ] if (is_chromeos) { # Already removed for all non-ChromeOS builds. sources -= [ @@ -1555,6 +1556,11 @@ if (is_win) { libs = [ "iphlpapi.lib" ] } + + if (is_chromecast && use_nss_certs) { + sources += [ "ssl/ssl_platform_key_chromecast_unittest.cc" ] + sources -= [ "ssl/ssl_platform_key_nss_unittest.cc" ] + } } # !is_android && !is_win && !is_mac @@ -1596,6 +1602,13 @@ } else { sources -= [ "proxy/proxy_resolver_perftest.cc" ] } + + # Some linker failures have been observed for this target on the Win64 + # continuous builder, see crbug.com/659369. + # TODO(sebmarchand): Remove this once we have some data. + if (is_win && linkrepro_root_dir != "") { + ldflags = [ "/LINKREPRO:" + linkrepro_root_dir + "/" + target_name ] + } } }
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc index 30a4e64..c078986f 100644 --- a/net/dns/host_resolver_impl.cc +++ b/net/dns/host_resolver_impl.cc
@@ -1457,9 +1457,7 @@ requests_.front()->info(), &addr_list)) { // This will destroy the Job. - CompleteRequests( - HostCache::Entry(OK, MakeAddressListForRequest(addr_list)), - base::TimeDelta()); + CompleteRequests(MakeCacheEntry(OK, addr_list), base::TimeDelta()); return true; } return false; @@ -1499,6 +1497,25 @@ DCHECK_EQ(1u, num_occupied_job_slots_); } + // MakeCacheEntry() and MakeCacheEntryWithTTL() are helpers to build a + // HostCache::Entry(). The address list is omited from the cache entry + // for errors. + HostCache::Entry MakeCacheEntry(int net_error, + const AddressList& addr_list) const { + return HostCache::Entry( + net_error, + net_error == OK ? MakeAddressListForRequest(addr_list) : AddressList()); + } + + HostCache::Entry MakeCacheEntryWithTTL(int net_error, + const AddressList& addr_list, + base::TimeDelta ttl) const { + return HostCache::Entry( + net_error, + net_error == OK ? MakeAddressListForRequest(addr_list) : AddressList(), + ttl); + } + AddressList MakeAddressListForRequest(const AddressList& list) const { if (requests_.empty()) return list; @@ -1627,9 +1644,7 @@ ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); // Don't store the |ttl| in cache since it's not obtained from the server. - CompleteRequests( - HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)), - ttl); + CompleteRequests(MakeCacheEntry(net_error, addr_list), ttl); } void StartDnsTask() { @@ -1711,12 +1726,12 @@ base::TimeDelta bounded_ttl = std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds)); - if (ContainsIcannNameCollisionIp(addr_list)) - net_error = ERR_ICANN_NAME_COLLISION; - - CompleteRequests( - HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl), - bounded_ttl); + if (ContainsIcannNameCollisionIp(addr_list)) { + CompleteRequestsWithError(ERR_ICANN_NAME_COLLISION); + } else { + CompleteRequests(MakeCacheEntryWithTTL(net_error, addr_list, ttl), + bounded_ttl); + } } void OnFirstDnsTransactionComplete() override {
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc index 15822d9..0b4807a9 100644 --- a/net/dns/host_resolver_impl_unittest.cc +++ b/net/dns/host_resolver_impl_unittest.cc
@@ -1503,6 +1503,12 @@ EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING)); EXPECT_THAT(request->WaitForResult(), IsError(ERR_ICANN_NAME_COLLISION)); + // ERR_ICANN_NAME_COLLISION is cached like any other error, using a + // fixed TTL for failed entries from proc-based resolver. That said, the + // fixed TTL is 0, so it will never be cached. + request = CreateRequest("single"); + EXPECT_THAT(request->ResolveFromCache(), IsError(ERR_DNS_CACHE_MISS)); + request = CreateRequest("multiple"); EXPECT_THAT(request->Resolve(), IsError(ERR_IO_PENDING)); EXPECT_THAT(request->WaitForResult(), IsError(ERR_ICANN_NAME_COLLISION)); @@ -1836,6 +1842,14 @@ EXPECT_THAT(requests_[1]->WaitForResult(), IsError(OK)); EXPECT_TRUE(requests_[1]->HasAddress("::127.0.53.53", 80)); + + // The mock responses for 4collision (and 6collision) have a TTL of 1 day. + // Test whether the ERR_ICANN_NAME_COLLISION failure was cached. + // On the one hand caching the failure makes sense, as the error is derived + // from the IP in the response. However for consistency with the the proc- + // based implementation the TTL is unused. + EXPECT_THAT(CreateRequest("4collision", 80)->ResolveFromCache(), + IsError(ERR_DNS_CACHE_MISS)); } TEST_F(HostResolverImplDnsTest, ServeFromHosts) {
diff --git a/net/net.gypi b/net/net.gypi index 6490373d..f104a94 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -2152,6 +2152,7 @@ 'ssl/ssl_connection_status_flags_unittest.cc', 'ssl/ssl_platform_key_android_unittest.cc', 'ssl/ssl_platform_key_mac_unittest.cc', + 'ssl/ssl_platform_key_nss_unittest.cc', 'ssl/ssl_platform_key_util_unittest.cc', 'ssl/ssl_private_key_test_util.cc', 'ssl/ssl_private_key_test_util.h',
diff --git a/net/ssl/ssl_platform_key_chromecast.cc b/net/ssl/ssl_platform_key_chromecast.cc index b913e77..5993a3bb 100644 --- a/net/ssl/ssl_platform_key_chromecast.cc +++ b/net/ssl/ssl_platform_key_chromecast.cc
@@ -41,11 +41,8 @@ SSLPrivateKey::Type GetType() override { return SSLPrivateKey::Type::RSA; } std::vector<SSLPrivateKey::Hash> GetDigestPreferences() override { - static const SSLPrivateKey::Hash kHashes[] = { - SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1, - SSLPrivateKey::Hash::MD5_SHA1}; - return std::vector<SSLPrivateKey::Hash>(kHashes, - kHashes + arraysize(kHashes)); + return std::vector<SSLPrivateKey::Hash>{SSLPrivateKey::Hash::SHA256, + SSLPrivateKey::Hash::SHA1}; } size_t GetMaxSignatureLengthInBytes() override {
diff --git a/net/ssl/ssl_platform_key_chromecast_unittest.cc b/net/ssl/ssl_platform_key_chromecast_unittest.cc new file mode 100644 index 0000000..78979c5 --- /dev/null +++ b/net/ssl/ssl_platform_key_chromecast_unittest.cc
@@ -0,0 +1,52 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/ssl/ssl_platform_key.h" + +#include <pk11pub.h> +#include <stdint.h> +#include <string.h> + +#include <memory> +#include <string> +#include <vector> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/memory/ref_counted.h" +#include "crypto/scoped_test_nss_db.h" +#include "net/ssl/ssl_private_key.h" +#include "net/ssl/ssl_private_key_test_util.h" +#include "net/test/cert_test_util.h" +#include "net/test/test_data_directory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +TEST(SSLPlatformKeyChromecastTest, KeyMatches) { + std::string pkcs8; + base::FilePath pkcs8_path = + GetTestCertsDirectory().AppendASCII("client_1.pk8"); + ASSERT_TRUE(base::ReadFileToString(pkcs8_path, &pkcs8)); + + // Import the key into a test NSS database. + crypto::ScopedTestNSSDB test_db; + scoped_refptr<X509Certificate> cert = ImportClientCertAndKeyFromFile( + GetTestCertsDirectory(), "client_1.pem", "client_1.pk8", test_db.slot()); + ASSERT_TRUE(cert); + + // Look up the key. + scoped_refptr<SSLPrivateKey> key = FetchClientCertPrivateKey(cert.get()); + ASSERT_TRUE(key); + + // Only support SHA-256 and SHA-1. + std::vector<SSLPrivateKey::Hash> expected_hashes = { + SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1, + }; + EXPECT_EQ(expected_hashes, key->GetDigestPreferences()); + + TestSSLPrivateKeyMatches(key.get(), pkcs8); +} + +} // namespace net
diff --git a/net/ssl/ssl_platform_key_mac.cc b/net/ssl/ssl_platform_key_mac.cc index 1e0d81f..373f432 100644 --- a/net/ssl/ssl_platform_key_mac.cc +++ b/net/ssl/ssl_platform_key_mac.cc
@@ -39,9 +39,10 @@ #include "third_party/boringssl/src/include/openssl/nid.h" #include "third_party/boringssl/src/include/openssl/rsa.h" -// TODO(davidben): Remove this after https://crbug.com/669240 is fixed. #if !defined(MAC_OS_X_VERSION_10_12) || \ - MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 + MAC_OS_X_VERSION_MIN_ALLOWED < MAC_OS_X_VERSION_10_12 +// Redeclare typedefs that only exist in 10.12+ to suppress +// -Wpartial-availability warnings. typedef CFStringRef SecKeyAlgorithm; #endif
diff --git a/net/ssl/ssl_platform_key_nss_unittest.cc b/net/ssl/ssl_platform_key_nss_unittest.cc new file mode 100644 index 0000000..85799cae --- /dev/null +++ b/net/ssl/ssl_platform_key_nss_unittest.cc
@@ -0,0 +1,141 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/ssl/ssl_platform_key.h" + +#include <keyhi.h> +#include <pk11pub.h> +#include <stdint.h> +#include <string.h> + +#include <memory> +#include <string> +#include <vector> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/memory/ref_counted.h" +#include "crypto/ec_private_key.h" +#include "crypto/scoped_nss_types.h" +#include "crypto/scoped_test_nss_db.h" +#include "net/ssl/ssl_private_key.h" +#include "net/ssl/ssl_private_key_test_util.h" +#include "net/test/cert_test_util.h" +#include "net/test/test_data_directory.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/ec.h" +#include "third_party/boringssl/src/include/openssl/ec_key.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/mem.h" + +namespace net { + +namespace { + +struct TestKey { + const char* cert_file; + const char* key_file; + SSLPrivateKey::Type key_type; +}; + +const TestKey kTestKeys[] = { + {"client_1.pem", "client_1.pk8", SSLPrivateKey::Type::RSA}, + {"client_4.pem", "client_4.pk8", SSLPrivateKey::Type::ECDSA_P256}, + {"client_5.pem", "client_5.pk8", SSLPrivateKey::Type::ECDSA_P384}, + {"client_6.pem", "client_6.pk8", SSLPrivateKey::Type::ECDSA_P521}, +}; + +std::string TestKeyToString(const testing::TestParamInfo<TestKey>& params) { + return SSLPrivateKeyTypeToString(params.param.key_type); +} + +} // namespace + +class SSLPlatformKeyNSSTest : public testing::TestWithParam<TestKey> {}; + +TEST_P(SSLPlatformKeyNSSTest, KeyMatches) { + const TestKey& test_key = GetParam(); + + std::string pkcs8; + base::FilePath pkcs8_path = + GetTestCertsDirectory().AppendASCII(test_key.key_file); + ASSERT_TRUE(base::ReadFileToString(pkcs8_path, &pkcs8)); + + // Import the key into a test NSS database. + crypto::ScopedTestNSSDB test_db; + scoped_refptr<X509Certificate> cert; + if (SSLPrivateKey::IsECDSAType(test_key.key_type)) { + // NSS cannot import unencrypted ECDSA keys, so we encrypt it with an empty + // password and import manually. + std::vector<uint8_t> pkcs8_vector(pkcs8.begin(), pkcs8.end()); + std::unique_ptr<crypto::ECPrivateKey> ec_private_key = + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(pkcs8_vector); + ASSERT_TRUE(ec_private_key); + std::vector<uint8_t> encrypted; + ASSERT_TRUE(ec_private_key->ExportEncryptedPrivateKey("", 1, &encrypted)); + + SECItem encrypted_item = {siBuffer, encrypted.data(), + static_cast<unsigned>(encrypted.size())}; + SECKEYEncryptedPrivateKeyInfo epki; + memset(&epki, 0, sizeof(epki)); + crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + ASSERT_EQ(SECSuccess, + SEC_QuickDERDecodeItem( + arena.get(), &epki, + SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), + &encrypted_item)); + + // NSS uses the serialized public key in X9.62 form as the "public value" + // for key ID purposes. + bssl::ScopedCBB cbb; + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(ec_private_key->key()); + ASSERT_TRUE(EC_POINT_point2cbb(cbb.get(), EC_KEY_get0_group(ec_key), + EC_KEY_get0_public_key(ec_key), + POINT_CONVERSION_UNCOMPRESSED, nullptr)); + uint8_t* public_value; + size_t public_value_len; + ASSERT_TRUE(CBB_finish(cbb.get(), &public_value, &public_value_len)); + bssl::UniquePtr<uint8_t> scoped_public_value(public_value); + SECItem public_item = {siBuffer, public_value, + static_cast<unsigned>(public_value_len)}; + + SECItem password_item = {siBuffer, nullptr, 0}; + ASSERT_EQ(SECSuccess, + PK11_ImportEncryptedPrivateKeyInfo( + test_db.slot(), &epki, &password_item, nullptr /* nickname */, + &public_item, PR_TRUE /* permanent */, PR_TRUE /* private */, + ecKey, KU_DIGITAL_SIGNATURE, nullptr /* wincx */)); + + cert = ImportCertFromFile(GetTestCertsDirectory(), test_key.cert_file); + ASSERT_TRUE(cert); + ASSERT_TRUE(ImportClientCertToSlot(cert, test_db.slot())); + } else { + cert = ImportClientCertAndKeyFromFile(GetTestCertsDirectory(), + test_key.cert_file, test_key.key_file, + test_db.slot()); + ASSERT_TRUE(cert); + } + + // Look up the key. + scoped_refptr<SSLPrivateKey> key = FetchClientCertPrivateKey(cert.get()); + ASSERT_TRUE(key); + + // All NSS keys are expected to have the same hash preferences. + std::vector<SSLPrivateKey::Hash> expected_hashes = { + SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384, + SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1, + }; + EXPECT_EQ(expected_hashes, key->GetDigestPreferences()); + + TestSSLPrivateKeyMatches(key.get(), pkcs8); +} + +INSTANTIATE_TEST_CASE_P(, + SSLPlatformKeyNSSTest, + testing::ValuesIn(kTestKeys), + TestKeyToString); + +} // namespace net
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index bfd3e45..798ef30 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -351,8 +351,434 @@ ] }, "Android Release (Nexus 5X)": { - "gtest_tests": [], - "isolated_scripts": [] + "gtest_tests": [ + { + "args": [ + "--enable-xml-result-parsing" + ], + "name": "angle_deqp_gles2_gles_tests", + "override_isolate_target": "angle_deqp_gles2_tests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "angle_deqp_gles2_tests", + "use_xvfb": false + }, + { + "override_isolate_target": "angle_end2end_tests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "angle_end2end_tests", + "use_xvfb": false + }, + { + "override_isolate_target": "angle_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "angle_unittests", + "use_xvfb": false + }, + { + "override_isolate_target": "gl_tests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "gl_tests", + "use_xvfb": false + }, + { + "override_isolate_target": "gl_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:25755a2c316937ee44a6432163dc5e2f9c85cf58" + } + ], + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ] + }, + "test": "gl_unittests", + "use_xvfb": false + } + ], + "isolated_scripts": [ + { + "args": [ + "context_lost", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_integration_test", + "name": "context_lost_tests", + "override_compile_targets": [ + "telemetry_gpu_integration_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + }, + { + "args": [ + "depth_capture", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_integration_test", + "name": "depth_capture_tests", + "override_compile_targets": [ + "telemetry_gpu_integration_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + }, + { + "args": [ + "gpu_process", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_test", + "name": "gpu_process_launch_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + }, + { + "args": [ + "gpu_rasterization", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_test", + "name": "gpu_rasterization_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + }, + { + "args": [ + "hardware_accelerated_feature", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_test", + "name": "hardware_accelerated_feature_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + }, + { + "args": [ + "maps", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--os-type", + "android", + "--build-revision", + "${got_revision}", + "--test-machine-name", + "${buildername}" + ], + "isolate_name": "telemetry_gpu_test", + "name": "maps_pixel_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + }, + { + "args": [ + "pixel", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", + "--refimg-cloud-storage-bucket", + "chromium-gpu-archive/reference-images", + "--os-type", + "android", + "--build-revision", + "${got_revision}", + "--test-machine-name", + "${buildername}" + ], + "isolate_name": "telemetry_gpu_integration_test", + "name": "pixel_test", + "non_precommit_args": [ + "--upload-refimg-to-cloud-storage" + ], + "override_compile_targets": [ + "telemetry_gpu_integration_test_run" + ], + "precommit_args": [ + "--download-refimg-from-cloud-storage" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + }, + { + "args": [ + "screenshot_sync", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_test", + "name": "screenshot_sync_tests", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + }, + { + "args": [ + "trace_test", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_test", + "name": "trace_test", + "override_compile_targets": [ + "telemetry_gpu_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + }, + { + "args": [ + "webgl_conformance", + "--show-stdout", + "--browser=android-chromium", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_integration_test", + "name": "webgl_conformance_tests", + "override_compile_targets": [ + "telemetry_gpu_integration_test_run" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "M", + "device_type": "bullhead", + "os": "Android" + } + ] + } + } + ] }, "Android Release (Nexus 6)": { "gtest_tests": [
diff --git a/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter b/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter index 0b9bc16..a81bc837 100644 --- a/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter +++ b/testing/buildbot/filters/site-per-process.interactive_ui_tests.filter
@@ -1,4 +1 @@ # List below tests to be excluded from running. - -# https://crbug.com/666858: No drag-and-drop events should fire... --*DragAndDropBrowserTest.CrossSiteDrag*
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 3cb924b..fc67d68 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -737,7 +737,6 @@ crbug.com/248938 [ Linux ] virtual/threaded/transitions/equivalent-background-image-no-transition.html [ Pass Timeout ] crbug.com/248938 [ Linux ] virtual/threaded/transitions/move-after-transition.html [ Pass Timeout ] crbug.com/248938 virtual/threaded/transitions/start-transform-transition.html [ Pass Failure ] -crbug.com/248938 virtual/threaded/animations/animation-direction-normal.html [ Pass Failure Timeout ] crbug.com/248938 virtual/threaded/animations/animation-iteration-event-destroy-renderer.html [ Pass Timeout ] crbug.com/248938 virtual/threaded/animations/transition-and-animation-3.html [ Pass Timeout ] crbug.com/446385 [ Win7 Debug ] http/tests/xmlhttprequest/xmlhttprequest-json-response-overflow.html [ Crash Pass Timeout ] @@ -2308,3 +2307,4 @@ # Added 2016-12-14 crbug.com/674048 [ Linux ] virtual/mojo-loading/http/tests/navigation/image-load-in-unload-handler.html [ Pass Timeout ] +crbug.com/674123 virtual/threaded/animations/animation-direction-normal.html [ Failure Timeout ]
diff --git a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-anchor-point.html b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-anchor-point.html index 2c9116e..d5530ed 100644 --- a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-anchor-point.html +++ b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-anchor-point.html
@@ -2,6 +2,7 @@ <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <script src="../../resources/run-after-layout-and-paint.js"></script> <style> .outer { width: 120px; @@ -27,16 +28,13 @@ } </style> <script type="text/javascript" charset="utf-8"> - if (window.testRunner) - testRunner.waitUntilDone(); - function doTest() { - window.setTimeout(function() { - document.getElementById('inner').className = 'inner composited changed'; - if (window.testRunner) - testRunner.notifyDone(); - }, 0); + if (window.testRunner) { + runAfterLayoutAndPaint(function() { + document.getElementById('inner').className = 'inner composited changed'; + }, true); + } } window.addEventListener('load', doTest, false); </script>
diff --git a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-animated-expected.txt b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-animated-expected.txt index ad32852..90c953b2 100644 --- a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-animated-expected.txt +++ b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-animated-expected.txt
@@ -1,5 +1,5 @@ Animation on original and reflection should both be paused half way through, giving 45deg rotation. 1 -PASS - "webkitTransform.0" property for "inner" element at 0.5s saw something close to: 0.76 +PASS - "webkitTransform.0" property for "inner" element at 0.5s saw something close to: 0.707107
diff --git a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-animated.html b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-animated.html index 6aae869..ce58291e 100644 --- a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-animated.html +++ b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-animated.html
@@ -42,7 +42,7 @@ <script type="text/javascript" charset="utf-8"> const expectedValues = [ // [time, element-id, property, expected-value, tolerance] - [0.5, "inner", "webkitTransform.0", 0.76, 0.1], + [0.5, "inner", "webkitTransform.0", 0.707107, 0.000001], ]; var pixelTest = true;
diff --git a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-transition-expected.txt b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-transition-expected.txt index 7e39ed9e..e2c570e 100644 --- a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-transition-expected.txt +++ b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-transition-expected.txt
@@ -1,3 +1,3 @@ 1 -PASS - "-webkit-transform.1" property for "inner" element at 0.5s saw something close to: 0.76 +PASS - "-webkit-transform.1" property for "inner" element at 0.5s saw something close to: 0.707107
diff --git a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-transition.html b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-transition.html index c51d4de..f4321414 100644 --- a/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-transition.html +++ b/third_party/WebKit/LayoutTests/compositing/reflections/nested-reflection-transition.html
@@ -39,7 +39,7 @@ const expectedValues = [ // [time, element-id, property, expected-value, tolerance] - [0.5, 'inner', '-webkit-transform.1', 0.76, 0.1], + [0.5, 'inner', '-webkit-transform.1', 0.707107, 0.000001], ]; function setupTest()
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/bug669714.html b/third_party/WebKit/LayoutTests/css3/flexbox/bug669714.html new file mode 100644 index 0000000..243a964 --- /dev/null +++ b/third_party/WebKit/LayoutTests/css3/flexbox/bug669714.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> + +<style> +html { line-height: 1; font-size: 18px; } +#relpos { position: relative; top: 1px; } +.flex { flex: 1; } +.flex { min-height: 0; } +.layout, .layout-column, .layout-row { display: flex; } +.layout-column { flex-direction: column; } +</style> + +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/check-layout-th.js"></script> + +<script> +function update() { + document.body.offsetHeight; + document.getElementById("relpos").innerText = " "; + checkLayout("#container"); +} +</script> + +<body onload="update();"> +<p>XXX and YYY should be on separate lines and not overlap, i.e. the height of +.flex should not be 0.</p> +<div class="layout-column" id="container"> + <div class="layout-row"> + <div class="layout-column"> + <div class="flex" data-expected-height="18">XXX<span id="relpos"></span></div> + <div>YYY</div> + </div> + </div> +</div>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-ImageBitmapSource.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-ImageBitmapSource.html new file mode 100644 index 0000000..cf139678 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-ImageBitmapSource.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> +async_test(t => { + var offscreen = new OffscreenCanvas(50, 50); + var ctx = offscreen.getContext('2d'); + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 50, 50); + createImageBitmap(offscreen).then(image => { + var output = new OffscreenCanvas(50, 50); + var outCtx = offscreen.getContext('2d'); + outCtx.drawImage(image, 0, 0); + var pixel = outCtx.getImageData(0, 0, 1, 1).data; + t.step(function() { + assert_array_equals(pixel, [0, 255, 0, 255]); + }); + t.done(); + }); +}, "Call createImageBitmap on OffscreenCanvas with 2D context"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-invalid-args-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-invalid-args-expected.txt index b8c0e7c..4fa88d53 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-invalid-args-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-invalid-args-expected.txt
@@ -5,10 +5,10 @@ PASS Rejected as expected: undefined PASS reason instanceof Error is true -TypeError: Failed to execute 'createImageBitmap' on 'Window': The provided value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or Blob or ImageData or ImageBitmap)' +TypeError: Failed to execute 'createImageBitmap' on 'Window': The provided value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or Blob or ImageData or ImageBitmap or OffscreenCanvas)' PASS Rejected as expected: null PASS reason instanceof Error is true -TypeError: Failed to execute 'createImageBitmap' on 'Window': The provided value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or Blob or ImageData or ImageBitmap)' +TypeError: Failed to execute 'createImageBitmap' on 'Window': The provided value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or Blob or ImageData or ImageBitmap or OffscreenCanvas)' PASS Rejected as expected: empty image PASS reason instanceof Error is true InvalidStateError: Failed to execute 'createImageBitmap' on 'Window': No image can be retrieved from the provided element.
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-invalid-args-in-workers-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-invalid-args-in-workers-expected.txt index ded2b579..eddad15 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-invalid-args-in-workers-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-invalid-args-in-workers-expected.txt
@@ -6,7 +6,7 @@ Starting worker: ./resources/canvas-createImageBitmap-invalid-args-in-workers.js PASS [Worker] Rejected as expected: null PASS [Worker] reason instanceof Error is true -[Worker] TypeError: Failed to execute 'createImageBitmap' on 'WorkerGlobalScope': The provided value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or Blob or ImageData or ImageBitmap)' +[Worker] TypeError: Failed to execute 'createImageBitmap' on 'WorkerGlobalScope': The provided value is not of type '(HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or Blob or ImageData or ImageBitmap or OffscreenCanvas)' PASS [Worker] Rejected as expected: invalid area PASS [Worker] reason instanceof Error is true [Worker] IndexSizeError: Failed to execute 'createImageBitmap' on 'WorkerGlobalScope': The source height provided is 0.
diff --git a/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes.html b/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes.html index f0743c3..d1eed450 100644 --- a/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes.html +++ b/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes.html
@@ -12,7 +12,7 @@ window.jsTestIsAsync = true; var documentsBefore; var documentsAfter; - // FIXME(keishi): Calling asyncGC twice to fix flakiness. + // FIXME(keishi): Calling asyncGC twice to fix flakiness, crbug.com/674194 asyncGC(function() { asyncGC(function() { documentsBefore = window.internals.numberOfLiveDocuments(); @@ -22,12 +22,15 @@ document.body.removeChild(frame); frame = null; + // FIXME(keishi): crbug.com/674194 asyncGC(function() { - documentsAfter = window.internals.numberOfLiveDocuments(); + asyncGC(function() { + documentsAfter = window.internals.numberOfLiveDocuments(); - // -1 is from removing frame itself. - shouldBe('documentsBefore - 1', 'documentsAfter'); - finishJSTest(); + // -1 is from removing frame itself. + shouldBe('documentsBefore - 1', 'documentsAfter'); + finishJSTest(); + }); }); }); });
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/headers.js b/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/headers.js index a87a75fe..d9af65c 100644 --- a/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/headers.js +++ b/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/headers.js
@@ -133,6 +133,7 @@ assert_equals(allValues.length, 1); assert_equals(size(headers), 4); headers.append('X-FETCH-TEST', 'response test field - append'); + headers.append('X-FETCH-TEST-2', 'response test field - append'); assert_equals(size(headers), 5, 'headers size should increase by 1.'); assert_equals(headers.get('X-FETCH-Test'), 'response test field - updated', @@ -142,18 +143,18 @@ assert_equals(allValues[0], 'response test field - updated'); assert_equals(allValues[1], 'response test field - append'); headers.set('X-FETch-Test', 'response test field - set'); - assert_equals(size(headers), 4, 'the second header should be deleted'); + assert_equals(size(headers), 5, 'the second header should be deleted'); allValues = headers.getAll('X-Fetch-Test'); assert_equals(allValues.length, 1, 'the second header should be deleted'); assert_equals(allValues[0], 'response test field - set'); headers.append('X-Fetch-TEST', 'response test field - append'); - assert_equals(size(headers), 5, 'headers size should increase by 1.'); + assert_equals(size(headers), 5, 'headers size should not increase by 1.'); headers.delete('X-FeTCH-Test'); - assert_equals(size(headers), 3, 'two headers should be deleted.'); + assert_equals(size(headers), 4, 'two headers should be deleted.'); // new Headers with sequence<sequence<ByteString>> headers = new Headers([['a', 'b'], ['c', 'd'], ['c', 'e']]); - assert_equals(size(headers), 3, 'headers size should match'); + assert_equals(size(headers), 2, 'headers size should match'); assert_equals(headers.get('a'), 'b'); assert_equals(headers.get('c'), 'd'); assert_equals(headers.getAll('c')[0], 'd'); @@ -161,7 +162,7 @@ // new Headers with Headers var headers2 = new Headers(headers); - assert_equals(size(headers2), 3, 'headers size should match'); + assert_equals(size(headers2), 2, 'headers size should match'); assert_equals(headers2.get('a'), 'b'); assert_equals(headers2.get('c'), 'd'); assert_equals(headers2.getAll('c')[0], 'd'); @@ -239,6 +240,8 @@ headers.set('a', '1'); headers.set('b', '2'); headers.set('c', '3'); + headers.append('a', '2'); + headers.append('a', '3'); const iterator = headers.entries(); @@ -246,11 +249,16 @@ headers.set('d', '4'); const keys = []; - for (let [key, value] of iterator) + const values = []; + for (let [key, value] of iterator) { keys.push(key); + values.push(value); + } assert_array_equals(keys, ['a', 'b', 'c'], 'The pairs to iterate over should be the return ' + 'value of an algorithm that implicitly makes a copy.'); + assert_array_equals(values, ['1,2,3', '2', '3'], + "The values should be combined and separated by ','."); }, 'Iteration mutation'); done();
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/offscreencanvas-read-blocked-no-crossorigin.html b/third_party/WebKit/LayoutTests/http/tests/security/offscreencanvas-read-blocked-no-crossorigin.html new file mode 100644 index 0000000..e88521b --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/security/offscreencanvas-read-blocked-no-crossorigin.html
@@ -0,0 +1,59 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> + +function verifyOffscreenCanvasTaintedThenDone(offscreen, t) { + assert_throws("SecurityError", function() { + offscreen.getContext("2d").getImageData(0, 0, 1, 1); + }, "Check getImageData blocked."); + offscreen.convertToBlob().then( + function() { + assert_unreached("Promise returned by convertToBlob was resolved."); + t.done(); + }, + rejectionValue => { + assert_equals(rejectionValue.name, "SecurityError"); + t.done(); + } + ); +} + +async_test(t => { + var image = new Image(); + // Notice that we don't set the image.crossOrigin property. + image.src = "http://localhost:8000/security/resources/abe-allow-star.php"; + image.onload = function() { + var offscreen = new OffscreenCanvas(10, 10); + var ctx = offscreen.getContext('2d'); + ctx.drawImage(image, 0, 0); + t.step(function() { + verifyOffscreenCanvasTaintedThenDone(offscreen, t); + }); + } +}, "Verify that an OffscreenCanvas tainted with cross-origin content cannot be read."); + +async_test(t => { + var image = new Image(); + // Notice that we don't set the image.crossOrigin property. + image.src = "http://localhost:8000/security/resources/abe-allow-star.php"; + image.onload = function() { + var offscreen = new OffscreenCanvas(10, 10); + var ctx = offscreen.getContext('2d'); + ctx.drawImage(image, 0, 0); + createImageBitmap(offscreen).then(imageBitmap => { + var offscreen2 = new OffscreenCanvas(10, 10); + var ctx2 = offscreen2.getContext('2d'); + ctx2.drawImage(imageBitmap, 0, 0); + t.step(function() { + verifyOffscreenCanvasTaintedThenDone(offscreen, t); + }); + }) + } +}, "Verify that createImageBitmap(OffscreenCanvas) propagates the origin-clean flag."); + + + + + +</script>
diff --git a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-session-multiple-close.html b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-session-multiple-close.html new file mode 100644 index 0000000..e6e8325 --- /dev/null +++ b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-session-multiple-close.html
@@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html> + <head> + <title>Test multiple calls to MediaKeySession.close()</title> + <script src="encrypted-media-utils.js"></script> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> + </head> + <body> + <script> + // This test verifies that Chrome handles multiple close() calls + // correctly. Currently the EME spec has the check for session + // already closed happen immediately when the method is called, + // but the action is performed asynchronously. + // https://github.com/w3c/encrypted-media/issues/365 + + async_test(function(test) + { + var initDataType; + var initData; + var mediaKeySession; + + navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration()).then(function(access) { + initDataType = access.getConfiguration().initDataTypes[0]; + initData = getInitData(initDataType); + return access.createMediaKeys(); + }).then(function(mediaKeys) { + mediaKeySession = mediaKeys.createSession(); + return mediaKeySession.generateRequest(initDataType, initData); + }).then(function() { + // Call close() multiple times. + return Promise.all([mediaKeySession.close(), mediaKeySession.close(), mediaKeySession.close()]); + }).then(function() { + test.done(); + }).catch(function(error) { + forceTestFailureFromPromise(test, error); + }); + }, 'Test multiple calls to MediaKeySession.close().'); + </script> + </body> +</html>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/nested-reflection-animated-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/nested-reflection-animated-expected.png index a2a21d98..f0f3eb6 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/nested-reflection-animated-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/nested-reflection-animated-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/nested-reflection-transition-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/nested-reflection-transition-expected.png index 49b0a43a..078d220 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/nested-reflection-transition-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/reflections/nested-reflection-transition-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.png index 4f14f67..e979726 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/nested-reflection-animated-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.png index 5a23a9e..a976873 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/reflections/nested-reflection-transition-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/nested-reflection-animated-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/nested-reflection-animated-expected.png index 8e87cc8..df49599 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/nested-reflection-animated-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/nested-reflection-animated-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/nested-reflection-transition-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/nested-reflection-transition-expected.png index 7183b18..6275431 100644 --- a/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/nested-reflection-transition-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/compositing/reflections/nested-reflection-transition-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLCanvasElement.html b/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLCanvasElement.html index 816b9de1..5c030ddc 100644 --- a/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLCanvasElement.html +++ b/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLCanvasElement.html
@@ -66,14 +66,14 @@ "Face - HTMLCanvasElement", () => { return new FaceDetector(); }, () => { return document.createElement("canvas"); }, - () => { return mockFaceDetectionReady; }, + () => { return mockFaceDetectionProviderReady; }, FaceDetectorDetectionResultTest ], [ "Face - OffscreenCanvas", () => { return new FaceDetector(); }, () => { return new OffscreenCanvas(300, 150); }, - () => { return mockFaceDetectionReady; }, + () => { return mockFaceDetectionProviderReady; }, FaceDetectorDetectionResultTest ], [
diff --git a/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLImageElement.html b/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLImageElement.html index 3eef1a2..c4ab7b5b 100644 --- a/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLImageElement.html +++ b/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLImageElement.html
@@ -58,7 +58,7 @@ [ "Face", () => { return new FaceDetector(); }, - () => { return mockFaceDetectionReady; }, + () => { return mockFaceDetectionProviderReady; }, FaceDetectorDetectionResultTest ], [
diff --git a/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLVideoElement.html b/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLVideoElement.html index 65ef40e..aafd565 100644 --- a/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLVideoElement.html +++ b/third_party/WebKit/LayoutTests/shapedetection/detection-HTMLVideoElement.html
@@ -62,7 +62,7 @@ [ "Face", () => { return new FaceDetector(); }, - () => { return mockFaceDetectionReady; }, + () => { return mockFaceDetectionProviderReady; }, FaceDetectorDetectionResultTest ], [
diff --git a/third_party/WebKit/LayoutTests/shapedetection/detection-ImageBitmap.html b/third_party/WebKit/LayoutTests/shapedetection/detection-ImageBitmap.html index f89df492..18c364ee 100644 --- a/third_party/WebKit/LayoutTests/shapedetection/detection-ImageBitmap.html +++ b/third_party/WebKit/LayoutTests/shapedetection/detection-ImageBitmap.html
@@ -66,7 +66,7 @@ [ "Face", () => { return new FaceDetector(); }, - () => { return mockFaceDetectionReady; }, + () => { return mockFaceDetectionProviderReady; }, FaceDetectorDetectionResultTest ], [
diff --git a/third_party/WebKit/LayoutTests/shapedetection/detection-options.html b/third_party/WebKit/LayoutTests/shapedetection/detection-options.html index 4954886..fb12e70 100644 --- a/third_party/WebKit/LayoutTests/shapedetection/detection-options.html +++ b/third_party/WebKit/LayoutTests/shapedetection/detection-options.html
@@ -10,7 +10,7 @@ async_test(function(t) { var img = document.getElementById("img"); var theMock = null; - mockFaceDetectionReady + mockFaceDetectionProviderReady .then(mock => { theMock = mock; return new FaceDetector();
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js index 3efddb2..c934619 100644 --- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js +++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
@@ -1,32 +1,58 @@ "use strict"; -let mockFaceDetectionReady = define( - 'mockFaceDetection', +let mockFaceDetectionProviderReady = define( + 'mockFaceDetectionProvider', ['third_party/WebKit/public/platform/modules/shapedetection/facedetection.mojom', + 'third_party/WebKit/public/platform/modules/shapedetection/facedetection_provider.mojom', 'mojo/public/js/bindings', 'mojo/public/js/connection', 'mojo/public/js/core', 'content/public/renderer/frame_interfaces', - ], (faceDetection, bindings, connection, mojo, interfaces) => { + ], (faceDetection, faceDetectionProvider, bindings, connection, mojo, interfaces) => { - class MockFaceDetection { + class MockFaceDetectionProvider { constructor() { interfaces.addInterfaceOverrideForTesting( - faceDetection.FaceDetection.name, + faceDetectionProvider.FaceDetectionProvider.name, pipe => this.bindToPipe(pipe)); } bindToPipe(pipe) { - this.stub_ = connection.bindHandleToStub(pipe, - faceDetection.FaceDetection); + this.stub_ = connection.bindHandleToStub( + pipe, faceDetectionProvider.FaceDetectionProvider); bindings.StubBindings(this.stub_).delegate = this; } - detect(frame_data, width, height, options) { - let receivedStruct = mojo.mapBuffer(frame_data, 0, width*height*4, 0); - this.buffer_data_ = new Uint32Array(receivedStruct.buffer); + createFaceDetection(request, options) { + this.mock_service_ = new MockFaceDetection(options); + this.mock_service_.stub_ = connection.bindHandleToStub( + request.handle, faceDetection.FaceDetection); + bindings.StubBindings(this.mock_service_.stub_).delegate = + this.mock_service_; + } + + getFrameData() { + return this.mock_service_.buffer_data_; + } + + getMaxDetectedFaces() { + return this.mock_service_.maxDetectedFaces_; + } + + getFastMode () { + return this.mock_service_.fastMode_; + } + } + + class MockFaceDetection { + constructor(options) { this.maxDetectedFaces_ = options.max_detected_faces; this.fastMode_ = options.fast_mode; + } + + detect(frame_data, width, height) { + let receivedStruct = mojo.mapBuffer(frame_data, 0, width*height*4, 0); + this.buffer_data_ = new Uint32Array(receivedStruct.buffer); return Promise.resolve({ result: { bounding_boxes: [ @@ -38,18 +64,6 @@ }); mojo.unmapBuffer(receivedStruct.buffer); } - - getFrameData() { - return this.buffer_data_; - } - - getMaxDetectedFaces() { - return this.maxDetectedFaces_; - } - - getFastMode () { - return this.fastMode_; - } } - return new MockFaceDetection(); + return new MockFaceDetectionProvider(); });
diff --git a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn index ccd985f..7a0a9a3 100644 --- a/third_party/WebKit/Source/bindings/core/v8/BUILD.gn +++ b/third_party/WebKit/Source/bindings/core/v8/BUILD.gn
@@ -164,8 +164,8 @@ "$bindings_core_v8_output_dir/FileOrUSVString.h", "$bindings_core_v8_output_dir/HTMLElementOrLong.cpp", "$bindings_core_v8_output_dir/HTMLElementOrLong.h", - "$bindings_core_v8_output_dir/HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmap.cpp", - "$bindings_core_v8_output_dir/HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmap.h", + "$bindings_core_v8_output_dir/HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas.cpp", + "$bindings_core_v8_output_dir/HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas.h", "$bindings_core_v8_output_dir/HTMLOptionElementOrHTMLOptGroupElement.cpp", "$bindings_core_v8_output_dir/HTMLOptionElementOrHTMLOptGroupElement.h", "$bindings_core_v8_output_dir/HTMLScriptElementOrSVGScriptElement.cpp",
diff --git a/third_party/WebKit/Source/bindings/core/v8/CallbackPromiseAdapter.h b/third_party/WebKit/Source/bindings/core/v8/CallbackPromiseAdapter.h index 3e46e81..cdd4380 100644 --- a/third_party/WebKit/Source/bindings/core/v8/CallbackPromiseAdapter.h +++ b/third_party/WebKit/Source/bindings/core/v8/CallbackPromiseAdapter.h
@@ -94,8 +94,9 @@ // // // In order to implement the above exceptions, we have template classes below. -// OnSuccess and OnError provide onSuccess and onError implementation, and there -// are utility templates that provide the trivial WebType holder. +// OnSuccessAdapter and OnErrorAdapter provide onSuccess and onError +// implementation, and there are utility templates that provide the trivial +// WebType holder. namespace internal { @@ -133,9 +134,9 @@ }; template <typename S, typename T> - class OnSuccess : public Base<S, T> { + class OnSuccessAdapter : public Base<S, T> { public: - explicit OnSuccess(ScriptPromiseResolver* resolver) + explicit OnSuccessAdapter(ScriptPromiseResolver* resolver) : Base<S, T>(resolver) {} void onSuccess(typename S::WebType result) override { ScriptPromiseResolver* resolver = this->resolver(); @@ -146,10 +147,10 @@ } }; template <typename T> - class OnSuccess<CallbackPromiseAdapterTrivialWebTypeHolder<void>, T> + class OnSuccessAdapter<CallbackPromiseAdapterTrivialWebTypeHolder<void>, T> : public Base<CallbackPromiseAdapterTrivialWebTypeHolder<void>, T> { public: - explicit OnSuccess(ScriptPromiseResolver* resolver) + explicit OnSuccessAdapter(ScriptPromiseResolver* resolver) : Base<CallbackPromiseAdapterTrivialWebTypeHolder<void>, T>(resolver) {} void onSuccess() override { ScriptPromiseResolver* resolver = this->resolver(); @@ -160,10 +161,10 @@ } }; template <typename S, typename T> - class OnError : public OnSuccess<S, T> { + class OnErrorAdapter : public OnSuccessAdapter<S, T> { public: - explicit OnError(ScriptPromiseResolver* resolver) - : OnSuccess<S, T>(resolver) {} + explicit OnErrorAdapter(ScriptPromiseResolver* resolver) + : OnSuccessAdapter<S, T>(resolver) {} void onError(typename T::WebType e) override { ScriptPromiseResolver* resolver = this->resolver(); if (!resolver->getExecutionContext() || @@ -174,11 +175,13 @@ } }; template <typename S> - class OnError<S, CallbackPromiseAdapterTrivialWebTypeHolder<void>> - : public OnSuccess<S, CallbackPromiseAdapterTrivialWebTypeHolder<void>> { + class OnErrorAdapter<S, CallbackPromiseAdapterTrivialWebTypeHolder<void>> + : public OnSuccessAdapter< + S, + CallbackPromiseAdapterTrivialWebTypeHolder<void>> { public: - explicit OnError(ScriptPromiseResolver* resolver) - : OnSuccess<S, CallbackPromiseAdapterTrivialWebTypeHolder<void>>( + explicit OnErrorAdapter(ScriptPromiseResolver* resolver) + : OnSuccessAdapter<S, CallbackPromiseAdapterTrivialWebTypeHolder<void>>( resolver) {} void onError() override { ScriptPromiseResolver* resolver = this->resolver(); @@ -192,12 +195,12 @@ public: template <typename S, typename T> class CallbackPromiseAdapter final - : public OnError<WebTypeHolder<S>, WebTypeHolder<T>> { + : public OnErrorAdapter<WebTypeHolder<S>, WebTypeHolder<T>> { WTF_MAKE_NONCOPYABLE(CallbackPromiseAdapter); public: explicit CallbackPromiseAdapter(ScriptPromiseResolver* resolver) - : OnError<WebTypeHolder<S>, WebTypeHolder<T>>(resolver) {} + : OnErrorAdapter<WebTypeHolder<S>, WebTypeHolder<T>>(resolver) {} }; };
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp index 9d38a76..663da08f 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -622,6 +622,12 @@ documentStyle->setDisplay(EDisplay::Block); documentStyle->setPosition(AbsolutePosition); + // Document::inheritHtmlAndBodyElementStyles will set the final overflow + // style values, but they should initially be auto to avoid premature + // scrollbar removal in PaintLayerScrollableArea::updateAfterStyleChange. + documentStyle->setOverflowX(EOverflow::Auto); + documentStyle->setOverflowY(EOverflow::Auto); + document.setupFontBuilder(*documentStyle); return documentStyle.release();
diff --git a/third_party/WebKit/Source/core/dom/AttributeCollection.h b/third_party/WebKit/Source/core/dom/AttributeCollection.h index 6221ae9..6e80e61f 100644 --- a/third_party/WebKit/Source/core/dom/AttributeCollection.h +++ b/third_party/WebKit/Source/core/dom/AttributeCollection.h
@@ -118,7 +118,7 @@ inline void MutableAttributeCollection::append(const QualifiedName& name, const AtomicString& value) { - m_attributes.append(Attribute(name, value)); + m_attributes.push_back(Attribute(name, value)); } inline void MutableAttributeCollection::remove(unsigned index) {
diff --git a/third_party/WebKit/Source/core/dom/CSSSelectorWatch.cpp b/third_party/WebKit/Source/core/dom/CSSSelectorWatch.cpp index a45caa6a..c81f41d 100644 --- a/third_party/WebKit/Source/core/dom/CSSSelectorWatch.cpp +++ b/third_party/WebKit/Source/core/dom/CSSSelectorWatch.cpp
@@ -159,7 +159,7 @@ if (!allCompound(selectorList)) continue; - m_watchedCallbackSelectors.append( + m_watchedCallbackSelectors.push_back( StyleRule::create(std::move(selectorList), callbackPropertySet)); } document().styleEngine().watchedSelectorsChanged();
diff --git a/third_party/WebKit/Source/core/dom/CSSSelectorWatchTest.cpp b/third_party/WebKit/Source/core/dom/CSSSelectorWatchTest.cpp index a41745b..e94963db 100644 --- a/third_party/WebKit/Source/core/dom/CSSSelectorWatchTest.cpp +++ b/third_party/WebKit/Source/core/dom/CSSSelectorWatchTest.cpp
@@ -53,15 +53,15 @@ CSSSelectorWatch& watch = CSSSelectorWatch::from(document()); Vector<String> selectors; - selectors.append(".a"); + selectors.push_back(".a"); watch.watchCSSSelectors(selectors); document().view()->updateAllLifecyclePhases(); selectors.clear(); - selectors.append(".b"); - selectors.append(".c"); - selectors.append("#nomatch"); + selectors.push_back(".b"); + selectors.push_back(".c"); + selectors.push_back("#nomatch"); watch.watchCSSSelectors(selectors); document().view()->updateAllLifecyclePhases();
diff --git a/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp b/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp index 46a280ad..6b89e35 100644 --- a/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp +++ b/third_party/WebKit/Source/core/dom/ChildFrameDisconnector.cpp
@@ -38,7 +38,7 @@ return; if (root.isHTMLElement() && root.isFrameOwnerElement()) - m_frameOwners.append(&toHTMLFrameOwnerElement(root)); + m_frameOwners.push_back(&toHTMLFrameOwnerElement(root)); for (Node* child = root.firstChild(); child; child = child->nextSibling()) collectFrameOwners(*child);
diff --git a/third_party/WebKit/Source/core/dom/ChildListMutationScope.cpp b/third_party/WebKit/Source/core/dom/ChildListMutationScope.cpp index dae3257..06597ed 100644 --- a/third_party/WebKit/Source/core/dom/ChildListMutationScope.cpp +++ b/third_party/WebKit/Source/core/dom/ChildListMutationScope.cpp
@@ -99,7 +99,7 @@ } m_lastAdded = child; - m_addedNodes.append(child); + m_addedNodes.push_back(child); } inline bool ChildListMutationAccumulator::isRemovedNodeInOrder(Node* child) { @@ -120,7 +120,7 @@ m_nextSibling = child->nextSibling(); } - m_removedNodes.append(child); + m_removedNodes.push_back(child); } void ChildListMutationAccumulator::enqueueMutationRecord() {
diff --git a/third_party/WebKit/Source/core/dom/ClientRectList.cpp b/third_party/WebKit/Source/core/dom/ClientRectList.cpp index 02c2dbf..a39e743 100644 --- a/third_party/WebKit/Source/core/dom/ClientRectList.cpp +++ b/third_party/WebKit/Source/core/dom/ClientRectList.cpp
@@ -33,7 +33,7 @@ ClientRectList::ClientRectList(const Vector<FloatQuad>& quads) { m_list.reserveInitialCapacity(quads.size()); for (const auto& quad : quads) - m_list.append(ClientRect::create(quad.boundingBox())); + m_list.push_back(ClientRect::create(quad.boundingBox())); } unsigned ClientRectList::length() const {
diff --git a/third_party/WebKit/Source/core/dom/ClientRectList.h b/third_party/WebKit/Source/core/dom/ClientRectList.h index 3f0d7de..463873dc 100644 --- a/third_party/WebKit/Source/core/dom/ClientRectList.h +++ b/third_party/WebKit/Source/core/dom/ClientRectList.h
@@ -66,7 +66,7 @@ explicit ClientRectList(const Rects& rects) { m_list.reserveInitialCapacity(rects.size()); for (const auto& r : rects) - m_list.append(ClientRect::create(FloatRect(r))); + m_list.push_back(ClientRect::create(FloatRect(r))); } explicit ClientRectList(const Vector<FloatQuad>&);
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp index 8e46d3dc..9247542 100644 --- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp +++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -76,7 +76,7 @@ fragment.removeChildren(); return; } - nodes.append(&node); + nodes.push_back(&node); if (ContainerNode* oldParent = node.parentNode()) oldParent->removeChild(&node, exceptionState); } @@ -728,7 +728,7 @@ continue; if (Node::InsertionShouldCallDidNotifySubtreeInsertions == node.insertedInto(this)) - postInsertionNotificationTargets.append(&node); + postInsertionNotificationTargets.push_back(&node); for (ShadowRoot* shadowRoot = node.youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) notifyNodeInsertedInternal(*shadowRoot, postInsertionNotificationTargets);
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.h b/third_party/WebKit/Source/core/dom/ContainerNode.h index 385aa49..e1f884a0 100644 --- a/third_party/WebKit/Source/core/dom/ContainerNode.h +++ b/third_party/WebKit/Source/core/dom/ContainerNode.h
@@ -460,7 +460,7 @@ inline void getChildNodes(ContainerNode& node, NodeVector& nodes) { DCHECK(!nodes.size()); for (Node* child = node.firstChild(); child; child = child->nextSibling()) - nodes.append(child); + nodes.push_back(child); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/DOMStringList.h b/third_party/WebKit/Source/core/dom/DOMStringList.h index 8e27a79..23b43ae2 100644 --- a/third_party/WebKit/Source/core/dom/DOMStringList.h +++ b/third_party/WebKit/Source/core/dom/DOMStringList.h
@@ -56,7 +56,7 @@ bool isEmpty() const { return m_strings.isEmpty(); } void clear() { m_strings.clear(); } - void append(const String& string) { m_strings.append(string); } + void append(const String& string) { m_strings.push_back(string); } void sort(); // Implements the IDL.
diff --git a/third_party/WebKit/Source/core/dom/DOMTokenList.cpp b/third_party/WebKit/Source/core/dom/DOMTokenList.cpp index 7a939fa..b931c68 100644 --- a/third_party/WebKit/Source/core/dom/DOMTokenList.cpp +++ b/third_party/WebKit/Source/core/dom/DOMTokenList.cpp
@@ -105,7 +105,7 @@ void DOMTokenList::add(const AtomicString& token, ExceptionState& exceptionState) { Vector<String> tokens; - tokens.append(token.getString()); + tokens.push_back(token.getString()); add(tokens, exceptionState); } @@ -122,7 +122,7 @@ continue; if (filteredTokens.contains(token)) continue; - filteredTokens.append(token); + filteredTokens.push_back(token); } if (!filteredTokens.isEmpty()) @@ -132,7 +132,7 @@ void DOMTokenList::remove(const AtomicString& token, ExceptionState& exceptionState) { Vector<String> tokens; - tokens.append(token.getString()); + tokens.push_back(token.getString()); remove(tokens, exceptionState); } @@ -205,7 +205,7 @@ AtomicString DOMTokenList::addToken(const AtomicString& input, const AtomicString& token) { Vector<String> tokens; - tokens.append(token.getString()); + tokens.push_back(token.getString()); return addTokens(input, tokens); } @@ -234,7 +234,7 @@ AtomicString DOMTokenList::removeToken(const AtomicString& input, const AtomicString& token) { Vector<String> tokens; - tokens.append(token.getString()); + tokens.push_back(token.getString()); return removeTokens(input, tokens); }
diff --git a/third_party/WebKit/Source/core/dom/DatasetDOMStringMap.cpp b/third_party/WebKit/Source/core/dom/DatasetDOMStringMap.cpp index ee7a019..e006a7a 100644 --- a/third_party/WebKit/Source/core/dom/DatasetDOMStringMap.cpp +++ b/third_party/WebKit/Source/core/dom/DatasetDOMStringMap.cpp
@@ -153,7 +153,7 @@ AttributeCollection attributes = m_element->attributes(); for (const Attribute& attr : attributes) { if (isValidAttributeName(attr.localName())) - names.append(convertAttributeNameToPropertyName(attr.localName())); + names.push_back(convertAttributeNameToPropertyName(attr.localName())); } }
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 4ed7156d..733298fd 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -5119,7 +5119,7 @@ void Document::pushCurrentScript(Element* newCurrentScript) { DCHECK(isHTMLScriptElement(newCurrentScript) || isSVGScriptElement(newCurrentScript)); - m_currentScriptStack.append(newCurrentScript); + m_currentScriptStack.push_back(newCurrentScript); } void Document::popCurrentScript() { @@ -5365,15 +5365,15 @@ linkElement->type(), linkElement->getIconType()); if (linkElement->getIconType() == Favicon) { if (firstFavicon.m_iconType != InvalidIcon) - secondaryIcons.append(firstFavicon); + secondaryIcons.push_back(firstFavicon); firstFavicon = newURL; } else if (linkElement->getIconType() == TouchIcon) { if (firstTouchIcon.m_iconType != InvalidIcon) - secondaryIcons.append(firstTouchIcon); + secondaryIcons.push_back(firstTouchIcon); firstTouchIcon = newURL; } else if (linkElement->getIconType() == TouchPrecomposedIcon) { if (firstTouchPrecomposedIcon.m_iconType != InvalidIcon) - secondaryIcons.append(firstTouchPrecomposedIcon); + secondaryIcons.push_back(firstTouchPrecomposedIcon); firstTouchPrecomposedIcon = newURL; } else { NOTREACHED(); @@ -5382,16 +5382,16 @@ Vector<IconURL> iconURLs; if (firstFavicon.m_iconType != InvalidIcon) - iconURLs.append(firstFavicon); + iconURLs.push_back(firstFavicon); else if (m_url.protocolIsInHTTPFamily() && iconTypesMask & Favicon) - iconURLs.append(IconURL::defaultFavicon(m_url)); + iconURLs.push_back(IconURL::defaultFavicon(m_url)); if (firstTouchIcon.m_iconType != InvalidIcon) - iconURLs.append(firstTouchIcon); + iconURLs.push_back(firstTouchIcon); if (firstTouchPrecomposedIcon.m_iconType != InvalidIcon) - iconURLs.append(firstTouchPrecomposedIcon); + iconURLs.push_back(firstTouchPrecomposedIcon); for (int i = secondaryIcons.size() - 1; i >= 0; --i) - iconURLs.append(secondaryIcons[i]); + iconURLs.push_back(secondaryIcons[i]); return iconURLs; } @@ -5813,7 +5813,7 @@ size_t beforePosition = m_topLayerElements.find(before); m_topLayerElements.insert(beforePosition, element); } else { - m_topLayerElements.append(element); + m_topLayerElements.push_back(element); } element->setIsInTopLayer(true); } @@ -6179,7 +6179,7 @@ for (Node& node : NodeTraversal::inclusiveAncestorsOf(*oldHoverNode)) { if (!mustBeInActiveChain || (node.isElementNode() && toElement(node).inActiveChain())) - nodesToRemoveFromChain.append(node); + nodesToRemoveFromChain.push_back(node); } } @@ -6189,7 +6189,7 @@ curr = curr->hoverAncestor()) { if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) - nodesToRemoveFromChain.append(curr->node()); + nodesToRemoveFromChain.push_back(curr->node()); } // TODO(mustaq): The two loops above may push a single node twice into @@ -6200,7 +6200,7 @@ for (LayoutObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) { if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) - nodesToAddToChain.append(curr->node()); + nodesToAddToChain.push_back(curr->node()); } size_t removeCount = nodesToRemoveFromChain.size();
diff --git a/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp b/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp index 8044c7f8..d66c171c 100644 --- a/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp
@@ -89,14 +89,14 @@ "share", "shoutbox", "sidebar", "skyscraper", "sponsor", "ad-break", "agegate", "pagination", "pager", "popup"}; for (auto word : words) { - unlikelyCandidates.append(word); + unlikelyCandidates.push_back(word); } } DEFINE_STATIC_LOCAL(Vector<String>, highlyLikelyCandidates, ()); if (highlyLikelyCandidates.isEmpty()) { auto words = {"and", "article", "body", "column", "main", "shadow"}; for (auto word : words) { - highlyLikelyCandidates.append(word); + highlyLikelyCandidates.push_back(word); } }
diff --git a/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollector.cpp b/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollector.cpp index 2a947f9..7a032525 100644 --- a/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollector.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentStyleSheetCollector.cpp
@@ -57,7 +57,7 @@ void DocumentStyleSheetCollector::appendSheetForList(StyleSheet* sheet) { if (m_styleSheetsForStyleSheetList) { - m_styleSheetsForStyleSheetList->append(sheet); + m_styleSheetsForStyleSheetList->push_back(sheet); } else { m_collection->appendSheetForList(sheet); }
diff --git a/third_party/WebKit/Source/core/dom/DocumentTest.cpp b/third_party/WebKit/Source/core/dom/DocumentTest.cpp index 09505a8..55e92fd 100644 --- a/third_party/WebKit/Source/core/dom/DocumentTest.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
@@ -177,16 +177,16 @@ void TestSynchronousMutationObserver::didChangeChildren( const ContainerNode& container) { - m_childrenChangedNodes.append(&container); + m_childrenChangedNodes.push_back(&container); } void TestSynchronousMutationObserver::didMergeTextNodes(Text& node, unsigned offset) { - m_mergeTextNodesRecords.append(new MergeTextNodesRecord(&node, offset)); + m_mergeTextNodesRecords.push_back(new MergeTextNodesRecord(&node, offset)); } void TestSynchronousMutationObserver::didSplitTextNode(const Text& node) { - m_splitTextNodes.append(&node); + m_splitTextNodes.push_back(&node); } void TestSynchronousMutationObserver::didUpdateCharacterData( @@ -194,17 +194,17 @@ unsigned offset, unsigned oldLength, unsigned newLength) { - m_updatedCharacterDataRecords.append(new UpdateCharacterDataRecord( + m_updatedCharacterDataRecords.push_back(new UpdateCharacterDataRecord( characterData, offset, oldLength, newLength)); } void TestSynchronousMutationObserver::nodeChildrenWillBeRemoved( ContainerNode& container) { - m_removedChildrenNodes.append(&container); + m_removedChildrenNodes.push_back(&container); } void TestSynchronousMutationObserver::nodeWillBeRemoved(Node& node) { - m_removedNodes.append(&node); + m_removedNodes.push_back(&node); } DEFINE_TRACE(TestSynchronousMutationObserver) {
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index c92dcff..d58a766 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -1062,7 +1062,7 @@ if (isSVGElement() && layoutObject()) { // Get the bounding rectangle from the SVG model. if (toSVGElement(this)->isSVGGraphicsElement()) - quads.append(layoutObject()->localToAbsoluteQuad( + quads.push_back(layoutObject()->localToAbsoluteQuad( layoutObject()->objectBoundingBox())); } else { // Get the bounding rectangle from the box model. @@ -1104,7 +1104,7 @@ if (isSVGElement() && !elementLayoutObject->isSVGRoot()) { // Get the bounding rectangle from the SVG model. if (toSVGElement(this)->isSVGGraphicsElement()) - quads.append(elementLayoutObject->localToAbsoluteQuad( + quads.push_back(elementLayoutObject->localToAbsoluteQuad( elementLayoutObject->objectBoundingBox())); return; } @@ -4023,8 +4023,8 @@ if (!activityLogger) return; Vector<String, 2> argv; - argv.append(element); - argv.append(fastGetAttribute(attr1)); + argv.push_back(element); + argv.push_back(fastGetAttribute(attr1)); activityLogger->logEvent("blinkAddElement", argv.size(), argv.data()); } @@ -4039,9 +4039,9 @@ if (!activityLogger) return; Vector<String, 3> argv; - argv.append(element); - argv.append(fastGetAttribute(attr1)); - argv.append(fastGetAttribute(attr2)); + argv.push_back(element); + argv.push_back(fastGetAttribute(attr1)); + argv.push_back(fastGetAttribute(attr2)); activityLogger->logEvent("blinkAddElement", argv.size(), argv.data()); } @@ -4057,10 +4057,10 @@ if (!activityLogger) return; Vector<String, 4> argv; - argv.append(element); - argv.append(fastGetAttribute(attr1)); - argv.append(fastGetAttribute(attr2)); - argv.append(fastGetAttribute(attr3)); + argv.push_back(element); + argv.push_back(fastGetAttribute(attr1)); + argv.push_back(fastGetAttribute(attr2)); + argv.push_back(fastGetAttribute(attr3)); activityLogger->logEvent("blinkAddElement", argv.size(), argv.data()); } @@ -4076,10 +4076,10 @@ if (!activityLogger) return; Vector<String, 4> argv; - argv.append(element); - argv.append(attributeName.toString()); - argv.append(oldValue); - argv.append(newValue); + argv.push_back(element); + argv.push_back(attributeName.toString()); + argv.push_back(oldValue); + argv.push_back(newValue); activityLogger->logEvent("blinkSetAttribute", argv.size(), argv.data()); }
diff --git a/third_party/WebKit/Source/core/dom/ElementRareData.h b/third_party/WebKit/Source/core/dom/ElementRareData.h index 36eaf6b..22763ff 100644 --- a/third_party/WebKit/Source/core/dom/ElementRareData.h +++ b/third_party/WebKit/Source/core/dom/ElementRareData.h
@@ -157,7 +157,7 @@ AttrNodeList* attrNodeList() { return m_attrNodeList.get(); } void removeAttrNodeList() { m_attrNodeList.clear(); } void addAttr(Attr* attr) { - ensureAttrNodeList().append(attr); + ensureAttrNodeList().push_back(attr); ScriptWrappableVisitor::writeBarrier(this, attr); }
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp index dc9c24da..4d59b660 100644 --- a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp +++ b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp
@@ -104,7 +104,7 @@ void ExecutionContext::dispatchErrorEvent(ErrorEvent* errorEvent, AccessControlStatus corsStatus) { if (m_inDispatchErrorEvent) { - m_pendingExceptions.append(errorEvent); + m_pendingExceptions.push_back(errorEvent); return; }
diff --git a/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp b/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp index 5002f3d4..3fef3b49 100644 --- a/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp +++ b/third_party/WebKit/Source/core/dom/FrameRequestCallbackCollection.cpp
@@ -21,7 +21,7 @@ FrameRequestCallbackCollection::CallbackId id = ++m_nextCallbackId; callback->m_cancelled = false; callback->m_id = id; - m_callbacks.append(callback); + m_callbacks.push_back(callback); TRACE_EVENT_INSTANT1("devtools.timeline", "RequestAnimationFrame", TRACE_EVENT_SCOPE_THREAD, "data",
diff --git a/third_party/WebKit/Source/core/dom/Fullscreen.cpp b/third_party/WebKit/Source/core/dom/Fullscreen.cpp index 60a9166..757f18f 100644 --- a/third_party/WebKit/Source/core/dom/Fullscreen.cpp +++ b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
@@ -820,7 +820,7 @@ void Fullscreen::pushFullscreenElementStack(Element& element, RequestType requestType) { - m_fullscreenElementStack.append(std::make_pair(&element, requestType)); + m_fullscreenElementStack.push_back(std::make_pair(&element, requestType)); } DEFINE_TRACE(Fullscreen) {
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp index 91a4f0be..eade5171 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp +++ b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
@@ -82,16 +82,16 @@ const CSSParserToken& token = tokenRange.consumeIncludingWhitespace(); switch (token.type()) { case PercentageToken: - rootMargin.append(Length(token.numericValue(), Percent)); + rootMargin.push_back(Length(token.numericValue(), Percent)); break; case DimensionToken: switch (token.unitType()) { case CSSPrimitiveValue::UnitType::Pixels: - rootMargin.append( + rootMargin.push_back( Length(static_cast<int>(floor(token.numericValue())), Fixed)); break; case CSSPrimitiveValue::UnitType::Percentage: - rootMargin.append(Length(token.numericValue(), Percent)); + rootMargin.push_back(Length(token.numericValue(), Percent)); break; default: exceptionState.throwDOMException( @@ -110,10 +110,10 @@ Vector<float>& thresholds, ExceptionState& exceptionState) { if (thresholdParameter.isDouble()) { - thresholds.append(static_cast<float>(thresholdParameter.getAsDouble())); + thresholds.push_back(static_cast<float>(thresholdParameter.getAsDouble())); } else { for (auto thresholdValue : thresholdParameter.getAsDoubleSequence()) - thresholds.append(static_cast<float>(thresholdValue)); + thresholds.push_back(static_cast<float>(thresholdValue)); } for (auto thresholdValue : thresholds) { @@ -383,7 +383,7 @@ void IntersectionObserver::enqueueIntersectionObserverEntry( IntersectionObserverEntry& entry) { - m_entries.append(&entry); + m_entries.push_back(&entry); toDocument(m_callback->getExecutionContext()) ->ensureIntersectionObserverController() .scheduleIntersectionObserverForDelivery(*this);
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp index caf859d..6b49dee2 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp +++ b/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp
@@ -92,7 +92,7 @@ HeapVector<Member<IntersectionObserver>> toRemove; for (auto& observer : m_trackedIntersectionObservers) { if (observer->root() == &root) - toRemove.append(observer); + toRemove.push_back(observer); } m_trackedIntersectionObservers.removeAll(toRemove); }
diff --git a/third_party/WebKit/Source/core/dom/MutationObserver.cpp b/third_party/WebKit/Source/core/dom/MutationObserver.cpp index cce4f48..0c595bb1 100644 --- a/third_party/WebKit/Source/core/dom/MutationObserver.cpp +++ b/third_party/WebKit/Source/core/dom/MutationObserver.cpp
@@ -186,7 +186,7 @@ void MutationObserver::enqueueMutationRecord(MutationRecord* mutation) { DCHECK(isMainThread()); - m_records.append(mutation); + m_records.push_back(mutation); activateObserver(this); InspectorInstrumentation::asyncTaskScheduled( m_callback->getExecutionContext(), mutation->type(), mutation); @@ -224,7 +224,7 @@ HeapVector<Member<MutationObserverRegistration>, 1> transientRegistrations; for (auto& registration : m_registrations) { if (registration->hasTransientRegistrations()) - transientRegistrations.append(registration); + transientRegistrations.push_back(registration); } for (const auto& registration : transientRegistrations) registration->clearTransientRegistrations();
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp index fce91f7..2b39822 100644 --- a/third_party/WebKit/Source/core/dom/Node.cpp +++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -1366,9 +1366,9 @@ HeapVector<Member<const Node>, 16> chain1; HeapVector<Member<const Node>, 16> chain2; if (attr1) - chain1.append(attr1); + chain1.push_back(attr1); if (attr2) - chain2.append(attr2); + chain2.push_back(attr2); if (attr1 && attr2 && start1 == start2 && start1) { // We are comparing two attributes on the same node. Crawl our attribute map @@ -1413,9 +1413,9 @@ // of the two immediate children. const Node* current; for (current = start1; current; current = current->parentOrShadowHostNode()) - chain1.append(current); + chain1.push_back(current); for (current = start2; current; current = current->parentOrShadowHostNode()) - chain2.append(current); + chain2.push_back(current); unsigned index1 = chain1.size(); unsigned index2 = chain2.size(); @@ -1578,7 +1578,7 @@ HeapVector<Member<const Node>, 16> chain; const Node* node = this; while (node->parentOrShadowHostNode()) { - chain.append(node); + chain.push_back(node); node = node->parentOrShadowHostNode(); } for (unsigned index = chain.size(); index > 0; --index) { @@ -2294,7 +2294,7 @@ DCHECK(insertionPoint->containingShadowRoot()); if (!insertionPoint->containingShadowRoot()->isOpenOrV0()) break; - filteredInsertionPoints.append(insertionPoint); + filteredInsertionPoints.push_back(insertionPoint); } return StaticNodeList::adopt(filteredInsertionPoints); }
diff --git a/third_party/WebKit/Source/core/dom/NodeRareData.h b/third_party/WebKit/Source/core/dom/NodeRareData.h index 57a313af..a3c23b7 100644 --- a/third_party/WebKit/Source/core/dom/NodeRareData.h +++ b/third_party/WebKit/Source/core/dom/NodeRareData.h
@@ -60,7 +60,7 @@ } void addRegistration(MutationObserverRegistration* registration) { - m_registry.append( + m_registry.push_back( TraceWrapperMember<MutationObserverRegistration>(this, registration)); }
diff --git a/third_party/WebKit/Source/core/dom/PresentationAttributeStyle.cpp b/third_party/WebKit/Source/core/dom/PresentationAttributeStyle.cpp index f9fcf82..a9009bb 100644 --- a/third_party/WebKit/Source/core/dom/PresentationAttributeStyle.cpp +++ b/third_party/WebKit/Source/core/dom/PresentationAttributeStyle.cpp
@@ -143,7 +143,7 @@ // Disallow caching. if (attr.name() == backgroundAttr) return; - result.attributesAndValues.append( + result.attributesAndValues.push_back( std::make_pair(attr.localName().impl(), attr.value())); } if (result.attributesAndValues.isEmpty())
diff --git a/third_party/WebKit/Source/core/dom/Range.cpp b/third_party/WebKit/Source/core/dom/Range.cpp index 9311eab..bf3832d 100644 --- a/third_party/WebKit/Source/core/dom/Range.cpp +++ b/third_party/WebKit/Source/core/dom/Range.cpp
@@ -590,7 +590,7 @@ if (processStart) { NodeVector nodes; for (Node* n = processStart; n && n != processEnd; n = n->nextSibling()) - nodes.append(n); + nodes.push_back(n); processNodes(action, nodes, commonRoot, fragment, exceptionState); } @@ -662,7 +662,7 @@ n = n->nextSibling(); for (unsigned i = startOffset; n && i < endOffset; i++, n = n->nextSibling()) - nodes.append(n); + nodes.push_back(n); processNodes(action, nodes, container, result, exceptionState); break; @@ -705,7 +705,7 @@ for (Node& runner : NodeTraversal::ancestorsOf(*container)) { if (runner == commonRoot) break; - ancestors.append(runner); + ancestors.push_back(runner); } Node* firstChildInAncestorToProcess = direction == ProcessContentsForward @@ -731,7 +731,7 @@ child = (direction == ProcessContentsForward) ? child->nextSibling() : child->previousSibling()) - nodes.append(child); + nodes.push_back(child); for (const auto& node : nodes) { Node* child = node.get();
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp index 2fb99a9..fe174e6 100644 --- a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
@@ -87,9 +87,9 @@ MockScriptLoader* scriptLoader3 = MockScriptLoader::create(m_element.get()); HeapVector<Member<MockScriptLoader>> scriptLoaders; - scriptLoaders.append(scriptLoader1); - scriptLoaders.append(scriptLoader2); - scriptLoaders.append(scriptLoader3); + scriptLoaders.push_back(scriptLoader1); + scriptLoaders.push_back(scriptLoader2); + scriptLoaders.push_back(scriptLoader3); for (ScriptLoader* scriptLoader : scriptLoaders) { m_scriptRunner->queueScriptForExecution(scriptLoader, @@ -98,7 +98,7 @@ for (size_t i = 0; i < scriptLoaders.size(); ++i) { EXPECT_CALL(*scriptLoaders[i], execute()).WillOnce(Invoke([this, i] { - m_order.append(i + 1); + m_order.push_back(i + 1); })); } @@ -148,19 +148,19 @@ m_scriptRunner->notifyScriptReady(scriptLoader5, ScriptRunner::Async); EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([this] { - m_order.append(1); + m_order.push_back(1); })); EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([this] { - m_order.append(2); + m_order.push_back(2); })); EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] { - m_order.append(3); + m_order.push_back(3); })); EXPECT_CALL(*scriptLoader4, execute()).WillOnce(Invoke([this] { - m_order.append(4); + m_order.push_back(4); })); EXPECT_CALL(*scriptLoader5, execute()).WillOnce(Invoke([this] { - m_order.append(5); + m_order.push_back(5); })); m_platform.runUntilIdle(); @@ -181,18 +181,18 @@ MockScriptLoader* scriptLoader = scriptLoader2; EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([scriptLoader, this] { - m_order.append(1); + m_order.push_back(1); m_scriptRunner->notifyScriptReady(scriptLoader, ScriptRunner::Async); })); scriptLoader = scriptLoader3; EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([scriptLoader, this] { - m_order.append(2); + m_order.push_back(2); m_scriptRunner->notifyScriptReady(scriptLoader, ScriptRunner::Async); })); EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] { - m_order.append(3); + m_order.push_back(3); })); // Make sure that re-entrant calls to notifyScriptReady don't cause @@ -222,7 +222,7 @@ MockScriptLoader* scriptLoader = scriptLoader2; EXPECT_CALL(*scriptLoader1, execute()) .WillOnce(Invoke([scriptLoader, &scriptLoader2, this] { - m_order.append(1); + m_order.push_back(1); m_scriptRunner->queueScriptForExecution(scriptLoader, ScriptRunner::InOrder); m_scriptRunner->notifyScriptReady(scriptLoader2, ScriptRunner::InOrder); @@ -231,14 +231,14 @@ scriptLoader = scriptLoader3; EXPECT_CALL(*scriptLoader2, execute()) .WillOnce(Invoke([scriptLoader, &scriptLoader3, this] { - m_order.append(2); + m_order.push_back(2); m_scriptRunner->queueScriptForExecution(scriptLoader, ScriptRunner::InOrder); m_scriptRunner->notifyScriptReady(scriptLoader3, ScriptRunner::InOrder); })); EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] { - m_order.append(3); + m_order.push_back(3); })); // Make sure that re-entrant calls to queueScriptForExecution don't cause @@ -267,7 +267,7 @@ if (i > 0) { EXPECT_CALL(*scriptLoaders[i], execute()).WillOnce(Invoke([this, i] { - m_order.append(i); + m_order.push_back(i); })); } } @@ -280,7 +280,7 @@ for (int i = 2; i < 20; i++) m_scriptRunner->notifyScriptReady(scriptLoaders[i], ScriptRunner::Async); - m_order.append(0); + m_order.push_back(0); })); m_platform.runUntilIdle(); @@ -301,13 +301,13 @@ m_scriptRunner->queueScriptForExecution(scriptLoader3, ScriptRunner::InOrder); EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([this] { - m_order.append(1); + m_order.push_back(1); })); EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([this] { - m_order.append(2); + m_order.push_back(2); })); EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] { - m_order.append(3); + m_order.push_back(3); })); EXPECT_CALL(*scriptLoader2, isReady()).WillRepeatedly(Return(true)); @@ -347,13 +347,13 @@ m_scriptRunner->notifyScriptReady(scriptLoader3, ScriptRunner::Async); EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([this] { - m_order.append(1); + m_order.push_back(1); })); EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([this] { - m_order.append(2); + m_order.push_back(2); })); EXPECT_CALL(*scriptLoader3, execute()).WillOnce(Invoke([this] { - m_order.append(3); + m_order.push_back(3); })); m_platform.runSingleTask(); @@ -376,10 +376,10 @@ m_scriptRunner->queueScriptForExecution(scriptLoader2, ScriptRunner::InOrder); EXPECT_CALL(*scriptLoader1, execute()).WillOnce(Invoke([this] { - m_order.append(1); + m_order.push_back(1); })); EXPECT_CALL(*scriptLoader2, execute()).WillOnce(Invoke([this] { - m_order.append(2); + m_order.push_back(2); })); m_scriptRunner->notifyScriptReady(scriptLoader1, ScriptRunner::InOrder);
diff --git a/third_party/WebKit/Source/core/dom/ScriptedAnimationController.cpp b/third_party/WebKit/Source/core/dom/ScriptedAnimationController.cpp index 74a2496..08aef2e 100644 --- a/third_party/WebKit/Source/core/dom/ScriptedAnimationController.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptedAnimationController.cpp
@@ -99,9 +99,9 @@ for (auto& event : m_eventQueue) { if (event && event->interfaceName() == eventInterfaceFilter) { m_perFrameEvents.remove(eventTargetKey(event.get())); - events.append(event.release()); + events.push_back(event.release()); } else { - remaining.append(event.release()); + remaining.push_back(event.release()); } } remaining.swap(m_eventQueue); @@ -170,14 +170,14 @@ void ScriptedAnimationController::enqueueTask( std::unique_ptr<WTF::Closure> task) { - m_taskQueue.append(std::move(task)); + m_taskQueue.push_back(std::move(task)); scheduleAnimationIfNeeded(); } void ScriptedAnimationController::enqueueEvent(Event* event) { InspectorInstrumentation::asyncTaskScheduled( event->target()->getExecutionContext(), event->type(), event); - m_eventQueue.append(event); + m_eventQueue.push_back(event); scheduleAnimationIfNeeded(); }
diff --git a/third_party/WebKit/Source/core/dom/ScriptedAnimationControllerTest.cpp b/third_party/WebKit/Source/core/dom/ScriptedAnimationControllerTest.cpp index 8497b5f..6ea6deb 100644 --- a/third_party/WebKit/Source/core/dom/ScriptedAnimationControllerTest.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptedAnimationControllerTest.cpp
@@ -50,7 +50,7 @@ const Vector<int>& order() const { return m_order; } private: - void runTask(int id) { m_order.append(id); } + void runTask(int id) { m_order.push_back(id); } Vector<int> m_order; };
diff --git a/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp b/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp index 4a5d1ee..9f7b67a 100644 --- a/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptedIdleTaskController.cpp
@@ -143,7 +143,7 @@ if (m_suspended) { if (callbackType == IdleDeadline::CallbackType::CalledByTimeout) { // Queue for execution when we are resumed. - m_pendingTimeouts.append(id); + m_pendingTimeouts.push_back(id); } // Just drop callbacks called while suspended, these will be reposted on the // idle task queue when we are resumed.
diff --git a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp index 3154fc2..0562cff 100644 --- a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp +++ b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
@@ -59,7 +59,7 @@ static const bool shouldOnlyMatchFirstElement = false; ALWAYS_INLINE static void appendElement(OutputType& output, Element& element) { - output.append(&element); + output.push_back(&element); } };
diff --git a/third_party/WebKit/Source/core/dom/SpaceSplitString.cpp b/third_party/WebKit/Source/core/dom/SpaceSplitString.cpp index 66abcbc4..6bf70dd 100644 --- a/third_party/WebKit/Source/core/dom/SpaceSplitString.cpp +++ b/third_party/WebKit/Source/core/dom/SpaceSplitString.cpp
@@ -64,7 +64,7 @@ while (end < length && isNotHTMLSpace<CharacterType>(characters[end])) ++end; - m_vector.append(AtomicString(characters + start, end - start)); + m_vector.push_back(AtomicString(characters + start, end - start)); start = end + 1; } @@ -103,7 +103,7 @@ void SpaceSplitString::Data::add(const AtomicString& string) { DCHECK(hasOneRef()); DCHECK(!contains(string)); - m_vector.append(string); + m_vector.push_back(string); } void SpaceSplitString::Data::remove(unsigned index) {
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp index 4fe3ecaf..a84beae 100644 --- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp +++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -137,7 +137,7 @@ } void StyleEngine::injectAuthorSheet(StyleSheetContents* authorSheet) { - m_injectedAuthorStyleSheets.append(TraceWrapperMember<CSSStyleSheet>( + m_injectedAuthorStyleSheets.push_back(TraceWrapperMember<CSSStyleSheet>( this, CSSStyleSheet::create(authorSheet, *m_document))); markDocumentDirty(); resolverChanged(AnalyzedStyleUpdate);
diff --git a/third_party/WebKit/Source/core/dom/StyleSheetCollection.cpp b/third_party/WebKit/Source/core/dom/StyleSheetCollection.cpp index f25b2d6..3359f33 100644 --- a/third_party/WebKit/Source/core/dom/StyleSheetCollection.cpp +++ b/third_party/WebKit/Source/core/dom/StyleSheetCollection.cpp
@@ -53,7 +53,7 @@ } void StyleSheetCollection::appendActiveStyleSheet(CSSStyleSheet* sheet) { - m_activeAuthorStyleSheets.append(sheet); + m_activeAuthorStyleSheets.push_back(sheet); } void StyleSheetCollection::appendActiveStyleSheets( @@ -64,12 +64,12 @@ void StyleSheetCollection::appendActiveStyleSheets( const HeapVector<TraceWrapperMember<CSSStyleSheet>>& sheets) { for (CSSStyleSheet* sheet : sheets) { - m_activeAuthorStyleSheets.append(sheet); + m_activeAuthorStyleSheets.push_back(sheet); } } void StyleSheetCollection::appendSheetForList(StyleSheet* sheet) { - m_styleSheetsForStyleSheetList.append( + m_styleSheetsForStyleSheetList.push_back( TraceWrapperMember<StyleSheet>(this, sheet)); }
diff --git a/third_party/WebKit/Source/core/dom/TouchList.h b/third_party/WebKit/Source/core/dom/TouchList.h index 8da2b54..df657dc9 100644 --- a/third_party/WebKit/Source/core/dom/TouchList.h +++ b/third_party/WebKit/Source/core/dom/TouchList.h
@@ -56,7 +56,7 @@ Touch* item(unsigned); const Touch* item(unsigned) const; - void append(Touch* touch) { m_values.append(touch); } + void append(Touch* touch) { m_values.push_back(touch); } DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/dom/TreeScope.cpp b/third_party/WebKit/Source/core/dom/TreeScope.cpp index 50ca8a1..aad09a6 100644 --- a/third_party/WebKit/Source/core/dom/TreeScope.cpp +++ b/third_party/WebKit/Source/core/dom/TreeScope.cpp
@@ -308,7 +308,7 @@ continue; if (node && node->isElementNode()) { - elements.append(toElement(node)); + elements.push_back(toElement(node)); lastNode = node; } } @@ -316,7 +316,7 @@ if (rootNode().isDocumentNode()) { if (Element* rootElement = toDocument(rootNode()).documentElement()) { if (elements.isEmpty() || elements.back() != rootElement) - elements.append(rootElement); + elements.push_back(rootElement); } } @@ -448,9 +448,9 @@ HeapVector<Member<const TreeScope>, 16> chain2; const TreeScope* current; for (current = this; current; current = current->parentTreeScope()) - chain1.append(current); + chain1.push_back(current); for (current = &otherScope; current; current = current->parentTreeScope()) - chain2.append(current); + chain2.push_back(current); unsigned index1 = chain1.size(); unsigned index2 = chain2.size(); @@ -492,11 +492,11 @@ const TreeScope& other) const { HeapVector<Member<const TreeScope>, 16> thisChain; for (const TreeScope* tree = this; tree; tree = tree->parentTreeScope()) - thisChain.append(tree); + thisChain.push_back(tree); HeapVector<Member<const TreeScope>, 16> otherChain; for (const TreeScope* tree = &other; tree; tree = tree->parentTreeScope()) - otherChain.append(tree); + otherChain.push_back(tree); // Keep popping out the last elements of these chains until a mismatched pair // is found. If |this| and |other| belong to different documents, null will be
diff --git a/third_party/WebKit/Source/core/dom/URLSearchParams.cpp b/third_party/WebKit/Source/core/dom/URLSearchParams.cpp index 44b85871..30ba1da48 100644 --- a/third_party/WebKit/Source/core/dom/URLSearchParams.cpp +++ b/third_party/WebKit/Source/core/dom/URLSearchParams.cpp
@@ -112,7 +112,7 @@ queryString.substring(endOfName + 1, nameValueEnd - endOfName - 1)); if (value.isNull()) value = ""; - m_params.append(std::make_pair(name, value)); + m_params.push_back(std::make_pair(name, value)); } start = nameValueEnd + 1; } @@ -126,7 +126,7 @@ } void URLSearchParams::append(const String& name, const String& value) { - m_params.append(std::make_pair(name, value)); + m_params.push_back(std::make_pair(name, value)); runUpdateSteps(); } @@ -152,7 +152,7 @@ Vector<String> result; for (const auto& param : m_params) { if (param.first == name) - result.append(param.second); + result.push_back(param.second); } return result; }
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.cpp index abafc42..e86a4e14 100644 --- a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.cpp +++ b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.cpp
@@ -126,7 +126,7 @@ Element* element) : m_constructionStack(definition->m_constructionStack), m_element(element) { // Push the construction stack. - m_constructionStack.append(element); + m_constructionStack.push_back(element); m_depth = m_constructionStack.size(); }
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementReactionQueue.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementReactionQueue.cpp index c54fd41a0..342f91e4 100644 --- a/third_party/WebKit/Source/core/dom/custom/CustomElementReactionQueue.cpp +++ b/third_party/WebKit/Source/core/dom/custom/CustomElementReactionQueue.cpp
@@ -19,7 +19,7 @@ } void CustomElementReactionQueue::add(CustomElementReaction* reaction) { - m_reactions.append(reaction); + m_reactions.push_back(reaction); } // There is one queue per element, so this could be invoked
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementReactionTestHelpers.h b/third_party/WebKit/Source/core/dom/custom/CustomElementReactionTestHelpers.h index e2cab72..c652c97 100644 --- a/third_party/WebKit/Source/core/dom/custom/CustomElementReactionTestHelpers.h +++ b/third_party/WebKit/Source/core/dom/custom/CustomElementReactionTestHelpers.h
@@ -110,7 +110,7 @@ // TODO(dominicc): Simply pass the initializer list when // HeapVector supports initializer lists like Vector. for (auto& command : commands) - m_commands.append(command); + m_commands.push_back(command); } ~TestReaction() override = default; DEFINE_INLINE_VIRTUAL_TRACE() {
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementRegistryTest.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementRegistryTest.cpp index fc29919..788812d 100644 --- a/third_party/WebKit/Source/core/dom/custom/CustomElementRegistryTest.cpp +++ b/third_party/WebKit/Source/core/dom/custom/CustomElementRegistryTest.cpp
@@ -219,7 +219,7 @@ } bool runConstructor(Element* element) override { - m_logs.append(Constructor); + m_logs.push_back(Constructor); m_element = element; return TestCustomElementDefinition::runConstructor(element); } @@ -229,30 +229,30 @@ bool hasAdoptedCallback() const override { return true; } void runConnectedCallback(Element* element) override { - m_logs.append(ConnectedCallback); + m_logs.push_back(ConnectedCallback); EXPECT_EQ(element, m_element); } void runDisconnectedCallback(Element* element) override { - m_logs.append(DisconnectedCallback); + m_logs.push_back(DisconnectedCallback); EXPECT_EQ(element, m_element); } void runAdoptedCallback(Element* element, Document* oldOwner, Document* newOwner) override { - m_logs.append(AdoptedCallback); + m_logs.push_back(AdoptedCallback); EXPECT_EQ(element, m_element); - m_adopted.append(new Adopted(oldOwner, newOwner)); + m_adopted.push_back(new Adopted(oldOwner, newOwner)); } void runAttributeChangedCallback(Element* element, const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue) override { - m_logs.append(AttributeChangedCallback); + m_logs.push_back(AttributeChangedCallback); EXPECT_EQ(element, m_element); - m_attributeChanged.append(AttributeChanged{name, oldValue, newValue}); + m_attributeChanged.push_back(AttributeChanged{name, oldValue, newValue}); } };
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementUpgradeSorter.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementUpgradeSorter.cpp index d3dc33ec..e915e924 100644 --- a/third_party/WebKit/Source/core/dom/custom/CustomElementUpgradeSorter.cpp +++ b/third_party/WebKit/Source/core/dom/custom/CustomElementUpgradeSorter.cpp
@@ -66,7 +66,7 @@ if (it == children.end()) return; if (it->get()->isElementNode() && m_elements->contains(toElement(*it))) - result->append(toElement(*it)); + result->push_back(toElement(*it)); sorted(result, *it); children.remove(it); }
diff --git a/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp b/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp index ec99d0f..e6cee541 100644 --- a/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp +++ b/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp
@@ -59,7 +59,7 @@ AtomicString lower = name.lower(); if (isValidName(lower, EmbedderNames)) return; - embedderCustomElementNames().append(lower); + embedderCustomElementNames().push_back(lower); } static inline bool isValidNCName(const AtomicString& name) { @@ -89,7 +89,7 @@ DEFINE_STATIC_LOCAL(Vector<AtomicString>, reservedNames, ()); if (reservedNames.isEmpty()) { // FIXME(crbug.com/426605): We should be able to remove this. - reservedNames.append(MathMLNames::annotation_xmlTag.localName()); + reservedNames.push_back(MathMLNames::annotation_xmlTag.localName()); } if (kNotFound == reservedNames.find(name))
diff --git a/third_party/WebKit/Source/core/dom/custom/V0CustomElementAsyncImportMicrotaskQueue.cpp b/third_party/WebKit/Source/core/dom/custom/V0CustomElementAsyncImportMicrotaskQueue.cpp index a1061215..bcd0434 100644 --- a/third_party/WebKit/Source/core/dom/custom/V0CustomElementAsyncImportMicrotaskQueue.cpp +++ b/third_party/WebKit/Source/core/dom/custom/V0CustomElementAsyncImportMicrotaskQueue.cpp
@@ -36,7 +36,7 @@ void V0CustomElementAsyncImportMicrotaskQueue::enqueue( V0CustomElementMicrotaskStep* step) { - m_queue.append(step); + m_queue.push_back(step); } void V0CustomElementAsyncImportMicrotaskQueue::doDispatch() { @@ -44,7 +44,7 @@ for (auto& step : m_queue) { if (V0CustomElementMicrotaskStep::Processing == step->process()) - remaining.append(step.release()); + remaining.push_back(step.release()); } m_queue.swap(remaining);
diff --git a/third_party/WebKit/Source/core/dom/custom/V0CustomElementCallbackQueue.h b/third_party/WebKit/Source/core/dom/custom/V0CustomElementCallbackQueue.h index 97ffa2f..d52b2c8 100644 --- a/third_party/WebKit/Source/core/dom/custom/V0CustomElementCallbackQueue.h +++ b/third_party/WebKit/Source/core/dom/custom/V0CustomElementCallbackQueue.h
@@ -60,7 +60,7 @@ bool processInElementQueue(ElementQueueId); void append(V0CustomElementProcessingStep* invocation) { - m_queue.append(invocation); + m_queue.push_back(invocation); } bool inCreatedCallback() const { return m_inCreatedCallback; }
diff --git a/third_party/WebKit/Source/core/dom/custom/V0CustomElementMicrotaskDispatcher.cpp b/third_party/WebKit/Source/core/dom/custom/V0CustomElementMicrotaskDispatcher.cpp index 64aaaf8..bbb9e99 100644 --- a/third_party/WebKit/Source/core/dom/custom/V0CustomElementMicrotaskDispatcher.cpp +++ b/third_party/WebKit/Source/core/dom/custom/V0CustomElementMicrotaskDispatcher.cpp
@@ -28,7 +28,7 @@ V0CustomElementCallbackQueue* queue) { ensureMicrotaskScheduledForElementQueue(); queue->setOwner(kMicrotaskQueueId); - m_elements.append(queue); + m_elements.push_back(queue); } void V0CustomElementMicrotaskDispatcher::
diff --git a/third_party/WebKit/Source/core/dom/custom/V0CustomElementProcessingStack.cpp b/third_party/WebKit/Source/core/dom/custom/V0CustomElementProcessingStack.cpp index 36c2d29..c43d4ef 100644 --- a/third_party/WebKit/Source/core/dom/custom/V0CustomElementProcessingStack.cpp +++ b/third_party/WebKit/Source/core/dom/custom/V0CustomElementProcessingStack.cpp
@@ -86,7 +86,7 @@ callbackQueue->setOwner(currentElementQueue()); - m_flattenedProcessingStack.append(callbackQueue); + m_flattenedProcessingStack.push_back(callbackQueue); ++s_elementQueueEnd; }
diff --git a/third_party/WebKit/Source/core/dom/custom/V0CustomElementProcessingStack.h b/third_party/WebKit/Source/core/dom/custom/V0CustomElementProcessingStack.h index 95e28d40..d3b4215 100644 --- a/third_party/WebKit/Source/core/dom/custom/V0CustomElementProcessingStack.h +++ b/third_party/WebKit/Source/core/dom/custom/V0CustomElementProcessingStack.h
@@ -77,7 +77,7 @@ // crash. V0CustomElementCallbackQueue* sentinel = 0; for (size_t i = 0; i < kNumSentinels; i++) - m_flattenedProcessingStack.append(sentinel); + m_flattenedProcessingStack.push_back(sentinel); DCHECK_EQ(s_elementQueueEnd, m_flattenedProcessingStack.size()); }
diff --git a/third_party/WebKit/Source/core/dom/custom/V0CustomElementSyncMicrotaskQueue.cpp b/third_party/WebKit/Source/core/dom/custom/V0CustomElementSyncMicrotaskQueue.cpp index d891e69b..0c898e8f5 100644 --- a/third_party/WebKit/Source/core/dom/custom/V0CustomElementSyncMicrotaskQueue.cpp +++ b/third_party/WebKit/Source/core/dom/custom/V0CustomElementSyncMicrotaskQueue.cpp
@@ -8,7 +8,7 @@ void V0CustomElementSyncMicrotaskQueue::enqueue( V0CustomElementMicrotaskStep* step) { - m_queue.append(step); + m_queue.push_back(step); } void V0CustomElementSyncMicrotaskQueue::doDispatch() {
diff --git a/third_party/WebKit/Source/core/dom/shadow/DistributedNodes.cpp b/third_party/WebKit/Source/core/dom/shadow/DistributedNodes.cpp index 3a8c665..9ba6b29 100644 --- a/third_party/WebKit/Source/core/dom/shadow/DistributedNodes.cpp +++ b/third_party/WebKit/Source/core/dom/shadow/DistributedNodes.cpp
@@ -40,7 +40,7 @@ DCHECK(!node->isActiveSlotOrActiveInsertionPoint()); size_t size = m_nodes.size(); m_indices.set(node, size); - m_nodes.append(node); + m_nodes.push_back(node); } size_t DistributedNodes::find(const Node* node) const {
diff --git a/third_party/WebKit/Source/core/dom/shadow/ElementShadowV0.cpp b/third_party/WebKit/Source/core/dom/shadow/ElementShadowV0.cpp index 28d5fda..e9209399 100644 --- a/third_party/WebKit/Source/core/dom/shadow/ElementShadowV0.cpp +++ b/third_party/WebKit/Source/core/dom/shadow/ElementShadowV0.cpp
@@ -71,9 +71,9 @@ if (isActiveInsertionPoint(*child)) { InsertionPoint* insertionPoint = toInsertionPoint(child); for (size_t i = 0; i < insertionPoint->distributedNodesSize(); ++i) - m_nodes.append(insertionPoint->distributedNodeAt(i)); + m_nodes.push_back(insertionPoint->distributedNodeAt(i)); } else { - m_nodes.append(child); + m_nodes.push_back(child); } } m_distributed.resize(m_nodes.size()); @@ -170,7 +170,7 @@ if (isHTMLShadowElement(*point)) { DCHECK(!shadowInsertionPoint); shadowInsertionPoint = toHTMLShadowElement(point); - shadowInsertionPoints.append(shadowInsertionPoint); + shadowInsertionPoints.push_back(shadowInsertionPoint); } else { pool.distributeTo(point, this); if (ElementShadow* shadow = @@ -208,7 +208,7 @@ m_nodeToInsertionPoints.add(node, nullptr); if (result.isNewEntry) result.storedValue->value = new DestinationInsertionPoints; - result.storedValue->value->append(insertionPoint); + result.storedValue->value->push_back(insertionPoint); } const SelectRuleFeatureSet& ElementShadowV0::ensureSelectFeatureSet() {
diff --git a/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.cpp b/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.cpp index 43ebb05..1e8baa6 100644 --- a/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.cpp +++ b/third_party/WebKit/Source/core/dom/shadow/InsertionPoint.cpp
@@ -293,7 +293,7 @@ if (!insertionPoints) return; for (size_t i = 0; i < insertionPoints->size(); ++i) - results.append(insertionPoints->at(i).get()); + results.push_back(insertionPoints->at(i).get()); DCHECK_NE(current, insertionPoints->back().get()); current = insertionPoints->back().get(); }
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp index fad2a8a0..835e03e 100644 --- a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp +++ b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
@@ -274,7 +274,7 @@ HeapVector<Member<InsertionPoint>> insertionPoints; for (InsertionPoint& insertionPoint : Traversal<InsertionPoint>::descendantsOf(*this)) - insertionPoints.append(&insertionPoint); + insertionPoints.push_back(&insertionPoint); ensureShadowRootRareDataV0().setDescendantInsertionPoints(insertionPoints);
diff --git a/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp b/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp index 110d27bc..77627b38 100644 --- a/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp +++ b/third_party/WebKit/Source/core/dom/shadow/SlotAssignment.cpp
@@ -170,7 +170,7 @@ m_slots.reserveCapacity(m_slotCount); for (HTMLSlotElement& slot : Traversal<HTMLSlotElement>::descendantsOf(*m_owner)) { - m_slots.append(&slot); + m_slots.push_back(&slot); } m_needsCollectSlots = false; DCHECK_EQ(m_slots.size(), m_slotCount);
diff --git a/third_party/WebKit/Source/core/editing/EditingStyle.cpp b/third_party/WebKit/Source/core/editing/EditingStyle.cpp index 0b43cbf..42b35e02 100644 --- a/third_party/WebKit/Source/core/editing/EditingStyle.cpp +++ b/third_party/WebKit/Source/core/editing/EditingStyle.cpp
@@ -854,11 +854,11 @@ inlineStyle->getPropertyCSSValue(textDecorationPropertyForEditing())) { if (!conflictingProperties) return true; - conflictingProperties->append(CSSPropertyTextDecoration); + conflictingProperties->push_back(CSSPropertyTextDecoration); // Because text-decoration expands to text-decoration-line when CSS3 // Text Decoration is enabled, we also state it as conflicting. if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) - conflictingProperties->append(CSSPropertyTextDecorationLine); + conflictingProperties->push_back(CSSPropertyTextDecorationLine); if (extractedStyle) extractedStyle->setProperty( textDecorationPropertyForEditing(), @@ -875,7 +875,7 @@ inlineStyle->getPropertyCSSValue(CSSPropertyDirection)) { if (!conflictingProperties) return true; - conflictingProperties->append(CSSPropertyDirection); + conflictingProperties->push_back(CSSPropertyDirection); if (extractedStyle) extractedStyle->setProperty( propertyID, inlineStyle->getPropertyValue(propertyID), @@ -885,7 +885,7 @@ if (!conflictingProperties) return true; - conflictingProperties->append(propertyID); + conflictingProperties->push_back(propertyID); if (extractedStyle) extractedStyle->setProperty(propertyID, @@ -902,24 +902,24 @@ HTMLElementEquivalents, (new HeapVector<Member<HTMLElementEquivalent>>)); if (!HTMLElementEquivalents.size()) { - HTMLElementEquivalents.append(HTMLElementEquivalent::create( + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( CSSPropertyFontWeight, CSSValueBold, HTMLNames::bTag)); - HTMLElementEquivalents.append(HTMLElementEquivalent::create( + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( CSSPropertyFontWeight, CSSValueBold, HTMLNames::strongTag)); - HTMLElementEquivalents.append(HTMLElementEquivalent::create( + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( CSSPropertyVerticalAlign, CSSValueSub, HTMLNames::subTag)); - HTMLElementEquivalents.append(HTMLElementEquivalent::create( + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( CSSPropertyVerticalAlign, CSSValueSuper, HTMLNames::supTag)); - HTMLElementEquivalents.append(HTMLElementEquivalent::create( + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( CSSPropertyFontStyle, CSSValueItalic, HTMLNames::iTag)); - HTMLElementEquivalents.append(HTMLElementEquivalent::create( + HTMLElementEquivalents.push_back(HTMLElementEquivalent::create( CSSPropertyFontStyle, CSSValueItalic, HTMLNames::emTag)); - HTMLElementEquivalents.append(HTMLTextDecorationEquivalent::create( + HTMLElementEquivalents.push_back(HTMLTextDecorationEquivalent::create( CSSValueUnderline, HTMLNames::uTag)); - HTMLElementEquivalents.append(HTMLTextDecorationEquivalent::create( + HTMLElementEquivalents.push_back(HTMLTextDecorationEquivalent::create( CSSValueLineThrough, HTMLNames::sTag)); - HTMLElementEquivalents.append(HTMLTextDecorationEquivalent::create( + HTMLElementEquivalents.push_back(HTMLTextDecorationEquivalent::create( CSSValueLineThrough, HTMLNames::strikeTag)); } @@ -958,15 +958,15 @@ // elementIsStyledSpanOrHTMLEquivalent depends on the fact each // HTMLAttriuteEquivalent matches exactly one attribute of exactly one // element except dirAttr. - HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create( + HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create( CSSPropertyColor, HTMLNames::fontTag, HTMLNames::colorAttr)); - HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create( + HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create( CSSPropertyFontFamily, HTMLNames::fontTag, HTMLNames::faceAttr)); - HTMLAttributeEquivalents.append(HTMLFontSizeEquivalent::create()); + HTMLAttributeEquivalents.push_back(HTMLFontSizeEquivalent::create()); - HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create( + HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create( CSSPropertyDirection, HTMLNames::dirAttr)); - HTMLAttributeEquivalents.append(HTMLAttributeEquivalent::create( + HTMLAttributeEquivalents.push_back(HTMLAttributeEquivalent::create( CSSPropertyUnicodeBidi, HTMLNames::dirAttr)); } @@ -1025,7 +1025,7 @@ if (extractedStyle) equivalent->addToStyle(element, extractedStyle); - conflictingAttributes.append(equivalent->attributeName()); + conflictingAttributes.push_back(equivalent->attributeName()); removed = true; }
diff --git a/third_party/WebKit/Source/core/editing/GranularityStrategyTest.cpp b/third_party/WebKit/Source/core/editing/GranularityStrategyTest.cpp index 80de4625..608c7571 100644 --- a/third_party/WebKit/Source/core/editing/GranularityStrategyTest.cpp +++ b/third_party/WebKit/Source/core/editing/GranularityStrategyTest.cpp
@@ -121,7 +121,7 @@ void GranularityStrategyTest::parseText(Text* text) { TextNodeVector textNodes; - textNodes.append(text); + textNodes.push_back(text); parseText(textNodes); } @@ -132,7 +132,7 @@ int wordStartIndexOffset = m_letterPos.size(); String str = text->wholeText(); for (size_t i = 0; i < str.length(); i++) { - m_letterPos.append(visiblePositionToContentsPoint( + m_letterPos.push_back(visiblePositionToContentsPoint( createVisiblePosition(Position(text, i)))); char c = str[i]; if (isASCIIAlphanumeric(c) && !wordStarted) { @@ -143,7 +143,7 @@ m_letterPos[i + wordStartIndexOffset].x()) / 2, m_letterPos[wordStartIndex].y()); - m_wordMiddles.append(wordMiddle); + m_wordMiddles.push_back(wordMiddle); wordStarted = false; } } @@ -156,7 +156,7 @@ .x(); IntPoint wordMiddle((m_letterPos[wordStartIndex].x() + xEnd) / 2, m_letterPos[wordStartIndex].y()); - m_wordMiddles.append(wordMiddle); + m_wordMiddles.push_back(wordMiddle); } } @@ -256,9 +256,9 @@ Vector<IntPoint> wordMiddlePos; TextNodeVector textNodes; - textNodes.append(text1); - textNodes.append(text2); - textNodes.append(text3); + textNodes.push_back(text1); + textNodes.push_back(text2); + textNodes.push_back(text3); parseText(textNodes); Position p1;
diff --git a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp index 87ccd8f..d3e75f53cf 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
@@ -170,7 +170,7 @@ "<div id='sample' contenteditable>hello world</div>", "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 0, 5); Range* range = controller().compositionRange(); @@ -189,7 +189,7 @@ "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(3, 12, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(3, 12, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 3, 12); // Subtract a character. @@ -218,7 +218,7 @@ "<div id='sample' contenteditable><b>🏠</b></div>", "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 0, 2); @@ -242,7 +242,7 @@ "<div id='sample' contenteditable><b>ః</b></div>", "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 0, 1); // 0xE0 0xB0 0x83 0xE0 0xB0 0x83, a telugu character with 2 code points in @@ -264,7 +264,7 @@ "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(3, 12, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(3, 12, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 3, 12); controller().setComposition(String("123hello789"), underlines, 11, 11); @@ -281,7 +281,7 @@ "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(3, 12, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(3, 12, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 3, 12); controller().commitText(String("123789"), 0); @@ -293,7 +293,7 @@ "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 0, 5); controller().finishComposingText(InputMethodController::KeepSelection); @@ -320,7 +320,7 @@ EXPECT_STREQ("foo", input->value().utf8().data()); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 3, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 3, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 0, 3); controller().setComposition(String(""), underlines, 0, 3); @@ -336,7 +336,7 @@ "<div id='sample' contenteditable>\nhello world</div>", "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 0, 5); Range* range = controller().compositionRange(); @@ -353,7 +353,7 @@ insertHTMLElement("<div id='sample' contenteditable>test</div>", "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(7, 8, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(7, 8, Color(255, 0, 0), false, 0)); controller().setCompositionFromExistingText(underlines, 7, 8); EXPECT_FALSE(controller().compositionRange()); @@ -364,7 +364,7 @@ "<input id='sample' type='password' size='24'>", "sample")); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); controller().setComposition("foo", underlines, 0, 3); controller().finishComposingText(InputMethodController::KeepSelection); @@ -698,7 +698,7 @@ EXPECT_EQ(2u, controller().getSelectionOffsets().end()); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); // The caret exceeds left boundary. // "*heABllo", where * stands for caret. @@ -762,7 +762,7 @@ EXPECT_EQ(17u, controller().getSelectionOffsets().end()); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); // The caret exceeds left boundary. // "*hello\nworld\n01234AB56789", where * stands for caret. @@ -852,9 +852,9 @@ EXPECT_EQ(2u, controller().getSelectionOffsets().end()); Vector<CompositionUnderline> underlines0; - underlines0.append(CompositionUnderline(0, 0, Color(255, 0, 0), false, 0)); + underlines0.push_back(CompositionUnderline(0, 0, Color(255, 0, 0), false, 0)); Vector<CompositionUnderline> underlines2; - underlines2.append(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); + underlines2.push_back(CompositionUnderline(0, 2, Color(255, 0, 0), false, 0)); controller().setComposition("AB", underlines2, 2, 2); // With previous composition. @@ -875,7 +875,7 @@ insertHTMLElement("<div id='sample' contenteditable></div>", "sample"); Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); controller().setComposition("hello", underlines, 5, 5); EXPECT_STREQ("hello", div->innerText().utf8().data()); EXPECT_EQ(5u, controller().getSelectionOffsets().start()); @@ -921,7 +921,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); editable->focus(); document().setTitle(emptyString()); @@ -941,7 +941,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); document().setTitle(emptyString()); controller().setComposition("hell", underlines, 4, 4); @@ -960,7 +960,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); document().setTitle(emptyString()); controller().setComposition("hello", underlines, 5, 5); @@ -980,7 +980,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); document().setTitle(emptyString()); controller().setComposition("hello", underlines, 5, 5); @@ -999,7 +999,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); // Insert new text without previous composition. document().setTitle(emptyString()); @@ -1027,7 +1027,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); // Insert empty text without previous composition. document().setTitle(emptyString()); @@ -1053,7 +1053,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); controller().setComposition("hello", underlines, 1, 1); document().updateStyleAndLayout(); @@ -1073,7 +1073,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); controller().setComposition("n", underlines, 1, 1); @@ -1091,7 +1091,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); controller().setComposition("hello", underlines, 1, 1); document().updateStyleAndLayout(); @@ -1111,7 +1111,7 @@ // Simulate composition in the |contentEditable|. Vector<CompositionUnderline> underlines; - underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); + underlines.push_back(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0)); controller().setComposition("hello", underlines, 1, 1); document().updateStyleAndLayout();
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp index c881ff3..75abe7d 100644 --- a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
@@ -508,7 +508,7 @@ if (inlineStyle->isEmpty()) { removeElementAttribute(element, styleAttr); if (isSpanWithoutAttributesOrUnstyledStyleSpan(element)) - unstyledSpans.append(element); + unstyledSpans.push_back(element); } } @@ -1006,7 +1006,7 @@ if (!shouldApplyInlineStyleToRun(style, runStart, pastEndNode)) continue; - runs.append(InlineRunToApplyStyle(runStart, runEnd, pastEndNode)); + runs.push_back(InlineRunToApplyStyle(runStart, runEnd, pastEndNode)); } for (auto& run : runs) { @@ -1339,7 +1339,7 @@ if (current->isStyledElement() && isStyledInlineElementToRemove(toElement(current))) { styledElement = toElement(current); - elementsToPushDown.append(styledElement); + elementsToPushDown.push_back(styledElement); } EditingStyle* styleToPushDown = EditingStyle::create(); @@ -2001,7 +2001,7 @@ if (!curr->isTextNode()) continue; - textNodes.append(toText(curr)); + textNodes.push_back(toText(curr)); } for (const auto& textNode : textNodes) {
diff --git a/third_party/WebKit/Source/core/editing/commands/BreakBlockquoteCommand.cpp b/third_party/WebKit/Source/core/editing/commands/BreakBlockquoteCommand.cpp index 2ea3a63..87ba904 100644 --- a/third_party/WebKit/Source/core/editing/commands/BreakBlockquoteCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/BreakBlockquoteCommand.cpp
@@ -195,7 +195,7 @@ HeapVector<Member<Element>> ancestors; for (Element* node = startNode->parentElement(); node && node != topBlockquote; node = node->parentElement()) - ancestors.append(node); + ancestors.push_back(node); // Insert a clone of the top blockquote after the break. Element* clonedBlockquote = topBlockquote->cloneElementWithoutChildren();
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp index 29a17ac7..8cafea5 100644 --- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -151,7 +151,7 @@ } void EditCommandComposition::append(SimpleEditCommand* command) { - m_commands.append(command); + m_commands.push_back(command); } void EditCommandComposition::append(EditCommandComposition* composition) { @@ -287,7 +287,7 @@ command->setParent(0); ensureComposition()->append(toSimpleEditCommand(command)); } - m_commands.append(command); + m_commands.push_back(command); } void CompositeEditCommand::applyCommandToComposite( @@ -301,7 +301,7 @@ } command->doApply(editingState); if (!editingState->isAborted()) - m_commands.append(command); + m_commands.push_back(command); } void CompositeEditCommand::appendCommandToComposite(
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp index 015917c..7f1aa4f 100644 --- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -204,7 +204,7 @@ // We only supports single selections. if (selectionModifier.selection().isNone()) return ranges; - ranges->append(firstRangeOf(selectionModifier.selection())); + ranges->push_back(firstRangeOf(selectionModifier.selection())); return ranges; }
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertParagraphSeparatorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertParagraphSeparatorCommand.cpp index ff2e6a0..2e1a000 100644 --- a/third_party/WebKit/Source/core/editing/commands/InsertParagraphSeparatorCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/InsertParagraphSeparatorCommand.cpp
@@ -141,7 +141,7 @@ if (insertionNode != outerBlock) { for (Element* n = insertionNode->parentElement(); n && n != outerBlock; n = n->parentElement()) - ancestors.append(n); + ancestors.push_back(n); } }
diff --git a/third_party/WebKit/Source/core/editing/commands/MergeIdenticalElementsCommand.cpp b/third_party/WebKit/Source/core/editing/commands/MergeIdenticalElementsCommand.cpp index d396fa0..01184001 100644 --- a/third_party/WebKit/Source/core/editing/commands/MergeIdenticalElementsCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/MergeIdenticalElementsCommand.cpp
@@ -78,7 +78,7 @@ HeapVector<Member<Node>> children; for (Node* child = m_element2->firstChild(); child && child != atChild; child = child->nextSibling()) - children.append(child); + children.push_back(child); for (auto& child : children) m_element1->appendChild(child.release(), exceptionState);
diff --git a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp index 3ec32c2..c59b7d0 100644 --- a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
@@ -341,7 +341,7 @@ for (Node& node : NodeTraversal::descendantsOf(*holder)) { if (!isNodeRendered(node) && !isTableStructureNode(&node)) - unrendered.append(&node); + unrendered.push_back(&node); } for (auto& node : unrendered)
diff --git a/third_party/WebKit/Source/core/editing/commands/SimplifyMarkupCommand.cpp b/third_party/WebKit/Source/core/editing/commands/SimplifyMarkupCommand.cpp index c7fd0fd..296a67f 100644 --- a/third_party/WebKit/Source/core/editing/commands/SimplifyMarkupCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/SimplifyMarkupCommand.cpp
@@ -65,7 +65,7 @@ while (currentNode != rootNode) { if (currentNode->parentNode() != rootNode && isRemovableBlock(currentNode)) - nodesToRemove.append(currentNode); + nodesToRemove.push_back(currentNode); currentNode = currentNode->parentNode(); if (!currentNode) @@ -90,7 +90,7 @@ for (Node& node : NodeTraversal::inclusiveAncestorsOf(*startingNode)) { if (node == topNodeWithStartingStyle) break; - nodesToRemove.append(static_cast<ContainerNode*>(&node)); + nodesToRemove.push_back(static_cast<ContainerNode*>(&node)); } } }
diff --git a/third_party/WebKit/Source/core/editing/commands/SplitElementCommand.cpp b/third_party/WebKit/Source/core/editing/commands/SplitElementCommand.cpp index c9864ae..c9bfcbc 100644 --- a/third_party/WebKit/Source/core/editing/commands/SplitElementCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/SplitElementCommand.cpp
@@ -50,7 +50,7 @@ HeapVector<Member<Node>> children; for (Node* node = m_element2->firstChild(); node != m_atChild; node = node->nextSibling()) - children.append(node); + children.push_back(node); DummyExceptionStateForTesting exceptionState;
diff --git a/third_party/WebKit/Source/core/editing/iterators/FullyClippedStateStack.cpp b/third_party/WebKit/Source/core/editing/iterators/FullyClippedStateStack.cpp index 5a0ed1b..740eb0e 100644 --- a/third_party/WebKit/Source/core/editing/iterators/FullyClippedStateStack.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/FullyClippedStateStack.cpp
@@ -77,7 +77,7 @@ HeapVector<Member<ContainerNode>, 100> ancestry; for (ContainerNode* parent = parentCrossingShadowBoundaries<Strategy>(*node); parent; parent = parentCrossingShadowBoundaries<Strategy>(*parent)) - ancestry.append(parent); + ancestry.push_back(parent); // Call pushFullyClippedState on each node starting with the earliest // ancestor.
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp index b190dd70..8a4f76b 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -251,7 +251,7 @@ RenderedDocumentMarker* newRenderedMarker = RenderedDocumentMarker::create(newMarker); if (list->isEmpty() || list->back()->endOffset() < newMarker.startOffset()) { - list->append(newRenderedMarker); + list->push_back(newRenderedMarker); } else { if (newMarker.type() != DocumentMarker::TextMatch && newMarker.type() != DocumentMarker::Composition) { @@ -449,7 +449,7 @@ continue; for (size_t i = 0; i < list->size(); ++i) - result.append(list->at(i).get()); + result.push_back(list->at(i).get()); } std::sort(result.begin(), result.end(), compareByStart); @@ -465,7 +465,7 @@ ++markerListIndex) { Member<MarkerList>& list = (*markers)[markerListIndex]; for (size_t j = 0; list.get() && j < list->size(); ++j) - result.append(list->at(j).get()); + result.push_back(list->at(j).get()); } } std::sort(result.begin(), result.end(), compareByStart); @@ -497,7 +497,7 @@ continue; if (node == endContainer && marker->startOffset() >= endOffset) continue; - foundMarkers.append(marker); + foundMarkers.push_back(marker); } } return foundMarkers; @@ -530,7 +530,7 @@ updateMarkerRenderedRectIfNeeded(node, *marker); if (!marker->isRendered()) continue; - result.append(marker->renderedRect()); + result.push_back(marker->renderedRect()); } } }
diff --git a/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp b/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp index c91ae783..c5d1638 100644 --- a/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp +++ b/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp
@@ -107,7 +107,7 @@ // AttributeCollection::iterator end = attributes.end(); for (const auto& attribute : attributes) { if (element.isURLAttribute(attribute) && !attribute.value().isEmpty()) - changes.append(AttributeChange( + changes.push_back(AttributeChange( &element, attribute.name(), KURL(parsedBaseURL, attribute.value()).getString())); }
diff --git a/third_party/WebKit/Source/core/editing/serializers/StyledMarkupAccumulator.cpp b/third_party/WebKit/Source/core/editing/serializers/StyledMarkupAccumulator.cpp index b1dacb4..1764373 100644 --- a/third_party/WebKit/Source/core/editing/serializers/StyledMarkupAccumulator.cpp +++ b/third_party/WebKit/Source/core/editing/serializers/StyledMarkupAccumulator.cpp
@@ -181,7 +181,7 @@ MarkupFormatter::appendAttributeValue(openTag, style->asText(), m_document->isHTMLDocument()); openTag.append("\">"); - m_reversedPrecedingMarkup.append(openTag.toString()); + m_reversedPrecedingMarkup.push_back(openTag.toString()); m_result.append("</div>"); } @@ -229,7 +229,7 @@ } void StyledMarkupAccumulator::pushMarkup(const String& str) { - m_reversedPrecedingMarkup.append(str); + m_reversedPrecedingMarkup.push_back(str); } void StyledMarkupAccumulator::appendInterchangeNewline() {
diff --git a/third_party/WebKit/Source/core/editing/serializers/StyledMarkupSerializer.cpp b/third_party/WebKit/Source/core/editing/serializers/StyledMarkupSerializer.cpp index e58430e..1aa8059 100644 --- a/third_party/WebKit/Source/core/editing/serializers/StyledMarkupSerializer.cpp +++ b/third_party/WebKit/Source/core/editing/serializers/StyledMarkupSerializer.cpp
@@ -362,7 +362,7 @@ // If node has no children, close the tag now. if (Strategy::hasChildren(*n)) { - ancestorsToClose.append(toContainerNode(n)); + ancestorsToClose.push_back(toContainerNode(n)); continue; } appendEndMarkup(*n);
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp index 67f9b06c..94d2d7cc 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -1084,7 +1084,7 @@ misspelling.decoration = TextDecorationTypeSpelling; misspelling.location = wordStart + misspellingLocation; misspelling.length = misspellingLength; - results.append(misspelling); + results.push_back(misspelling); } wordStart = wordEnd; }
diff --git a/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.cpp b/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.cpp index 3118350..4ba54f2 100644 --- a/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.cpp +++ b/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.cpp
@@ -31,10 +31,10 @@ Vector<UChar> out; for (const auto& codePoint : codePoints) { if (U16_LENGTH(codePoint) == 2) { - out.append(U16_LEAD(codePoint)); - out.append(U16_TRAIL(codePoint)); + out.push_back(U16_LEAD(codePoint)); + out.push_back(U16_TRAIL(codePoint)); } else { - out.append(static_cast<UChar>(codePoint)); + out.push_back(static_cast<UChar>(codePoint)); } } return out;
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp index feaa2599..7003e7b 100644 --- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp +++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
@@ -7,6 +7,7 @@ #include "core/html/HTMLCanvasElement.h" #include "core/html/HTMLVideoElement.h" #include "core/html/ImageData.h" +#include "core/offscreencanvas/OffscreenCanvas.h" #include "platform/graphics/skia/SkiaUtils.h" #include "platform/image-decoders/ImageDecoder.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -687,6 +688,42 @@ m_image->setPremultiplied(parsedOptions.premultiplyAlpha); } +ImageBitmap::ImageBitmap(OffscreenCanvas* offscreenCanvas, + Optional<IntRect> cropRect, + const ImageBitmapOptions& options) { + SourceImageStatus status; + RefPtr<Image> input = offscreenCanvas->getSourceImageForCanvas( + &status, PreferNoAcceleration, SnapshotReasonCreateImageBitmap, + FloatSize(offscreenCanvas->size())); + if (status != NormalSourceImageStatus) + return; + ParsedOptions parsedOptions = + parseOptions(options, cropRect, IntSize(input->width(), input->height())); + if (dstBufferSizeHasOverflow(parsedOptions)) + return; + + bool isPremultiplyAlphaReverted = false; + if (!parsedOptions.premultiplyAlpha) { + parsedOptions.premultiplyAlpha = true; + isPremultiplyAlphaReverted = true; + } + m_image = cropImageAndApplyColorSpaceConversion( + input.get(), parsedOptions, PremultiplyAlpha, + ColorBehavior::transformToGlobalTarget()); + if (!m_image) + return; + if (isPremultiplyAlphaReverted) { + parsedOptions.premultiplyAlpha = false; + m_image = StaticBitmapImage::create(premulSkImageToUnPremul( + m_image->imageForCurrentFrame(ColorBehavior::transformToGlobalTarget()) + .get())); + } + if (!m_image) + return; + m_image->setOriginClean(offscreenCanvas->originClean()); + m_image->setPremultiplied(parsedOptions.premultiplyAlpha); +} + ImageBitmap::ImageBitmap(const void* pixelData, uint32_t width, uint32_t height, @@ -946,6 +983,12 @@ return new ImageBitmap(canvas, cropRect, options); } +ImageBitmap* ImageBitmap::create(OffscreenCanvas* offscreenCanvas, + Optional<IntRect> cropRect, + const ImageBitmapOptions& options) { + return new ImageBitmap(offscreenCanvas, cropRect, options); +} + ImageBitmap* ImageBitmap::create(ImageData* data, Optional<IntRect> cropRect, const ImageBitmapOptions& options) {
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.h b/third_party/WebKit/Source/core/frame/ImageBitmap.h index 018ac22..99fd4d5 100644 --- a/third_party/WebKit/Source/core/frame/ImageBitmap.h +++ b/third_party/WebKit/Source/core/frame/ImageBitmap.h
@@ -25,6 +25,7 @@ class HTMLVideoElement; class ImageData; class ImageDecoder; +class OffscreenCanvas; enum AlphaDisposition { PremultiplyAlpha, @@ -58,6 +59,9 @@ static ImageBitmap* create(HTMLCanvasElement*, Optional<IntRect>, const ImageBitmapOptions& = ImageBitmapOptions()); + static ImageBitmap* create(OffscreenCanvas*, + Optional<IntRect>, + const ImageBitmapOptions& = ImageBitmapOptions()); static ImageBitmap* create(ImageData*, Optional<IntRect>, const ImageBitmapOptions& = ImageBitmapOptions()); @@ -144,6 +148,7 @@ Document*, const ImageBitmapOptions&); ImageBitmap(HTMLCanvasElement*, Optional<IntRect>, const ImageBitmapOptions&); + ImageBitmap(OffscreenCanvas*, Optional<IntRect>, const ImageBitmapOptions&); ImageBitmap(ImageData*, Optional<IntRect>, const ImageBitmapOptions&); ImageBitmap(ImageBitmap*, Optional<IntRect>, const ImageBitmapOptions&); ImageBitmap(PassRefPtr<StaticBitmapImage>);
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp index 0e3afe2..bee46e6 100644 --- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
@@ -42,6 +42,7 @@ #include "core/html/HTMLVideoElement.h" #include "core/html/ImageData.h" #include "core/imagebitmap/ImageBitmapOptions.h" +#include "core/offscreencanvas/OffscreenCanvas.h" #include "core/svg/graphics/SVGImage.h" #include "core/workers/WorkerGlobalScope.h" #include "platform/CrossThreadFunctional.h" @@ -93,6 +94,8 @@ return value.getAsImageData(); if (value.isImageBitmap()) return value.getAsImageBitmap(); + if (value.isOffscreenCanvas()) + return value.getAsOffscreenCanvas(); ASSERT_NOT_REACHED(); return nullptr; }
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h index 26a7049d..4bc74d88 100644 --- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
@@ -31,7 +31,7 @@ #ifndef ImageBitmapFactories_h #define ImageBitmapFactories_h -#include "bindings/core/v8/HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmap.h" +#include "bindings/core/v8/HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas.h" #include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptPromiseResolver.h" #include "bindings/core/v8/ScriptState.h" @@ -55,7 +55,7 @@ class ImageBitmapOptions; class WebTaskRunner; -typedef HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmap +typedef HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvas ImageBitmapSourceUnion; class ImageBitmapFactories final
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl index fd5341c..13ace66 100644 --- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl
@@ -35,7 +35,8 @@ HTMLCanvasElement or Blob or ImageData or - ImageBitmap) ImageBitmapSource; + ImageBitmap or + OffscreenCanvas) ImageBitmapSource; [ LegacyTreatAsPartialInterface,
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp index 648ff5a0..0a17cb9 100644 --- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
@@ -39,6 +39,7 @@ #include "core/paint/PaintLayer.h" #include "core/style/ComputedStyle.h" #include "platform/LengthFunctions.h" +#include "wtf/AutoReset.h" #include "wtf/MathExtras.h" #include <limits> @@ -68,7 +69,8 @@ : LayoutBlock(element), m_orderIterator(this), m_numberOfInFlowChildrenOnFirstLine(-1), - m_hasDefiniteHeight(SizeDefiniteness::Unknown) { + m_hasDefiniteHeight(SizeDefiniteness::Unknown), + m_inLayout(false) { DCHECK(!childrenInline()); if (!isAnonymous()) UseCounter::count(document(), UseCounter::CSSFlexibleBox); @@ -353,6 +355,8 @@ return; m_relaidOutChildren.clear(); + WTF::AutoReset<bool> reset1(&m_inLayout, true); + DCHECK_EQ(m_hasDefiniteHeight, SizeDefiniteness::Unknown); if (updateLogicalWidthAndColumnWidth()) relayoutChildren = true; @@ -391,15 +395,16 @@ updateLayerTransformAfterLayout(); + // We have to reset this, because changes to our ancestors' style can affect + // this value. Also, this needs to be before we call updateAfterLayout, as + // that function may re-enter this one. + m_hasDefiniteHeight = SizeDefiniteness::Unknown; + // Update our scroll information if we're overflow:auto/scroll/hidden now // that we know if we overflow or not. updateAfterLayout(); clearNeedsLayout(); - - // We have to reset this, because changes to our ancestors' style can affect - // this value. - m_hasDefiniteHeight = SizeDefiniteness::Unknown; } void LayoutFlexibleBox::paintChildren(const PaintInfo& paintInfo, @@ -832,8 +837,12 @@ if (m_hasDefiniteHeight == SizeDefiniteness::Indefinite) return false; bool definite = child.computePercentageLogicalHeight(flexBasis) != -1; - m_hasDefiniteHeight = - definite ? SizeDefiniteness::Definite : SizeDefiniteness::Indefinite; + if (m_inLayout) { + // We can reach this code even while we're not laying ourselves out, such + // as from mainSizeForPercentageResolution. + m_hasDefiniteHeight = + definite ? SizeDefiniteness::Definite : SizeDefiniteness::Indefinite; + } return definite; } return true;
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h index 396a526..ddb6f03 100644 --- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h +++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h
@@ -254,6 +254,7 @@ // This is SizeIsUnknown outside of layoutBlock() mutable SizeDefiniteness m_hasDefiniteHeight; + bool m_inLayout; }; DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutFlexibleBox, isFlexibleBox());
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp index 66c354d..fa4679a 100644 --- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp +++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -6,6 +6,7 @@ #include "core/dom/ExceptionCode.h" #include "core/fileapi/Blob.h" +#include "core/frame/ImageBitmap.h" #include "core/html/ImageData.h" #include "core/html/canvas/CanvasAsyncBlobCreator.h" #include "core/html/canvas/CanvasContextCreationAttributes.h" @@ -111,6 +112,30 @@ return image.release(); } +IntSize OffscreenCanvas::bitmapSourceSize() const { + return m_size; +} + +ScriptPromise OffscreenCanvas::createImageBitmap( + ScriptState* scriptState, + EventTarget&, + Optional<IntRect> cropRect, + const ImageBitmapOptions& options, + ExceptionState& exceptionState) { + if ((cropRect && + !ImageBitmap::isSourceSizeValid(cropRect->width(), cropRect->height(), + exceptionState)) || + !ImageBitmap::isSourceSizeValid(bitmapSourceSize().width(), + bitmapSourceSize().height(), + exceptionState)) + return ScriptPromise(); + if (!ImageBitmap::isResizeOptionValid(options, exceptionState)) + return ScriptPromise(); + return ImageBitmapSource::fulfillImageBitmap( + scriptState, + isPaintable() ? ImageBitmap::create(this, cropRect, options) : nullptr); +} + bool OffscreenCanvas::isOpaque() const { if (!m_context) return false;
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h index 5750fbc..7640b0b5 100644 --- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h +++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.h
@@ -27,7 +27,8 @@ OffscreenRenderingContext; class CORE_EXPORT OffscreenCanvas final : public EventTargetWithInlineData, - public CanvasImageSource { + public CanvasImageSource, + public ImageBitmapSource { DEFINE_WRAPPERTYPEINFO(); public: @@ -103,6 +104,14 @@ return m_executionContext.get(); } + // ImageBitmapSource implementation + IntSize bitmapSourceSize() const final; + ScriptPromise createImageBitmap(ScriptState*, + EventTarget&, + Optional<IntRect>, + const ImageBitmapOptions&, + ExceptionState&) final; + // CanvasImageSource implementation PassRefPtr<Image> getSourceImageForCanvas(SourceImageStatus*, AccelerationHint,
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/fileBasedSearchResultsPane.css b/third_party/WebKit/Source/devtools/front_end/sources/fileBasedSearchResultsPane.css index d4ad56c..bb91341 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/fileBasedSearchResultsPane.css +++ b/third_party/WebKit/Source/devtools/front_end/sources/fileBasedSearchResultsPane.css
@@ -32,6 +32,7 @@ li.search-result .search-result-file-name { font-weight: bold; color: #222; + white-space: normal; } li.search-result .search-result-matches-count {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js index 0527edc..e6031df 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js +++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js
@@ -1502,7 +1502,7 @@ var data = this.data[columnId]; if (data instanceof Node) { cell.appendChild(data); - } else { + } else if (data !== null) { cell.textContent = data; if (this.dataGrid._columns[columnId].longText) cell.title = data;
diff --git a/third_party/WebKit/Source/modules/fetch/FetchHeaderList.cpp b/third_party/WebKit/Source/modules/fetch/FetchHeaderList.cpp index abbd34f3..ca24581 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchHeaderList.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchHeaderList.cpp
@@ -130,14 +130,22 @@ void FetchHeaderList::sortAndCombine() { // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine // "To sort and combine a header list..." - - // TODO(jsbell): Implement the combining part - this currently just sorts. + if (m_headerList.isEmpty()) + return; std::sort( m_headerList.begin(), m_headerList.end(), [](const std::unique_ptr<Header>& a, const std::unique_ptr<Header>& b) { return WTF::codePointCompareLessThan(a->first, b->first); }); + + for (size_t index = m_headerList.size() - 1; index > 0; --index) { + if (m_headerList[index - 1]->first == m_headerList[index]->first) { + m_headerList[index - 1]->second.append(","); + m_headerList[index - 1]->second.append(m_headerList[index]->second); + m_headerList.remove(index, 1); + } + } } bool FetchHeaderList::isValidHeaderName(const String& name) {
diff --git a/third_party/WebKit/Source/modules/mediastream/BUILD.gn b/third_party/WebKit/Source/modules/mediastream/BUILD.gn index d0787b6..a33f22d 100644 --- a/third_party/WebKit/Source/modules/mediastream/BUILD.gn +++ b/third_party/WebKit/Source/modules/mediastream/BUILD.gn
@@ -24,6 +24,7 @@ "MediaStreamRegistry.h", "MediaStreamTrack.cpp", "MediaStreamTrack.h", + "MediaStreamTrackContentHint.h", "MediaStreamTrackEvent.cpp", "MediaStreamTrackEvent.h", "NavigatorMediaStream.cpp",
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl index 335adfd..07a29a2 100644 --- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl +++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.idl
@@ -42,7 +42,6 @@ readonly attribute DOMString label; attribute boolean enabled; readonly attribute boolean muted; - [RuntimeEnabled=MediaStreamTrackContentHint] attribute DOMString contentHint; attribute EventHandler onmute; attribute EventHandler onunmute; readonly attribute MediaStreamTrackState readyState;
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackContentHint.h b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackContentHint.h new file mode 100644 index 0000000..9bda605 --- /dev/null +++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackContentHint.h
@@ -0,0 +1,24 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MediaStreamTrackContentHint_h +#define MediaStreamTrackContentHint_h + +#include "modules/mediastream/MediaStreamTrack.h" + +namespace blink { + +class MediaStreamTrackContentHint final { + public: + static String contentHint(const MediaStreamTrack& track) { + return track.contentHint(); + } + static void setContentHint(MediaStreamTrack& track, const String& hint) { + track.setContentHint(hint); + } +}; + +} // namespace blink + +#endif // MediaStreamTrack_h
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackContentHint.idl b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackContentHint.idl new file mode 100644 index 0000000..d4ace6f --- /dev/null +++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrackContentHint.idl
@@ -0,0 +1,10 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/mst-content-hint/#extension-to-mediastreamtrack +[ + RuntimeEnabled=MediaStreamTrackContentHint, +] partial interface MediaStreamTrack { + attribute DOMString contentHint; +};
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni index cbc4dc9..a1be7baa 100644 --- a/third_party/WebKit/Source/modules/modules_idl_files.gni +++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -582,6 +582,7 @@ "mediasource/VideoTrackSourceBuffer.idl", "mediasource/HTMLVideoElementMediaSource.idl", "mediasource/URLMediaSource.idl", + "mediastream/MediaStreamTrackContentHint.idl", "mediastream/NavigatorMediaStream.idl", "mediastream/NavigatorUserMedia.idl", "mediastream/URLMediaStream.idl",
diff --git a/third_party/WebKit/Source/modules/plugins/Plugin.idl b/third_party/WebKit/Source/modules/plugins/Plugin.idl index 6f0b0461..f8db981 100644 --- a/third_party/WebKit/Source/modules/plugins/Plugin.idl +++ b/third_party/WebKit/Source/modules/plugins/Plugin.idl
@@ -18,6 +18,8 @@ Boston, MA 02110-1301, USA. */ +// https://html.spec.whatwg.org/multipage/webappapis.html#plugins-2 + [ ImplementedAs=DOMPlugin ] interface Plugin { @@ -25,7 +27,7 @@ readonly attribute DOMString filename; readonly attribute DOMString description; readonly attribute unsigned long length; - getter MimeType item([Default=Undefined] optional unsigned long index); - MimeType namedItem([Default=Undefined] optional DOMString name); + getter MimeType? item([Default=Undefined] optional unsigned long index); + MimeType? namedItem([Default=Undefined] optional DOMString name); [NotEnumerable, ImplementedAs=namedItem] getter MimeType ([Default=Undefined] optional DOMString name); };
diff --git a/third_party/WebKit/Source/modules/plugins/PluginArray.idl b/third_party/WebKit/Source/modules/plugins/PluginArray.idl index e107399..5bcbbcf 100644 --- a/third_party/WebKit/Source/modules/plugins/PluginArray.idl +++ b/third_party/WebKit/Source/modules/plugins/PluginArray.idl
@@ -18,12 +18,14 @@ Boston, MA 02110-1301, USA. */ +// https://html.spec.whatwg.org/multipage/webappapis.html#plugins-2 + [ ImplementedAs=DOMPluginArray ] interface PluginArray { readonly attribute unsigned long length; - getter Plugin item([Default=Undefined] optional unsigned long index); - Plugin namedItem([Default=Undefined] optional DOMString name); + getter Plugin? item([Default=Undefined] optional unsigned long index); + Plugin? namedItem([Default=Undefined] optional DOMString name); [NotEnumerable, ImplementedAs=namedItem] getter Plugin ([Default=Undefined] optional DOMString name); void refresh([Default=Undefined] optional boolean reload); };
diff --git a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp index fc557c67..982ecd4 100644 --- a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp +++ b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
@@ -10,7 +10,9 @@ #include "core/frame/LocalFrame.h" #include "core/html/canvas/CanvasImageSource.h" #include "modules/shapedetection/DetectedFace.h" +#include "modules/shapedetection/FaceDetectorOptions.h" #include "public/platform/InterfaceProvider.h" +#include "public/platform/modules/shapedetection/facedetection_provider.mojom-blink.h" namespace blink { @@ -21,13 +23,18 @@ FaceDetector::FaceDetector(LocalFrame& frame, const FaceDetectorOptions& options) - : ShapeDetector(frame), - m_faceDetectorOptions(mojom::blink::FaceDetectorOptions::New()) { - frame.interfaceProvider()->getInterface(mojo::GetProxy(&m_faceService)); + : ShapeDetector(frame) { + mojom::blink::FaceDetectorOptionsPtr faceDetectorOptions = + mojom::blink::FaceDetectorOptions::New(); + faceDetectorOptions->max_detected_faces = options.maxDetectedFaces(); + faceDetectorOptions->fast_mode = options.fastMode(); + mojom::blink::FaceDetectionProviderPtr provider; + frame.interfaceProvider()->getInterface(mojo::GetProxy(&provider)); + provider->CreateFaceDetection(mojo::GetProxy(&m_faceService), + std::move(faceDetectorOptions)); + m_faceService.set_connection_error_handler(convertToBaseCallback(WTF::bind( &FaceDetector::onFaceServiceConnectionError, wrapWeakPersistent(this)))); - m_faceDetectorOptions->max_detected_faces = options.maxDetectedFaces(); - m_faceDetectorOptions->fast_mode = options.fastMode(); } ScriptPromise FaceDetector::doDetect( @@ -43,7 +50,6 @@ } m_faceServiceRequests.add(resolver); m_faceService->Detect(std::move(sharedBufferHandle), imageWidth, imageHeight, - m_faceDetectorOptions.Clone(), convertToBaseCallback(WTF::bind( &FaceDetector::onDetectFaces, wrapPersistent(this), wrapPersistent(resolver))));
diff --git a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h index 5372762..8fcdcd9a 100644 --- a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h +++ b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h
@@ -10,12 +10,12 @@ #include "bindings/core/v8/ScriptWrappable.h" #include "modules/ModulesExport.h" #include "modules/canvas2d/CanvasRenderingContext2D.h" -#include "modules/shapedetection/FaceDetectorOptions.h" #include "modules/shapedetection/ShapeDetector.h" #include "public/platform/modules/shapedetection/facedetection.mojom-blink.h" namespace blink { +class FaceDetectorOptions; class LocalFrame; class MODULES_EXPORT FaceDetector final : public ShapeDetector, @@ -40,7 +40,6 @@ void onFaceServiceConnectionError(); mojom::blink::FaceDetectionPtr m_faceService; - mojom::blink::FaceDetectorOptionsPtr m_faceDetectorOptions; HeapHashSet<Member<ScriptPromiseResolver>> m_faceServiceRequests; };
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.idl b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.idl index 45c6d0d..1a1bc79e 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.idl +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.idl
@@ -391,7 +391,7 @@ void clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); /* Query Objects */ - WebGLQuery createQuery(); + WebGLQuery? createQuery(); void deleteQuery(WebGLQuery? query); GLboolean isQuery(WebGLQuery? query); void beginQuery(GLenum target, WebGLQuery query); @@ -400,7 +400,7 @@ [CallWith=ScriptState] any getQueryParameter(WebGLQuery query, GLenum pname); /* Sampler Objects */ - WebGLSampler createSampler(); + WebGLSampler? createSampler(); void deleteSampler(WebGLSampler? sampler); GLboolean isSampler(WebGLSampler? sampler); void bindSampler(GLuint unit, WebGLSampler? sampler); @@ -409,7 +409,7 @@ [CallWith=ScriptState] any getSamplerParameter(WebGLSampler sampler, GLenum pname); /* Sync objects */ - WebGLSync fenceSync(GLenum condition, GLbitfield flags); + WebGLSync? fenceSync(GLenum condition, GLbitfield flags); GLboolean isSync(WebGLSync? sync); void deleteSync(WebGLSync? sync); GLenum clientWaitSync(WebGLSync sync, GLbitfield flags, GLuint64 timeout); @@ -418,14 +418,14 @@ [CallWith=ScriptState] any getSyncParameter(WebGLSync sync, GLenum pname); /* Transform Feedback */ - WebGLTransformFeedback createTransformFeedback(); + WebGLTransformFeedback? createTransformFeedback(); void deleteTransformFeedback(WebGLTransformFeedback? feedback); GLboolean isTransformFeedback(WebGLTransformFeedback? feedback); void bindTransformFeedback(GLenum target, WebGLTransformFeedback? feedback); void beginTransformFeedback(GLenum primitiveMode); void endTransformFeedback(); void transformFeedbackVaryings(WebGLProgram program, sequence<DOMString> varyings, GLenum bufferMode); - WebGLActiveInfo getTransformFeedbackVarying(WebGLProgram program, GLuint index); + WebGLActiveInfo? getTransformFeedbackVarying(WebGLProgram program, GLuint index); void pauseTransformFeedback(); void resumeTransformFeedback(); @@ -441,7 +441,7 @@ void uniformBlockBinding(WebGLProgram program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); /* Vertex Array Objects */ - WebGLVertexArrayObject createVertexArray(); + WebGLVertexArrayObject? createVertexArray(); void deleteVertexArray(WebGLVertexArrayObject? vertexArray); GLboolean isVertexArray(WebGLVertexArrayObject? vertexArray); void bindVertexArray(WebGLVertexArrayObject? vertexArray);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.cpp index 497855cf..02f0062 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPathDisplayItem.cpp
@@ -20,7 +20,7 @@ void BeginClipPathDisplayItem::appendToWebDisplayItemList( const IntRect& visualRect, WebDisplayItemList* list) const { - list->appendClipPathItem(m_clipPath, SkClipOp::kIntersect, true); + list->appendClipPathItem(m_clipPath, true); } void BeginClipPathDisplayItem::analyzeForGpuRasterization(
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn index 417010a..00ed7da 100644 --- a/third_party/WebKit/Source/web/BUILD.gn +++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -357,6 +357,7 @@ "tests/RootScrollerTest.cpp", "tests/RunAllTests.cpp", "tests/ScreenWakeLockTest.cpp", + "tests/ScrollbarsTest.cpp", "tests/ScrollingCoordinatorTest.cpp", "tests/SpinLockTest.cpp", "tests/TextFinderTest.cpp",
diff --git a/third_party/WebKit/Source/web/tests/ScrollbarsTest.cpp b/third_party/WebKit/Source/web/tests/ScrollbarsTest.cpp new file mode 100644 index 0000000..eee9d256 --- /dev/null +++ b/third_party/WebKit/Source/web/tests/ScrollbarsTest.cpp
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/layout/LayoutView.h" +#include "core/paint/PaintLayerScrollableArea.h" +#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h" +#include "platform/testing/UnitTestHelpers.h" +#include "public/web/WebScriptSource.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "web/WebLocalFrameImpl.h" +#include "web/tests/sim/SimDisplayItemList.h" +#include "web/tests/sim/SimRequest.h" +#include "web/tests/sim/SimTest.h" + +namespace blink { + +namespace { + +class ScrollbarsTest : private ScopedRootLayerScrollingForTest, public SimTest { + public: + ScrollbarsTest() : ScopedRootLayerScrollingForTest(true) {} +}; + +TEST_F(ScrollbarsTest, DocumentStyleRecalcPreservesScrollbars) { + v8::HandleScope handleScope(v8::Isolate::GetCurrent()); + webView().resize(WebSize(800, 600)); + SimRequest request("https://example.com/test.html", "text/html"); + loadURL("https://example.com/test.html"); + request.complete("<style> body { width: 1600px; height: 1200px; } </style>"); + PaintLayerScrollableArea* plsa = document().layoutView()->getScrollableArea(); + + compositor().beginFrame(); + ASSERT_TRUE(plsa->verticalScrollbar() && plsa->horizontalScrollbar()); + + // Forces recalc of LayoutView's computed style in Document::updateStyle, + // without invalidating layout. + mainFrame().executeScriptAndReturnValue(WebScriptSource( + "document.querySelector('style').sheet.insertRule('body {}', 1);")); + + compositor().beginFrame(); + ASSERT_TRUE(plsa->verticalScrollbar() && plsa->horizontalScrollbar()); +} + +} // namespace + +} // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/sim/SimTest.cpp b/third_party/WebKit/Source/web/tests/sim/SimTest.cpp index a3e01fe0..8350a076 100644 --- a/third_party/WebKit/Source/web/tests/sim/SimTest.cpp +++ b/third_party/WebKit/Source/web/tests/sim/SimTest.cpp
@@ -61,6 +61,10 @@ return *m_webViewHelper.webView(); } +WebLocalFrameImpl& SimTest::mainFrame() { + return *webView().mainFrameImpl(); +} + const SimWebViewClient& SimTest::webViewClient() const { return m_webViewClient; }
diff --git a/third_party/WebKit/Source/web/tests/sim/SimTest.h b/third_party/WebKit/Source/web/tests/sim/SimTest.h index b56f41f..d3a84a7 100644 --- a/third_party/WebKit/Source/web/tests/sim/SimTest.h +++ b/third_party/WebKit/Source/web/tests/sim/SimTest.h
@@ -15,6 +15,7 @@ namespace blink { class WebViewImpl; +class WebLocalFrameImpl; class Document; class LocalDOMWindow; @@ -29,6 +30,7 @@ SimPage& page(); Document& document(); WebViewImpl& webView(); + WebLocalFrameImpl& mainFrame(); const SimWebViewClient& webViewClient() const; SimCompositor& compositor();
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn index 755e69f9..36b465af 100644 --- a/third_party/WebKit/public/BUILD.gn +++ b/third_party/WebKit/public/BUILD.gn
@@ -662,6 +662,7 @@ "platform/modules/serviceworker/service_worker_event_status.mojom", "platform/modules/shapedetection/barcodedetection.mojom", "platform/modules/shapedetection/facedetection.mojom", + "platform/modules/shapedetection/facedetection_provider.mojom", "platform/modules/websockets/websocket.mojom", "platform/referrer.mojom", "web/window_features.mojom",
diff --git a/third_party/WebKit/public/platform/WebDisplayItemList.h b/third_party/WebKit/public/platform/WebDisplayItemList.h index 0a46f5edd..138e38e3 100644 --- a/third_party/WebKit/public/platform/WebDisplayItemList.h +++ b/third_party/WebKit/public/platform/WebDisplayItemList.h
@@ -13,7 +13,6 @@ #include "WebVector.h" #include "third_party/skia/include/core/SkBlendMode.h" -#include "third_party/skia/include/core/SkClipOp.h" #include "third_party/skia/include/core/SkRefCnt.h" class SkColorFilter; @@ -47,7 +46,7 @@ virtual void appendClipItem(const WebRect& clipRect, const WebVector<SkRRect>& roundedClipRects) {} virtual void appendEndClipItem() {} - virtual void appendClipPathItem(const SkPath&, SkClipOp, bool antialias) {} + virtual void appendClipPathItem(const SkPath&, bool antialias) {} virtual void appendEndClipPathItem() {} virtual void appendFloatClipItem(const WebFloatRect& clipRect) {} virtual void appendEndFloatClipItem() {}
diff --git a/third_party/WebKit/public/platform/modules/shapedetection/barcodedetection.mojom b/third_party/WebKit/public/platform/modules/shapedetection/barcodedetection.mojom index eddeab5..b293b98 100644 --- a/third_party/WebKit/public/platform/modules/shapedetection/barcodedetection.mojom +++ b/third_party/WebKit/public/platform/modules/shapedetection/barcodedetection.mojom
@@ -20,5 +20,5 @@ // row-major order. // TODO(mcasas): Consider using mojo::Bitmap here, https://crbug.com/665488. Detect(handle<shared_buffer> frame_data, uint32 width, uint32 height) - => (array<BarcodeDetectionResult> results); + => (array<BarcodeDetectionResult> results); };
diff --git a/third_party/WebKit/public/platform/modules/shapedetection/facedetection.mojom b/third_party/WebKit/public/platform/modules/shapedetection/facedetection.mojom index a078b7ce..d661b3a 100644 --- a/third_party/WebKit/public/platform/modules/shapedetection/facedetection.mojom +++ b/third_party/WebKit/public/platform/modules/shapedetection/facedetection.mojom
@@ -24,7 +24,6 @@ // |frame_data| contains tightly packed image pixels in ARGB32 format, // row-major order. // TODO(mcasas): Consider using mojo::Bitmap here, https://crbug.com/665488. - Detect(handle<shared_buffer> frame_data, uint32 width, uint32 height, - FaceDetectorOptions options) + Detect(handle<shared_buffer> frame_data, uint32 width, uint32 height) => (FaceDetectionResult result); };
diff --git a/third_party/WebKit/public/platform/modules/shapedetection/facedetection_provider.mojom b/third_party/WebKit/public/platform/modules/shapedetection/facedetection_provider.mojom new file mode 100644 index 0000000..cab419e5 --- /dev/null +++ b/third_party/WebKit/public/platform/modules/shapedetection/facedetection_provider.mojom
@@ -0,0 +1,13 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://wicg.github.io/shape-detection-api/#api + +module blink.mojom; + +import "facedetection.mojom"; + +interface FaceDetectionProvider { + CreateFaceDetection(FaceDetection& request, FaceDetectorOptions options); +};
diff --git a/tools/boilerplate.py b/tools/boilerplate.py index b26493e..ada43a0 100755 --- a/tools/boilerplate.py +++ b/tools/boilerplate.py
@@ -61,13 +61,11 @@ return base def _CppImplementation(filename): - include = '#include "' + _RemoveTestSuffix(filename) + '.h"' - return '\n'.join(['', include]) + return '\n#include "' + _RemoveTestSuffix(filename) + '.h"\n' def _ObjCppImplementation(filename): - include = '#import "' + _RemoveTestSuffix(filename) + '.h"' - return '\n'.join(['', include]) + return '\n#import "' + _RemoveTestSuffix(filename) + '.h"\n' def _CreateFile(filename):
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index 6ab466f..cfe94cb 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -27,7 +27,7 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md # Reverting problematic clang rolls is safe, though. -CLANG_REVISION = '288545' +CLANG_REVISION = '289575' use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ if use_head_revision:
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 4fa4726..8a58680 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -38195,6 +38195,18 @@ </summary> </histogram> +<histogram name="NetworkTimeTracker.TimeBetweenFetches" units="ms"> + <owner>estark@chromium.org</owner> + <owner>mab@chromium.org</owner> + <summary> + NetworkTimeTracker makes periodic queries to obtain a secure timestamp over + the network. This histogram records the delta between each secure timestamp + and the previous one, to measure how often time queries are made. The first + time query is not recorded, because there is no previous query from which to + compute a delta. + </summary> +</histogram> + <histogram name="NetworkTimeTracker.TimeQueryLatency" units="ms"> <owner>estark@chromium.org</owner> <owner>mab@chromium.org</owner> @@ -83347,6 +83359,8 @@ <int value="355" label="Sets the maximum length of the lock screen PIN."/> <int value="356" label="Enables users to set weak PINs for the lock screen PIN."/> + <int value="357" + label="Enables domain admins to sets a device policy wallpaper."/> </enum> <enum name="EnterprisePolicyInvalidations" type="int"> @@ -85571,7 +85585,7 @@ <int value="10" label="kAppView"/> <int value="11" label="kAudio"/> <int value="12" label="kAudioCapture"/> - <int value="13" label="kAudioModem"/> + <int value="13" label="kDeleted_AudioModem"/> <int value="14" label="kAutofillPrivate"/> <int value="15" label="kAutomation"/> <int value="16" label="kAutoTestPrivate"/> @@ -85593,8 +85607,8 @@ <int value="32" label="kContentSettings"/> <int value="33" label="kContextMenus"/> <int value="34" label="kCookie"/> - <int value="35" label="kCopresence"/> - <int value="36" label="kCopresencePrivate"/> + <int value="35" label="kDeleted_Copresence"/> + <int value="36" label="kDeleted_CopresencePrivate"/> <int value="37" label="kCryptotokenPrivate"/> <int value="38" label="kDataReductionProxy"/> <int value="39" label="kDiagnostics"/> @@ -85759,6 +85773,7 @@ <int value="198" label="kResourcesPrivate"/> <int value="199" label="kDisplaySource"/> <int value="200" label="kClipboard"/> + <int value="201" label="kNetworkingOnc"/> </enum> <enum name="ExtensionServiceVerifyAllSuccess" type="int"> @@ -96754,6 +96769,8 @@ <int value="-1073741643" label="0xC00000B5 - STATUS_IO_TIMEOUT"/> <int value="-1073741630" label="0xC00000C2 - STATUS_ADAPTER_HARDWARE_ERROR"/> <int value="-1073741591" label="0xC00000E9 - STATUS_UNEXPECTED_IO_ERROR"/> + <int value="-1073741435" label="0xC0000185 - STATUS_IO_DEVICE_ERROR"/> + <int value="-1073740669" label="0xC0000483 - STATUS_DEVICE_HARDWARE_ERROR"/> <int value="-1073740023" label="0xC0000709 - STATUS_HARDWARE_MEMORY_ERROR"/> <int value="0" label="0x00000000 - STATUS_SUCCESS"/> </enum> @@ -105850,9 +105867,11 @@ <enum name="VariationsHeadersURLValidationResult" type="int"> <int value="0" label="Rejected: Invalid URL."/> - <int value="1" label="Rejected: Not https."/> + <int value="1" label="Rejected: Not https. (Deprecated)"/> <int value="2" label="Rejected: Not Google domain."/> <int value="3" label="Should append headers."/> + <int value="4" label="Rejected: Neither http, nor https."/> + <int value="5" label="Rejected: Is a Google domain, but not https."/> </enum> <enum name="VariationsPermanentConsistencyCountryResult" type="int"> @@ -113011,35 +113030,35 @@ <affected-histogram name="PasswordManager.TotalAccountsHiRes.WithScheme"/> </histogram_suffixes> -<histogram_suffixes name="PaymentRequestOutcome"> +<histogram_suffixes name="PaymentRequestOutcome" separator="."> <suffix name="Completed" label="The Payment Request was completed"/> <suffix name="UserAborted" label="The Payment Request was aborted by the user"/> <suffix name="OtherAborted" label="The Payment Request was aborted but not but the user"/> - <affected-histogram name="PaymentRequest.NumberOfSelectionAdds_ContactInfo"/> - <affected-histogram name="PaymentRequest.NumberOfSelectionAdds_CreditCards"/> + <affected-histogram name="PaymentRequest.NumberOfSelectionAdds.ContactInfo"/> + <affected-histogram name="PaymentRequest.NumberOfSelectionAdds.CreditCards"/> <affected-histogram - name="PaymentRequest.NumberOfSelectionAdds_ShippingAddress"/> + name="PaymentRequest.NumberOfSelectionAdds.ShippingAddress"/> <affected-histogram - name="PaymentRequest.NumberOfSelectionChanges_ContactInfo"/> + name="PaymentRequest.NumberOfSelectionChanges.ContactInfo"/> <affected-histogram - name="PaymentRequest.NumberOfSelectionChanges_CreditCards"/> + name="PaymentRequest.NumberOfSelectionChanges.CreditCards"/> <affected-histogram - name="PaymentRequest.NumberOfSelectionChanges_ShippingAddress"/> - <affected-histogram name="PaymentRequest.NumberOfSelectionEdits_ContactInfo"/> - <affected-histogram name="PaymentRequest.NumberOfSelectionEdits_CreditCards"/> + name="PaymentRequest.NumberOfSelectionChanges.ShippingAddress"/> + <affected-histogram name="PaymentRequest.NumberOfSelectionEdits.ContactInfo"/> + <affected-histogram name="PaymentRequest.NumberOfSelectionEdits.CreditCards"/> <affected-histogram - name="PaymentRequest.NumberOfSelectionEdits_ShippingAddress"/> + name="PaymentRequest.NumberOfSelectionEdits.ShippingAddress"/> <affected-histogram - name="PaymentRequest.NumberOfSuggestionsShown_ContactInfo"/> + name="PaymentRequest.NumberOfSuggestionsShown.ContactInfo"/> <affected-histogram - name="PaymentRequest.NumberOfSuggestionsShown_CreditCards"/> + name="PaymentRequest.NumberOfSuggestionsShown.CreditCards"/> <affected-histogram - name="PaymentRequest.NumberOfSuggestionsShown_ShippingAddress"/> + name="PaymentRequest.NumberOfSuggestionsShown.ShippingAddress"/> </histogram_suffixes> -<histogram_suffixes name="PaymentRequestSection"> +<histogram_suffixes name="PaymentRequestSection" separator="."> <suffix name="ContactInfo" label="For the contact info section of a Payment Request"/> <suffix name="CreditCards"
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn index a6e576b2..8914f3c 100644 --- a/tools/perf/chrome_telemetry_build/BUILD.gn +++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -85,57 +85,7 @@ data = [ "//tools/perf/chrome_telemetry_build/", - - # Breakdown the catapult directory so we can exclude - # third_party/catapult/tracing/test_data. See crbug.com/670284 - "//third_party/catapult/AUTHORS", - "//third_party/catapult/bin/", - "//third_party/catapult/catapult_build/", - "//third_party/catapult/codereview.settings", - "//third_party/catapult/common/", - "//third_party/catapult/CONTRIBUTING.md", - "//third_party/catapult/dashboard/", - "//third_party/catapult/dependency_manager/", - "//third_party/catapult/devil/", - "//third_party/catapult/docs/", - "//third_party/catapult/experimental/", - "//third_party/catapult/firefighter/", - "//third_party/catapult/hooks/", - "//third_party/catapult/infra/", - "//third_party/catapult/LICENSE", - "//third_party/catapult/navbar.md", - "//third_party/catapult/netlog_viewer/", - "//third_party/catapult/OWNERS", - "//third_party/catapult/PRESUBMIT.py", - "//third_party/catapult/pylintrc", - "//third_party/catapult/README.md", - "//third_party/catapult/systrace/", - "//third_party/catapult/telemetry/", - "//third_party/catapult/third_party/", - "//third_party/catapult/trace_processor/", - - # We don't want to include catapult/tracing/test_data - "//third_party/catapult/tracing/app.yaml", - "//third_party/catapult/tracing/bin/", - "//third_party/catapult/tracing/bower.json", - "//third_party/catapult/tracing/BUILD.gn", - "//third_party/catapult/tracing/docs/", - "//third_party/catapult/tracing/images/", - "//third_party/catapult/tracing/LICENSE", - "//third_party/catapult/tracing/OWNERS", - "//third_party/catapult/tracing/package.json", - "//third_party/catapult/tracing/PRESUBMIT.py", - "//third_party/catapult/tracing/README.md", - "//third_party/catapult/tracing/skp_data/", - "//third_party/catapult/tracing/third_party/", - "//third_party/catapult/tracing/trace_viewer.gyp", - "//third_party/catapult/tracing/trace_viewer.gypi", - "//third_party/catapult/tracing/tracing/", - "//third_party/catapult/tracing/tracing_build/", - "//third_party/catapult/tracing/tracing_examples/", - "//third_party/catapult/tracing/tracing_project.py", - "//third_party/catapult/WATCHLISTS", - + "//third_party/catapult/", "//components/crash/content/tools/generate_breakpad_symbols.py", ]
diff --git a/ui/accessibility/ax_tree_combiner.cc b/ui/accessibility/ax_tree_combiner.cc index 72a2e95b..b983e995 100644 --- a/ui/accessibility/ax_tree_combiner.cc +++ b/ui/accessibility/ax_tree_combiner.cc
@@ -168,12 +168,6 @@ } void AXTreeCombiner::ProcessTree(const AXTreeUpdate* tree) { - // The root of each tree may contain a transform that needs to apply - // to all of its descendants. - gfx::Transform old_transform = transform_; - if (!tree->nodes.empty() && tree->nodes[0].transform) - transform_.ConcatTransform(*tree->nodes[0].transform); - int32_t tree_id = tree->tree_data.tree_id; for (size_t i = 0; i < tree->nodes.size(); ++i) { AXNodeData node = tree->nodes[i]; @@ -186,9 +180,9 @@ for (size_t j = 0; j < node.child_ids.size(); ++j) node.child_ids[j] = MapId(tree_id, node.child_ids[j]); - // Reset the offset container ID because we make all bounding boxes - // absolute. - node.offset_container_id = -1; + // Map the container id. + if (node.offset_container_id > 0) + node.offset_container_id = MapId(tree_id, node.offset_container_id); // Map other int attributes that refer to node IDs, and remove the // AX_ATTR_CHILD_TREE_ID attribute. @@ -211,10 +205,6 @@ } } - // Apply the transformation to the object's bounds to put it in - // the coordinate space of the root frame. - transform_.TransformRect(&node.location); - // See if this node has a child tree. As a sanity check make sure the // child tree lists this tree as its parent tree id. const AXTreeUpdate* child_tree = nullptr; @@ -237,9 +227,6 @@ if (child_tree) ProcessTree(child_tree); } - - // Reset the transform. - transform_ = old_transform; } } // namespace ui
diff --git a/ui/accessibility/ax_tree_combiner.h b/ui/accessibility/ax_tree_combiner.h index 37b9fa56..ce8fbc7 100644 --- a/ui/accessibility/ax_tree_combiner.h +++ b/ui/accessibility/ax_tree_combiner.h
@@ -9,7 +9,6 @@ #include "ui/accessibility/ax_export.h" #include "ui/accessibility/ax_tree_update.h" -#include "ui/gfx/transform.h" namespace ui { @@ -19,8 +18,7 @@ // // Since node IDs are relative to each ID, it has to renumber all of the IDs // and update all of the attributes that reference IDs of other nodes to -// ensure they point to the right node. It also applies transformations to -// local bounding rectangles to make them global. +// ensure they point to the right node. // // It also makes sure the final combined tree points to the correct focused // node across all of the trees based on the focused tree ID of the root tree. @@ -45,7 +43,6 @@ std::map<int32_t, const AXTreeUpdate*> tree_id_map_; std::map<std::pair<int32_t, int32_t>, int32_t> tree_id_node_id_map_; AXTreeUpdate combined_; - gfx::Transform transform_; };
diff --git a/ui/accessibility/ax_tree_combiner_unittest.cc b/ui/accessibility/ax_tree_combiner_unittest.cc index 49fbccc..b80771d 100644 --- a/ui/accessibility/ax_tree_combiner_unittest.cc +++ b/ui/accessibility/ax_tree_combiner_unittest.cc
@@ -149,57 +149,6 @@ AX_ATTR_UNIQUE_CELL_IDS)[0]); } -TEST(CombineAXTreesTest, Coordinates) { - AXTreeUpdate parent_tree; - parent_tree.has_tree_data = true; - parent_tree.tree_data.tree_id = 1; - parent_tree.root_id = 1; - parent_tree.nodes.resize(3); - parent_tree.nodes[0].id = 1; - parent_tree.nodes[0].child_ids.push_back(2); - parent_tree.nodes[0].child_ids.push_back(3); - parent_tree.nodes[1].id = 2; - parent_tree.nodes[1].role = AX_ROLE_BUTTON; - parent_tree.nodes[1].location = gfx::RectF(50, 10, 200, 100); - parent_tree.nodes[2].id = 3; - parent_tree.nodes[2].role = AX_ROLE_IFRAME; - parent_tree.nodes[2].AddIntAttribute(AX_ATTR_CHILD_TREE_ID, 2); - - AXTreeUpdate child_tree; - child_tree.has_tree_data = true; - child_tree.tree_data.parent_tree_id = 1; - child_tree.tree_data.tree_id = 2; - child_tree.root_id = 1; - child_tree.nodes.resize(2); - child_tree.nodes[0].id = 1; - child_tree.nodes[0].child_ids.push_back(2); - - child_tree.nodes[0].transform.reset(new gfx::Transform()); - child_tree.nodes[0].transform->Translate(0, 300); - child_tree.nodes[0].transform->Scale(2.0, 2.0); - - child_tree.nodes[1].id = 2; - child_tree.nodes[1].role = AX_ROLE_BUTTON; - child_tree.nodes[1].location = gfx::RectF(50, 10, 200, 100); - - AXTreeCombiner combiner; - combiner.AddTree(parent_tree, true); - combiner.AddTree(child_tree, false); - combiner.Combine(); - - const AXTreeUpdate& combined = combiner.combined(); - - ASSERT_EQ(5U, combined.nodes.size()); - EXPECT_EQ(50, combined.nodes[1].location.x()); - EXPECT_EQ(10, combined.nodes[1].location.y()); - EXPECT_EQ(200, combined.nodes[1].location.width()); - EXPECT_EQ(100, combined.nodes[1].location.height()); - EXPECT_EQ(100, combined.nodes[4].location.x()); - EXPECT_EQ(320, combined.nodes[4].location.y()); - EXPECT_EQ(400, combined.nodes[4].location.width()); - EXPECT_EQ(200, combined.nodes[4].location.height()); -} - TEST(CombineAXTreesTest, FocusedTree) { AXTreeUpdate parent_tree; parent_tree.has_tree_data = true;
diff --git a/ui/compositor/clip_recorder.cc b/ui/compositor/clip_recorder.cc index 7e4e3145..f04632b 100644 --- a/ui/compositor/clip_recorder.cc +++ b/ui/compositor/clip_recorder.cc
@@ -49,14 +49,14 @@ void ClipRecorder::ClipPath(const gfx::Path& clip_path) { bool antialias = false; context_.list_->CreateAndAppendPairedBeginItem<cc::ClipPathDisplayItem>( - clip_path, SkClipOp::kIntersect, antialias); + clip_path, antialias); RecordCloser(CLIP_PATH); } void ClipRecorder::ClipPathWithAntiAliasing(const gfx::Path& clip_path) { bool antialias = true; context_.list_->CreateAndAppendPairedBeginItem<cc::ClipPathDisplayItem>( - clip_path, SkClipOp::kIntersect, antialias); + clip_path, antialias); RecordCloser(CLIP_PATH); }